Compare commits

...

84 Commits

Author SHA1 Message Date
Joseph Wynn dda6d748c8
1.6.0 2021-02-24 12:37:30 +13:00
Joseph Wynn a31c454ed1
Merge pull request #103 from salomvary/master
Add registers.site to context when rendering template
2021-02-24 12:29:45 +13:00
Joseph Wynn f2be2c53be
1.5.5 2021-01-25 17:10:01 +13:00
Joseph Wynn 6cc3a082a1
Automatically convert tabbed indentation to spaces 2021-01-25 17:10:00 +13:00
Joseph Wynn 2f7c0124eb
1.5.4 2021-01-25 17:10:00 +13:00
Márton Salomváry 25c6695da4 Add registers.site to context when rendering template
Fixes #101.
2021-01-01 14:07:03 +01:00
Joseph Wynn 7679f4b8f5
Merge pull request #100 from danielpietzsch/improveRegeneratePerformance
Improving build performance when a lot of images have already been resized before
2020-12-15 14:37:15 +13:00
Daniel Pietzsch 82e868966c Making sure full image is loaded when auto_rotate config option is used
because then we need the full image right at the start – as before – and 
there's no need to load "properties only" first, to then load the full 
image right after.
2020-11-08 21:43:29 +01:00
Daniel Pietzsch fbc35b8ef9 Loading full images when auto_rotate option is turned on.
Because we need the full image for the auto rotation
2020-11-07 23:30:23 +01:00
Daniel Pietzsch 749e6cc068 By default, loading images using .ping instead of .read
This gives an increase in performance and reduces memory usage when a 
lot of resized images already exist. Because this now by default loads 
only images meta data – omitting pixel data.

Pixel data is only loaded when an images actually needs resized versions 
generated.
2020-11-07 23:05:27 +01:00
Joseph Wynn fa00c4c9cf
Update README.md 2020-07-17 12:33:00 +12:00
Joseph Wynn 4b75f67558
Make it clear that the plugin does nothing without a `sizes` config 2020-07-17 12:31:13 +12:00
Joseph Wynn 307f3c6284
Merge branch 'fishpercolator-master' 2020-01-17 10:07:47 +13:00
Quinn f3103be702
More permissive rmagick dep 2019-12-23 14:09:04 +00:00
Joseph Wynn 5715734bde
Only test on modern versions of Ruby 2019-09-05 14:58:53 +12:00
Joseph Wynn 8cb3c53dd7
1.5.3 2019-09-05 14:46:26 +12:00
Joseph Wynn 16ab99deac
Works with Jekyll 4 2019-09-05 14:45:41 +12:00
Joseph Wynn 91a540c266
Warn when image doesn't exist instead of throwing SyntaxError 2019-09-05 14:45:32 +12:00
Joseph Wynn 48c36e75b9
Upgrade cucumber to 3.1 2019-09-05 14:45:10 +12:00
Joseph Wynn 9d6f549855
Update stale.yml 2019-06-06 15:20:20 +12:00
Joseph Wynn 4d90cd177e
Add probot-stale 2019-06-06 13:36:27 +12:00
Joseph Wynn 3d7f0e609b
Merge pull request #80 from arnog/patch-1
Incompatibility with ImageMagick 7
2019-02-04 14:37:42 +13:00
Joseph Wynn 6444d327de
Create a "Troubleshooting" section 2019-02-04 14:36:44 +13:00
Arno Gourdol b9791014de
Incompatibility with ImageMagick 7
Added note and workaround about incompatibility with ImageMagick 7
2019-01-30 10:03:32 -08:00
Joseph Wynn 6d323718cf
wow what year is it 2018-08-25 12:11:30 +12:00
Joseph Wynn 0153b9fb9e
Update default templates 2018-08-23 16:04:11 +12:00
Joseph Wynn 6533035416
Merge pull request #75 from danielpietzsch/contributing
Adding information to README on how to set up the repository for development
2018-08-23 14:27:57 +12:00
Daniel Pietzsch 855c3a70e4 adding information to readme on how to set up the repository for development 2018-08-22 22:20:37 +02:00
Joseph Wynn bc61757f2a
Merge pull request #73 from kenman345/patch-1
Update README.md
2018-07-12 09:07:56 +12:00
Ken Salomon 38e3b1f92f
Update README.md 2018-07-10 09:37:05 -04:00
Joseph Wynn 3cf3bc7be3
Move sample templates into sample-templates/ directory; update README 2018-07-02 14:22:37 +12:00
Joseph Wynn d902ec743d
Remove Gemnasium badge from README 2018-07-02 13:47:36 +12:00
Joseph Wynn c559bcced3
Usability: Don't raise an exception when config is missing or invalid 2018-06-30 19:39:58 -07:00
Joseph Wynn b76e2d3365
Docs: Clarify that a responsive_image config block is required 2018-06-29 23:57:20 -07:00
Joseph Wynn 1df929e20d
Bump version to 1.5.1 2018-06-20 13:14:07 -07:00
Joseph Wynn 7a3dbf1ab9
Merge pull request #71 from decipher-media/master
Add condition to extra image generation to only operate on 'files' re…
2018-06-21 08:13:07 +12:00
Christopher Peterson ac86fb2440 Add feature test for recursive glob in extra-image generation 2018-06-18 12:37:24 -04:00
Christopher Peterson aaaabbc2c0 Add condition to extra image generation to only operate on 'files' returned by the glob 2018-06-12 09:49:24 -04:00
Joseph Wynn 311f434ed7 Bump version to 1.5.0 2018-01-23 15:07:14 +13:00
Joseph Wynn b628a11925
Merge pull request #68 from driehuis/master
Add option to strip EXIF profiles
2018-01-23 15:05:17 +13:00
Bert Driehuis cafec3c926 Add feature tests for EXIF strip 2018-01-19 02:13:21 +01:00
Bert Driehuis 826b5f715e Add option to strip EXIF profiles 2018-01-19 01:08:35 +01:00
Joseph Wynn c9da267bee Merge pull request #67 from wildlyinaccurate/enable-caching-in-config-yml
Enable "cache" option in _config.yml
2017-07-16 21:59:15 +01:00
Joseph Wynn aba1d58246 Enable "cache" option in _config.yml
Fixes #66
2017-07-16 21:22:24 +01:00
Joseph Wynn b1ac375f60 1.3.1 2017-07-01 15:08:28 +01:00
Joseph Wynn bd52112bae 1.3.0 2017-06-21 19:48:27 +01:00
Joseph Wynn 66b0f3fce9 Merge pull request #65 from wildlyinaccurate/jericbryledy-master
Add save_to_source option
2017-06-21 19:44:27 +01:00
Joseph Wynn e334930825 Update tests to be more descriptive; reduce test cases
I've updated the `Scenario` for these to be more descriptive about what they're actually testing. I've also removed some redundant test cases (I think it's enough to test this with just one image) and used the Given-When-Then format to improve readability.
2017-06-21 19:34:18 +01:00
Jeric Bryle Sy Dy 2ad615952e added test to save_to_source 2017-06-20 17:22:40 +08:00
Jeric Bryle Sy Dy 93bb666bff option to directly save resized images to destination directory (#49) 2017-06-20 16:55:58 +08:00
Joseph Wynn 893486fb45 Tidy up unused test cruft 2017-04-05 13:56:07 +01:00
Joseph Wynn 3e4fac4132 Merge pull request #55 from wildlyinaccurate/jameswood-exif-rotate
Rotate resized images based on EXIF data
2017-03-13 08:45:27 +00:00
Joseph Wynn a23bdf5895 Fix auto_rotate name in Jekyll::ResponsiveImage::Config#DEFAULTS 2017-03-13 08:41:37 +00:00
Joseph Wynn 98a3b143af Merge pull request #56 from wildlyinaccurate/update-dependencies
Update dependencies and run tests on latest Rubies
2017-03-12 15:05:06 +00:00
Joseph Wynn b16abdc43c Update dependencies and run tests on latest Rubies 2017-03-12 14:59:25 +00:00
Joseph Wynn 7ad3967c71 Minor version bump for new functionality 2017-03-12 14:16:20 +00:00
Joseph Wynn 73bd82d547 Write tests for auto_rotate option 2017-03-12 14:14:53 +00:00
Joseph Wynn ffc51f648b Rename auto rotate option to auto_rotate 2017-03-12 14:14:45 +00:00
jameswood db264444ac rotate resized images based on exif info
EXIF rotation information embedded by the capture device is now
respected when generating output images. Original images remain
untouched.
2017-03-10 16:03:03 +11:00
Joseph Wynn 0c342075c7 Set the linguist-vendored attribute on features/test-site/*
This prevents Linguist from including the directory in the GitHub language stats
2017-01-09 11:37:19 +13:00
Joseph Wynn 00ded027ad Tidy up tests 2016-12-29 22:19:48 +13:00
Joseph Wynn 85b56541fb Merge pull request #44 from wildlyinaccurate/remove-redundant-tests
Remove redundant tests
2016-12-29 22:08:24 +13:00
Joseph Wynn 746205e726 Consolidate some tests to reduce the test:code ratio 2016-12-29 22:04:49 +13:00
Joseph Wynn ba3db6eba7 Use SimpleCov directly so that coverage can be inspected locally 2016-12-29 22:00:36 +13:00
Joseph Wynn fd041dc44a 1.1.0 2016-12-28 23:19:25 +13:00
Joseph Wynn c8eb8c0c58 Merge pull request #42 from wildlyinaccurate/maintain-source-interlace
Maintain source image interlace mode
2016-12-28 23:18:58 +13:00
Joseph Wynn c2e3465a7e Fix `rake release` 2016-12-28 23:16:20 +13:00
Joseph Wynn 8fa0543494 Maintain source image interlace mode 2016-12-28 23:14:13 +13:00
Joseph Wynn 804d30dbb5 Merge pull request #41 from wildlyinaccurate/rename-gem
Rename gem to jekyll-responsive-image
2016-12-28 23:13:01 +13:00
Joseph Wynn d7451d2681 Typo 2016-12-28 22:58:04 +13:00
Joseph Wynn 03356da52d Rename gem to jekyll-responsive-image
This PR also drops support for Ruby <2.0
2016-12-28 22:56:27 +13:00
Joseph Wynn 8d962b2631 Merge pull request #39 from wildlyinaccurate/clean-up-tests
Remove some redundant test code
2016-10-18 22:13:44 +01:00
Joseph Wynn 39ee353912 Remove some redundant test code 2016-10-18 22:11:06 +01:00
Joseph Wynn dba32db868 v1.0.1 2016-10-16 18:08:07 +01:00
Joseph Wynn 9a4f6dc9d0 1.0.0 2016-10-14 21:21:20 +01:00
Joseph Wynn 1d7273ec5a Merge pull request #36 from wildlyinaccurate/source-directory-take-2
Take 2 of "treat paths as relative to Jekyll `source` directory"
2016-10-14 21:18:45 +01:00
Joseph Wynn 854aa4cf00 pre4 2016-10-11 23:25:43 +01:00
Joseph Wynn 0d3f099057 Fix for using a custom `source` directory
Paths are still passed around as relative. Code which needs to read files
(images, templates) and code which needs to manipulate paths
(Jekyll::ResponsiveImage::Utils#image_hash) has to be aware of the site source
path.

This got a bit messy in the end, but I couldn't find a better way without doing
a big refactor of the entire plugin.
2016-10-11 23:25:43 +01:00
Joseph Wynn 83358e79b5 Resize handler tweaks 2016-10-11 23:25:43 +01:00
Joseph Wynn 4de5db835d Refactor to config class 2016-10-11 23:25:43 +01:00
Joseph Wynn 6d569710b9 More test improvements 2016-10-11 23:25:43 +01:00
Joseph Wynn b47f12a1db An actual failing test now 2016-10-11 23:25:43 +01:00
Joseph Wynn 354f693afc Another refactor to try and avoid `include` 2016-10-11 23:25:43 +01:00
Joseph Wynn a1a183c3d4 More Ruby 1.9 fixes (#37)
* Pin terminal-ansicolor to 1.3.0

* Pin mime-types to <3

* Pin rest-client to <2

* Pin tins to 1.6.0
2016-10-11 23:25:33 +01:00
47 changed files with 843 additions and 451 deletions

1
.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
features/test-site/* linguist-vendored

10
.github/stale.yml vendored Normal file
View 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

View File

@ -1,10 +1,12 @@
sudo: false
dist: trusty
language: ruby
bundler_args: --without debug
before_script: bundle exec jekyll --version
script: bundle exec rake features_with_coveralls
rvm:
- 2.2
- 2.1
- 2.0
- 1.9
- '2.6'
- '2.5'
- '2.4'
- '2.3'
- '2.2'

10
Gemfile
View File

@ -1,14 +1,12 @@
source 'https://rubygems.org/'
gemspec
group :development do
gem 'rake'
gem 'cucumber', '~> 2.1'
gem 'test-unit', '~> 3.1'
gem 'cucumber', '~> 3.1'
gem 'test-unit', '~> 3.2'
gem 'simplecov', :require => false
gem 'coveralls', :require => false
platform :ruby_18, :ruby_19 do
gem 'simplecov', '>= 0.10', '< 0.12'
end
end

View File

@ -1,6 +1,6 @@
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
of this software and associated documentation files (the "Software"), to deal

286
README.md
View File

@ -1,80 +1,53 @@
# Jekyll Responsive Images
# jekyll-responsive-image
Jekyll Responsive Images is 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/).
[![Build Status](https://img.shields.io/travis/wildlyinaccurate/jekyll-responsive-image.svg?style=flat-square)](https://travis-ci.org/wildlyinaccurate/jekyll-responsive-image)
[![Coverage Status](https://img.shields.io/coveralls/wildlyinaccurate/jekyll-responsive-image.svg?style=flat-square)](https://coveralls.io/repos/github/wildlyinaccurate/jekyll-responsive-image/badge.svg?branch=master)
[![Dependency Status](https://img.shields.io/gemnasium/wildlyinaccurate/jekyll-responsive-images.svg?style=flat-square)](https://gemnasium.com/wildlyinaccurate/jekyll-responsive-images)
## 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
gems: [jekyll/responsive_image]
plugins:
- 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:
# [Required]
# Path to the image template.
template: _includes/responsive-image.html
# [Optional, Default: 85]
# Quality to use when resizing images.
default_quality: 90
# [Optional, Default: []]
# An array of resize configuration objects. Each object must contain at least
# a `width` value.
sizes:
- width: 480 # [Required] How wide the resized image will be.
quality: 80 # [Optional] Overrides default_quality for this size.
- width: 320
- width: 480
- width: 800
- 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)
# %{width} Width of the resized image
# %{height} Height of the resized image
#
output_path_format: assets/resized/%{width}/%{basename}
# [Optional, Default: []]
# By default, only images referenced by the responsive_image and responsive_image_block
# tags are resized. Here you can set a list of paths or path globs to resize other
# images. This is useful for resizing images which will be referenced from stylesheets.
extra_images:
- assets/foo/bar.png
- assets/bgs/*.png
- assets/avatars/*.{jpeg,jpg}
```
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.
@ -106,73 +79,34 @@ You can use Liquid variables as attributes with the `responsive_image_block` tag
{% assign alt = 'Lorem ipsum...' %}
{% responsive_image_block %}
path: {{ path }}
alt: {{ alt }}
{% if title %}
title: {{ title }}
{% endif %}
path: {{ path }}
alt: {{ alt }}
{% if title %}
title: {{ title }}
{% endif %}
{% endresponsive_image_block %}
```
### Template
## Templates
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 }} /{{ original.path }} {{ original.width }}w">
```
#### 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>
```
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 | 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. |
| 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
@ -187,3 +121,135 @@ Image objects (like `original` and each object in `resized`) contain the followi
| `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
responsive_image:
# [Required]
# Path to the image template.
template: _includes/responsive-image.html
# [Optional, Default: 85]
# Quality to use when resizing images.
default_quality: 90
# [Optional, Default: []]
# An array of resize configuration objects. Each object must contain at least
# a `width` value.
sizes:
- width: 480 # [Required] How wide the resized image will be.
quality: 80 # [Optional] Overrides default_quality for this size.
- width: 800
- width: 1400
quality: 90
# [Optional, Default: false]
# Rotate resized images depending on their EXIF rotation attribute. Useful for
# working with JPGs directly from digital cameras and smartphones
auto_rotate: false
# [Optional, Default: false]
# Strip EXIF and other JPEG profiles. Helps to minimize JPEG size and win friends
# at Google PageSpeed.
strip: false
# [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)
# %{width} Width of the resized image
# %{height} Height of the resized image
#
output_path_format: assets/resized/%{width}/%{basename}
# [Optional, Default: true]
# Whether or not to save the generated assets into the source folder.
save_to_source: false
# [Optional, Default: false]
# Cache the result of {% responsive_image %} and {% responsive_image_block %}
# tags. See the "Caching" section of the README for more information.
cache: false
# [Optional, Default: []]
# By default, only images referenced by the responsive_image and responsive_image_block
# tags are resized. Here you can set a list of paths or path globs to resize other
# images. This is useful for resizing images which will be referenced from stylesheets.
extra_images:
- assets/foo/bar.png
- assets/bgs/*.png
- assets/avatars/*.{jpeg,jpg}
```
## Troubleshooting
### Error: Can't install RMagick
`jekyll-responsive-image` uses `rmagick` which is currently incompatible with ImageMagick 7. If you get an error like:
```
Can't install RMagick 2.16.0. Can't find MagickWand.h
```
Then you will need to install ImageMagick 6. If you are using Homebrew on Mac OS, this can be done with the following commands:
```
$ brew uninstall imagemagick
$ brew install imagemagick@6 && brew link imagemagick@6 --force
```
## 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.
The recommended way to enable caching is on an image-by-image basis, by adding `cache: true` to the tag:
```twig
{% responsive_image path: 'assets/my-file.jpg' cache: true %}
{% responsive_image_block %}
path: assets/my-file.jpg
cache: true
{% endresponsive_image_block %}
```
You can also enable it for all images by adding `cache: true` to your `_config.yml`:
```yaml
responsive_image:
cache: true
template: _includes/responsive-image.html
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.

View File

@ -9,7 +9,7 @@ rescue Bundler::BundlerError => e
end
require 'rake'
require 'jekyll/responsive_image/version'
require 'jekyll-responsive-image/version'
require 'cucumber/rake/task'
require 'coveralls/rake/task'
@ -21,8 +21,8 @@ task :features_with_coveralls => [:features, 'coveralls:push']
task :default => [:features]
task :release do |t|
system "gem build jekyll-responsive_image.gemspec"
system "git tag v#{Jekyll::ResponsiveImage::VERSION} -a -m 'Tagged release of jekyll-responsive_image-#{Jekyll::ResponsiveImage::VERSION}.gem'"
system "gem build jekyll-responsive-image.gemspec"
system "git tag v#{Jekyll::ResponsiveImage::VERSION} -a -m 'Tagged release of jekyll-responsive-image-#{Jekyll::ResponsiveImage::VERSION}.gem'"
system "git push --tags"
system "gem push jekyll-responsive_image-#{Jekyll::ResponsiveImage::VERSION}.gem"
system "gem push jekyll-responsive-image-#{Jekyll::ResponsiveImage::VERSION}.gem"
end

File diff suppressed because one or more lines are too long

View File

@ -1,35 +1,38 @@
Feature: Extra image generation
As a Jekyll user
I want to resize images that aren't used in posts or pages
In order to use them in my stylesheets
Scenario: Resizing a single image
Scenario: Specifying a single image and glob patterns
Given I have a responsive_image configuration with:
"""
sizes:
- width: 100
extra_images:
- assets/everybody-loves-jalapeño-pineapple-cornbread.png
- assets/*.jpeg
"""
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/progressive-100x50.jpeg" 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/progressive-100x50.jpeg" should exist
Scenario: Using glob patterns
Scenario: Specifying a recursive glob pattern
Given I have a responsive_image configuration with:
"""
sizes:
- width: 100
extra_images:
- assets/*.png
- 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
Given I have copied my site to "sub-dir/my-site-copy"
@ -42,19 +45,8 @@ Feature: Extra image generation
extra_images:
- assets/*.png
"""
And I have a file "index.html" with "Hello, world!"
When I run Jekyll
Then the image "sub-dir/my-site-copy/assets/resized/everybody-loves-jalapeño-pineapple-cornbread-100x50.png" should have the dimensions "100x50"
And the file "_site/assets/resized/everybody-loves-jalapeño-pineapple-cornbread-100x50.png" should exist
Scenario: No extra images
Given I have a responsive_image configuration with:
"""
sizes:
- width: 100
"""
And I have a file "index.html" with "Hello, world!"
When I run Jekyll
Then the file "assets/resized/everybody-loves-jalapeño-pineapple-cornbread-100x50.png" should not exist
And the file "_site/assets/resized/progressive-100x50.jpeg" should not exist

View File

@ -1,8 +1,4 @@
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:
"""
@ -10,7 +6,6 @@ Feature: Responsive image generation
sizes:
- width: 100
"""
And I have a file "index.html" with "{% responsive_image path: assets/everybody-loves-jalapeño-pineapple-cornbread.png alt: Foobar %}"
When I run Jekyll
Then the image "assets/resized/everybody-loves-jalapeño-pineapple-cornbread-100x50.png" should have the dimensions "100x50"
@ -24,31 +19,101 @@ Feature: Responsive image generation
sizes:
- width: 100
"""
And I have a file "index.html" with:
"""
{% responsive_image path: assets/everybody-loves-jalapeño-pineapple-cornbread.png %}
{% responsive_image path: assets/subdir/test.png %}
{% responsive_image path: assets/everybody-loves-jalapeño-pineapple-cornbread.png cache: true %}
"""
When I run Jekyll
Then the file "assets/resized/everybody-loves-jalapeño-pineapple-cornbread-100.png" should exist
And the file "_site/assets/resized/everybody-loves-jalapeño-pineapple-cornbread-100.png" should exist
And the file "assets/resized/subdir/test-100.png" should exist
And the file "_site/assets/resized/subdir/test-100.png" should exist
Scenario: Honouring source image interlace mode
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/progressive.jpeg %}"
When I run Jekyll
Then the image "assets/resized/progressive-100x50.jpeg" should be interlaced
Scenario: Honouring Jekyll 'source' configuration
Given I have copied my site to "sub-dir/my-site-copy"
Given I have copied my site to "my-site-copy/src"
And I have a configuration with:
"""
source: sub-dir/my-site-copy
source: my-site-copy/src
responsive_image:
base_path: assets
template: _includes/responsive-image.html
output_path_format: assets/resized/%{dirname}/%{width}/%{basename}
sizes:
- width: 100
"""
And I have a file "sub-dir/my-site-copy/index.html" with "{% responsive_image path: assets/everybody-loves-jalapeño-pineapple-cornbread.png %}"
And I have a file "my-site-copy/src/index.html" with "{% responsive_image path: assets/subdir/test.png %}"
When I run Jekyll
Then the image "sub-dir/my-site-copy/assets/resized/everybody-loves-jalapeño-pineapple-cornbread-100x50.png" should have the dimensions "100x50"
And the file "_site/assets/resized/everybody-loves-jalapeño-pineapple-cornbread-100x50.png" should exist
Then the image "my-site-copy/src/assets/resized/subdir/100/test.png" should have the dimensions "100x50"
And the file "_site/assets/resized/subdir/100/test.png" should exist
Scenario: Images can be auto-rotated based on EXIF rotation
Given I have a responsive_image configuration with:
"""
template: _includes/responsive-image.html
sizes:
- width: 100
auto_rotate: true
"""
And I have a file "index.html" with "{% responsive_image path: assets/exif-rotation.jpeg %}"
When I run Jekyll
Then the file "_site/assets/resized/exif-rotation-100x200.jpeg" should exist
Scenario: Images aren't auto-rotated by default
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/exif-rotation.jpeg %}
{% responsive_image path: assets/progressive.jpeg %}
"""
When I run Jekyll
Then the file "_site/assets/resized/exif-rotation-100x50.jpeg" should exist
Then the file "_site/assets/resized/progressive-100x50.jpeg" should exist
Scenario: Images should not be stripped of EXIF info by default
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/exif-rotation.jpeg %}
"""
When I run Jekyll
Then the file "_site/assets/resized/exif-rotation-100x50.jpeg" should exist
Then the image "_site/assets/resized/exif-rotation-100x50.jpeg" should have an EXIF orientation
Scenario: Images can be stripped of EXIF info
Given I have a responsive_image configuration with:
"""
template: _includes/responsive-image.html
sizes:
- width: 100
strip: true
"""
And I have a file "index.html" with:
"""
{% responsive_image path: assets/exif-rotation.jpeg %}
"""
When I run Jekyll
Then the file "_site/assets/resized/exif-rotation-100x50.jpeg" should exist
Then the image "_site/assets/resized/exif-rotation-100x50.jpeg" should have no EXIF orientation

View File

@ -0,0 +1,32 @@
Feature: Image hashes inside responsive image templates
Scenario: Using the {% responsive_image %} tag
Given I have copied my site to "my-site-copy/src"
And I have a configuration with:
"""
source: my-site-copy/src
responsive_image:
template: _includes/hash.html
output_path_format: assets/resized/%{dirname}/%{width}/%{basename}
sizes:
- width: 100
"""
And I have a file "my-site-copy/src/index.html" with "{% responsive_image path: assets/subdir/test.png %}"
When I run Jekyll
Then the file "_site/index.html" should contain:
"""
path: assets/subdir/test.png
width: 300
height: 150
basename: test.png
dirname: subdir
filename: test
extension: png
path: assets/resized/subdir/100/test.png
width: 100
height: 50
basename: test.png
dirname: resized/subdir/100
filename: test
extension: png
"""

12
features/plugin.feature Normal file
View 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

View File

@ -1,19 +1,27 @@
Feature: Jekyll responsive_image_block tag
As a Jekyll template developer
I want to include Liquid variables when rendering my responsive images
In order to dynamically generate my responsive images
Scenario: Simple image tag
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' %}
{% assign alt = 'Lorem ipsum' %}
{% responsive_image_block %}
path: {{ path }}
title: Magic rainbow adventure!
alt: {{ alt }}
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: 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
@ -41,7 +49,6 @@ Feature: Jekyll responsive_image_block tag
"""
{% assign path = 'assets/everybody-loves-jalapeño-pineapple-cornbread.png' %}
{% assign alt = 'Lorem ipsum' %}
{% responsive_image_block %}
path: {{ path }}
@ -63,4 +70,4 @@ Feature: Jekyll responsive_image_block tag
path: {{ path }}
{% endresponsive_image_block %}
"""
Then Jekyll should throw a "SyntaxError"
Then Jekyll should throw a "Magick::ImageMagickError"

View File

@ -1,8 +1,4 @@
Feature: Jekyll responsive_image tag
As a Jekyll template developer
I want to include responsive images in my page
In order to best cater for devices of all sizes
Scenario: Simple image tag
Given I have a responsive_image configuration with "template" set to "_includes/responsive-image.html"
And I have a file "index.html" with "{% responsive_image path: assets/everybody-loves-jalapeño-pineapple-cornbread.png alt: Foobar %}"
@ -22,10 +18,7 @@ Feature: Jekyll responsive_image tag
Scenario: Adding custom attributes
Given I have a responsive_image configuration with "template" set to "_includes/responsive-image.html"
And I have a file "index.html" with:
"""
{% responsive_image path: assets/everybody-loves-jalapeño-pineapple-cornbread.png alt: 'Foobar bazbar' title: "Lorem Ipsum" %}
"""
And I have a file "index.html" with "{% responsive_image path: assets/everybody-loves-jalapeño-pineapple-cornbread.png alt: 'Foobar bazbar' title: 'Lorem Ipsum' %}"
When I run Jekyll
Then I should see "<img alt=\"Foobar bazbar\" src=\"/assets/everybody-loves-jalapeño-pineapple-cornbread.png\" title=\"Lorem Ipsum\"" in "_site/index.html"
@ -48,9 +41,6 @@ Feature: Jekyll responsive_image tag
Then I should see "<img alt=\"\" src=\"/assets/subdir/test.png\"" in "_site/index.html"
And I should see "/assets/resized/test-100x50.png 100w,/assets/resized/test-200x100.png 200w,/assets/subdir/test.png 300w" in "_site/index.html"
And the file "assets/resized/test-100x50.png" should exist
And the file "assets/resized/test-200x100.png" should exist
Scenario: Overriding the template
Given I have a responsive_image configuration with:
"""
@ -58,11 +48,10 @@ Feature: Jekyll responsive_image tag
sizes:
- width: 50
- width: 100
- width: 150
"""
And I have a file "index.html" with "{% responsive_image path: assets/everybody-loves-jalapeño-pineapple-cornbread.png template: _includes/custom-template.html %}"
When I run Jekyll
Then I should see "[50, 100, 150]" in "_site/index.html"
Then I should see "[50, 100]" in "_site/index.html"
Scenario: Overriding the generated filenames
Given I have a responsive_image configuration with:
@ -75,5 +64,3 @@ Feature: Jekyll responsive_image tag
And I have a file "index.html" with "{% responsive_image path: assets/everybody-loves-jalapeño-pineapple-cornbread.png %}"
When I run Jekyll
Then I should see "/assets/everybody-loves-jalapeño-pineapple-cornbread.png-resized/100/everybody-loves-jalapeño-pineapple-cornbread-50.png 100w" in "_site/index.html"
And the file "assets/everybody-loves-jalapeño-pineapple-cornbread.png-resized/100/everybody-loves-jalapeño-pineapple-cornbread-50.png" should exist
And the file "_site/assets/everybody-loves-jalapeño-pineapple-cornbread.png-resized/100/everybody-loves-jalapeño-pineapple-cornbread-50.png" should exist

View File

@ -0,0 +1,28 @@
Feature: Save to source
Scenario: Resized images are saved to the source directory by default
Given I have a responsive_image configuration with:
"""
sizes:
- width: 100
extra_images:
- assets/everybody-loves-jalapeño-pineapple-cornbread.png
"""
And I have a file "index.html" with "Hello, world!"
When I run Jekyll
Then the file "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
Scenario: Resized images can be saved to the destination directory only with save_to_source: false
Given I have a responsive_image configuration with:
"""
save_to_source: false
sizes:
- width: 100
extra_images:
- assets/everybody-loves-jalapeño-pineapple-cornbread.png
- assets/*.jpeg
"""
And I have a file "index.html" with "Hello, world!"
When I run Jekyll
Then the file "assets/resized/everybody-loves-jalapeño-pineapple-cornbread-100x50.png" should not exist
But the file "_site/assets/resized/everybody-loves-jalapeño-pineapple-cornbread-100x50.png" should exist

View File

@ -1,5 +1,3 @@
include Test::Unit::Assertions
When /^I run Jekyll$/ do
run_jekyll
end
@ -8,6 +6,10 @@ Then /^Jekyll should throw a "(.+)"$/ do |error_class|
assert_raise(Object.const_get(error_class)) { run_jekyll }
end
Then /^there should be no errors$/ do
# Implicit pass
end
Given /^I have copied my site to "(.+)"$/ do |path|
new_site_dir = File.join(TEST_DIR, path)
@ -18,6 +20,10 @@ Given /^I have copied my site to "(.+)"$/ do |path|
.each { |f| FileUtils.mv(f, new_site_dir) }
end
Given /^I have no configuration$/ do
write_file('_config.yml', '')
end
Given /^I have a configuration with:$/ do |config|
write_file('_config.yml', config)
end
@ -43,6 +49,10 @@ Then /^I should see "(.+)" in "(.*)"$/ do |text, file|
assert contents.inspect.include?(text), "Expected to find #{text.inspect} in #{contents.inspect}"
end
Then /^the file "(.+)" should contain:$/ do |file, contents|
assert_equal contents.strip, File.open(file).readlines.join.strip
end
Then /^the file "(.+)" should exist$/ do |path|
assert File.exist?(path)
end
@ -57,6 +67,24 @@ Then /^the image "(.+)" should have the dimensions "(\d+)x(\d+)"$/ do |path, wid
img.destroy!
end
Then /^the image "(.+)" should be interlaced$/ do |path|
img = Magick::Image::read(path).first
assert_equal Magick::JPEGInterlace, img.interlace
img.destroy!
end
Then /^the image "(.+)" should have an EXIF orientation$/ do |path|
img = Magick::Image::read(path).first
assert_not_equal img.orientation.to_i, 0
img.destroy!
end
Then /^the image "(.+)" should have no EXIF orientation$/ do |path|
img = Magick::Image::read(path).first
assert_equal img.orientation.to_i, 0
img.destroy!
end
def write_file(path, contents)
File.open(path, 'w') do |f|
f.write(contents)

View File

@ -1,10 +1,14 @@
if ENV['CI']
require 'coveralls'
Coveralls.wear!
end
require 'simplecov'
require 'coveralls'
require 'test/unit'
require 'jekyll/responsive_image'
formatters = [SimpleCov::Formatter::HTMLFormatter]
formatters << Coveralls::SimpleCov::Formatter if ENV['CI']
SimpleCov.formatters = formatters
SimpleCov.start
require 'test/unit/assertions'
require 'jekyll-responsive-image'
TEST_DIR = File.join('/', 'tmp', 'jekyll')
@ -14,3 +18,5 @@ def run_jekyll(options = {})
site = Jekyll::Site.new(options)
site.process
end
World(Test::Unit::Assertions)

View File

@ -1 +1 @@
<img src="{{ site.baseurl }}/{{ path }}">
<img src="{{ site.baseurl }}/{{ original.path }}">

View File

@ -0,0 +1,16 @@
path: {{ original.path }}
width: {{ original.width }}
height: {{ original.height }}
basename: {{ original.basename }}
dirname: {{ original.dirname }}
filename: {{ original.filename }}
extension: {{ original.extension }}
{% for i in resized %}
path: {{ i.path }}
width: {{ i.width }}
height: {{ i.height }}
basename: {{ i.basename }}
dirname: {{ i.dirname }}
filename: {{ i.filename }}
extension: {{ i.extension }}
{% endfor %}

View File

@ -1 +1,3 @@
<img alt="{{ alt }}" src="/{{ path }}" title="{{ title }}" srcset="{% for i in resized %}/{{ i.path }} {{ i.width }}w,{% endfor %}/{{ original.path }} {{ original.width }}w">
{% 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">

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

View File

@ -0,0 +1,27 @@
# -*- encoding: utf-8 -*-
lib = File.expand_path('../lib/', __FILE__)
$:.unshift lib unless $:.include?(lib)
require 'jekyll-responsive-image/version'
Gem::Specification.new do |spec|
spec.name = 'jekyll-responsive-image'
spec.version = Jekyll::ResponsiveImage::VERSION
spec.authors = ['Joseph Wynn']
spec.email = ['joseph@wildlyinaccurate.com']
spec.summary = 'Responsive image management for Jekyll'
spec.homepage = 'https://github.com/wildlyinaccurate/jekyll-responsive-image'
spec.licenses = ['MIT']
spec.description = %q{
Highly configurable Jekyll plugin for managing responsive images. Automatically
resizes images and provides a Liquid template tag for loading the images with
picture, img srcset, Imager.js, etc.
}
spec.files = `git ls-files -z lib/`.split("\u0000")
spec.executables = []
spec.require_paths = ['lib']
spec.add_runtime_dependency 'jekyll', ['>= 2.0', "< 5.0"]
spec.add_runtime_dependency 'rmagick', ['>= 2.0', '< 5.0']
end

View File

@ -1,32 +0,0 @@
# -*- encoding: utf-8 -*-
lib = File.expand_path('../lib/', __FILE__)
$:.unshift lib unless $:.include?(lib)
require 'jekyll/responsive_image/version'
Gem::Specification.new do |spec|
spec.name = 'jekyll-responsive_image'
spec.version = Jekyll::ResponsiveImage::VERSION
spec.authors = ['Joseph Wynn']
spec.email = ['joseph@wildlyinaccurate.com']
spec.summary = 'Responsive images for Jekyll via srcset'
spec.homepage = 'https://github.com/wildlyinaccurate/jekyll-responsive-image'
spec.licenses = ['MIT']
spec.description = %q{
Jekyll Responsive Images is a Jekyll plugin and utility for automatically resizing images.
Its intended use is for sites which want to display responsive images using something like srcset or Imager.js.
}
spec.files = `git ls-files -z lib/`.split("\u0000")
spec.executables = []
spec.require_paths = ['lib']
if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.0.0')
max_jekyll_version = '3.0'
else
max_jekyll_version = '4.0'
end
spec.add_runtime_dependency 'jekyll', ['>= 2.0', "< #{max_jekyll_version}"]
spec.add_runtime_dependency 'rmagick', ['>= 2.0', '< 3.0']
end

View File

@ -0,0 +1,19 @@
require 'fileutils'
require 'yaml'
require 'jekyll'
require 'rmagick'
require 'jekyll-responsive-image/version'
require 'jekyll-responsive-image/config'
require 'jekyll-responsive-image/utils'
require 'jekyll-responsive-image/render_cache'
require 'jekyll-responsive-image/image_processor'
require 'jekyll-responsive-image/resize_handler'
require 'jekyll-responsive-image/renderer'
require 'jekyll-responsive-image/tag'
require 'jekyll-responsive-image/block'
require 'jekyll-responsive-image/extra_image_generator'
Liquid::Template.register_tag('responsive_image', Jekyll::ResponsiveImage::Tag)
Liquid::Template.register_tag('responsive_image_block', Jekyll::ResponsiveImage::Block)

View File

@ -0,0 +1,18 @@
module Jekyll
module ResponsiveImage
class Block < Liquid::Block
include Jekyll::ResponsiveImage::Utils
def render(context)
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
end
end
end
end

View File

@ -0,0 +1,37 @@
module Jekyll
module ResponsiveImage
class Config
DEFAULTS = {
'default_quality' => 85,
'base_path' => 'assets',
'output_path_format' => 'assets/resized/%{filename}-%{width}x%{height}.%{extension}',
'sizes' => [],
'extra_images' => [],
'auto_rotate' => false,
'save_to_source' => true,
'cache' => false,
'strip' => false
}
def initialize(site)
@site = site
end
def valid_config(config)
config.has_key?('responsive_image') && config['responsive_image'].is_a?(Hash)
end
def to_h
config = {}
if valid_config(@site.config)
config = @site.config['responsive_image']
end
DEFAULTS.merge(config)
.merge(site_source: @site.source, site_dest: @site.dest)
end
end
end
end

View File

@ -0,0 +1,25 @@
module Jekyll
module ResponsiveImage
class ExtraImageGenerator < Jekyll::Generator
include Jekyll::ResponsiveImage::Utils
include FileTest
def generate(site)
config = Config.new(site).to_h
site_source = Pathname.new(site.source)
config['extra_images'].each do |pathspec|
Dir.glob(site.in_source_dir(pathspec)) do |image_path|
if FileTest.file?(image_path)
path = Pathname.new(image_path)
relative_image_path = path.relative_path_from(site_source)
result = ImageProcessor.process(relative_image_path, config)
result[:resized].each { |image| keep_resized_image!(site, image) }
end
end
end
end
end
end
end

View File

@ -0,0 +1,24 @@
module Jekyll
module ResponsiveImage
class ImageProcessor
include ResponsiveImage::Utils
def process(image_path, config)
absolute_image_path = File.expand_path(image_path.to_s, config[:site_source])
Jekyll.logger.warn "Invalid image path specified: #{image_path.inspect}" unless File.file?(absolute_image_path)
resize_handler = ResizeHandler.new(absolute_image_path, config)
{
original: image_hash(config, image_path, resize_handler.original_image.columns, resize_handler.original_image.rows),
resized: resize_handler.resize_image,
}
end
def self.process(image_path, config)
self.new.process(image_path, config)
end
end
end
end

View File

@ -1,5 +1,5 @@
module Jekyll
class ResponsiveImage
module ResponsiveImage
class RenderCache
attr_accessor :store

View File

@ -0,0 +1,41 @@
module Jekyll
module ResponsiveImage
class Renderer
include Jekyll::ResponsiveImage::Utils
def initialize(site, attributes)
@site = site
@attributes = attributes
end
def render_responsive_image
config = Config.new(@site).to_h
use_cache = config['cache'] || @attributes['cache']
cache_key = @attributes.to_s
result = use_cache ? RenderCache.get(cache_key) : nil
if result.nil?
image = ImageProcessor.process(@attributes['path'], config)
@attributes['original'] = image[:original]
@attributes['resized'] = image[:resized]
@attributes['resized'].each { |resized| keep_resized_image!(@site, resized) }
image_template = @site.in_source_dir(@attributes['template'] || config['template'])
partial = File.read(image_template)
template = Liquid::Template.parse(partial)
info = {
registers: { site: @site }
}
result = template.render!(@attributes.merge(@site.site_payload), info)
RenderCache.set(cache_key, result)
end
result
end
end
end
end

View File

@ -0,0 +1,111 @@
module Jekyll
module ResponsiveImage
class ResizeHandler
include ResponsiveImage::Utils
attr_reader :original_image
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 = []
@config['sizes'].each do |size|
width = size['width']
ratio = width.to_f / @original_image.columns.to_f
height = (@original_image.rows.to_f * ratio).round
next unless needs_resizing?(width)
image_path = @original_image.filename.force_encoding(Encoding::UTF_8)
filepath = format_output_path(@config['output_path_format'], @config, image_path, width, height)
resized.push(image_hash(@config, filepath, width, height))
site_source_filepath = File.expand_path(filepath, @config[:site_source])
site_dest_filepath = File.expand_path(filepath, @config[:site_dest])
if @config['save_to_source']
target_filepath = site_source_filepath
else
target_filepath = site_dest_filepath
end
# Don't resize images more than once
next if File.exist?(target_filepath)
ensure_output_dir_exists!(target_filepath)
ensure_output_dir_exists!(site_dest_filepath)
Jekyll.logger.info "Generating #{target_filepath}"
load_full_image unless @original_image_pixels_loaded
if @config['strip']
@original_image.strip!
end
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
Jekyll.logger.info "Copying resized image to #{site_dest_filepath}"
FileUtils.copy_file(site_source_filepath, site_dest_filepath)
end
i.destroy!
end
@original_image.destroy!
resized
end
def format_output_path(format, config, image_path, width, height)
params = symbolize_keys(image_hash(config, image_path, width, height))
Pathname.new(format % params).cleanpath.to_s
end
def needs_resizing?(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
def ensure_output_dir_exists!(path)
dir = File.dirname(path)
unless Dir.exist?(dir)
Jekyll.logger.info "Creating output directory #{dir}"
FileUtils.mkdir_p(dir)
end
end
end
end
end

View File

@ -1,8 +1,6 @@
module Jekyll
class ResponsiveImage
module ResponsiveImage
class Tag < Liquid::Tag
include Jekyll::ResponsiveImage::Common
def initialize(tag_name, markup, tokens)
super
@ -15,7 +13,7 @@ module Jekyll
end
def render(context)
render_responsive_image(context, @attributes)
Renderer.new(context.registers[:site], @attributes).render_responsive_image
end
end
end

View File

@ -1,8 +1,13 @@
require 'pathname'
module Jekyll
class ResponsiveImage
module ResponsiveImage
module Utils
def keep_resized_image!(site, image)
keep_dir = File.dirname(image['path'])
site.config['keep_files'] << keep_dir unless site.config['keep_files'].include?(keep_dir)
end
def symbolize_keys(hash)
result = {}
hash.each_key do |key|
@ -11,17 +16,11 @@ module Jekyll
result
end
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(base_path, image_path, width, height)
def image_hash(config, image_path, width, height)
{
'path' => image_path,
'dirname' => relative_dirname(base_path, image_path),
'dirname' => relative_dirname(config, image_path),
'basename' => File.basename(image_path),
'filename' => File.basename(image_path, '.*'),
'extension' => File.extname(image_path).delete('.'),
@ -30,9 +29,9 @@ module Jekyll
}
end
def relative_dirname(base_path, image_path)
path = Pathname.new(image_path).expand_path
base = Pathname.new(base_path).expand_path
def relative_dirname(config, image_path)
path = Pathname.new(File.expand_path(image_path, config[:site_source]))
base = Pathname.new(File.expand_path(config['base_path'], config[:site_source]))
path.relative_path_from(base).dirname.to_s.delete('.')
end

View File

@ -0,0 +1,5 @@
module Jekyll
module ResponsiveImage
VERSION = '1.6.0'.freeze
end
end

View File

@ -1,19 +0,0 @@
require 'fileutils'
require 'yaml'
require 'jekyll'
require 'rmagick'
require 'jekyll/responsive_image/version'
require 'jekyll/responsive_image/defaults'
require 'jekyll/responsive_image/utils'
require 'jekyll/responsive_image/render_cache'
require 'jekyll/responsive_image/image_processor'
require 'jekyll/responsive_image/resize_handler'
require 'jekyll/responsive_image/common'
require 'jekyll/responsive_image/tag'
require 'jekyll/responsive_image/block'
require 'jekyll/responsive_image/extra_image_generator'
Liquid::Template.register_tag('responsive_image', Jekyll::ResponsiveImage::Tag)
Liquid::Template.register_tag('responsive_image_block', Jekyll::ResponsiveImage::Block)

View File

@ -1,21 +0,0 @@
module Jekyll
class ResponsiveImage
class Block < Liquid::Block
include Jekyll::ResponsiveImage::Common
def render(context)
attributes = YAML.load(super)
render_responsive_image(context, attributes)
end
end
end
end

View File

@ -1,46 +0,0 @@
module Jekyll
class ResponsiveImage
module Common
include Jekyll::ResponsiveImage::Utils
def make_config(site)
ResponsiveImage.defaults.dup
.merge(site.config['responsive_image'])
.merge(:site_source => site.source, :site_dest => site.dest)
end
def keep_resized_image!(site, image)
keep_dir = File.dirname(image['path'])
site.config['keep_files'] << keep_dir unless site.config['keep_files'].include?(keep_dir)
end
def render_responsive_image(context, attributes)
cache_key = attributes.to_s
result = attributes['cache'] ? RenderCache.get(cache_key) : nil
if result.nil?
site = context.registers[:site]
config = make_config(site)
absolute_image_path = site.in_source_dir(attributes['path'].to_s)
image = ImageProcessor.process(absolute_image_path, attributes['path'], config)
attributes['original'] = image[:original]
attributes['resized'] = image[:resized]
attributes['resized'].each { |resized| keep_resized_image!(site, resized) }
image_template = site.in_source_dir(attributes['template'] || config['template'])
partial = File.read(image_template)
template = Liquid::Template.parse(partial)
result = template.render!(attributes.merge(site.site_payload))
RenderCache.set(cache_key, result)
end
result
end
end
end
end

View File

@ -1,15 +0,0 @@
module Jekyll
class ResponsiveImage
@defaults = {
'default_quality' => 85,
'base_path' => 'assets',
'output_path_format' => 'assets/resized/%{filename}-%{width}x%{height}.%{extension}',
'sizes' => [],
'extra_images' => []
}.freeze
class << self
attr_reader :defaults
end
end
end

View File

@ -1,20 +0,0 @@
module Jekyll
class ResponsiveImage
class ExtraImageGenerator < Jekyll::Generator
include Jekyll::ResponsiveImage::Common
def generate(site)
config = make_config(site)
config['extra_images'].each do |pathspec|
Dir.glob(site.in_source_dir(pathspec)) do |image_path|
relative_image_path = image_path.sub(/^#{Regexp.escape(image_path)}/, '')
result = ImageProcessor.process(image_path, relative_image_path, config)
result[:resized].each { |image| keep_resized_image!(site, image) }
end
end
end
end
end
end

View File

@ -1,23 +0,0 @@
module Jekyll
class ResponsiveImage
class ImageProcessor
include ResponsiveImage::Utils
def process(absolute_image_path, relative_image_path, config)
raise SyntaxError.new("Invalid image path specified: #{absolute_image_path}") unless File.file?(absolute_image_path)
resize_handler = ResizeHandler.new
img = Magick::Image::read(absolute_image_path).first
{
original: image_hash(config['base_path'], relative_image_path, img.columns, img.rows),
resized: resize_handler.resize_image(img, config),
}
end
def self.process(absolute_image_path, relative_image_path, config)
self.new.process(absolute_image_path, relative_image_path, config)
end
end
end
end

View File

@ -1,59 +0,0 @@
module Jekyll
class ResponsiveImage
class ResizeHandler
include ResponsiveImage::Utils
def resize_image(img, config)
resized = []
config['sizes'].each do |size|
width = size['width']
ratio = width.to_f / img.columns.to_f
height = (img.rows.to_f * ratio).round
next unless needs_resizing?(img, width)
image_path = img.filename.force_encoding(Encoding::UTF_8)
filepath = format_output_path(config['output_path_format'], config['base_path'], image_path, width, height)
resized.push(image_hash(config['base_path'], filepath, width, height))
site_source_filepath = File.expand_path(filepath, config[:site_source])
site_dest_filepath = File.expand_path(filepath, config[:site_dest])
# Don't resize images more than once
next if File.exist?(site_source_filepath)
ensure_output_dir_exists!(File.dirname(site_source_filepath))
ensure_output_dir_exists!(File.dirname(site_dest_filepath))
Jekyll.logger.info "Generating #{filepath}"
i = img.scale(ratio)
i.write(site_source_filepath) do |f|
f.quality = size['quality'] || config['default_quality']
end
# Ensure the generated file is copied to the _site directory
FileUtils.copy_file(site_source_filepath, site_dest_filepath)
i.destroy!
end
img.destroy!
resized
end
def needs_resizing?(img, width)
img.columns > width
end
def ensure_output_dir_exists!(dir)
unless Dir.exist?(dir)
Jekyll.logger.info "Creating output directory #{dir}"
FileUtils.mkdir_p(dir)
end
end
end
end
end

View File

@ -1,5 +0,0 @@
module Jekyll
class ResponsiveImage
VERSION = '1.0.0.pre3'.freeze
end
end

View 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>

View 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>

View 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">

View 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">