FEATURE: add support for responsive images in posts
When creating lightboxes we will attempt to create 1.5x and 2x thumbnails for retina screens, this can be controlled with a new hidden site setting called responsice_post_image_sizes, if you wish to create 3x images run SiteSetting.responsive_post_image_sizes = "1|1.5|2|3" The default should be good for most of the setups as it balances filesize with quality. 3x thumbs can get big.
This commit is contained in:
parent
73443d889c
commit
ad0e768742
|
@ -914,6 +914,9 @@ files:
|
||||||
default: 'gz'
|
default: 'gz'
|
||||||
type: list
|
type: list
|
||||||
list_type: compact
|
list_type: compact
|
||||||
|
responsive_post_image_sizes:
|
||||||
|
default: "1|1.5|2"
|
||||||
|
hidden: true
|
||||||
crawl_images:
|
crawl_images:
|
||||||
default: true
|
default: true
|
||||||
max_image_width:
|
max_image_width:
|
||||||
|
|
|
@ -231,6 +231,10 @@ class CookedPostProcessor
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def add_to_size_cache(url, w, h)
|
||||||
|
@size_cache[url] = [w, h]
|
||||||
|
end
|
||||||
|
|
||||||
def get_size(url)
|
def get_size(url)
|
||||||
return @size_cache[url] if @size_cache.has_key?(url)
|
return @size_cache[url] if @size_cache.has_key?(url)
|
||||||
|
|
||||||
|
@ -285,6 +289,15 @@ class CookedPostProcessor
|
||||||
|
|
||||||
if upload = Upload.get_from_url(src)
|
if upload = Upload.get_from_url(src)
|
||||||
upload.create_thumbnail!(width, height, crop)
|
upload.create_thumbnail!(width, height, crop)
|
||||||
|
|
||||||
|
each_responsive_ratio do |ratio|
|
||||||
|
resized_w = (width * ratio).to_i
|
||||||
|
resized_h = (height * ratio).to_i
|
||||||
|
|
||||||
|
if upload.width && resized_w <= upload.width
|
||||||
|
upload.create_thumbnail!(resized_w, resized_h, crop)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
add_lightbox!(img, original_width, original_height, upload)
|
add_lightbox!(img, original_width, original_height, upload)
|
||||||
|
@ -299,6 +312,15 @@ class CookedPostProcessor
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def each_responsive_ratio
|
||||||
|
SiteSetting
|
||||||
|
.responsive_post_image_sizes
|
||||||
|
.split('|')
|
||||||
|
.map(&:to_f)
|
||||||
|
.sort
|
||||||
|
.each { |r| yield r if r > 1 }
|
||||||
|
end
|
||||||
|
|
||||||
def add_lightbox!(img, original_width, original_height, upload = nil)
|
def add_lightbox!(img, original_width, original_height, upload = nil)
|
||||||
# first, create a div to hold our lightbox
|
# first, create a div to hold our lightbox
|
||||||
lightbox = create_node("div", "lightbox-wrapper")
|
lightbox = create_node("div", "lightbox-wrapper")
|
||||||
|
@ -320,12 +342,30 @@ class CookedPostProcessor
|
||||||
|
|
||||||
if upload
|
if upload
|
||||||
thumbnail = upload.thumbnail(w, h)
|
thumbnail = upload.thumbnail(w, h)
|
||||||
|
|
||||||
img["src"] =
|
|
||||||
if thumbnail && thumbnail.filesize.to_i < upload.filesize
|
if thumbnail && thumbnail.filesize.to_i < upload.filesize
|
||||||
upload.thumbnail(w, h).url
|
img["src"] = upload.thumbnail(w, h).url
|
||||||
|
|
||||||
|
srcset = +""
|
||||||
|
|
||||||
|
each_responsive_ratio do |ratio|
|
||||||
|
resized_w = (w * ratio).to_i
|
||||||
|
resized_h = (h * ratio).to_i
|
||||||
|
|
||||||
|
if upload.width && resized_w > upload.width
|
||||||
|
cooked_url = UrlHelper.cook_url(upload.url)
|
||||||
|
srcset << ", #{cooked_url} #{ratio}x"
|
||||||
else
|
else
|
||||||
upload.url
|
if t = upload.thumbnail(resized_w, resized_h)
|
||||||
|
cooked_url = UrlHelper.cook_url(t.url)
|
||||||
|
srcset << ", #{cooked_url} #{ratio}x"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
img["srcset"] = "#{img["src"]}#{srcset}" if srcset.length > 0
|
||||||
|
|
||||||
|
else
|
||||||
|
img["src"] = upload.url
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,51 @@ describe CookedPostProcessor do
|
||||||
|
|
||||||
context ".post_process_images" do
|
context ".post_process_images" do
|
||||||
|
|
||||||
|
before do
|
||||||
|
SiteSetting.responsive_post_image_sizes = ""
|
||||||
|
end
|
||||||
|
|
||||||
|
context "responsive images" do
|
||||||
|
it "includes responsive images on demand" do
|
||||||
|
|
||||||
|
SiteSetting.responsive_post_image_sizes = "1|1.5|3"
|
||||||
|
|
||||||
|
upload = Fabricate(:upload, width: 2000, height: 1500, filesize: 10000)
|
||||||
|
post = Fabricate(:post, raw: "hello <img src='#{upload.url}'>")
|
||||||
|
|
||||||
|
# fake some optimized images
|
||||||
|
OptimizedImage.create!(
|
||||||
|
url: 'http://a.b.c/666x500.jpg',
|
||||||
|
width: 666,
|
||||||
|
height: 500,
|
||||||
|
upload_id: upload.id,
|
||||||
|
sha1: SecureRandom.hex,
|
||||||
|
extension: '.jpg',
|
||||||
|
filesize: 500
|
||||||
|
)
|
||||||
|
|
||||||
|
# fake 3x optimized image, we lose 2 pixels here over original due to rounding on downsize
|
||||||
|
OptimizedImage.create!(
|
||||||
|
url: 'http://a.b.c/1998x1500.jpg',
|
||||||
|
width: 1998,
|
||||||
|
height: 1500,
|
||||||
|
upload_id: upload.id,
|
||||||
|
sha1: SecureRandom.hex,
|
||||||
|
extension: '.jpg',
|
||||||
|
filesize: 800
|
||||||
|
)
|
||||||
|
|
||||||
|
cpp = CookedPostProcessor.new(post)
|
||||||
|
|
||||||
|
cpp.add_to_size_cache(upload.url, 2000, 1500)
|
||||||
|
cpp.post_process_images
|
||||||
|
|
||||||
|
# 1.5x is skipped cause we have a missing thumb
|
||||||
|
expect(cpp.html).to include('srcset="http://a.b.c/666x500.jpg, http://a.b.c/1998x1500.jpg 3.0x"')
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
shared_examples "leave dimensions alone" do
|
shared_examples "leave dimensions alone" do
|
||||||
it "doesn't use them" do
|
it "doesn't use them" do
|
||||||
expect(cpp.html).to match(/src="http:\/\/foo.bar\/image.png" width="" height=""/)
|
expect(cpp.html).to match(/src="http:\/\/foo.bar\/image.png" width="" height=""/)
|
||||||
|
|
Loading…
Reference in New Issue