Przeglądaj źródła

Fix avatar and header issues by using custom geometry detector (#6515)

* Fix avatar and header issues by using custom geometry detector

Revert a part of #6508. The file passed to dynamic styles method
was not actually a file, but an instance of Paperclip::Attachment,
which broke all styles by always returning {} from the method.

One problem with GIF avatars was that Paperclip::GeometryDetector
reported wrong dimensions for them, e.g. 120x120 GIF avatar would
for some reason be detected as 120x53. By writing our own geometry
parser, we can use FastImage, which also happens to be faster than
ImageMagick, to detect image dimensions, which are also correct.

Unfortunately, this PR does not implement skipping a `convert`
entirely if the dimensions are already correct, as I found no easy
way to write that behaviour into Paperclip without rewriting the
Paperclip::Thumbnail class.

* Only invoke convert if dimension or format needs to be changed
master
Eugen Rochko 6 lat temu
committed by GitHub
rodzic
commit
a7171af0a3
Nie znaleziono w bazie danych klucza dla tego podpisu ID klucza GPG: 4AEE18F83AFDEB23
10 zmienionych plików z 73 dodań i 34 usunięć
  1. +1
    -0
      Gemfile
  2. +2
    -0
      Gemfile.lock
  3. +11
    -0
      app/lib/fast_geometry_parser.rb
  4. +3
    -9
      app/models/concerns/account_avatar.rb
  5. +3
    -9
      app/models/concerns/account_header.rb
  6. +19
    -8
      app/models/media_attachment.rb
  7. +7
    -6
      app/models/preview_card.rb
  8. +2
    -2
      app/models/site_upload.rb
  9. +1
    -0
      config/application.rb
  10. +24
    -0
      lib/paperclip/lazy_thumbnail.rb

+ 1
- 0
Gemfile Wyświetl plik

@@ -40,6 +40,7 @@ gem 'omniauth', '~> 1.2'

gem 'doorkeeper', '~> 4.2'
gem 'fast_blank', '~> 1.0'
gem 'fastimage'
gem 'goldfinger', '~> 2.1'
gem 'hiredis', '~> 0.6'
gem 'redis-namespace', '~> 1.5'


+ 2
- 0
Gemfile.lock Wyświetl plik

@@ -185,6 +185,7 @@ GEM
faraday (0.14.0)
multipart-post (>= 1.2, < 3)
fast_blank (1.0.0)
fastimage (2.1.1)
ffi (1.9.18)
fog-core (1.45.0)
builder
@@ -641,6 +642,7 @@ DEPENDENCIES
fabrication (~> 2.18)
faker (~> 1.7)
fast_blank (~> 1.0)
fastimage
fog-core (~> 1.45)
fog-local (~> 0.4)
fog-openstack (~> 0.1)


+ 11
- 0
app/lib/fast_geometry_parser.rb Wyświetl plik

@@ -0,0 +1,11 @@
# frozen_string_literal: true

class FastGeometryParser
def self.from_file(file)
width, height = FastImage.size(file.path)

raise Paperclip::Errors::NotIdentifiedByImageMagickError if width.nil?

Paperclip::Geometry.new(width, height)
end
end

+ 3
- 9
app/models/concerns/account_avatar.rb Wyświetl plik

@@ -7,15 +7,9 @@ module AccountAvatar

class_methods do
def avatar_styles(file)
styles = {}
geometry = Paperclip::Geometry.from_file(file)

styles[:original] = '120x120#' if geometry.width != geometry.height || geometry.width > 120 || geometry.height > 120
styles[:static] = { format: 'png', convert_options: '-coalesce' } if file.content_type == 'image/gif'

styles = { original: { geometry: '120x120#', file_geometry_parser: FastGeometryParser } }
styles[:static] = { format: 'png', convert_options: '-coalesce', file_geometry_parser: FastGeometryParser } if file.content_type == 'image/gif'
styles
rescue Paperclip::Errors::NotIdentifiedByImageMagickError
{}
end

private :avatar_styles
@@ -23,7 +17,7 @@ module AccountAvatar

included do
# Avatar upload
has_attached_file :avatar, styles: ->(f) { avatar_styles(f) }, convert_options: { all: '-strip' }
has_attached_file :avatar, styles: ->(f) { avatar_styles(f) }, convert_options: { all: '-strip' }, processors: [:lazy_thumbnail]
validates_attachment_content_type :avatar, content_type: IMAGE_MIME_TYPES
validates_attachment_size :avatar, less_than: 2.megabytes
end


+ 3
- 9
app/models/concerns/account_header.rb Wyświetl plik

@@ -7,15 +7,9 @@ module AccountHeader

class_methods do
def header_styles(file)
styles = {}
geometry = Paperclip::Geometry.from_file(file)

styles[:original] = '700x335#' unless geometry.width == 700 && geometry.height == 335
styles[:static] = { format: 'png', convert_options: '-coalesce' } if file.content_type == 'image/gif'

styles = { original: { geometry: '700x335#', file_geometry_parser: FastGeometryParser } }
styles[:static] = { format: 'png', convert_options: '-coalesce', file_geometry_parser: FastGeometryParser } if file.content_type == 'image/gif'
styles
rescue Paperclip::Errors::NotIdentifiedByImageMagickError
{}
end

private :header_styles
@@ -23,7 +17,7 @@ module AccountHeader

included do
# Header upload
has_attached_file :header, styles: ->(f) { header_styles(f) }, convert_options: { all: '-strip' }
has_attached_file :header, styles: ->(f) { header_styles(f) }, convert_options: { all: '-strip' }, processors: [:lazy_thumbnail]
validates_attachment_content_type :header, content_type: IMAGE_MIME_TYPES
validates_attachment_size :header, less_than: 2.megabytes
end


+ 19
- 8
app/models/media_attachment.rb Wyświetl plik

@@ -32,7 +32,18 @@ class MediaAttachment < ApplicationRecord
IMAGE_MIME_TYPES = ['image/jpeg', 'image/png', 'image/gif'].freeze
VIDEO_MIME_TYPES = ['video/webm', 'video/mp4'].freeze

IMAGE_STYLES = { original: '1280x1280>', small: '400x400>' }.freeze
IMAGE_STYLES = {
original: {
geometry: '1280x1280>',
file_geometry_parser: FastGeometryParser,
},

small: {
geometry: '400x400>',
file_geometry_parser: FastGeometryParser,
},
}.freeze

VIDEO_STYLES = {
small: {
convert_options: {
@@ -167,16 +178,16 @@ class MediaAttachment < ApplicationRecord
end

def image_geometry(file)
geo = Paperclip::Geometry.from_file file
width, height = FastImage.size(file.path)

return {} if width.nil?

{
width: geo.width.to_i,
height: geo.height.to_i,
size: "#{geo.width.to_i}x#{geo.height.to_i}",
aspect: geo.width.to_f / geo.height.to_f,
width: width,
height: height,
size: "#{width}x#{height}",
aspect: width.to_f / height.to_f,
}
rescue Paperclip::Errors::NotIdentifiedByImageMagickError
{}
end

def video_metadata(file)


+ 7
- 6
app/models/preview_card.rb Wyświetl plik

@@ -33,7 +33,7 @@ class PreviewCard < ApplicationRecord

has_and_belongs_to_many :statuses

has_attached_file :image, styles: { original: '400x400>' }, convert_options: { all: '-quality 80 -strip' }
has_attached_file :image, styles: { original: { geometry: '400x400>', file_geometry_parser: FastGeometryParser } }, convert_options: { all: '-quality 80 -strip' }

include Attachmentable
include Remotable
@@ -58,10 +58,11 @@ class PreviewCard < ApplicationRecord

return if file.nil?

geo = Paperclip::Geometry.from_file(file)
self.width = geo.width.to_i
self.height = geo.height.to_i
rescue Paperclip::Errors::NotIdentifiedByImageMagickError
nil
width, height = FastImage.size(file.path)

return nil if width.nil?

self.width = width
self.height = height
end
end

+ 2
- 2
app/models/site_upload.rb Wyświetl plik

@@ -34,8 +34,8 @@ class SiteUpload < ApplicationRecord

return if tempfile.nil?

geometry = Paperclip::Geometry.from_file(tempfile)
self.meta = { width: geometry.width.to_i, height: geometry.height.to_i }
width, height = FastImage.size(tempfile.path)
self.meta = { width: width, height: height }
end

def clear_cache


+ 1
- 0
config/application.rb Wyświetl plik

@@ -7,6 +7,7 @@ require 'rails/all'
Bundler.require(*Rails.groups)

require_relative '../app/lib/exceptions'
require_relative '../lib/paperclip/lazy_thumbnail'
require_relative '../lib/paperclip/gif_transcoder'
require_relative '../lib/paperclip/video_transcoder'
require_relative '../lib/mastodon/snowflake'


+ 24
- 0
lib/paperclip/lazy_thumbnail.rb Wyświetl plik

@@ -0,0 +1,24 @@
# frozen_string_literal: true

module Paperclip
class LazyThumbnail < Paperclip::Thumbnail
def make
return @file unless needs_convert?
Paperclip::Thumbnail.make(file, options, attachment)
end

private

def needs_convert?
needs_different_geometry? || needs_different_format?
end

def needs_different_geometry?
!@target_geometry.nil? && @current_geometry.width != @target_geometry.width && @current_geometry.height != @target_geometry.height
end

def needs_different_format?
@format.present? && @current_format != @format
end
end
end

Ładowanie…
Anuluj
Zapisz