# encoding: BINARY # frozen_string_literal: true require 'stringio' # Determine image format and size class ImageSize class FormatError < StandardError; end # Array joining with 'x' class Size < Array # join using 'x' def to_s join('x') end end class ImageReader # :nodoc: attr_reader :data def initialize(data_or_io) @io = if data_or_io.is_a?(String) StringIO.new(data_or_io) elsif data_or_io.respond_to?(:read) && data_or_io.respond_to?(:eof?) data_or_io else raise ArgumentError, "expected data as String or an object responding to read and eof?, got #{data_or_io.class}" end @data = String.new # not frozen end CHUNK = 1024 def [](offset, length) while !@io.eof? && @data.length < offset + length data = @io.read(CHUNK) break unless data data.force_encoding(@data.encoding) if data.respond_to?(:encoding) @data << data end @data[offset, length] end end # Given path to image finds its format, width and height def self.path(path) File.open(path, 'rb'){ |f| new(f) } end # Used for svg def self.dpi @dpi || 72 end # Used for svg def self.dpi=(dpi) @dpi = dpi.to_f end # Given image as any class responding to read and eof? or data as String, finds its format and dimensions def initialize(data) ir = ImageReader.new(data) @format = detect_format(ir) return unless @format @width, @height = send("size_of_#{@format}", ir) end # Image format attr_reader :format # Image width attr_reader :width alias_method :w, :width # Image height attr_reader :height alias_method :h, :height # get image width and height as an array which to_s method returns "#{width}x#{height}" def size Size.new([width, height]) if format end private SVG_R = /]*)>/.freeze def detect_format(ir) head = ir[0, 1024] case when head[0, 6] =~ /GIF8[79]a/ then :gif when head[0, 8] == "\211PNG\r\n\032\n" then detect_png_type(ir) when head[0, 8] == "\212MNG\r\n\032\n" then :mng when head[0, 2] == "\377\330" then :jpeg when head[0, 2] == 'BM' then :bmp when head[0, 2] =~ /P[1-7]/ then :ppm when head =~ /\#define\s+\S+\s+\d+/ then :xbm when head[0, 4] == "II*\000" then :tiff when head[0, 4] == "MM\000*" then :tiff when head =~ %r{/\* XPM \*/} then :xpm when head[0, 4] == '8BPS' then :psd when head[0, 3] =~ /[FC]WS/ then :swf when head[SVG_R] || head =~ /<\?xml|