rszr 0.8.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 035d5f7341e71cdc9b5ba70de6e116acd8d8459e
4
- data.tar.gz: 3119e97a26295db8f3931821d6ae835aaa6166ee
2
+ SHA256:
3
+ metadata.gz: ea3437991dd4694e35653020632c3fc360f787e1d391834780fdf118991a90ce
4
+ data.tar.gz: 37ccc3f8693e4fe9d41939cfc2d3786ef72ed24e344059f1dd4e4492efcae862
5
5
  SHA512:
6
- metadata.gz: 003305cff18cc4678a13f238e17d709351a36efea86b5ca2de751d15f933211c0d107601f2be6aa70dfc92a30a87615fdf3372dae26552190d21911451d33445
7
- data.tar.gz: 732e05777cf4adc9c87515e043a226ed42bd56d0c76e3a28bf645fa22b492fed2cb2a473dbdccd4980b76a23b2d7bf579ec45c68a305a07c77f890697ff82e66
6
+ metadata.gz: 35b8219e81c0f89e4b51719617c13edf71421d7e3ed4e1998f8e26fc017545da76c5164c0bbd63c16e5c617cfdd4f5cb1f07a8e0bbdc83b7bb90ea7fbbd71907
7
+ data.tar.gz: fd4361d89e0ff577032da1dea39686c035604d98e5b6b935ca8de8f1289bdfe6cf5678c8842406c0b9c5829cfab2c03af8350670638824a99deeb176e4675428
data/README.md CHANGED
@@ -60,6 +60,9 @@ image.width => 400
60
60
  image.height => 300
61
61
  image.dimensions => [400, 300]
62
62
  image.format => "jpeg"
63
+ image[0, 0] => <Rszr::Color::RGBA @red=38, @green=115, @blue=141, @alpha=255>
64
+ image[0, 0].to_hex => "26738dff"
65
+ image[0, 0].to_hex(rgb: true) => "26738d"
63
66
  ```
64
67
 
65
68
  ### Transformations
@@ -68,6 +71,8 @@ For each transformation, there is a bang! and non-bang method.
68
71
  The bang method changes the image in place, while the non-bang method
69
72
  creates a copy of the image in memory.
70
73
 
74
+ #### Resizing
75
+
71
76
  ```ruby
72
77
  # auto height
73
78
  image.resize(400, :auto)
@@ -78,6 +83,22 @@ image.resize(:auto, 300)
78
83
  # scale factor
79
84
  image.resize(0.5)
80
85
 
86
+ # resize to fill
87
+ image.resize(400, 300, crop: true)
88
+
89
+ # resize to fill with gravity
90
+ # where gravity in [:n, :nw, :w, :sw, :w, :se, :e, :ne, :center]
91
+ image.resize(400, 300, crop: gravity)
92
+
93
+ # save memory, do not duplicate instance
94
+ image.resize!(400, :auto)
95
+ ```
96
+
97
+ Check out the [full list and demo of resize options](https://mtgrosser.github.io/rszr/resizing.html)!
98
+
99
+ #### Other transformations
100
+
101
+ ```ruby
81
102
  # crop
82
103
  image.crop(200, 200, 100, 100)
83
104
 
@@ -98,9 +119,6 @@ image.flop
98
119
 
99
120
  # initialize copy
100
121
  image.dup
101
-
102
- # save memory, do not duplicate instance
103
- image.resize!(400, :auto)
104
122
  ```
105
123
 
106
124
  ### Filters
@@ -146,12 +164,12 @@ Rszr.autorotate = true
146
164
 
147
165
  ## Rails / ActiveStorage interface
148
166
 
149
- Rszr provides a drop-in interface to the `image_resizing` gem.
167
+ Rszr provides a drop-in interface to the `image_processing` gem.
150
168
  It is faster than both `mini_magick` and `vips` and way easier to install than the latter.
151
169
 
152
170
  ```ruby
153
171
  # Gemfile
154
- gem 'image_resizing'
172
+ gem 'image_processing'
155
173
  gem 'rszr'
156
174
 
157
175
  # config/initializers/rszr.rb
data/ext/rszr/image.c CHANGED
@@ -140,6 +140,32 @@ static VALUE rszr_image_height(VALUE self)
140
140
  return INT2NUM(height);
141
141
  }
142
142
 
143
+
144
+ static VALUE rszr_image__pixel_get(VALUE self, VALUE rb_x, VALUE rb_y)
145
+ {
146
+ rszr_image_handle * handle;
147
+ Imlib_Color color_return;
148
+ VALUE rb_rgba;
149
+ int x, y;
150
+
151
+ Check_Type(rb_x, T_FIXNUM);
152
+ x = FIX2INT(rb_x);
153
+ Check_Type(rb_y, T_FIXNUM);
154
+ y = FIX2INT(rb_y);
155
+
156
+ Data_Get_Struct(self, rszr_image_handle, handle);
157
+
158
+ imlib_context_set_image(handle->image);
159
+ imlib_image_query_pixel(x, y, &color_return);
160
+
161
+ rb_rgba = rb_ary_new3(4, INT2NUM(color_return.red),
162
+ INT2NUM(color_return.green),
163
+ INT2NUM(color_return.blue),
164
+ INT2NUM(color_return.alpha));
165
+ return rb_rgba;
166
+ }
167
+
168
+
143
169
  /*
144
170
  static VALUE rszr_image_get_quality(VALUE self)
145
171
  {
@@ -309,7 +335,7 @@ static VALUE rszr_image__sharpen_bang(VALUE self, VALUE rb_radius)
309
335
  if (radius >= 0) {
310
336
  imlib_image_sharpen(radius);
311
337
  } else {
312
- imlib_image_blur(radius);
338
+ imlib_image_blur(-radius);
313
339
  }
314
340
 
315
341
  return self;
@@ -475,6 +501,7 @@ void Init_rszr_image()
475
501
  rb_define_private_method(cImage, "_turn!", rszr_image__turn_bang, 1);
476
502
  rb_define_private_method(cImage, "_rotate", rszr_image__rotate, 2);
477
503
  rb_define_private_method(cImage, "_sharpen!", rszr_image__sharpen_bang, 1);
504
+ rb_define_private_method(cImage, "_pixel", rszr_image__pixel_get, 2);
478
505
 
479
506
  rb_define_private_method(cImage, "_save", rszr_image__save, 3);
480
507
  }
data/lib/rszr/color.rb ADDED
@@ -0,0 +1,25 @@
1
+ module Rszr
2
+ module Color
3
+
4
+ class RGBA
5
+ attr_reader :red, :green, :blue, :alpha
6
+
7
+ def initialize(red, green, blue, alpha = 255)
8
+ if red < 0 || red > 255 || green < 0 || green > 255 || blue < 0 || blue > 255 || alpha < 0 || alpha > 255
9
+ raise ArgumentError, 'color out of range'
10
+ end
11
+ @red, @green, @blue, @alpha = red, green, blue, alpha
12
+ end
13
+
14
+ def to_i(rgb: false)
15
+ i = red.to_i << 24 | green.to_i << 16 | blue.to_i << 8 | alpha.to_i
16
+ rgb ? i >> 8 : i
17
+ end
18
+
19
+ def to_hex(rgb: false)
20
+ "%0#{rgb ? 6 : 8}x" % to_i(rgb: rgb)
21
+ end
22
+ end
23
+
24
+ end
25
+ end
data/lib/rszr/image.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  module Rszr
2
2
  class Image
3
+ GRAVITIES = [true, :center, :n, :nw, :w, :sw, :s, :se, :e, :ne].freeze
4
+
3
5
  extend Identification
4
6
  include Buffered
5
7
  include Orientation
@@ -37,6 +39,12 @@ module Rszr
37
39
  fmt = fmt.to_s if fmt.is_a?(Symbol)
38
40
  self._format = fmt
39
41
  end
42
+
43
+ def [](x, y)
44
+ if x >= 0 && x <= width - 1 && y >= 0 && y <= height - 1
45
+ Color::RGBA.new(*_pixel(x, y))
46
+ end
47
+ end
40
48
 
41
49
  def inspect
42
50
  fmt = format
@@ -166,47 +174,100 @@ module Rszr
166
174
  # 400, 300, background: rgba
167
175
  # 400, 300, skew: true
168
176
 
169
- def calculate_size(*args, crop: nil, skew: nil)
170
- options = args.last.is_a?(Hash) ? args.pop : {}
177
+ def calculate_size(*args, crop: nil, skew: nil, inflate: true)
178
+ #options = args.last.is_a?(Hash) ? args.pop : {}
171
179
  #assert_valid_keys options, :crop, :background, :skew #:extend, :width, :height, :max_width, :max_height, :box
172
- original_width, original_height = width, height
173
- x, y, = 0, 0
174
180
  if args.size == 1
175
- scale = args.first
176
- raise ArgumentError, "scale factor #{scale.inspect} out of range" unless scale > 0 && scale < 1
177
- new_width = original_width.to_f * scale
178
- new_height = original_height.to_f * scale
181
+ calculate_size_for_scale(args.first)
179
182
  elsif args.size == 2
180
183
  box_width, box_height = args
181
- if :auto == box_width && box_height.is_a?(Numeric)
182
- new_height = box_height
183
- new_width = box_height.to_f / original_height.to_f * original_width.to_f
184
- elsif box_width.is_a?(Numeric) && :auto == box_height
185
- new_width = box_width
186
- new_height = box_width.to_f / original_width.to_f * original_height.to_f
184
+ if args.include?(:auto)
185
+ calculate_size_for_auto(box_width, box_height)
187
186
  elsif box_width.is_a?(Numeric) && box_height.is_a?(Numeric)
188
- if skew
189
- new_width, new_height = box_width, box_height
187
+ if not inflate and width <= box_width and height <= box_height
188
+ [0, 0, width, height, width, height]
189
+ elsif skew
190
+ calculate_size_for_skew(box_width, box_height)
190
191
  elsif crop
191
- # TODO: calculate x, y offset if crop
192
+ calculate_size_for_crop(box_width, box_height, crop)
192
193
  else
193
- scale = original_width.to_f / original_height.to_f
194
- box_scale = box_width.to_f / box_height.to_f
195
- if scale >= box_scale # wider
196
- new_width = box_width
197
- new_height = original_height.to_f * box_width.to_f / original_width.to_f
198
- else # narrower
199
- new_height = box_height
200
- new_width = original_width.to_f * box_height.to_f / original_height.to_f
201
- end
194
+ calculate_size_for_limit(box_width, box_height)
202
195
  end
203
- else
204
- raise ArgumentError, "unconclusive arguments #{args.inspect} #{options.inspect}"
205
196
  end
206
197
  else
207
198
  raise ArgumentError, "wrong number of arguments (#{args.size} for 1..2)"
208
199
  end
209
- [x, y, original_width, original_height, new_width.round, new_height.round]
200
+ end
201
+
202
+ def calculate_size_for_scale(factor)
203
+ raise ArgumentError, "scale factor #{factor.inspect} out of range" unless factor > 0 && factor < 1
204
+ [0, 0, width, height, (width.to_f * factor).round, (height.to_f * factor).round]
205
+ end
206
+
207
+ def calculate_size_for_skew(box_width, box_height)
208
+ [0, 0, width, height, box_width, box_height]
209
+ end
210
+
211
+ def calculate_size_for_auto(box_width, box_height)
212
+ if :auto == box_width && box_height.is_a?(Numeric)
213
+ new_height = box_height
214
+ new_width = (box_height.to_f / height.to_f * width.to_f).round
215
+ elsif box_width.is_a?(Numeric) && :auto == box_height
216
+ new_width = box_width
217
+ new_height = (box_width.to_f / width.to_f * height.to_f).round
218
+ else
219
+ raise ArgumentError, "unconclusive arguments #{box_width.inspect}, #{box_height.inspect}"
220
+ end
221
+ [0, 0, width, height, new_width, new_height]
222
+ end
223
+
224
+ def calculate_size_for_crop(box_width, box_height, crop)
225
+ raise ArgumentError, "invalid crop gravity" unless GRAVITIES.include?(crop)
226
+ aspect = width.to_f / height.to_f
227
+ box_aspect = box_width.to_f / box_height.to_f
228
+ if aspect >= box_aspect # wider than box
229
+ src_width = (box_width.to_f * height.to_f / box_height.to_f).round
230
+ src_height = height
231
+ x = crop_horizontally(src_width, crop)
232
+ y = 0
233
+ else # narrower than box
234
+ src_width = width
235
+ src_height = (box_height.to_f * width.to_f / box_width.to_f).round
236
+ x = 0
237
+ y = crop_vertically(src_height, crop)
238
+ end
239
+ [x, y, src_width, src_height, box_width, box_height]
240
+ end
241
+
242
+ def crop_horizontally(src_width, crop)
243
+ case crop
244
+ when :nw, :w, :sw then 0
245
+ when :ne, :e, :se then width - src_width
246
+ else
247
+ ((width - src_width).to_f / 2.to_f).round
248
+ end
249
+ end
250
+
251
+ def crop_vertically(src_height, crop)
252
+ case crop
253
+ when :nw, :n, :ne then 0
254
+ when :sw, :s, :se then height - src_height
255
+ else
256
+ ((height - src_height).to_f / 2.to_f).round
257
+ end
258
+ end
259
+
260
+ def calculate_size_for_limit(box_width, box_height)
261
+ scale = width.to_f / height.to_f
262
+ box_scale = box_width.to_f / box_height.to_f
263
+ if scale >= box_scale # wider
264
+ new_width = box_width
265
+ new_height = (height.to_f * box_width.to_f / width.to_f).round
266
+ else # narrower
267
+ new_height = box_height
268
+ new_width = (width.to_f * box_height.to_f / height.to_f).round
269
+ end
270
+ [0, 0, width, height, new_width, new_height]
210
271
  end
211
272
 
212
273
  def format_from_filename(path)
@@ -51,7 +51,7 @@ module ImageProcessing
51
51
  # Resizes the image to not be larger than the specified dimensions.
52
52
  def resize_to_limit(width, height, **options)
53
53
  width, height = default_dimensions(width, height)
54
- thumbnail(width, height, **options)
54
+ thumbnail(width, height, inflate: false, **options)
55
55
  end
56
56
 
57
57
  # Resizes the image to fit within the specified dimensions.
@@ -62,8 +62,8 @@ module ImageProcessing
62
62
 
63
63
  # Resizes the image to fill the specified dimensions, applying any
64
64
  # necessary cropping.
65
- def resize_to_fill(width, height, **options)
66
- thumbnail(width, height, crop: :center, **options)
65
+ def resize_to_fill(width, height, gravity: :center, **options)
66
+ thumbnail(width, height, crop: gravity, **options)
67
67
  end
68
68
 
69
69
  private
data/lib/rszr/stream.rb CHANGED
@@ -13,7 +13,7 @@ module Rszr
13
13
  raise ArgumentError, "data must be File or String, got #{data.class}"
14
14
  end
15
15
  @data.binmode
16
- @data.seek(start, IO::SEEK_CUR)
16
+ @data.seek(start)
17
17
  @pos = 0
18
18
  end
19
19
 
@@ -33,7 +33,7 @@ module Rszr
33
33
  end
34
34
 
35
35
  def substream
36
- self.class.new(self, pos)
36
+ self.class.new(self, @data.pos)
37
37
  end
38
38
 
39
39
  def fast_forward
data/lib/rszr/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Rszr
2
- VERSION = '0.8.0'
2
+ VERSION = '1.0.0'
3
3
  end
data/lib/rszr.rb CHANGED
@@ -9,6 +9,7 @@ require 'rszr/stream'
9
9
  require 'rszr/identification'
10
10
  require 'rszr/orientation'
11
11
  require 'rszr/buffered'
12
+ require 'rszr/color'
12
13
  require 'rszr/image'
13
14
 
14
15
  module Rszr
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rszr
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthias Grosser
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-10-08 00:00:00.000000000 Z
11
+ date: 2021-10-31 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Fast image resizer - do one thing and do it fast.
14
14
  email:
@@ -18,49 +18,49 @@ extensions:
18
18
  - ext/rszr/extconf.rb
19
19
  extra_rdoc_files: []
20
20
  files:
21
+ - LICENSE
22
+ - README.md
23
+ - Rakefile
24
+ - ext/rszr/errors.c
25
+ - ext/rszr/errors.h
26
+ - ext/rszr/extconf.rb
27
+ - ext/rszr/image.c
28
+ - ext/rszr/image.h
29
+ - ext/rszr/rszr.c
30
+ - ext/rszr/rszr.h
31
+ - lib/rszr.rb
21
32
  - lib/rszr/batch_transformation.rb
22
33
  - lib/rszr/buffered.rb
34
+ - lib/rszr/color.rb
23
35
  - lib/rszr/identification.rb
24
36
  - lib/rszr/image.rb
25
37
  - lib/rszr/image_processing.rb
26
38
  - lib/rszr/orientation.rb
27
39
  - lib/rszr/stream.rb
28
40
  - lib/rszr/version.rb
29
- - lib/rszr.rb
30
- - ext/rszr/extconf.rb
31
- - ext/rszr/errors.h
32
- - ext/rszr/image.h
33
- - ext/rszr/rszr.h
34
- - ext/rszr/errors.c
35
- - ext/rszr/image.c
36
- - ext/rszr/rszr.c
37
- - LICENSE
38
- - README.md
39
- - Rakefile
40
41
  homepage: https://github.com/mtgrosser/rszr
41
42
  licenses:
42
43
  - MIT
43
44
  metadata: {}
44
- post_install_message:
45
+ post_install_message:
45
46
  rdoc_options: []
46
47
  require_paths:
47
48
  - lib
48
49
  - ext
49
50
  required_ruby_version: !ruby/object:Gem::Requirement
50
51
  requirements:
51
- - - '>='
52
+ - - ">="
52
53
  - !ruby/object:Gem::Version
53
54
  version: '0'
54
55
  required_rubygems_version: !ruby/object:Gem::Requirement
55
56
  requirements:
56
- - - '>='
57
+ - - ">="
57
58
  - !ruby/object:Gem::Version
58
59
  version: '0'
59
60
  requirements:
60
61
  - imlib2
61
- rubyforge_project:
62
- rubygems_version: 2.0.14.1
63
- signing_key:
62
+ rubygems_version: 3.1.4
63
+ signing_key:
64
64
  specification_version: 4
65
65
  summary: Fast image resizer
66
66
  test_files: []