pura-image 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 200a23ef9a4ba80b7499eee4b910eaf6e34c40bf8ad3eec6cdf98b579388ccd9
4
- data.tar.gz: 277147726deb52d9db3b63fa91968c71af2b4eaf672ba8fe8c582e9f8ddeea5e
3
+ metadata.gz: 6e595cde6db52041e2cfd43fe678c8f42d2f02396db44d6d1f72a77db96f15d7
4
+ data.tar.gz: 320aafe82456416eb38b45b53dae2f452118a6dd0bcbc1ef30ff13661f735125
5
5
  SHA512:
6
- metadata.gz: e638cbec0e311ea2b6443319c264f45b1453481dac6f86a4f7ca47dd726c1f60527c58edd627801505a5c243702e058d21023c79f05dafaa1ed8e3b7b3c8e814
7
- data.tar.gz: d3fb43c72fd71a8ebf8947759ecd672ef9789b63c563dc81ddd63da17f44b2685f1edfadf655e75e7e9b68d5af146c5f56975676024873f56083216eca6b4cda
6
+ metadata.gz: ca3bd535aca6ace92343ec86132c78ca08a87f073b5e5a266a40522684dfb7d54297c25543f82a6216c5692cc1ca46af6ea535c08376dd7927fb86fc0b0fa611
7
+ data.tar.gz: bcf34c74223f1b4e6d3f5cfceab9ec4143152adf086bdb30ada1fb9d0a6b096efe7e111b6e10affd477b4c6cdfcd43cf009f8e881887278b000465a85f63b499
data/Gemfile CHANGED
@@ -3,3 +3,4 @@ source "https://rubygems.org"
3
3
  gemspec
4
4
 
5
5
  gem "rubocop", require: false
6
+ gem "erb", require: false # RuboCop configuration templates on Ruby distributions without default ERB
data/README.md CHANGED
@@ -1,113 +1,84 @@
1
1
  # pura-image
2
2
 
3
- Pure Ruby image processing library with **zero C extension dependencies**. Bundles all **pura-*** format gems and provides an `ImageProcessing` adapter for Rails Active Storage.
3
+ Image processing in Ruby, without installing libvips or ImageMagick. Bundles the **pura-*** codec gems and provides a pipeline API and Rails Active Storage integration.
4
4
 
5
- ## Why this exists (in 30 seconds)
6
-
7
- Stop installing system libraries just to resize an image in Rails.
5
+ ## Installation
8
6
 
9
- ```diff
7
+ ```ruby
10
8
  # Gemfile
11
- + gem "pura-image"
12
- ```
9
+ gem "pura-image"
13
10
 
14
- ```ruby
15
11
  # config/application.rb
16
12
  config.active_storage.variant_processor = :pura
17
13
  ```
18
14
 
19
- ```diff
20
- # Dockerfile
21
- - RUN apt-get install -y libvips-dev imagemagick
22
- ```
15
+ The adapter does not require `image_processing`, `ruby-vips`, or `mini_magick`. Remove `image_processing` from your Gemfile if nothing else uses it. Requiring pura-image does not change your processor setting; select `:pura` explicitly.
23
16
 
24
- That's it. No `brew install vips`. No `apt install imagemagick`. No C compiler. Works on macOS, Linux, Windows, Docker, CI, ruby.wasm anywhere Ruby runs.
17
+ The codecs are written in Ruby. PNG compression uses Ruby's standard `zlib` library, which must be available in your Ruby runtime. No additional image library or image-specific native extension needs to be installed.
25
18
 
26
- - **Drop-in** for `ImageProcessing::Vips` / `ImageProcessing::MiniMagick`
27
- - ✅ **7 formats** — JPEG, PNG, BMP, GIF, TIFF, ICO/CUR, WebP
28
- - ✅ **Some operations are faster than C** (no process-spawn overhead — see [Benchmark](#benchmark))
29
- - ✅ **Runs on ruby.wasm, JRuby, TruffleRuby**
19
+ ## Supported formats and limitations
30
20
 
31
- ## Supported Formats
21
+ All decoded images currently use **8-bit RGB** pixels. Alpha, color profiles, EXIF metadata, and animation are not preserved. This matters for transparent logos and photographs whose orientation is stored in EXIF; pura-image does not yet auto-orient them.
32
22
 
33
- | Format | Decode | Encode | Gem |
34
- |--------|--------|--------|-----|
35
- | JPEG | | | [pura-jpeg](https://github.com/komagata/pura-jpeg) |
36
- | PNG | | | [pura-png](https://github.com/komagata/pura-png) |
37
- | BMP | | | [pura-bmp](https://github.com/komagata/pura-bmp) |
38
- | GIF | | | [pura-gif](https://github.com/komagata/pura-gif) |
39
- | TIFF | | | [pura-tiff](https://github.com/komagata/pura-tiff) |
40
- | ICO/CUR | | | [pura-ico](https://github.com/komagata/pura-ico) |
41
- | WebP | | | [pura-webp](https://github.com/komagata/pura-webp) |
23
+ | Format | Decode | Encode | Limitations |
24
+ |--------|--------|--------|-------------|
25
+ | JPEG | Baseline | Baseline | No progressive JPEG or EXIF orientation correction |
26
+ | PNG | Non-interlaced | RGB | No Adam7; alpha/tRNS discarded; 16-bit input reduced to 8-bit |
27
+ | BMP | Supported by pura-bmp | 24-bit RGB | Alpha is not preserved |
28
+ | GIF | First image | Single image | Animation is not preserved; transparent pixels are flattened |
29
+ | TIFF | 8-bit strips: uncompressed, LZW, PackBits | Uncompressed | First IFD only; alpha is discarded |
30
+ | ICO | BMP/PNG entries | PNG entries | Alpha is not preserved |
31
+ | CUR | Read through pura-ico | Not supported | Saving `.cur` raises `ArgumentError` |
32
+ | WebP | VP8 lossy | VP8L lossless | No VP8L/VP8X decode; **encoded WebP cannot be read back by pura-webp yet** |
42
33
 
43
- Format auto-detection by magic bytes no extension guessing needed for decode.
44
-
45
- ## Installation
46
-
47
- ```bash
48
- gem install pura-image
49
- ```
34
+ See each [pura-* codec repository](https://github.com/komagata?tab=repositories&q=pura-) for its detailed restrictions. WebP also lacks the VP8 loop filter and multi-partition frame support. Format detection uses magic bytes; output format comes from the destination extension.
50
35
 
51
36
  ## Usage
52
37
 
53
38
  ```ruby
54
39
  require "pura-image"
55
40
 
56
- # Load any format (auto-detected from magic bytes)
57
41
  image = Pura::Image.load("photo.jpg")
58
- image = Pura::Image.load("logo.png")
59
- image.width #=> 800
60
- image.height #=> 600
61
-
62
- # Save to any format (detected from extension)
63
- Pura::Image.save(image, "output.png")
64
-
65
- # Convert between formats
66
- Pura::Image.convert("input.bmp", "output.jpg", quality: 85)
67
- Pura::Image.convert("photo.tiff", "photo.png")
42
+ thumb = image.resize_to_limit(800, 600).rotate(90).grayscale
43
+ Pura::Image.save(thumb, "thumb.png", compression: 6)
44
+ Pura::Image.convert("photo.bmp", "photo.jpg", quality: 85)
68
45
  ```
69
46
 
70
- ## Image Operations
47
+ Operations return a new image:
71
48
 
72
- All operations from the `image_processing` gem are supported:
49
+ | Operation | Behavior |
50
+ |-----------|----------|
51
+ | `resize_to_limit(w, h)` | Fit without enlarging |
52
+ | `resize_to_fit(w, h)` | Fit, allowing enlargement |
53
+ | `resize_to_fill(w, h)` | Fill, then center-crop |
54
+ | `resize_to_cover(w, h)` | Cover without cropping |
55
+ | `resize_and_pad(w, h, background: [0, 0, 0])` | Fit and center on an RGB background |
56
+ | `crop(x, y, w, h)` | Crop a positive integer region entirely inside the image |
57
+ | `rotate(degrees)` | Multiples of 90 degrees only |
58
+ | `grayscale` | Convert RGB to equal channels |
59
+ | `strip` | Return a copy; the current image model already discards metadata |
73
60
 
74
- ```ruby
75
- image = Pura::Image.load("photo.jpg")
61
+ `resize_to_limit` and `resize_to_fit` accept one `nil` dimension to leave that side unbounded. Supply at least one positive integer dimension. For example, `resize_to_fit(400, nil)` resizes to width 400 while preserving aspect ratio.
76
62
 
77
- # Resize
78
- image.resize_to_limit(800, 600) # downsize only, keep aspect ratio
79
- image.resize_to_fit(400, 400) # resize to fit, keep aspect ratio
80
- image.resize_to_fill(400, 400) # fill exact size, center crop excess
81
- image.resize_and_pad(400, 400) # fit within bounds, pad with black
82
- image.resize_to_cover(400, 400) # cover bounds, no crop
83
-
84
- # Transform
85
- image.crop(10, 10, 200, 200) # crop region
86
- image.rotate(90) # rotate 90/180/270 degrees
87
- image.grayscale # convert to grayscale
88
-
89
- # Chain operations
90
- result = Pura::Image.load("photo.jpg")
91
- .resize_to_limit(800, 600)
92
- .rotate(90)
93
- .grayscale
94
-
95
- Pura::Image.save(result, "thumb.jpg", quality: 80)
96
- ```
97
-
98
- ## Rails Active Storage Integration
63
+ These are a subset of the operations available in Vips/ImageMagick. Unsupported keyword options, such as `gravity:`, raise `ArgumentError`; they are not silently ignored. Saver options are passed to the selected codec: JPEG supports `quality:` and `subsampling:`, PNG supports `compression:`, and GIF supports `max_colors:`.
99
64
 
100
- Drop-in replacement for libvips/ImageMagick:
65
+ ## Pipeline API
101
66
 
102
67
  ```ruby
103
- # Gemfile
104
- gem "pura-image"
68
+ require "image_processing/pura"
105
69
 
106
- # config/application.rb
107
- config.active_storage.variant_processor = :pura
70
+ pipeline = ImageProcessing::Pura.source("photo.jpg")
71
+ pipeline.resize_to_limit(400, nil).convert("png").call(destination: "thumb.png")
72
+ pipeline.resize_to_limit(100, 100).call(destination: "small.jpg")
73
+
74
+ ImageProcessing::Pura.valid_image?("photo.jpg") # true when this backend can decode it
108
75
  ```
109
76
 
110
- Models and views stay exactly the same:
77
+ The chainable API is provided by [pura-processing](https://github.com/komagata/pura-processing), adapted from `image_processing` under the MIT license. Only `loader(page: 0)` is supported; other pages and unknown loader options are rejected.
78
+
79
+ ## Rails Active Storage
80
+
81
+ With the processor configuration above, use ordinary variants:
111
82
 
112
83
  ```ruby
113
84
  class User < ApplicationRecord
@@ -121,63 +92,19 @@ end
121
92
  <%= image_tag user.avatar.variant(:thumb) %>
122
93
  ```
123
94
 
124
- No `brew install vips`. No `apt install imagemagick`. Just `gem install` and go.
125
-
126
- ### ImageProcessing::Pura API
127
-
128
- ```ruby
129
- require "image_processing/pura"
130
-
131
- # Same API as ImageProcessing::Vips
132
- processed = ImageProcessing::Pura
133
- .source("photo.jpg")
134
- .resize_to_limit(400, 400)
135
- .convert("png")
136
- .call(destination: "output.png")
137
-
138
- # Pipeline branching
139
- pipeline = ImageProcessing::Pura.source("photo.jpg")
140
- large = pipeline.resize_to_limit(800, 800).call(destination: "large.jpg")
141
- medium = pipeline.resize_to_limit(500, 500).call(destination: "medium.jpg")
142
- small = pipeline.resize_to_limit(300, 300).call(destination: "small.jpg")
143
-
144
- # Validation
145
- ImageProcessing::Pura.valid_image?("photo.jpg") #=> true
146
- ```
147
-
148
- ## Benchmark
149
-
150
- 400×400 image, Ruby 4.0.2 + YJIT vs ffmpeg (C + SIMD).
151
-
152
- ### Decode
95
+ The dedicated transformer handles supported image variants without the `image_processing` gem. This does not provide PDF/video previewers or a metadata analyzer. Image format and operation limitations above also apply to Rails variants.
153
96
 
154
- | Format | pura-* | ffmpeg | vs ffmpeg |
155
- |--------|--------|--------|-----------|
156
- | TIFF | **14 ms** | 59 ms | 🚀 **4× faster** |
157
- | BMP | **39 ms** | 59 ms | 🚀 **1.5× faster** |
158
- | GIF | 77 ms | 65 ms | ~1× (comparable) |
159
- | PNG | 111 ms | 60 ms | 1.9× slower |
160
- | JPEG | 304 ms | 55 ms | 5.5× slower |
97
+ The integration CI exercises a real upload and variant generation on Rails 7.2, 8.0, and 8.1, with eager loading both enabled and disabled, and checks that `:disabled` is left unchanged.
161
98
 
162
- ### Encode
99
+ ## Browser demo
163
100
 
164
- | Format | pura-* | ffmpeg | vs ffmpeg |
165
- |--------|--------|--------|-----------|
166
- | TIFF | **0.8 ms** | 58 ms | 🚀 **73× faster** |
167
- | BMP | **35 ms** | 58 ms | 🚀 **1.7× faster** |
168
- | PNG | **52 ms** | 61 ms | 🚀 **faster** |
169
- | JPEG | 238 ms | 62 ms | 3.8× slower |
170
- | GIF | 377 ms | 59 ms | 6.4× slower |
101
+ The [ruby.wasm demo](https://komagata.github.io/pura-image/) runs transformations in the browser. See [demo/README.md](demo/README.md). Runtime support depends on the Ruby version and available standard libraries; CRuby CI results should not be read as verification of every alternative Ruby implementation.
171
102
 
172
- 5 out of 11 operations are **faster than C** (ffmpeg process-spawn overhead).
103
+ ## Performance
173
104
 
174
- ## Why pure Ruby?
105
+ The earlier 400×400 benchmark compared Ruby 4.0.2 + YJIT to a new ffmpeg process for every operation. Its measurements include ffmpeg process startup and do not establish that the codec is faster than an in-process C library such as libvips.
175
106
 
176
- - **`gem install` and go** no `brew install`, no `apt install`, no C compiler
177
- - **Works everywhere Ruby works** — CRuby, ruby.wasm, mruby, JRuby, TruffleRuby
178
- - **Edge/Wasm ready** — browsers (ruby.wasm), sandboxed environments, no system libraries needed
179
- - **Perfect for dev/CI** — no ImageMagick/libvips setup. `rails new` → image upload → it just works
180
- - **7 formats, 1 interface** — unified API across JPEG, PNG, BMP, GIF, TIFF, ICO, WebP
107
+ For Rails deployment decisions, measure the complete decode–resize–encode pipeline with your own photographs, and compare output quality, file size, latency, and peak memory under the same settings. pura-image prioritizes installation convenience; native codecs are usually the appropriate comparison for throughput-sensitive workloads.
181
108
 
182
109
  ## License
183
110
 
@@ -10,10 +10,6 @@ module ImageProcessing
10
10
 
11
11
  def self.valid_image?(file)
12
12
  path = file.respond_to?(:path) ? file.path : file.to_s
13
- data = File.binread(path, 8)
14
- format = ::Pura::Image::Processor.detect_format(data)
15
- return false unless format
16
-
17
13
  ::Pura::Image::Processor.load(path)
18
14
  true
19
15
  rescue StandardError
@@ -27,7 +23,9 @@ module ImageProcessing
27
23
  false
28
24
  end
29
25
 
30
- def self.load_image(path_or_image, **_options)
26
+ def self.load_image(path_or_image, page: 0)
27
+ raise ArgumentError, "only the first image (page: 0) is supported" unless page.is_a?(Integer) && page.zero?
28
+
31
29
  if path_or_image.is_a?(::Pura::Image::Wrapper)
32
30
  path_or_image
33
31
  elsif path_or_image.is_a?(String)
@@ -43,45 +41,36 @@ module ImageProcessing
43
41
  ::Pura::Image::Processor.save(wrapper, destination.to_s, **options)
44
42
  end
45
43
 
46
- def resize_to_limit(width, height, **_options)
47
- w = image.width
48
- h = image.height
49
-
50
- return image if w <= (width || w) && h <= (height || h)
51
-
52
- width ||= w
53
- height ||= h
54
- image.resize_to_fit(width, height)
44
+ def resize_to_limit(width, height)
45
+ image.resize_to_limit(width, height)
55
46
  end
56
47
 
57
- def resize_to_fit(width, height, **_options)
58
- width ||= image.width
59
- height ||= image.height
48
+ def resize_to_fit(width, height)
60
49
  image.resize_to_fit(width, height)
61
50
  end
62
51
 
63
- def resize_to_fill(width, height, **_options)
52
+ def resize_to_fill(width, height)
64
53
  image.resize_to_fill(width, height)
65
54
  end
66
55
 
67
- def resize_and_pad(width, height, background: nil, **_options)
56
+ def resize_and_pad(width, height, background: nil)
68
57
  bg = background || [0, 0, 0]
69
58
  image.resize_and_pad(width, height, background: bg)
70
59
  end
71
60
 
72
- def resize_to_cover(width, height, **_options)
61
+ def resize_to_cover(width, height)
73
62
  image.resize_to_cover(width, height)
74
63
  end
75
64
 
76
- def crop(left, top, width, height, **_options)
65
+ def crop(left, top, width, height)
77
66
  image.crop(left, top, width, height)
78
67
  end
79
68
 
80
- def rotate(degrees, **_options)
69
+ def rotate(degrees)
81
70
  image.rotate(degrees)
82
71
  end
83
72
 
84
- def colourspace(space, **_options)
73
+ def colourspace(space)
85
74
  if %w[b-w grey16].include?(space.to_s)
86
75
  image.grayscale
87
76
  else
@@ -89,11 +78,11 @@ module ImageProcessing
89
78
  end
90
79
  end
91
80
 
92
- def strip(**_options)
81
+ def strip
93
82
  image.strip
94
83
  end
95
84
 
96
- def convert(format, **_options)
85
+ def convert(format)
97
86
  # Store desired format for save_image
98
87
  @format = format.to_s.delete(".")
99
88
  image
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pura
4
+ module Image
5
+ # Rails versions before variant_transformer= select the backend in Variation.
6
+ module LegacyVariation
7
+ private
8
+
9
+ def transformer
10
+ return super unless ActiveStorage.variant_processor == :pura
11
+
12
+ Pura::Image::Transformer.new(transformations.except(:format))
13
+ end
14
+ end
15
+ end
16
+ end
@@ -34,19 +34,14 @@ module Pura
34
34
  end
35
35
 
36
36
  def resize_to_limit(max_width, max_height)
37
- return dup_image if @width <= max_width && @height <= max_height
37
+ scale = fit_scale(max_width, max_height)
38
+ return dup_image if scale >= 1
38
39
 
39
- scale = [@width.to_f / max_width, @height.to_f / max_height].max
40
- new_w = [(@width / scale).round, 1].max
41
- new_h = [(@height / scale).round, 1].max
42
- resize(new_w, new_h)
40
+ resize_scaled(scale)
43
41
  end
44
42
 
45
43
  def resize_to_fit(max_width, max_height)
46
- scale = [@width.to_f / max_width, @height.to_f / max_height].max
47
- new_w = [(@width / scale).round, 1].max
48
- new_h = [(@height / scale).round, 1].max
49
- resize(new_w, new_h)
44
+ resize_scaled(fit_scale(max_width, max_height))
50
45
  end
51
46
 
52
47
  def resize_to_fill(fill_width, fill_height)
@@ -91,6 +86,22 @@ module Pura
91
86
 
92
87
  private
93
88
 
89
+ def fit_scale(max_width, max_height)
90
+ dimensions = [max_width, max_height].compact
91
+ unless dimensions.any? && dimensions.all? { |value| value.is_a?(Integer) && value.positive? }
92
+ raise ArgumentError, "provide at least one positive integer dimension"
93
+ end
94
+
95
+ scales = []
96
+ scales << (max_width.to_f / @width) if max_width
97
+ scales << (max_height.to_f / @height) if max_height
98
+ scales.min
99
+ end
100
+
101
+ def resize_scaled(scale)
102
+ resize([(@width * scale).round, 1].max, [(@height * scale).round, 1].max)
103
+ end
104
+
94
105
  def dup_image
95
106
  self.class.new(@width, @height, @pixels.dup)
96
107
  end
@@ -22,8 +22,7 @@ module Pura
22
22
  ".gif" => :gif,
23
23
  ".tif" => :tiff, ".tiff" => :tiff,
24
24
  ".webp" => :webp,
25
- ".ico" => :ico,
26
- ".cur" => :ico
25
+ ".ico" => :ico
27
26
  }.freeze
28
27
 
29
28
  class << self
@@ -97,22 +96,22 @@ module Pura
97
96
  def encode_with_format(image, path, format, **options)
98
97
  case format
99
98
  when :jpeg
100
- Pura::Jpeg.encode(image, path, quality: options.fetch(:quality, 85))
99
+ Pura::Jpeg.encode(image, path, **options)
101
100
  when :png
102
101
  png_img = Pura::Png::Image.new(image.width, image.height, image.pixels)
103
- Pura::Png.encode(png_img, path, compression: options.fetch(:compression, 6))
102
+ Pura::Png.encode(png_img, path, **options)
104
103
  when :bmp
105
104
  bmp_img = Pura::Bmp::Image.new(image.width, image.height, image.pixels)
106
- Pura::Bmp.encode(bmp_img, path)
105
+ Pura::Bmp.encode(bmp_img, path, **options)
107
106
  when :gif
108
107
  gif_img = Pura::Gif::Image.new(image.width, image.height, image.pixels)
109
- Pura::Gif.encode(gif_img, path)
108
+ Pura::Gif.encode(gif_img, path, **options)
110
109
  when :tiff
111
110
  tiff_img = Pura::Tiff::Image.new(image.width, image.height, image.pixels)
112
- Pura::Tiff.encode(tiff_img, path)
111
+ Pura::Tiff.encode(tiff_img, path, **options)
113
112
  when :ico
114
113
  ico_img = Pura::Ico::Image.new(image.width, image.height, image.pixels)
115
- Pura::Ico.encode(ico_img, path)
114
+ Pura::Ico.encode(ico_img, path, **options)
116
115
  when :webp
117
116
  raise ArgumentError, "WebP support requires the pura-webp gem" unless defined?(Pura::Webp)
118
117
 
@@ -1,45 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Only define railtie if Rails is available
4
- if defined?(Rails)
5
- require "rails/railtie"
6
-
7
- module Pura
8
- module Image
9
- class Railtie < Rails::Railtie
10
- initializer "pura_image.set_variant_processor", before: "active_storage.configs" do |app|
11
- app.config.active_storage.variant_processor = :pura
12
- end
13
-
14
- initializer "pura_image.patch_active_storage_variation" do
15
- ActiveSupport.on_load(:active_storage_blob) do
16
- require "image_processing/pura"
17
-
18
- variation_patch = Module.new do
19
- private
20
-
21
- def transformer
22
- if ActiveStorage.variant_processor == :pura && ActiveStorage.variant_transformer.nil?
23
- @pura_transformer ||= begin
24
- klass = Class.new(ActiveStorage::Transformers::ImageProcessingTransformer) do
25
- private
26
-
27
- def processor
28
- ImageProcessing::Pura
29
- end
30
- end
31
-
32
- klass.new(transformations.except(:format))
33
- end
34
- else
35
- super
3
+ require "rails/railtie"
4
+
5
+ module Pura
6
+ module Image
7
+ class Railtie < Rails::Railtie
8
+ initializer "pura_image.configure_active_storage", after: "active_storage.configs" do |app|
9
+ app.config.after_initialize do
10
+ if defined?(ActiveStorage) && ActiveStorage.variant_processor == :pura
11
+ require_relative "transformer"
12
+ if ActiveStorage.respond_to?(:variant_transformer=)
13
+ ActiveStorage.variant_transformer = Pura::Image::Transformer
14
+ else
15
+ require_relative "legacy_variation"
16
+ ActiveSupport.on_load(:active_storage_blob) do
17
+ unless ActiveStorage::Variation < Pura::Image::LegacyVariation
18
+ ActiveStorage::Variation.prepend(Pura::Image::LegacyVariation)
36
19
  end
37
20
  end
38
21
  end
39
-
40
- unless ActiveStorage::Variation.ancestors.include?(variation_patch)
41
- ActiveStorage::Variation.prepend(variation_patch)
42
- end
43
22
  end
44
23
  end
45
24
  end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "image_processing/pura"
4
+ require "active_storage/transformers/transformer"
5
+
6
+ module Pura
7
+ module Image
8
+ # Uses Active Storage's backend-independent lifecycle without image_processing.
9
+ class Transformer < ActiveStorage::Transformers::Transformer
10
+ SUPPORTED_OPERATIONS = %i[
11
+ resize_to_limit resize_to_fit resize_to_fill resize_and_pad resize_to_cover
12
+ crop rotate grayscale colourspace strip
13
+ ].freeze
14
+
15
+ private
16
+
17
+ def process(file, format:)
18
+ operations = transformations.each_with_object([]) do |(name, argument), result|
19
+ raise ArgumentError, "unsupported transformation: #{name}" unless SUPPORTED_OPERATIONS.include?(name.to_sym)
20
+
21
+ result << [name, argument] if argument.present?
22
+ end
23
+
24
+ ImageProcessing::Pura.source(file).convert(format).apply(operations).call
25
+ end
26
+ end
27
+ end
28
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Pura
4
4
  module Image
5
- VERSION = "0.3.0"
5
+ VERSION = "0.4.0"
6
6
  end
7
7
  end
data/pura-image.gemspec CHANGED
@@ -20,13 +20,13 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.files = Dir["lib/**/*.rb"] + ["test/fixtures/test_64x64.jpg"] + ["pura-image.gemspec", "Gemfile", "Rakefile", "README.md", "LICENSE"]
22
22
 
23
- spec.add_dependency "pura-jpeg", "~> 0.1"
24
- spec.add_dependency "pura-png", "~> 0.1"
25
- spec.add_dependency "pura-bmp", "~> 0.1"
26
- spec.add_dependency "pura-gif", "~> 0.1"
27
- spec.add_dependency "pura-tiff", "~> 0.1"
28
- spec.add_dependency "pura-ico", "~> 0.1"
29
- spec.add_dependency "pura-webp", "~> 0.2"
23
+ spec.add_dependency "pura-jpeg", "~> 0.1", ">= 0.1.1"
24
+ spec.add_dependency "pura-png", "~> 0.1", ">= 0.1.1"
25
+ spec.add_dependency "pura-bmp", "~> 0.1", ">= 0.1.1"
26
+ spec.add_dependency "pura-gif", "~> 0.1", ">= 0.1.1"
27
+ spec.add_dependency "pura-tiff", "~> 0.1", ">= 0.1.1"
28
+ spec.add_dependency "pura-ico", "~> 0.1", ">= 0.1.1"
29
+ spec.add_dependency "pura-webp", "~> 0.2", ">= 0.2.1"
30
30
  spec.add_dependency "pura-processing", "~> 0.1"
31
31
  spec.add_development_dependency "minitest", "~> 5.0"
32
32
  spec.add_development_dependency "rake", "~> 13.0"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pura-image
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - komagata
@@ -16,6 +16,9 @@ dependencies:
16
16
  - - "~>"
17
17
  - !ruby/object:Gem::Version
18
18
  version: '0.1'
19
+ - - ">="
20
+ - !ruby/object:Gem::Version
21
+ version: 0.1.1
19
22
  type: :runtime
20
23
  prerelease: false
21
24
  version_requirements: !ruby/object:Gem::Requirement
@@ -23,6 +26,9 @@ dependencies:
23
26
  - - "~>"
24
27
  - !ruby/object:Gem::Version
25
28
  version: '0.1'
29
+ - - ">="
30
+ - !ruby/object:Gem::Version
31
+ version: 0.1.1
26
32
  - !ruby/object:Gem::Dependency
27
33
  name: pura-png
28
34
  requirement: !ruby/object:Gem::Requirement
@@ -30,6 +36,9 @@ dependencies:
30
36
  - - "~>"
31
37
  - !ruby/object:Gem::Version
32
38
  version: '0.1'
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: 0.1.1
33
42
  type: :runtime
34
43
  prerelease: false
35
44
  version_requirements: !ruby/object:Gem::Requirement
@@ -37,6 +46,9 @@ dependencies:
37
46
  - - "~>"
38
47
  - !ruby/object:Gem::Version
39
48
  version: '0.1'
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: 0.1.1
40
52
  - !ruby/object:Gem::Dependency
41
53
  name: pura-bmp
42
54
  requirement: !ruby/object:Gem::Requirement
@@ -44,6 +56,9 @@ dependencies:
44
56
  - - "~>"
45
57
  - !ruby/object:Gem::Version
46
58
  version: '0.1'
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: 0.1.1
47
62
  type: :runtime
48
63
  prerelease: false
49
64
  version_requirements: !ruby/object:Gem::Requirement
@@ -51,6 +66,9 @@ dependencies:
51
66
  - - "~>"
52
67
  - !ruby/object:Gem::Version
53
68
  version: '0.1'
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: 0.1.1
54
72
  - !ruby/object:Gem::Dependency
55
73
  name: pura-gif
56
74
  requirement: !ruby/object:Gem::Requirement
@@ -58,6 +76,9 @@ dependencies:
58
76
  - - "~>"
59
77
  - !ruby/object:Gem::Version
60
78
  version: '0.1'
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: 0.1.1
61
82
  type: :runtime
62
83
  prerelease: false
63
84
  version_requirements: !ruby/object:Gem::Requirement
@@ -65,6 +86,9 @@ dependencies:
65
86
  - - "~>"
66
87
  - !ruby/object:Gem::Version
67
88
  version: '0.1'
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: 0.1.1
68
92
  - !ruby/object:Gem::Dependency
69
93
  name: pura-tiff
70
94
  requirement: !ruby/object:Gem::Requirement
@@ -72,6 +96,9 @@ dependencies:
72
96
  - - "~>"
73
97
  - !ruby/object:Gem::Version
74
98
  version: '0.1'
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: 0.1.1
75
102
  type: :runtime
76
103
  prerelease: false
77
104
  version_requirements: !ruby/object:Gem::Requirement
@@ -79,6 +106,9 @@ dependencies:
79
106
  - - "~>"
80
107
  - !ruby/object:Gem::Version
81
108
  version: '0.1'
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: 0.1.1
82
112
  - !ruby/object:Gem::Dependency
83
113
  name: pura-ico
84
114
  requirement: !ruby/object:Gem::Requirement
@@ -86,6 +116,9 @@ dependencies:
86
116
  - - "~>"
87
117
  - !ruby/object:Gem::Version
88
118
  version: '0.1'
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ version: 0.1.1
89
122
  type: :runtime
90
123
  prerelease: false
91
124
  version_requirements: !ruby/object:Gem::Requirement
@@ -93,6 +126,9 @@ dependencies:
93
126
  - - "~>"
94
127
  - !ruby/object:Gem::Version
95
128
  version: '0.1'
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: 0.1.1
96
132
  - !ruby/object:Gem::Dependency
97
133
  name: pura-webp
98
134
  requirement: !ruby/object:Gem::Requirement
@@ -100,6 +136,9 @@ dependencies:
100
136
  - - "~>"
101
137
  - !ruby/object:Gem::Version
102
138
  version: '0.2'
139
+ - - ">="
140
+ - !ruby/object:Gem::Version
141
+ version: 0.2.1
103
142
  type: :runtime
104
143
  prerelease: false
105
144
  version_requirements: !ruby/object:Gem::Requirement
@@ -107,6 +146,9 @@ dependencies:
107
146
  - - "~>"
108
147
  - !ruby/object:Gem::Version
109
148
  version: '0.2'
149
+ - - ">="
150
+ - !ruby/object:Gem::Version
151
+ version: 0.2.1
110
152
  - !ruby/object:Gem::Dependency
111
153
  name: pura-processing
112
154
  requirement: !ruby/object:Gem::Requirement
@@ -163,9 +205,11 @@ files:
163
205
  - Rakefile
164
206
  - lib/image_processing/pura.rb
165
207
  - lib/pura-image.rb
208
+ - lib/pura/image/legacy_variation.rb
166
209
  - lib/pura/image/operations.rb
167
210
  - lib/pura/image/processor.rb
168
211
  - lib/pura/image/railtie.rb
212
+ - lib/pura/image/transformer.rb
169
213
  - lib/pura/image/version.rb
170
214
  - pura-image.gemspec
171
215
  - test/fixtures/test_64x64.jpg