# frozen_string_literal: true require "fastimage" module Notare class ImageDimensions EMUS_PER_INCH = 914_400 DEFAULT_DPI = 96 def self.read(path) FastImage.size(path) || raise(ArgumentError, "Could not read image dimensions: #{path}") end def self.calculate_emus(path, width: nil, height: nil) native_width, native_height = read(path) calculate_dimensions_emu(native_width, native_height, width, height) end def self.calculate_dimensions_emu(native_width, native_height, width, height) if width && height [parse_dimension(width), parse_dimension(height)] elsif width w = parse_dimension(width) ratio = native_height.to_f / native_width [w, (w * ratio).to_i] elsif height h = parse_dimension(height) ratio = native_width.to_f / native_height [(h * ratio).to_i, h] else pixels_to_emus(native_width, native_height) end end def self.parse_dimension(value) case value when Integer pixels_to_emus(value, 0).first when /\A(\d+(?:\.\d+)?)\s*in\z/i (::Regexp.last_match(1).to_f * EMUS_PER_INCH).to_i when /\A(\d+(?:\.\d+)?)\s*cm\z/i (::Regexp.last_match(1).to_f * 360_000).to_i when /\A(\d+(?:\.\d+)?)\s*px\z/i, /\A(\d+)\z/ pixels_to_emus(::Regexp.last_match(1).to_i, 0).first else raise ArgumentError, "Invalid dimension format: #{value}. Use '2in', '5cm', '100px', or integer pixels." end end def self.pixels_to_emus(width_px, height_px) emu_per_pixel = EMUS_PER_INCH / DEFAULT_DPI [(width_px * emu_per_pixel).to_i, (height_px * emu_per_pixel).to_i] end end end