Low commit activity in last 3 years
Reads width, height, format, DPI, and color depth from image file headers (PNG, JPEG, GIF, BMP, WebP, TIFF, ICO, SVG, AVIF) without loading the full image. Zero dependencies, fast, and memory-efficient.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies
 Project Readme

philiprehberger-image_size

Tests Gem Version Last updated

Image dimension detection from file headers without full decode

Requirements

  • Ruby >= 3.1

Installation

Add to your Gemfile:

gem "philiprehberger-image_size"

Or install directly:

gem install philiprehberger-image_size

Usage

require "philiprehberger/image_size"

info = Philiprehberger::ImageSize.of("photo.png")
info.width   # => 1920
info.height  # => 1080
info.format  # => :png

Dimensions Only

width, height = Philiprehberger::ImageSize.dimensions("banner.jpg")

Format Detection

format = Philiprehberger::ImageSize.format("image.webp")
# => :webp

IO Objects

File.open("photo.gif", "rb") do |f|
  info = Philiprehberger::ImageSize.of(f)
  puts info.to_s  # => "GIF 320x240"
end

Animation Detection

info = Philiprehberger::ImageSize.of("animation.gif")
info.animated?  # => true

Alpha Channel Detection

info = Philiprehberger::ImageSize.of("transparent.png")
info.alpha?  # => true

EXIF Orientation

info = Philiprehberger::ImageSize.of("rotated.jpg")
info.orientation  # => 6
# Width and height reflect actual display dimensions (swapped for 90/270 rotation)

ImageInfo Value Object

info = Philiprehberger::ImageSize.of("photo.bmp")
info.to_a  # => [640, 480]
info.to_h  # => { width: 640, height: 480, format: :bmp, animated: false, alpha: false, orientation: nil }

Megapixels

info = Philiprehberger::ImageSize.of("photo.png")
info.megapixels  # => 2.1

DPI Extraction

info = Philiprehberger::ImageSize.of("print-ready.jpg")
info.dpi  # => { x: 300.0, y: 300.0 } or nil if not available

Supported sources: JPEG (JFIF APP0), PNG (pHYs chunk), TIFF (resolution tags), BMP (pixels per meter).

Color Depth

info = Philiprehberger::ImageSize.of("photo.png")
info.color_depth  # => 24 (bits per pixel) or nil if not detectable

Supported formats: PNG (bit depth * channels), BMP (from header), JPEG (precision * components from SOF marker).

Interlace Detection

info = Philiprehberger::ImageSize.of("progressive.jpg")
info.interlaced?  # => true (progressive JPEG)

info = Philiprehberger::ImageSize.of("interlaced.png")
info.interlaced?  # => true (Adam7 interlacing)

Computed Properties

info = Philiprehberger::ImageSize.of("photo.png")
info.aspect_ratio  # => 1.78
info.landscape?    # => true
info.portrait?     # => false
info.square?       # => false
info.area          # => 2073600
info.megapixels    # => 2.1
info.rotated?      # => false

Fit Within a Bounding Box

info = Philiprehberger::ImageSize.of("photo.png") # 1920x1080
info.fit_within(400, 400)  # => [400, 225]   # scaled down, aspect preserved
info.fit_within(3000, 3000) # => [1920, 1080] # no upscale

API

Philiprehberger::ImageSize

Method Description
.of(path_or_io) Returns ImageInfo with width, height, format, and metadata
.dimensions(path_or_io) Returns [width, height] array
.format(path_or_io) Returns format symbol (:png, :jpeg, :gif, :bmp, :webp, :tiff, :ico, :cur, :svg, :avif)

Philiprehberger::ImageSize::ImageInfo

Method Description
#width Image width in pixels (display dimensions for rotated JPEG)
#height Image height in pixels (display dimensions for rotated JPEG)
#format Format symbol
#animated? Whether the image is animated (GIF, WebP, APNG)
#alpha? Whether the image has an alpha channel
#interlaced? Whether the image uses interlaced (PNG Adam7) or progressive (JPEG) encoding
#orientation EXIF orientation (1-8), nil if not applicable
#aspect_ratio Width divided by height as Float
#landscape? Whether width > height
#portrait? Whether height > width
#square? Whether width == height
#area Total pixel count (width * height)
#megapixels Area in megapixels, rounded to 1 decimal
#dpi DPI as { x: Float, y: Float } hash, or nil
#color_depth Bits per pixel (PNG, BMP, JPEG), or nil
#rotated? Whether EXIF orientation indicates 90/270 rotation
#fit_within(max_w, max_h) Returns [w, h] scaled to fit inside a bounding box (preserves aspect ratio, never upscales)
#to_a Returns [width, height]
#to_h Returns hash with all attributes
#to_s Returns "FORMAT WxH" string

Development

bundle install
bundle exec rspec
bundle exec rubocop

Support

If you find this project useful:

Star the repo

🐛 Report issues

💡 Suggest features

❤️ Sponsor development

🌐 All Open Source Projects

💻 GitHub Profile

🔗 LinkedIn Profile

License

MIT