easyimg_utils 0.6.6 → 0.7.4

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: 4d9ac6449342efa070a858c26d96378947ca77231bcdc97339321b5dac0a316b
4
- data.tar.gz: 22617abf8420c0cf4276e2198e02cae542aa29555d8579fcd66c60127e70afbe
3
+ metadata.gz: 491f7066a8af2e40049a6986c894498d507d99b2b02caf4321f59abb25a05dd1
4
+ data.tar.gz: e6d42410ed62a4a0829c648b5622b28845930fa18853202e6ac507d0e7e34186
5
5
  SHA512:
6
- metadata.gz: 947e70b56bfeb36bf1c4d0e51bf5ba02bca9124083d46c27a55dd2669fcc3b06dbbfc48c9e2b0acfc6f42db89d6c71df1a125e30b6ff0d1f8431a5c535234828
7
- data.tar.gz: a19e9e5da426cf4ab50f7040419158c30fede078f8545c6f6fa7e4fb4a3d3b2dfdcd3e41ebdce4ee3e43e6dfba2f8d75a76262e516190f7e8ee2ee0f45c4e41d
6
+ metadata.gz: 57a595c6b1b171e44600bcdd043a36f90ce89453fc5d57e40fd8016a5f6518be8753c247bd613b2e5318ee6db05ababb9735a0c47b928775b96a4ef5bd99dac0
7
+ data.tar.gz: aa6f56c7307732c2f4f93f2298d32d0e2de8d164a2cee099f5ebdc18e433bccb162e43c5b3bd2e4ad9d2c87d0398c131531d10dcceb8099bbce4873d19d5fd19
checksums.yaml.gz.sig CHANGED
Binary file
data.tar.gz.sig CHANGED
Binary file
data/lib/easyimg_utils.rb CHANGED
@@ -7,6 +7,7 @@ require 'x4ss'
7
7
  require 'rmagick'
8
8
  require 'webp_ffi'
9
9
  require 'rxfhelper'
10
+ require 'detectfaces'
10
11
 
11
12
  # requirements:
12
13
  #
@@ -19,6 +20,8 @@ require 'rxfhelper'
19
20
  # webp-ffi dependencies
20
21
  # apt-get install libjpeg-dev libpng-dev libtiff-dev libwebp-dev
21
22
  #
23
+ # detectfaces dependencies
24
+ # apt-get install libopencv-dev
22
25
 
23
26
 
24
27
 
@@ -54,6 +57,7 @@ class EasyImgUtils
54
57
  * add_svg # adds an SVG transparency overlay. usage: add_svg('/tmp/image1.svg')
55
58
  * add_text # e.g. add_text('some text')
56
59
  * animate Creates an animated gif e.g. animate('/tmp/a%d.png', '/tmp/b.gif')
60
+ * best_viewport # returns the best viewing region on the y-axis
57
61
  * blur # e.g. blur(x: 231, y: 123, w: 85, h: 85)
58
62
  * capture_screen # takes a screenshot of the desktop
59
63
  * calc_resize # e.g. calc_resize '640x480' #=> 640x491
@@ -63,6 +67,7 @@ class EasyImgUtils
63
67
  * convert # convert from 1 img format to another
64
68
  * crop # e.g. crop(x: 231, y: 123, w: 85, h: 85)
65
69
  * fax_effect # Produces a high-contrast, two colour image
70
+ * faces # Returns an array of bounding boxes for detected faces
66
71
  * greyscale # Reduces the image to 256 shades of grey
67
72
  * info # returns the dimension of the image in a Hash object
68
73
  * make_thumbnail # similar to resize but faster for sizes less than 10% of original image
@@ -89,20 +94,35 @@ class EasyImgUtils
89
94
 
90
95
  # e.g. calc_resize '1449x1932', '640x480' #=> 480x640
91
96
  # e.g. calc_resize '518x1024', '*518x500' #=> "518x1024"
92
- # the asterisk denotes a guaranteed the image will be resized using x or y
97
+ # the asterisk denotes a guarantee the image will be resized to a
98
+ # minimum size on either dimension
93
99
  #
94
- def self.calc_resize(geometry, new_geometry, force: false)
100
+ # e.g. calc_resize '1920x1088', '*518x*500' #=> "882x500"
101
+ # 2 asterisks denotes a guaranteed minumum size on both dimensions
102
+ #
103
+ def self.calc_resize(geometry, new_geometry)
95
104
 
96
105
  xy = geometry.split('x',2)
97
106
  xy2 = new_geometry.split('x',2)
98
107
 
99
108
  # find any locked geometry which guarantees the resize on either x or y
100
- lock = xy2.find {|x| x =~ /^\*/}
109
+ locks = xy2.select {|x| x =~ /^\*/}
101
110
 
102
111
  a = xy.map {|x| x[/\d+/].to_i}
103
112
  a2 = xy2.map {|x| x[/\d+/].to_i}
113
+
114
+ i = if locks.length > 1 then
104
115
 
105
- i = lock ? a2.index(lock[1..-1].to_i) : a.index(a.max)
116
+ a.index(a.min)
117
+
118
+ elsif locks.any?
119
+
120
+ lock = locks.first
121
+ a2.index(lock[1..-1].to_i)
122
+
123
+ else
124
+ a.index(a.max)
125
+ end
106
126
 
107
127
  factor = a2[i] / a[i].to_f
108
128
 
@@ -171,6 +191,42 @@ class EasyImgUtils
171
191
 
172
192
  end
173
193
 
194
+ # Used where images are perhaps cropped using CSS to a letterbox size image.
195
+ # Works best with portrait mode photos of selfies or natural
196
+ # landscapes with a lot of sky
197
+ #
198
+ # Returns the starting y pos as a percentage of the image using face
199
+ # detection and high contrast detection on the y-axis
200
+ #
201
+ def best_viewport()
202
+
203
+ percentage = 0
204
+
205
+ read() do |img|
206
+
207
+ found = faces()
208
+
209
+ index = if found.any? then
210
+
211
+ # find the top y
212
+ box = found.max_by {|x, y, width, height| y}
213
+ y, height = box.values_at 1, 3
214
+ y - (height / 2)
215
+
216
+ else
217
+
218
+ y_maxcontrast(img)
219
+
220
+ end
221
+
222
+ percentage = (100 / (img.rows / index.to_f)).round
223
+
224
+ end
225
+
226
+ return percentage
227
+
228
+ end
229
+
174
230
  def blur(x: 0, y: 0, w: 80, h: 80, strength: 8, quality: nil)
175
231
 
176
232
  width, height = w, h
@@ -304,6 +360,10 @@ class EasyImgUtils
304
360
 
305
361
  end
306
362
 
363
+ def faces()
364
+ DetectFaces.new(@file_in).faces
365
+ end
366
+
307
367
  def fax_effect(threshold: 0.55, quality: nil)
308
368
 
309
369
  read() do |img|
@@ -475,7 +535,7 @@ class EasyImgUtils
475
535
 
476
536
  end
477
537
 
478
- alias feathered_around vignette
538
+ alias feathered_around vignette
479
539
 
480
540
  private
481
541
 
@@ -545,5 +605,37 @@ class EasyImgUtils
545
605
 
546
606
  end
547
607
  end
608
+
609
+ # returns the y index of the pixel containing the most contrast using the
610
+ # y-axis center of the image
611
+ #
612
+ def y_maxcontrast(img)
548
613
 
614
+ rows, cols = img.rows, img.columns
615
+ center = (cols / 2).round
616
+ pixels = img.get_pixels(center,0,1,rows)
617
+
618
+ rgb = []
619
+ px = pixels[0]
620
+ rgb = [px.red, px.green, px.blue].map { |v| 255*(v/65535.0) }
621
+
622
+ a = pixels[1..-1].map do |pixel,i|
623
+
624
+ c = [pixel.red, pixel.green, pixel.blue].map { |v| 255*(v/65535.0) }
625
+ rgb[0] - c[0]
626
+ rgb.map.with_index {|x,i| (x - c[i]).abs.to_i}
627
+
628
+ end
629
+
630
+ a2 = a.map(&:sum)
631
+ puts 'a2: ' + a2.inspect if @debug
632
+ #a2.index(a2.max) + 1
633
+ # attempt to detect the 1st occurrence of contrast
634
+ r = a2.detect {|x| x > 600}
635
+ # otherwise select any occurrence of high contrast
636
+ r = a2.max unless r
637
+ a2.index(r) + 1
638
+
639
+ end
640
+
549
641
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: easyimg_utils
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.6
4
+ version: 0.7.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Robertson
@@ -35,7 +35,7 @@ cert_chain:
35
35
  KY48n99T12IOioQ4ghCO1L/UAg2taLOcZbMv4WpV1p9bXKhnrow81zeogZjjiNGS
36
36
  OmTAjCfyGFPC/1eXnSV5Smv8
37
37
  -----END CERTIFICATE-----
38
- date: 2021-03-22 00:00:00.000000000 Z
38
+ date: 2021-03-30 00:00:00.000000000 Z
39
39
  dependencies:
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: rmagick
@@ -117,6 +117,26 @@ dependencies:
117
117
  - - "~>"
118
118
  - !ruby/object:Gem::Version
119
119
  version: '0.2'
120
+ - !ruby/object:Gem::Dependency
121
+ name: detectfaces
122
+ requirement: !ruby/object:Gem::Requirement
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ version: 0.1.0
127
+ - - "~>"
128
+ - !ruby/object:Gem::Version
129
+ version: '0.1'
130
+ type: :runtime
131
+ prerelease: false
132
+ version_requirements: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: 0.1.0
137
+ - - "~>"
138
+ - !ruby/object:Gem::Version
139
+ version: '0.1'
120
140
  description:
121
141
  email: digital.robertson@gmail.com
122
142
  executables: []
metadata.gz.sig CHANGED
Binary file