[![Gem Version](https://img.shields.io/gem/v/image_size?logo=rubygems)](https://rubygems.org/gems/image_size)
[![Check](https://img.shields.io/github/actions/workflow/status/toy/image_size/check.yml?label=check&logo=github)](https://github.com/toy/image_size/actions/workflows/check.yml)
[![Rubocop](https://img.shields.io/github/actions/workflow/status/toy/image_size/rubocop.yml?label=rubocop&logo=rubocop)](https://github.com/toy/image_size/actions/workflows/rubocop.yml)

# image_size

Measure image size/dimensions using pure Ruby.
Formats: `apng`, `avif`, `bmp`, `cur`, `emf`, `gif`, `heic`, `heif`, `icns`, `ico`, `j2c`, `jp2`, `jpeg`, `jpx`, `mng`, `pam`, `pbm`, `pcx`, `pgm`, `png`, `ppm`, `psd`, `svg`, `swf`, `tiff`, `webp`, `xbm`, `xpm`.

## Installation

```sh
gem install image_size
```

### Bundler

Add to your `Gemfile`:

```ruby
gem 'image_size', '~> 3.0'
```

## Usage

```ruby
image_size = ImageSize.path('spec/images/jpeg/436x429.jpeg')

image_size.format       #=> :jpeg
image_size.width        #=> 436
image_size.height       #=> 429
image_size.w            #=> 436
image_size.h            #=> 429
image_size.size         #=> [436, 429]
image_size.size.to_s    #=> "436x429"
"#{image_size.size}"    #=> "436x429"
image_size.size.width   #=> 436
image_size.size.height  #=> 429
image_size.size.w       #=> 436
image_size.size.h       #=> 429
image_size.media_type   #=> "image/jpeg"
image_size.media_types  #=> ["image/jpeg"]
image_size.byte_size    #=> 10938
```

Or using `IO` object:

```ruby
image_size = File.open('spec/images/jpeg/436x429.jpeg', 'rb'){ |fh| ImageSize.new(fh) }
```

Any object responding to `read` and `eof?`:

```ruby
require 'image_size'

image_size = ImageSize.new(ARGF)
```

Works with `open-uri`, see [experimental HTTP server interface below](#experimental-fetch-image-meta-from-http-server):

```ruby
require 'image_size'
require 'open-uri'

image_size = URI.parse('http://www.rubycgi.org/image/ruby_gtk_book_title.jpg').open('rb') do |fh|
  ImageSize.new(fh)
end

image_size = open('http://www.rubycgi.org/image/ruby_gtk_book_title.jpg', 'rb') do |fh|
  ImageSize.new(fh)
end
```

Note that starting with version `2.0.0` the object given to `ImageSize` will not be rewound before or after use.
So rewind if needed before passing to `ImageSize` and/or rewind after passing to `ImageSize` before reading data.

```ruby
require 'image_size'

File.open('spec/images/jpeg/436x429.jpeg', 'rb') do |fh|
  image_size = ImageSize.new(fh)

  fh.rewind
  data = fh.read
end

File.open('spec/images/jpeg/436x429.jpeg', 'rb') do |fh|
  data = fh.read
  fh.rewind

  image_size = ImageSize.new(fh)
end
```

### Configuration

DPI used for converting `svg` and `emf` dimensions can be configured from default 72:

```ruby
ImageSize.dpi = 150
```

Chunk size used for reading files, IO and from remote can be configured from default 4096:

```ruby
ImageSize.chunk_size = 256
```

### Experimental: fetch image meta from HTTP server

If server recognises Range header, only needed chunks will be fetched even for TIFF images, otherwise required amount
of data will be fetched, in most cases first few kilobytes (TIFF images is an exception).

```ruby
require 'image_size/uri'

url = 'http://upload.wikimedia.org/wikipedia/commons/b/b4/Mardin_1350660_1350692_33_images.jpg'
p ImageSize.url(url).size
```

This interface is as fast as dedicated gem fastimage for images with meta information in the header:

```ruby
url = 'http://upload.wikimedia.org/wikipedia/commons/b/b4/Mardin_1350660_1350692_33_images.jpg'
puts Benchmark.measure{ p FastImage.size(url) }
```
```
[9545, 6623]
  0.004176   0.001974   0.006150 (  0.282889)
```
```ruby
puts Benchmark.measure{ p ImageSize.url(url).size }
```
```
[9545, 6623]
  0.005604   0.001406   0.007010 (  0.238629)
```

And considerably faster for images with meta information at the end of file:

```ruby
url = "https://upload.wikimedia.org/wikipedia/commons/c/c7/Curiosity%27s_Vehicle_System_Test_Bed_%28VSTB%29_Rover_%28PIA15876%29.tif"
puts Benchmark.measure{ p FastImage.size(url) }
```
```
[7360, 4912]
  0.331284   0.247295   0.578579 (  6.027051)
```
```ruby
puts Benchmark.measure{ p ImageSize.url(url).size }
```
```
[7360, 4912]
  0.006247   0.001045   0.007292 (  0.197631)
```

#### Configuration

Maximum number of redirects can be configured from default 5:

```ruby
ImageSize.max_redirects = 10
```

Or redirects can be disabled:

```ruby
ImageSize.max_redirects = 0
```

A url checker can be added to reduce SSRF risk:

```ruby
ImageSize.uri_checker = lambda do |uri|
  raise 'host is not allowed' unless uri.host == 'upload.wikipedia.org'
end
```

Alternatively `private_address_check` gem can be of help:

```ruby
require "private_address_check/tcpsocket_ext"

PrivateAddressCheck.only_public_connections do
  ImageSize.url(url).size
end
```

## Licence

This code is free to use under the terms of the [Ruby's licence](LICENSE.txt).

Original author: Keisuke Minami <keisuke@rccn.com>.\
Further development 2010-2026 Ivan Kuchin https://github.com/toy/image_size
