mirror of
https://github.com/discourse/discourse.git
synced 2025-06-06 13:06:56 +08:00
FEATURE: new 'crop_tall_images' site setting
This commit is contained in:
@ -45,6 +45,8 @@ class OptimizedImage < ActiveRecord::Base
|
|||||||
if extension =~ /\.svg$/i
|
if extension =~ /\.svg$/i
|
||||||
FileUtils.cp(original_path, temp_path)
|
FileUtils.cp(original_path, temp_path)
|
||||||
resized = true
|
resized = true
|
||||||
|
elsif opts[:crop]
|
||||||
|
resized = crop(original_path, temp_path, width, height, opts)
|
||||||
else
|
else
|
||||||
resized = resize(original_path, temp_path, width, height, opts)
|
resized = resize(original_path, temp_path, width, height, opts)
|
||||||
end
|
end
|
||||||
@ -124,6 +126,25 @@ class OptimizedImage < ActiveRecord::Base
|
|||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.crop_instructions(from, to, dimensions, opts={})
|
||||||
|
%W{
|
||||||
|
convert
|
||||||
|
#{from}[0]
|
||||||
|
-gravity north
|
||||||
|
-background transparent
|
||||||
|
-thumbnail #{opts[:width]}
|
||||||
|
-crop #{dimensions}+0+0
|
||||||
|
-unsharp 2x0.5+0.7+0
|
||||||
|
-quality 98
|
||||||
|
-profile #{File.join(Rails.root, 'vendor', 'data', 'RT_sRGB.icm')}
|
||||||
|
#{to}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.crop_instructions_animated(from, to, dimensions, opts={})
|
||||||
|
resize_instructions_animated(from, to, dimensions, opts)
|
||||||
|
end
|
||||||
|
|
||||||
def self.downsize_instructions(from, to, dimensions, opts={})
|
def self.downsize_instructions(from, to, dimensions, opts={})
|
||||||
%W{
|
%W{
|
||||||
convert
|
convert
|
||||||
@ -144,6 +165,11 @@ class OptimizedImage < ActiveRecord::Base
|
|||||||
optimize("resize", from, to, "#{width}x#{height}", opts)
|
optimize("resize", from, to, "#{width}x#{height}", opts)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.crop(from, to, width, height, opts={})
|
||||||
|
opts[:width] = width
|
||||||
|
optimize("crop", from, to, "#{width}x#{height}", opts)
|
||||||
|
end
|
||||||
|
|
||||||
def self.downsize(from, to, dimensions, opts={})
|
def self.downsize(from, to, dimensions, opts={})
|
||||||
optimize("downsize", from, to, dimensions, opts)
|
optimize("downsize", from, to, dimensions, opts)
|
||||||
end
|
end
|
||||||
|
@ -29,18 +29,16 @@ class Upload < ActiveRecord::Base
|
|||||||
thumbnail(width, height).present?
|
thumbnail(width, height).present?
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_thumbnail!(width, height)
|
def create_thumbnail!(width, height, crop=false)
|
||||||
return unless SiteSetting.create_thumbnails?
|
return unless SiteSetting.create_thumbnails?
|
||||||
|
|
||||||
thumbnail = OptimizedImage.create_for(
|
opts = {
|
||||||
self,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
filename: self.original_filename,
|
filename: self.original_filename,
|
||||||
allow_animation: SiteSetting.allow_animated_thumbnails
|
allow_animation: SiteSetting.allow_animated_thumbnails,
|
||||||
)
|
crop: crop && SiteSetting.crop_tall_images
|
||||||
|
}
|
||||||
|
|
||||||
if thumbnail
|
if thumbnail = OptimizedImage.create_for(self, width, height, opts)
|
||||||
self.width = width
|
self.width = width
|
||||||
self.height = height
|
self.height = height
|
||||||
save(validate: false)
|
save(validate: false)
|
||||||
|
@ -1094,6 +1094,7 @@ en:
|
|||||||
max_users_notified_per_group_mention: "Maximum number of users that may recieve a notification if a group is mentioned (if threshold is met no notifications will be raised)"
|
max_users_notified_per_group_mention: "Maximum number of users that may recieve a notification if a group is mentioned (if threshold is met no notifications will be raised)"
|
||||||
|
|
||||||
create_thumbnails: "Create thumbnails and lightbox images that are too large to fit in a post."
|
create_thumbnails: "Create thumbnails and lightbox images that are too large to fit in a post."
|
||||||
|
crop_tall_images: "When creating a thumbnail of a tall image, crop it instead of generating a thin thumbnail."
|
||||||
|
|
||||||
email_time_window_mins: "Wait (n) minutes before sending any notification emails, to give users a chance to edit and finalize their posts."
|
email_time_window_mins: "Wait (n) minutes before sending any notification emails, to give users a chance to edit and finalize their posts."
|
||||||
private_email_time_window_seconds: "Wait (n) seconds before sending any private notification emails, to give users a chance to edit and finalize their messages."
|
private_email_time_window_seconds: "Wait (n) seconds before sending any private notification emails, to give users a chance to edit and finalize their messages."
|
||||||
|
@ -613,6 +613,7 @@ files:
|
|||||||
type: list
|
type: list
|
||||||
default: ''
|
default: ''
|
||||||
create_thumbnails: true
|
create_thumbnails: true
|
||||||
|
crop_tall_images: true
|
||||||
clean_up_uploads: true
|
clean_up_uploads: true
|
||||||
clean_orphan_uploads_grace_period_hours: 1
|
clean_orphan_uploads_grace_period_hours: 1
|
||||||
purge_deleted_uploads_grace_period_days: 30
|
purge_deleted_uploads_grace_period_days: 30
|
||||||
|
@ -194,7 +194,10 @@ class CookedPostProcessor
|
|||||||
original_width, original_height = get_size(src)
|
original_width, original_height = get_size(src)
|
||||||
|
|
||||||
# can't reach the image...
|
# can't reach the image...
|
||||||
if original_width.nil? || original_height.nil?
|
if original_width.nil? ||
|
||||||
|
original_height.nil? ||
|
||||||
|
original_width == 0 ||
|
||||||
|
original_height == 0
|
||||||
Rails.logger.info "Can't reach '#{src}' to get its dimension."
|
Rails.logger.info "Can't reach '#{src}' to get its dimension."
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@ -204,8 +207,16 @@ class CookedPostProcessor
|
|||||||
|
|
||||||
return if is_a_hyperlink?(img)
|
return if is_a_hyperlink?(img)
|
||||||
|
|
||||||
|
crop = false
|
||||||
|
if SiteSetting.crop_tall_images && (original_width.to_f / original_height.to_f < 0.75)
|
||||||
|
crop = true
|
||||||
|
width, height = ImageSizer.crop(original_width, original_height)
|
||||||
|
img["width"] = width
|
||||||
|
img["height"] = height
|
||||||
|
end
|
||||||
|
|
||||||
if upload = Upload.get_from_url(src)
|
if upload = Upload.get_from_url(src)
|
||||||
upload.create_thumbnail!(width, height)
|
upload.create_thumbnail!(width, height, crop)
|
||||||
end
|
end
|
||||||
|
|
||||||
add_lightbox!(img, original_width, original_height, upload)
|
add_lightbox!(img, original_width, original_height, upload)
|
||||||
|
@ -16,4 +16,19 @@ module ImageSizer
|
|||||||
[(w * ratio).floor, (h * ratio).floor]
|
[(w * ratio).floor, (h * ratio).floor]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.crop(width, height, opts = {})
|
||||||
|
return if width.blank? || height.blank?
|
||||||
|
|
||||||
|
max_width = (opts[:max_width] || SiteSetting.max_image_width).to_f
|
||||||
|
max_height = (opts[:max_height] || SiteSetting.max_image_height).to_f
|
||||||
|
|
||||||
|
w = width.to_f
|
||||||
|
h = height.to_f
|
||||||
|
|
||||||
|
return [w.floor, h.floor] if w <= max_width && h <= max_height
|
||||||
|
|
||||||
|
ratio = max_width / w
|
||||||
|
[max_width.floor, [max_height, (h * ratio)].min.floor]
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -110,7 +110,7 @@ describe CookedPostProcessor do
|
|||||||
SiteSetting.create_thumbnails = true
|
SiteSetting.create_thumbnails = true
|
||||||
|
|
||||||
Upload.expects(:get_from_url).returns(upload)
|
Upload.expects(:get_from_url).returns(upload)
|
||||||
FastImage.stubs(:size).returns([1000, 2000])
|
FastImage.stubs(:size).returns([1750, 2000])
|
||||||
|
|
||||||
# hmmm this should be done in a cleaner way
|
# hmmm this should be done in a cleaner way
|
||||||
OptimizedImage.expects(:resize).returns(true)
|
OptimizedImage.expects(:resize).returns(true)
|
||||||
@ -120,8 +120,8 @@ describe CookedPostProcessor do
|
|||||||
|
|
||||||
it "generates overlay information" do
|
it "generates overlay information" do
|
||||||
cpp.post_process_images
|
cpp.post_process_images
|
||||||
expect(cpp.html).to match_html '<p><div class="lightbox-wrapper"><a data-download-href="/uploads/default/e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98" href="/uploads/default/1/1234567890123456.jpg" class="lightbox" title="logo.png"><img src="/uploads/default/optimized/1X/e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98_1_690x1380.png" width="690" height="1380"><div class="meta">
|
expect(cpp.html).to match_html '<p><div class="lightbox-wrapper"><a data-download-href="/uploads/default/e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98" href="/uploads/default/1/1234567890123456.jpg" class="lightbox" title="logo.png"><img src="/uploads/default/optimized/1X/e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98_1_690x788.png" width="690" height="788"><div class="meta">
|
||||||
<span class="filename">logo.png</span><span class="informations">1000x2000 1.21 KB</span><span class="expand"></span>
|
<span class="filename">logo.png</span><span class="informations">1750x2000 1.21 KB</span><span class="expand"></span>
|
||||||
</div></a></div></p>'
|
</div></a></div></p>'
|
||||||
expect(cpp).to be_dirty
|
expect(cpp).to be_dirty
|
||||||
end
|
end
|
||||||
@ -143,7 +143,7 @@ describe CookedPostProcessor do
|
|||||||
Discourse.stubs(:base_uri).returns(base_uri)
|
Discourse.stubs(:base_uri).returns(base_uri)
|
||||||
|
|
||||||
Upload.expects(:get_from_url).returns(upload)
|
Upload.expects(:get_from_url).returns(upload)
|
||||||
FastImage.stubs(:size).returns([1000, 2000])
|
FastImage.stubs(:size).returns([1750, 2000])
|
||||||
|
|
||||||
# hmmm this should be done in a cleaner way
|
# hmmm this should be done in a cleaner way
|
||||||
OptimizedImage.expects(:resize).returns(true)
|
OptimizedImage.expects(:resize).returns(true)
|
||||||
@ -153,8 +153,8 @@ describe CookedPostProcessor do
|
|||||||
|
|
||||||
it "generates overlay information" do
|
it "generates overlay information" do
|
||||||
cpp.post_process_images
|
cpp.post_process_images
|
||||||
expect(cpp.html).to match_html '<p><div class="lightbox-wrapper"><a data-download-href="/subfolder/uploads/default/e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98" href="/subfolder/uploads/default/1/1234567890123456.jpg" class="lightbox" title="logo.png"><img src="/subfolder/uploads/default/optimized/1X/e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98_1_690x1380.png" width="690" height="1380"><div class="meta">
|
expect(cpp.html).to match_html '<p><div class="lightbox-wrapper"><a data-download-href="/subfolder/uploads/default/e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98" href="/subfolder/uploads/default/1/1234567890123456.jpg" class="lightbox" title="logo.png"><img src="/subfolder/uploads/default/optimized/1X/e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98_1_690x788.png" width="690" height="788"><div class="meta">
|
||||||
<span class="filename">logo.png</span><span class="informations">1000x2000 1.21 KB</span><span class="expand"></span>
|
<span class="filename">logo.png</span><span class="informations">1750x2000 1.21 KB</span><span class="expand"></span>
|
||||||
</div></a></div></p>'
|
</div></a></div></p>'
|
||||||
expect(cpp).to be_dirty
|
expect(cpp).to be_dirty
|
||||||
end
|
end
|
||||||
@ -172,7 +172,7 @@ describe CookedPostProcessor do
|
|||||||
SiteSetting.create_thumbnails = true
|
SiteSetting.create_thumbnails = true
|
||||||
|
|
||||||
Upload.expects(:get_from_url).returns(upload)
|
Upload.expects(:get_from_url).returns(upload)
|
||||||
FastImage.stubs(:size).returns([1000, 2000])
|
FastImage.stubs(:size).returns([1750, 2000])
|
||||||
|
|
||||||
# hmmm this should be done in a cleaner way
|
# hmmm this should be done in a cleaner way
|
||||||
OptimizedImage.expects(:resize).returns(true)
|
OptimizedImage.expects(:resize).returns(true)
|
||||||
@ -181,8 +181,8 @@ describe CookedPostProcessor do
|
|||||||
|
|
||||||
it "generates overlay information" do
|
it "generates overlay information" do
|
||||||
cpp.post_process_images
|
cpp.post_process_images
|
||||||
expect(cpp.html).to match_html '<p><div class="lightbox-wrapper"><a data-download-href="/uploads/default/e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98" href="/uploads/default/1/1234567890123456.jpg" class="lightbox" title="WAT"><img src="/uploads/default/optimized/1X/e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98_1_690x1380.png" title="WAT" width="690" height="1380"><div class="meta">
|
expect(cpp.html).to match_html '<p><div class="lightbox-wrapper"><a data-download-href="/uploads/default/e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98" href="/uploads/default/1/1234567890123456.jpg" class="lightbox" title="WAT"><img src="/uploads/default/optimized/1X/e9d71f5ee7c92d6dc9e92ffdad17b8bd49418f98_1_690x788.png" title="WAT" width="690" height="788"><div class="meta">
|
||||||
<span class="filename">WAT</span><span class="informations">1000x2000 1.21 KB</span><span class="expand"></span>
|
<span class="filename">WAT</span><span class="informations">1750x2000 1.21 KB</span><span class="expand"></span>
|
||||||
</div></a></div></p>'
|
</div></a></div></p>'
|
||||||
expect(cpp).to be_dirty
|
expect(cpp).to be_dirty
|
||||||
end
|
end
|
||||||
|
Reference in New Issue
Block a user