Class: DynamicImage::Format
- Inherits:
-
Object
- Object
- DynamicImage::Format
- Defined in:
- lib/dynamic_image/format.rb
Overview
DynamicImage Format
A registry of the image formats DynamicImage understands. Each format knows its content types, extensions, the magic bytes that identify it, the options it is saved with, and whether it can hold more than one frame.
Formats are looked up by name, by content type, or by sniffing the first bytes of a file. Uploads are always identified by sniffing, never by the content type the client claims.
Instance Attribute Summary collapse
-
#alpha ⇒ Boolean
readonly
Whether the format holds an alpha channel.
-
#animated ⇒ Boolean
readonly
Whether the format holds more than one frame.
-
#content_types ⇒ Array<String>
readonly
The content types, canonical one first.
-
#extensions ⇒ Array<String>
readonly
The file extensions, preferred one first.
-
#magic_bytes ⇒ Array<String>
readonly
Byte sequences identifying the format.
-
#name ⇒ String
readonly
The format name, such as "JPEG".
-
#offset ⇒ Integer
readonly
Where in the header the magic bytes sit.
-
#save_options ⇒ Hash
readonly
Options passed to vips when writing.
-
#signature ⇒ Object
readonly
Returns the value of attribute signature.
Class Method Summary collapse
-
.content_type(type) ⇒ DynamicImage::Format?
Finds the format for a content type.
-
.content_types ⇒ Array<String>
Every content type of every registered format.
-
.find(name) ⇒ DynamicImage::Format?
Finds a format by name.
-
.formats ⇒ Array<DynamicImage::Format>
All registered formats.
-
.iso_brands(bytes) ⇒ Array<String>
The brands declared by an ISO base media file, major brand first, followed by the compatible brands.
-
.register(name, **opts) ⇒ DynamicImage::Format
Registers a format.
-
.sniff(bytes) ⇒ DynamicImage::Format?
Identifies a format from the first bytes of a file.
Instance Method Summary collapse
-
#alpha? ⇒ Boolean
Returns true if the format supports an alpha channel.
-
#animated? ⇒ Boolean
Returns true if the format supports multiple frames.
-
#content_type ⇒ String
The canonical content type.
-
#default_options ⇒ Hash
Defaults every format definition is merged over.
-
#extension ⇒ String
The preferred file extension, leading dot included.
-
#initialize(name, options) ⇒ Format
constructor
A new instance of Format.
-
#matches?(bytes) ⇒ Boolean
Returns true if the given header belongs to this format.
-
#mime_type ⇒ Mime::Type
The canonical content type as a Mime::Type.
Constructor Details
#initialize(name, options) ⇒ Format
Returns a new instance of Format.
42 43 44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/dynamic_image/format.rb', line 42 def initialize(name, ) = .merge() @name = name @animated = [:animated] @alpha = [:alpha] @content_types = Array([:content_type]) @extensions = Array([:extension]) @magic_bytes = [:magic_bytes].map(&:b) @offset = [:offset] @signature = [:signature] @save_options = [:save_options] end |
Instance Attribute Details
#alpha ⇒ Boolean (readonly)
Returns whether the format holds an alpha channel.
36 37 |
# File 'lib/dynamic_image/format.rb', line 36 attr_reader :name, :animated, :alpha, :content_types, :extensions, :magic_bytes, :offset, :save_options, :signature |
#animated ⇒ Boolean (readonly)
Returns whether the format holds more than one frame.
36 37 |
# File 'lib/dynamic_image/format.rb', line 36 attr_reader :name, :animated, :alpha, :content_types, :extensions, :magic_bytes, :offset, :save_options, :signature |
#content_types ⇒ Array<String> (readonly)
Returns the content types, canonical one first.
36 37 |
# File 'lib/dynamic_image/format.rb', line 36 attr_reader :name, :animated, :alpha, :content_types, :extensions, :magic_bytes, :offset, :save_options, :signature |
#extensions ⇒ Array<String> (readonly)
Returns the file extensions, preferred one first.
36 37 |
# File 'lib/dynamic_image/format.rb', line 36 attr_reader :name, :animated, :alpha, :content_types, :extensions, :magic_bytes, :offset, :save_options, :signature |
#magic_bytes ⇒ Array<String> (readonly)
Returns byte sequences identifying the format.
36 37 |
# File 'lib/dynamic_image/format.rb', line 36 attr_reader :name, :animated, :alpha, :content_types, :extensions, :magic_bytes, :offset, :save_options, :signature |
#name ⇒ String (readonly)
Returns the format name, such as "JPEG".
36 37 38 |
# File 'lib/dynamic_image/format.rb', line 36 def name @name end |
#offset ⇒ Integer (readonly)
Returns where in the header the magic bytes sit.
36 37 |
# File 'lib/dynamic_image/format.rb', line 36 attr_reader :name, :animated, :alpha, :content_types, :extensions, :magic_bytes, :offset, :save_options, :signature |
#save_options ⇒ Hash (readonly)
Returns options passed to vips when writing.
36 37 |
# File 'lib/dynamic_image/format.rb', line 36 attr_reader :name, :animated, :alpha, :content_types, :extensions, :magic_bytes, :offset, :save_options, :signature |
#signature ⇒ Object (readonly)
Returns the value of attribute signature.
36 37 |
# File 'lib/dynamic_image/format.rb', line 36 attr_reader :name, :animated, :alpha, :content_types, :extensions, :magic_bytes, :offset, :save_options, :signature |
Class Method Details
.content_type(type) ⇒ DynamicImage::Format?
Finds the format for a content type.
107 108 109 |
# File 'lib/dynamic_image/format.rb', line 107 def content_type(type) formats.filter { |f| f.content_types.include?(type) }.first end |
.content_types ⇒ Array<String>
Every content type of every registered format.
114 115 116 |
# File 'lib/dynamic_image/format.rb', line 114 def content_types formats.flat_map(&:content_types) end |
.find(name) ⇒ DynamicImage::Format?
Finds a format by name. Case insensitive, and "JPG" is understood as an alias for "JPEG".
122 123 124 125 126 |
# File 'lib/dynamic_image/format.rb', line 122 def find(name) key = name.to_s.upcase key = "JPEG" if key == "JPG" registered_formats[key] end |
.formats ⇒ Array<DynamicImage::Format>
All registered formats.
131 132 133 |
# File 'lib/dynamic_image/format.rb', line 131 def formats registered_formats.map { |_, f| f } end |
.iso_brands(bytes) ⇒ Array<String>
The brands declared by an ISO base media file, major brand first, followed by the compatible brands. Empty for
anything that isn't an ftyp box.
162 163 164 165 166 |
# File 'lib/dynamic_image/format.rb', line 162 def iso_brands(bytes) return [] unless bytes.to_s.bytesize >= 12 && bytes[4, 4] == "ftyp".b [bytes[8, 4]] + bytes[16...bytes.unpack1("N")].to_s.scan(/.{4}/m) end |
.register(name, **opts) ⇒ DynamicImage::Format
Registers a format.
Each option sets the attribute of the same name, except content_type and extension, which are singular
here and accept either one value or a list. Anything left out falls back to #default_options.
143 144 145 |
# File 'lib/dynamic_image/format.rb', line 143 def register(name, **opts) registered_formats[name] = new(name, opts) end |
.sniff(bytes) ⇒ DynamicImage::Format?
Identifies a format from the first bytes of a file.
151 152 153 154 155 |
# File 'lib/dynamic_image/format.rb', line 151 def sniff(bytes) return unless bytes formats.find { |format| format.matches?(bytes) } end |
Instance Method Details
#alpha? ⇒ Boolean
Returns true if the format supports an alpha channel.
66 67 68 |
# File 'lib/dynamic_image/format.rb', line 66 def alpha? alpha end |
#animated? ⇒ Boolean
Returns true if the format supports multiple frames.
59 60 61 |
# File 'lib/dynamic_image/format.rb', line 59 def animated? animated end |
#content_type ⇒ String
The canonical content type.
84 85 86 |
# File 'lib/dynamic_image/format.rb', line 84 def content_type content_types.first end |
#default_options ⇒ Hash
Defaults every format definition is merged over.
178 179 180 181 |
# File 'lib/dynamic_image/format.rb', line 178 def { animated: false, alpha: false, content_type: [], extension: [], magic_bytes: [], offset: 0, signature: nil, save_options: {} } end |
#extension ⇒ String
The preferred file extension, leading dot included.
91 92 93 |
# File 'lib/dynamic_image/format.rb', line 91 def extension extensions.first end |
#matches?(bytes) ⇒ Boolean
Returns true if the given header belongs to this format.
74 75 76 77 78 79 |
# File 'lib/dynamic_image/format.rb', line 74 def matches?(bytes) header = bytes.to_s[offset..].to_s return false unless magic_bytes.any? { |b| header.start_with?(b) } signature.nil? || signature.call(bytes) end |
#mime_type ⇒ Mime::Type
The canonical content type as a Mime::Type.
98 99 100 |
# File 'lib/dynamic_image/format.rb', line 98 def mime_type Mime::Type.lookup(content_type) end |