From b0802abae2f58b7b982808844cdc50aee462fd2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Wed, 15 Jul 2015 17:15:43 +0200 Subject: [PATCH] FIX: crop & optimize user background profile/card images --- app/controllers/uploads_controller.rb | 8 +-- app/models/upload.rb | 95 ++++++++++++++----------- app/models/user_avatar.rb | 4 +- config/locales/server.en.yml | 2 - lib/image_sizer.rb | 8 +-- spec/components/email/receiver_spec.rb | 5 +- spec/fixtures/images/logo-dev.png | Bin 5527 -> 3196 bytes spec/fixtures/images/logo.png | Bin 2701 -> 2297 bytes spec/models/upload_spec.rb | 12 ++-- 9 files changed, 70 insertions(+), 64 deletions(-) diff --git a/app/controllers/uploads_controller.rb b/app/controllers/uploads_controller.rb index 923f62407..1036e1936 100644 --- a/app/controllers/uploads_controller.rb +++ b/app/controllers/uploads_controller.rb @@ -59,13 +59,7 @@ class UploadsController < ApplicationController content_type = file.content_type end - # when we're dealing with an avatar, crop it to its maximum size - if type == "avatar" && FileHelper.is_image?(filename) - max = Discourse.avatar_sizes.max - OptimizedImage.resize(tempfile.path, tempfile.path, max, max, allow_animation: SiteSetting.allow_animated_avatars) - end - - upload = Upload.create_for(current_user.id, tempfile, filename, tempfile.size, content_type: content_type) + upload = Upload.create_for(current_user.id, tempfile, filename, tempfile.size, content_type: content_type, image_type: type) if upload.errors.empty? && current_user.admin? retain_hours = params[:retain_hours].to_i diff --git a/app/models/upload.rb b/app/models/upload.rb index 995a185b2..b8e0a1e5f 100644 --- a/app/models/upload.rb +++ b/app/models/upload.rb @@ -49,13 +49,62 @@ class Upload < ActiveRecord::Base File.extname(original_filename) end + # list of image types that will be cropped + CROPPED_IMAGE_TYPES ||= ["avatar", "profile_background", "card_background"] + # options # - content_type # - origin + # - image_type def self.create_for(user_id, file, filename, filesize, options = {}) - sha1 = Digest::SHA1.file(file).hexdigest + DistributedMutex.synchronize("upload_#{user_id}_#{filename}") do + # do some work on images + if FileHelper.is_image?(filename) + if filename =~ /\.svg$/i + svg = Nokogiri::XML(file).at_css("svg") + w = svg["width"].to_i + h = svg["height"].to_i + else + # fix orientation first + fix_image_orientation(file.path) + # retrieve image info + image_info = FastImage.new(file) rescue nil + w, h = *(image_info.try(:size) || [0, 0]) + end + + # default size + width, height = ImageSizer.resize(w, h) + + # make sure we're at the beginning of the file (both FastImage and Nokogiri move the pointer) + file.rewind + + # crop images depending on their type + if CROPPED_IMAGE_TYPES.include?(options[:image_type]) + allow_animation = false + max_pixel_ratio = Discourse::PIXEL_RATIOS.max + + case options[:image_type] + when "avatar" + allow_animation = SiteSetting.allow_animated_avatars + width = height = Discourse.avatar_sizes.max + when "profile_background" + max_width = 850 * max_pixel_ratio + width, height = ImageSizer.resize(w, h, max_width: max_width, max_height: max_width) + when "card_background" + max_width = 590 * max_pixel_ratio + width, height = ImageSizer.resize(w, h, max_width: max_width, max_height: max_width) + end + + OptimizedImage.resize(file.path, file.path, width, height, allow_animation: allow_animation) + end + + # optimize image + ImageOptim.new.optimize_image!(file.path) rescue nil + end + + # compute the sha of the file + sha1 = Digest::SHA1.file(file).hexdigest - DistributedMutex.synchronize("upload_#{sha1}") do # do we already have that upload? upload = find_by(sha1: sha1) @@ -75,13 +124,12 @@ class Upload < ActiveRecord::Base upload.filesize = filesize upload.sha1 = sha1 upload.url = "" + upload.width = width + upload.height = height upload.origin = options[:origin][0...1000] if options[:origin] - if FileHelper.is_image?(filename) - # deal with width & height for images - upload = resize_image(filename, file, upload) - # optimize image - ImageOptim.new.optimize_image!(file.path) rescue nil + if FileHelper.is_image?(filename) && (upload.width == 0 || upload.height == 0) + upload.errors.add(:base, I18n.t("upload.images.size_not_found")) end return upload unless upload.save @@ -97,43 +145,10 @@ class Upload < ActiveRecord::Base end end - # return the uploaded file upload end end - def self.resize_image(filename, file, upload) - begin - if filename =~ /\.svg$/i - svg = Nokogiri::XML(file).at_css("svg") - width, height = svg["width"].to_i, svg["height"].to_i - if width == 0 || height == 0 - upload.errors.add(:base, I18n.t("upload.images.size_not_found")) - else - upload.width, upload.height = ImageSizer.resize(width, height) - end - else - # fix orientation first - Upload.fix_image_orientation(file.path) - # retrieve image info - image_info = FastImage.new(file, raise_on_failure: true) - # compute image aspect ratio - upload.width, upload.height = ImageSizer.resize(*image_info.size) - end - # make sure we're at the beginning of the file - # (FastImage and Nokogiri move the pointer) - file.rewind - rescue FastImage::ImageFetchFailure - upload.errors.add(:base, I18n.t("upload.images.fetch_failure")) - rescue FastImage::UnknownImageType - upload.errors.add(:base, I18n.t("upload.images.unknown_image_type")) - rescue FastImage::SizeNotFound - upload.errors.add(:base, I18n.t("upload.images.size_not_found")) - end - - upload - end - def self.get_from_url(url) return if url.blank? # we store relative urls, so we need to remove any host/cdn diff --git a/app/models/user_avatar.rb b/app/models/user_avatar.rb index bc33d1889..a2e6d1e63 100644 --- a/app/models/user_avatar.rb +++ b/app/models/user_avatar.rb @@ -20,7 +20,7 @@ class UserAvatar < ActiveRecord::Base max = Discourse.avatar_sizes.max gravatar_url = "http://www.gravatar.com/avatar/#{email_hash}.png?s=#{max}&d=404" tempfile = FileHelper.download(gravatar_url, SiteSetting.max_image_size_kb.kilobytes, "gravatar") - upload = Upload.create_for(user.id, tempfile, 'gravatar.png', tempfile.size, { origin: gravatar_url }) + upload = Upload.create_for(user.id, tempfile, 'gravatar.png', tempfile.size, origin: gravatar_url, image_type: "avatar") if gravatar_upload_id != upload.id gravatar_upload.try(:destroy!) @@ -68,7 +68,7 @@ class UserAvatar < ActiveRecord::Base ext = FastImage.type(tempfile).to_s tempfile.rewind - upload = Upload.create_for(user.id, tempfile, "external-avatar." + ext, tempfile.size, { origin: avatar_url }) + upload = Upload.create_for(user.id, tempfile, "external-avatar." + ext, tempfile.size, origin: avatar_url, image_type: "avatar") user.uploaded_avatar_id = upload.id unless user.user_avatar diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 177e0e55d..f267c054d 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -2055,8 +2055,6 @@ en: too_large: "Sorry, the file you are trying to upload is too big (maximum size is %{max_size_kb}KB)." images: too_large: "Sorry, the image you are trying to upload is too big (maximum size is %{max_size_kb}KB), please resize it and try again." - fetch_failure: "Sorry, there has been an error while fetching the image." - unknown_image_type: "Sorry, but the file you tried to upload doesn't appear to be an image." size_not_found: "Sorry, but we couldn't determine the size of the image. Maybe your image is corrupted?" flag_reason: diff --git a/lib/image_sizer.rb b/lib/image_sizer.rb index 3fa016004..cc4ee8a6b 100644 --- a/lib/image_sizer.rb +++ b/lib/image_sizer.rb @@ -1,18 +1,18 @@ module ImageSizer # Resize an image to the aspect ratio we want - def self.resize(width, height) + def self.resize(width, height, opts = {}) return if width.blank? || height.blank? - max_width = SiteSetting.max_image_width.to_f - max_height = SiteSetting.max_image_height.to_f + 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_height / h].min; + ratio = [max_width / w, max_height / h].min [(w * ratio).floor, (h * ratio).floor] end diff --git a/spec/components/email/receiver_spec.rb b/spec/components/email/receiver_spec.rb index 24bc176be..a94951d18 100644 --- a/spec/components/email/receiver_spec.rb +++ b/spec/components/email/receiver_spec.rb @@ -303,8 +303,11 @@ This is a link http://example.com" let(:upload_sha) { '04df605be528d03876685c52166d4b063aabb78a' } it "creates a post with an attachment" do + Upload.stubs(:fix_image_orientation) + ImageOptim.any_instance.stubs(:optimize_image!) + start_count = topic.posts.count - Upload.find_by(sha1: upload_sha).try :destroy + Upload.find_by(sha1: upload_sha).try(:destroy) receiver.process diff --git a/spec/fixtures/images/logo-dev.png b/spec/fixtures/images/logo-dev.png index 7cbeb6d6ce5fb485d2741664c8ff5ae112d467f7..b8475b693b4d1b97ecfa7f0fc964739b0c7b71f7 100644 GIT binary patch literal 3196 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 literal 5527 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 ZEig1XFfh7sv9tgH002ovPDHLkV1f@9jfnsN diff --git a/spec/fixtures/images/logo.png b/spec/fixtures/images/logo.png index d09fee186e1ab1c8d53c547b201c30780fb82ed4..5c900b61f70312ad23e30265c92dca79feba84b4 100644 GIT binary patch delta 2235 zcmV;s2t@ad75Nd6BLV@2kzqG~0I5&_uJ7d=B=KA#|M{*|9wFHqB6|MYS9wAhTQms(2wNEdZ;Q35vS_s&1$pBM)zs0IkOqUV9Q}h(Nt) z{L+h$)`jRRBzPSn^m#n^t7!i3rR+c>pWBP+FC%OoB48dN7))XEW-FY39V7E_G~e%{ z3xTfcGb1p#VgRkt8beh3$bxXpdG?oA`o4NEA0X~bBh4HnA2B-jpYOkmAV(e{%26WmXf*9eBLbwlV8?UXA0+Kb zEWhQKt;2Tw+?16{B=n0{pfMsosaCcmBP(rI;$KD}vt|ISy^D}wDUoCge`ykCYDF=S z^Z)<=5Oh*bQveW9fWObLKp=4MV2|IQFy|2*7ytkV5=lfsRCr#0<(lQcyE+VqSBkAb zDQw5x_2=&H?rzuJ-S2;Xfw9mA*f{qc+xOKuAGWLyNs~0tC==1BZirO6Nv+19%WfJ1 zi$nT9`ZKt|9akw=hjB+9g z>kjhCOP6;3lB_za?^__mof3~pc^PmnJqz@W>2bN7Bm)Hby2=>@Ac&=fJh zoJf#oN3eG7`}k9o!I24C8%HxKZO6>_;=l$kE871#ay5poVOuge7D0a*G0zN;)aQ=8wUrf$-vp9k=1WCX5%RFzFl-Xy7QH!`i|5Utp-OEm(} zEGt+^y}HpC`nw)9Wnr99e(prGf zws}U#EiePnN$&ok3iQTp0kU$?#6Y74AW+1lOBz$IXjP#(ln`IC;APR$WI~opilC2= zRDuqFm&%~wZ=C6DLtvQ%*pPTN=#EsX;+7&e?v zM$5b)8WE0U9!fm3_rx-5t%9odWyb zQ=r#c(^a6)s?b(3G*5uKj6C;Tgc!W@4*@&s+Js#N+Lob(mawJFMBup{d`cehxAs(j zfIbxj!ToY**wdcel{46CWqmNsO*Lo*XrrM33f;;XwsViJTp9XG>t*{!l`Z{27(OU( zPAnlXw$-Cg=P->xw@9x5ZAv&8+wBZ7RG&8VqlF~8SCmSNdvC%~GtdiK>;RhNp+UZfdV{LalVj62`qr!9VJP(`8ir1! zWh-#|KzloYwhEv@gfc0+R)-d2XHNF%#u7(MM@xdB^KWL^Rra(lLz~b_I+dY+mHtEM z0L`tukf&P{mwGXO@+gRlbodyU&GMx?3>N11$lfllEKp!2N)=k!6&M@L(b6G@3VpOS zHQSGQS#h*e1Wib11s*Kk%e%V!x0dT6%*?c&LtrhSCUu z6$Ytc5Lf`zTXfKM;C(a(jLNcq8OhkZ4iSL@UX;DlJ7WMUgYTyDxm^G~KXIW)u}YZl zhvAbYfTl&zyxU`&0BtjMaA0$El7jkbn~G@zYCv`(cV%c`P7M$bpsCvL6PlcZa?oR6 zly{#`gOoXZCO|fZhStKMRF@V;AvSbMxuLv#=w$~$-9QhF97s(%WMdzHLjx+ORN6>{ zb?s8kYI2rMu#`M@_f{G5*Fmi3G4lg-97fQtK=OOE3J&xYSQgM=>8QLHoz^|bdpR*% zg+BW20jNzc4xIwx-P;NBtJk5*%t!$=$7_UjmCi@B!n;v&joAgz__itSZ+^a@$q?MFd>M{i;`zdeSBe);e&e#?&NC4RE<^VrB&W z>ugHA`sU%gjW@4?OslVBxZdMICx(Vwiu(ay$D>FL z{d+|G$Ksuh`?putw;qS##_Q$9NYC&5`7Vt0b`!@LhK5-)3~FS55eL{jj_Rk?{SM;^ z7oLe@dwL?tzGb56Ha09g*U#7K$-n;o=ijaK-BaWB^|zs{C!0%X-$?SUSibr{co}~X zuH-M-jUtgw``AZiAF}apie5UlzS04Ia(eSwZd_SkVa}m=<$D;J8~>Mi_@JAOp@U{t zV~C)kzz-2LOm&AY2O6I84;i%K0P>JP8_>B91+=G|@M_LL=s%|t(zt-@uc`n5002ov JPDHLkV1nuxHq-zB delta 2634 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 diff --git a/spec/models/upload_spec.rb b/spec/models/upload_spec.rb index 1e41637fe..2e3d17c6b 100644 --- a/spec/models/upload_spec.rb +++ b/spec/models/upload_spec.rb @@ -45,7 +45,10 @@ describe Upload do context "#create_for" do - before { Upload.stubs(:fix_image_orientation) } + before do + Upload.stubs(:fix_image_orientation) + ImageOptim.any_instance.stubs(:optimize_image!) + end it "does not create another upload if it already exists" do Upload.expects(:find_by).with(sha1: image_sha1).returns(upload) @@ -65,13 +68,6 @@ describe Upload do Upload.create_for(user_id, image, image_filename, image_filesize) end - it "does not create an upload when there is an error with FastImage" do - FileHelper.expects(:is_image?).returns(true) - Upload.expects(:save).never - upload = Upload.create_for(user_id, attachment, attachment_filename, attachment_filesize) - expect(upload.errors.size).to be > 0 - end - it "does not compute width & height for non-image" do FastImage.any_instance.expects(:size).never upload = Upload.create_for(user_id, attachment, attachment_filename, attachment_filesize)