Ruby on Rails: как вы проверяете, является ли файл изображением?

Как вы можете проверить, является ли файл изображением? Я думаю, вы можете использовать такой метод:

def image?(file)
  file.to_s.include?(".gif") or file.to_s.include?(".png") or file.to_s.include?(".jpg")
end

Но это может быть немного неэффективным и неправильным. Любые идеи?

(Я использую плагин paperclip, кстати, но я не вижу никаких способов определить, является ли файл изображением в папке)

Ответы

Ответ 1

Я бы использовал ruby-filemagic gem, который является привязкой Ruby для libmagic.

Ответ 2

Один из подходов - использовать соглашение "магическое число" для чтения первых бит файла.
http://www.astro.keele.ac.uk/oldusers/rno/Computing/File_magic.html

Примеры:

  "BM" is a Bitmap image
  "GIF8" is a GIF image
  "\xff\xd8\xff\xe0" is a JPEG image

Пример в Ruby:

  def bitmap?(data)
    return data[0,2]=="MB"
  end

  def gif?(data)
    return data[0,4]=="GIF8"
  end

  def jpeg?(data)
    return data[0,4]=="\xff\xd8\xff\xe0"
  end

  def file_is_image?(filename)
    f = File.open(filename,'rb')  # rb means to read using binary
    data = f.read(9)              # magic numbers are up to 9 bytes
    f.close
    return bitmap?(data) or gif?(data) or jpeg?(data)
  end

Зачем использовать это вместо расширения имени файла или модуля filemagic?

Чтобы определить тип данных перед записью любых данных на диск. Например, мы можем прочитать поток данных для загрузки, прежде чем писать какие-либо данные на диск. Если магическое число не соответствует типу содержимого веб-формы, мы можем немедленно сообщить об ошибке.

Мы реализуем наш код реального мира несколько иначе. Мы создаем хэш: каждый ключ представляет собой строку магического числа, каждое значение представляет собой символ: bitmap,: gif,: jpeg и т.д. Если кто-то хочет увидеть наш код реального мира, не стесняйтесь связаться со мной здесь.

Ответ 3

Поскольку вы используете Paperclip, вы можете использовать встроенный метод validates_attachment_content_type в модели, где используется "has_attached_file", и указать, какие типы файлов вы хотите разрешить.

Вот пример из приложения, в котором пользователи загружают аватар для своего профиля:

has_attached_file :avatar, 
                  :styles => { :thumb => "48x48#" },
                  :default_url => "/images/avatars/missing_avatar.png",
                  :default_style => :thumb

validates_attachment_content_type :avatar, :content_type => ["image/jpeg", "image/pjpeg", "image/png", "image/x-png", "image/gif"]

Документация находится здесь http://dev.thoughtbot.com/paperclip/classes/Paperclip/ClassMethods.html

Ответ 4

Пожалуйста, проверьте его один раз

MIME::Types.type_for('tmp/img1.jpg').first.try(:media_type)
=> "image"

MIME::Types.type_for('tmp/img1.jpeg').first.try(:media_type)
=> "image"

MIME::Types.type_for('tmp/img1.gif').first.try(:media_type)
=> "image"

MIME::Types.type_for('tmp/ima1.png').first.try(:media_type)
=> "image"

Ответ 5

У imagemagick есть команда под названием identity, которая обрабатывает это: check w/paperclip documentation - возможно, это способ справиться с этим из вашего RoR-приложения.

Ответ 6

Как дополнение к ответу Джоэля, в Rails 5 мне пришлось преобразовать строку сравнения в байт-код. Например:

def jpeg?(data)
  return data[0,4]=="\xff\xd8\xff\xe0".b
end