diff --git a/app/assets/stylesheets/common/d-editor.scss b/app/assets/stylesheets/common/d-editor.scss
index c4a7979588b..401a4cc4f60 100644
--- a/app/assets/stylesheets/common/d-editor.scss
+++ b/app/assets/stylesheets/common/d-editor.scss
@@ -187,6 +187,10 @@
&.site-icon {
padding-bottom: 0;
}
+ &.resizable {
+ object-fit: cover;
+ object-position: top;
+ }
}
.d-editor-preview .image-wrapper {
diff --git a/lib/cooked_post_processor.rb b/lib/cooked_post_processor.rb
index bd56c12ca04..2ec33c0d2c7 100644
--- a/lib/cooked_post_processor.rb
+++ b/lib/cooked_post_processor.rb
@@ -308,29 +308,34 @@ class CookedPostProcessor
end
def convert_to_link!(img)
+ w, h = img["width"].to_i, img["height"].to_i
+ user_width, user_height = (w > 0 && h > 0 && [w, h]) ||
+ get_size_from_attributes(img) ||
+ get_size_from_image_sizes(img["src"], @opts[:image_sizes])
+
+ limit_size!(img)
+
src = img["src"]
return if src.blank? || is_a_hyperlink?(img) || is_svg?(img)
- width, height = img["width"].to_i, img["height"].to_i
- # TODO: store original dimentions in db
original_width, original_height = (get_size(src) || [0, 0]).map(&:to_i)
-
- # can't reach the image...
if original_width == 0 || original_height == 0
Rails.logger.info "Can't reach '#{src}' to get its dimension."
return
end
- return if original_width <= width && original_height <= height
return if original_width <= SiteSetting.max_image_width && original_height <= SiteSetting.max_image_height
- crop = SiteSetting.min_ratio_to_crop > 0
- crop &&= original_width.to_f / original_height.to_f < SiteSetting.min_ratio_to_crop
+ user_width, user_height = [original_width, original_height] if user_width.to_i <= 0 && user_height.to_i <= 0
+ width, height = user_width, user_height
+
+ crop = SiteSetting.min_ratio_to_crop > 0 && width.to_f / height.to_f < SiteSetting.min_ratio_to_crop
if crop
- width, height = ImageSizer.crop(original_width, original_height)
- img["width"] = width
- img["height"] = height
+ width, height = ImageSizer.crop(width, height)
+ img["width"], img["height"] = width, height
+ else
+ width, height = ImageSizer.resize(width, height)
end
# if the upload already exists and is attached to a different post,
@@ -700,10 +705,7 @@ class CookedPostProcessor
def post_process_images
extract_images.each do |img|
- unless add_image_placeholder!(img)
- limit_size!(img)
- convert_to_link!(img)
- end
+ convert_to_link!(img) unless add_image_placeholder!(img)
end
end
diff --git a/spec/components/cooked_post_processor_spec.rb b/spec/components/cooked_post_processor_spec.rb
index 799e3a3cd3a..d9866515626 100644
--- a/spec/components/cooked_post_processor_spec.rb
+++ b/spec/components/cooked_post_processor_spec.rb
@@ -416,12 +416,17 @@ describe CookedPostProcessor do
end
context "with unsized images" do
+ fab!(:upload) { Fabricate(:image_upload, width: 123, height: 456) }
+
+ fab!(:post) do
+ Fabricate(:post, raw: <<~HTML)
+
+ HTML
+ end
- fab!(:post) { Fabricate(:post_with_unsized_images) }
let(:cpp) { CookedPostProcessor.new(post) }
it "adds the width and height to images that don't have them" do
- FastImage.expects(:size).returns([123, 456])
cpp.post_process
expect(cpp.html).to match(/width="123" height="456"/)
expect(cpp).to be_dirty
@@ -430,6 +435,8 @@ describe CookedPostProcessor do
end
context "with large images" do
+ fab!(:upload) { Fabricate(:image_upload, width: 1750, height: 2000) }
+
fab!(:post) do
Fabricate(:post, raw: <<~HTML)
@@ -441,13 +448,9 @@ describe CookedPostProcessor do
before do
SiteSetting.max_image_height = 2000
SiteSetting.create_thumbnails = true
- FastImage.expects(:size).returns([1750, 2000])
end
it "generates overlay information" do
- OptimizedImage.expects(:resize).returns(true)
- FileStore::BaseStore.any_instance.expects(:get_depth_for).returns(0)
-
cpp.post_process
expect(cpp.html).to match_html <<~HTML
@@ -468,6 +471,8 @@ describe CookedPostProcessor do
end
it 'should not add lightbox' do
+ FastImage.expects(:size).returns([1750, 2000])
+
cpp.post_process
expect(cpp.html).to match_html <<~HTML
@@ -482,6 +487,8 @@ describe CookedPostProcessor do
end
it 'should not add lightbox' do
+ FastImage.expects(:size).returns([1750, 2000])
+
cpp.post_process
expect(cpp.html).to match_html <<~HTML
@@ -495,6 +502,8 @@ describe CookedPostProcessor do
end
it 'should not add lightbox' do
+ FastImage.expects(:size).returns([1750, 2000])
+
SiteSetting.crawl_images = true
cpp.post_process
@@ -537,8 +546,8 @@ describe CookedPostProcessor do
context "when the upload is attached to the correct post" do
before do
+ FastImage.expects(:size).returns([1750, 2000])
OptimizedImage.expects(:resize).returns(true)
- FileStore::BaseStore.any_instance.expects(:get_depth_for).returns(0)
Discourse.store.class.any_instance.expects(:has_been_uploaded?).at_least_once.returns(true)
upload.update(secure: true, access_control_post: post)
end
@@ -568,6 +577,8 @@ describe CookedPostProcessor do
end
context "with tall images" do
+ fab!(:upload) { Fabricate(:image_upload, width: 860, height: 2000) }
+
fab!(:post) do
Fabricate(:post, raw: <<~HTML)
@@ -578,10 +589,6 @@ describe CookedPostProcessor do
before do
SiteSetting.create_thumbnails = true
- FastImage.expects(:size).returns([860, 2000])
- OptimizedImage.expects(:resize).never
- OptimizedImage.expects(:crop).returns(true)
- FileStore::BaseStore.any_instance.expects(:get_depth_for).returns(0)
end
it "crops the image" do
@@ -594,6 +601,8 @@ describe CookedPostProcessor do
end
context "with iPhone X screenshots" do
+ fab!(:upload) { Fabricate(:image_upload, width: 1125, height: 2436) }
+
fab!(:post) do
Fabricate(:post, raw: <<~HTML)
@@ -604,10 +613,6 @@ describe CookedPostProcessor do
before do
SiteSetting.create_thumbnails = true
- FastImage.expects(:size).returns([1125, 2436])
- OptimizedImage.expects(:resize).returns(true)
- OptimizedImage.expects(:crop).never
- FileStore::BaseStore.any_instance.expects(:get_depth_for).returns(0)
end
it "crops the image" do
@@ -625,6 +630,8 @@ describe CookedPostProcessor do
end
context "with large images when using subfolders" do
+ fab!(:upload) { Fabricate(:image_upload, width: 1750, height: 2000) }
+
fab!(:post) do
Fabricate(:post, raw: <<~HTML)
@@ -635,13 +642,10 @@ describe CookedPostProcessor do
before do
set_subfolder "/subfolder"
+ stub_request(:get, "http://#{Discourse.current_hostname}/subfolder#{upload.url}").to_return(status: 200, body: File.new(Discourse.store.path_for(upload)))
SiteSetting.max_image_height = 2000
SiteSetting.create_thumbnails = true
- FastImage.expects(:size).returns([1750, 2000])
- OptimizedImage.expects(:resize).returns(true)
-
- FileStore::BaseStore.any_instance.expects(:get_depth_for).returns(0)
end
it "generates overlay information" do
@@ -670,6 +674,8 @@ describe CookedPostProcessor do
end
context "with title and alt" do
+ fab!(:upload) { Fabricate(:image_upload, width: 1750, height: 2000) }
+
fab!(:post) do
Fabricate(:post, raw: <<~HTML)
@@ -681,9 +687,6 @@ describe CookedPostProcessor do
before do
SiteSetting.max_image_height = 2000
SiteSetting.create_thumbnails = true
- FastImage.expects(:size).returns([1750, 2000])
- OptimizedImage.expects(:resize).returns(true)
- FileStore::BaseStore.any_instance.expects(:get_depth_for).returns(0)
end
it "generates overlay information using image title and ignores alt" do
@@ -701,6 +704,8 @@ describe CookedPostProcessor do
end
context "with title only" do
+ fab!(:upload) { Fabricate(:image_upload, width: 1750, height: 2000) }
+
fab!(:post) do
Fabricate(:post, raw: <<~HTML)
@@ -712,9 +717,6 @@ describe CookedPostProcessor do
before do
SiteSetting.max_image_height = 2000
SiteSetting.create_thumbnails = true
- FastImage.expects(:size).returns([1750, 2000])
- OptimizedImage.expects(:resize).returns(true)
- FileStore::BaseStore.any_instance.expects(:get_depth_for).returns(0)
end
it "generates overlay information using image title" do
@@ -732,6 +734,8 @@ describe CookedPostProcessor do
end
context "with alt only" do
+ fab!(:upload) { Fabricate(:image_upload, width: 1750, height: 2000) }
+
fab!(:post) do
Fabricate(:post, raw: <<~HTML)
@@ -743,9 +747,6 @@ describe CookedPostProcessor do
before do
SiteSetting.max_image_height = 2000
SiteSetting.create_thumbnails = true
- FastImage.expects(:size).returns([1750, 2000])
- OptimizedImage.expects(:resize).returns(true)
- FileStore::BaseStore.any_instance.expects(:get_depth_for).returns(0)
end
it "generates overlay information using image alt" do
diff --git a/spec/fabricators/upload_fabricator.rb b/spec/fabricators/upload_fabricator.rb
index 01d05d9da55..72bcb6c7232 100644
--- a/spec/fabricators/upload_fabricator.rb
+++ b/spec/fabricators/upload_fabricator.rb
@@ -21,6 +21,20 @@ Fabricator(:upload) do
extension "png"
end
+Fabricator(:image_upload, from: :upload) do
+ after_create do |upload|
+ file = Tempfile.new(['fabricated', '.png'])
+ `convert -size #{upload.width}x#{upload.height} xc:white "#{file.path}"`
+
+ upload.url = Discourse.store.store_upload(file, upload)
+ upload.sha1 = Upload.generate_digest(file.path)
+
+ WebMock
+ .stub_request(:get, "http://#{Discourse.current_hostname}#{upload.url}")
+ .to_return(status: 200, body: File.new(file.path))
+ end
+end
+
Fabricator(:video_upload, from: :upload) do
original_filename "video.mp4"
width nil