rucaptcha 3.1.4-x86_64-linux → 3.2.2-x86_64-linux

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: ff317f82aed6e9eb27b8962c9b442e810c059dfd3aac1c55a68e13ce8cd6a637
4
- data.tar.gz: 8ad9053734a5ff28db4de12e300a443dc8c9e8c7fc69bd1539124f3fb443e1c6
3
+ metadata.gz: b9929c47ee05d21aaa93af6c757c0d9026a018455682b1ea32abf93fe016fe2e
4
+ data.tar.gz: 810713f651e42cf7ae5fb03192327c3de8b70284fdddaa9469b2bc230d37dd97
5
5
  SHA512:
6
- metadata.gz: 4c3591bb1cdb1389480c079a31628d2a1aeafa90f2dea257b42d4e44edd79e9588294c00e5eb5a5e55fbd346bc32b8d0fa7181366b6e9ff4e8ac3fa50338375d
7
- data.tar.gz: 1e2e5838d6a818d0056f34132cbe5038e5ca6504c48fdff9828adc14cac06252cc1ea85a5cb83e73a156b2b43a3064d1d4be7d2605579ec4c41be407be99caa9
6
+ metadata.gz: c15d8a70f57136f75a83c61fb5596da152e02394d1640fa0f35279cabeec9cfc3ad5d97b326376eaed48076e984ab86b56827445017056add80c28bbccf0c137
7
+ data.tar.gz: ac734b427b500e44866363b09d60bbb2ccd2824b800bb9ceb59f3a4458ca726b26cac49b5f3b47f15902584abbb69f4f6c56120d1080f3fd0afb40c076ac3cbb
data/README.md CHANGED
@@ -37,6 +37,7 @@ Create `config/initializers/rucaptcha.rb`
37
37
  RuCaptcha.configure do
38
38
  # Custom captcha code expire time if you need, default: 2 minutes
39
39
  # self.expires_in = 120
40
+
40
41
   # [Requirement / 重要]
41
42
  # Store Captcha code where, this config more like Rails config.cache_store
42
43
  # default: Read config info from `Rails.application.config.cache_store`
@@ -44,10 +45,25 @@ RuCaptcha.configure do
44
45
   # 默认:会从 Rails 配置的 cache_store 里面读取相同的配置信息,并尝试用可以运行的方式,用于存储验证码字符
45
46
   # 但如果是 [:null_store, :memory_store, :file_store] 之类的,你可以通过下面的配置项单独给 RuCaptcha 配置 cache_store
46
47
   self.cache_store = :mem_cache_store
48
+
49
+ # If you wants disable `cache_store` check warning, you can do it, default: false
47
50
  # 如果想要 disable cache_store 的 warning,就设置为 true,default false
48
51
  # self.skip_cache_store_check = true
52
+
49
53
  # Chars length, default: 5, allows: [3 - 7]
50
54
  # self.length = 5
55
+
56
+ # Enable or disable Strikethrough, default: true
57
+ # self.line = true
58
+
59
+ # Enable or disable noise, default: false
60
+ # self.noise = false
61
+
62
+ # Set the image format, default: png, allows: [jpeg, png, webp]
63
+ # self.format = 'png'
64
+
65
+ # Custom mount path, default: '/rucaptcha'
66
+ # self.mount_path = '/rucaptcha'
51
67
  end
52
68
  ```
53
69
 
data/Rakefile CHANGED
@@ -27,9 +27,14 @@ end
27
27
  RSpec::Core::RakeTask.new(:spec)
28
28
  task default: :spec
29
29
 
30
+ def create_captcha(length = 5, difficulty = 5)
31
+ require "rucaptcha"
32
+ RuCaptchaCore.create(length, difficulty, false, false, "png")
33
+ end
34
+
30
35
  task :preview do
31
36
  require "rucaptcha"
32
- res = RuCaptchaCore.create(5, 5)
37
+ res = create_captcha()
33
38
  warn "-------------------------\n#{res[0]}"
34
39
  puts res[1].pack("c*")
35
40
  end
@@ -38,11 +43,11 @@ task :memory do
38
43
  require "rucaptcha"
39
44
  require "memory_profiler"
40
45
 
41
- RuCaptchaCore.create(5, 5)
46
+ create_captcha()
42
47
 
43
48
  report = MemoryProfiler.report do
44
49
  1000.times do
45
- RuCaptchaCore.create(5, 5)
50
+ create_captcha()
46
51
  end
47
52
  end
48
53
 
@@ -57,10 +62,10 @@ task :benchmark do
57
62
  require "rucaptcha"
58
63
  require "benchmark/ips"
59
64
 
60
- RuCaptchaCore.create(5, 5)
65
+ RuCaptchaCore.create(5, 5, true, true, "png")
61
66
 
62
67
  Benchmark.ips do |x|
63
- x.report("Generate image") { RuCaptchaCore.create(5, 5) }
68
+ x.report("Generate image") { RuCaptchaCore.create(5, 5, true, true, "png") }
64
69
  x.compare!
65
70
  end
66
71
  end
@@ -1,6 +1,4 @@
1
- use image::{ImageBuffer, Rgb};
2
- use imageproc::drawing::{draw_cubic_bezier_curve_mut, draw_text_mut};
3
- use imageproc::noise::gaussian_noise_mut;
1
+ use image::{ImageBuffer, Rgba};
4
2
  use rand::{thread_rng, Rng};
5
3
  use rusttype::{Font, Scale};
6
4
  use std::io::Cursor;
@@ -15,21 +13,21 @@ static FONT_BYTES1: &[u8; 145008] = include_bytes!("../fonts/FuzzyBubbles-Regula
15
13
  static FONT_BYTES2: &[u8; 37792] = include_bytes!("../fonts/Handlee-Regular.ttf");
16
14
 
17
15
  // https://coolors.co/cc0b8f-7c0abe-5700c8-3c2ea4-3d56a8-3fa67e-45bb30-69d003-a0d003-d8db02
18
- static COLORS: [(u8, u8, u8); 14] = [
19
- (197, 166, 3),
20
- (187, 87, 5),
21
- (176, 7, 7),
22
- (186, 9, 56),
23
- (204, 11, 143),
24
- (124, 10, 190),
25
- (87, 0, 200),
26
- (61, 86, 168),
27
- (63, 166, 126),
28
- (69, 187, 48),
29
- (105, 208, 3),
30
- (160, 208, 3),
31
- (216, 219, 2),
32
- (50, 50, 50),
16
+ static COLORS: [(u8, u8, u8, u8); 14] = [
17
+ (197, 166, 3, 255),
18
+ (187, 87, 5, 255),
19
+ (176, 7, 7, 255),
20
+ (186, 9, 56, 255),
21
+ (204, 11, 143, 255),
22
+ (124, 10, 190, 255),
23
+ (87, 0, 200, 255),
24
+ (61, 86, 168, 255),
25
+ (63, 166, 126, 255),
26
+ (69, 187, 48, 255),
27
+ (105, 208, 3, 255),
28
+ (160, 208, 3, 255),
29
+ (216, 219, 2, 255),
30
+ (50, 50, 50, 255),
33
31
  ];
34
32
 
35
33
  static SCALE_SM: u32 = 32;
@@ -51,18 +49,18 @@ fn get_captcha(len: usize) -> Vec<String> {
51
49
  }
52
50
 
53
51
  #[allow(unused)]
54
- fn get_color() -> Rgb<u8> {
52
+ fn get_color() -> Rgba<u8> {
55
53
  let rnd = rand_num(COLORS.len() - 1);
56
54
  let c = COLORS[rnd];
57
- Rgb([c.0, c.1, c.2])
55
+ Rgba([c.0, c.1, c.2, c.3])
58
56
  }
59
57
 
60
- fn get_colors(num: usize) -> Vec<Rgb<u8>> {
58
+ fn get_colors(num: usize) -> Vec<Rgba<u8>> {
61
59
  let rnd = rand_num(COLORS.len());
62
60
  let mut out = vec![];
63
61
  for i in 0..num {
64
62
  let c = COLORS[(rnd + i) % COLORS.len()];
65
- out.push(Rgb([c.0, c.1, c.2]))
63
+ out.push(Rgba([c.0, c.1, c.2, c.3]))
66
64
  }
67
65
 
68
66
  out
@@ -80,13 +78,13 @@ fn get_font() -> Font<'static> {
80
78
  }
81
79
  }
82
80
 
83
- fn get_image(width: usize, height: usize) -> ImageBuffer<Rgb<u8>, Vec<u8>> {
81
+ fn get_image(width: usize, height: usize) -> ImageBuffer<Rgba<u8>, Vec<u8>> {
84
82
  ImageBuffer::from_fn(width as u32, height as u32, |_, _| {
85
- image::Rgb([255, 255, 255])
83
+ image::Rgba([255, 255, 255, 255])
86
84
  })
87
85
  }
88
86
 
89
- fn cyclic_write_character(res: &[String], image: &mut ImageBuffer<Rgb<u8>, Vec<u8>>) {
87
+ fn cyclic_write_character(res: &[String], image: &mut ImageBuffer<Rgba<u8>, Vec<u8>>, lines: bool) {
90
88
  let c = (image.width() - 20) / res.len() as u32;
91
89
  let y = image.height() / 3 - 15;
92
90
 
@@ -107,7 +105,10 @@ fn cyclic_write_character(res: &[String], image: &mut ImageBuffer<Rgb<u8>, Vec<u
107
105
  // Draw line, ellipse first as background
108
106
  for (i, _) in res.iter().enumerate() {
109
107
  let line_color = line_colors[i];
110
- draw_interference_line(1, image, line_color);
108
+
109
+ if lines {
110
+ draw_interference_line(1, image, line_color);
111
+ }
111
112
  draw_interference_ellipse(1, image, line_color);
112
113
  }
113
114
 
@@ -121,7 +122,7 @@ fn cyclic_write_character(res: &[String], image: &mut ImageBuffer<Rgb<u8>, Vec<u
121
122
  for j in 0..(rand_num(3) + 1) as i32 {
122
123
  // Draw text again with offset
123
124
  let offset = j * (rand_num(2) as i32);
124
- draw_text_mut(
125
+ imageproc::drawing::draw_text_mut(
125
126
  image,
126
127
  color,
127
128
  10 + offset + (i as u32 * c) as i32,
@@ -137,7 +138,7 @@ fn cyclic_write_character(res: &[String], image: &mut ImageBuffer<Rgb<u8>, Vec<u
137
138
  }
138
139
  }
139
140
 
140
- fn draw_interference_line(num: usize, image: &mut ImageBuffer<Rgb<u8>, Vec<u8>>, color: Rgb<u8>) {
141
+ fn draw_interference_line(num: usize, image: &mut ImageBuffer<Rgba<u8>, Vec<u8>>, color: Rgba<u8>) {
141
142
  for _ in 0..num {
142
143
  let width = image.width();
143
144
  let height = image.height();
@@ -153,7 +154,7 @@ fn draw_interference_line(num: usize, image: &mut ImageBuffer<Rgb<u8>, Vec<u8>>,
153
154
  let ctrl_x2 = get_next((width / 12) as f32, width / 12 * 3);
154
155
  let ctrl_y2 = get_next(x1, height - 5);
155
156
  // Randomly draw bezier curves
156
- draw_cubic_bezier_curve_mut(
157
+ imageproc::drawing::draw_cubic_bezier_curve_mut(
157
158
  image,
158
159
  (x1, y1),
159
160
  (x2, y2),
@@ -166,8 +167,8 @@ fn draw_interference_line(num: usize, image: &mut ImageBuffer<Rgb<u8>, Vec<u8>>,
166
167
 
167
168
  fn draw_interference_ellipse(
168
169
  num: usize,
169
- image: &mut ImageBuffer<Rgb<u8>, Vec<u8>>,
170
- color: Rgb<u8>,
170
+ image: &mut ImageBuffer<Rgba<u8>, Vec<u8>>,
171
+ color: Rgba<u8>,
171
172
  ) {
172
173
  for _ in 0..num {
173
174
  // max cycle width 20px
@@ -189,6 +190,9 @@ pub struct CaptchaBuilder {
189
190
  width: usize,
190
191
  height: usize,
191
192
  complexity: usize,
193
+ line: bool,
194
+ noise: bool,
195
+ format: image::ImageFormat,
192
196
  }
193
197
 
194
198
  impl CaptchaBuilder {
@@ -198,6 +202,9 @@ impl CaptchaBuilder {
198
202
  width: 220,
199
203
  height: 70,
200
204
  complexity: 5,
205
+ line: true,
206
+ noise: false,
207
+ format: image::ImageFormat::Png,
201
208
  }
202
209
  }
203
210
 
@@ -206,15 +213,26 @@ impl CaptchaBuilder {
206
213
  self
207
214
  }
208
215
 
209
- // pub fn width(mut self, width: usize) -> Self {
210
- // self.width = width;
211
- // self
212
- // }
216
+ pub fn line(mut self, line: bool) -> Self {
217
+ self.line = line;
218
+ self
219
+ }
220
+
221
+ pub fn noise(mut self, noise: bool) -> Self {
222
+ self.noise = noise;
223
+ self
224
+ }
225
+
226
+ pub fn format(mut self, format: &str) -> Self {
227
+ self.format = match format {
228
+ "png" => image::ImageFormat::Png,
229
+ "jpg" | "jpeg" => image::ImageFormat::Jpeg,
230
+ "webp" => image::ImageFormat::WebP,
231
+ _ => image::ImageFormat::Png,
232
+ };
213
233
 
214
- // pub fn height(mut self, height: usize) -> Self {
215
- // self.height = height;
216
- // self
217
- // }
234
+ self
235
+ }
218
236
 
219
237
  pub fn complexity(mut self, complexity: usize) -> Self {
220
238
  let mut complexity = complexity;
@@ -238,20 +256,86 @@ impl CaptchaBuilder {
238
256
  let mut image = get_image(self.width, self.height);
239
257
 
240
258
  // Loop to write the verification code string into the background image
241
- cyclic_write_character(&res, &mut image);
242
-
243
- gaussian_noise_mut(
244
- &mut image,
245
- (self.complexity - 1) as f64,
246
- ((10 * self.complexity) - 10) as f64,
247
- ((5 * self.complexity) - 5) as u64,
248
- );
259
+ cyclic_write_character(&res, &mut image, self.line);
260
+
261
+ if self.noise {
262
+ imageproc::noise::gaussian_noise_mut(
263
+ &mut image,
264
+ (self.complexity - 1) as f64,
265
+ ((10 * self.complexity) - 10) as f64,
266
+ ((5 * self.complexity) - 5) as u64,
267
+ );
268
+ }
249
269
 
250
270
  let mut bytes: Vec<u8> = Vec::new();
251
271
  image
252
- .write_to(&mut Cursor::new(&mut bytes), image::ImageFormat::Jpeg)
272
+ .write_to(&mut Cursor::new(&mut bytes), image::ImageFormat::Png)
253
273
  .unwrap();
254
274
 
255
275
  Captcha { text, image: bytes }
256
276
  }
257
277
  }
278
+
279
+ #[cfg(test)]
280
+ mod tests {
281
+ use super::*;
282
+
283
+ #[test]
284
+ fn test_format() {
285
+ let mut builder = CaptchaBuilder::new();
286
+ assert_eq!(builder.format, image::ImageFormat::Png);
287
+
288
+ builder = builder.format("jpg");
289
+ assert_eq!(builder.format, image::ImageFormat::Jpeg);
290
+ builder = builder.format("jpeg");
291
+ assert_eq!(builder.format, image::ImageFormat::Jpeg);
292
+ builder = builder.format("webp");
293
+ assert_eq!(builder.format, image::ImageFormat::WebP);
294
+ builder = builder.format("png");
295
+ assert_eq!(builder.format, image::ImageFormat::Png);
296
+ builder = builder.format("gif");
297
+ assert_eq!(builder.format, image::ImageFormat::Png);
298
+ }
299
+
300
+ #[test]
301
+ fn test_line() {
302
+ let mut builder = CaptchaBuilder::new();
303
+ assert!(builder.line);
304
+
305
+ builder = builder.line(false);
306
+ assert!(!builder.line);
307
+ }
308
+
309
+ #[test]
310
+ fn test_noise() {
311
+ let mut builder = CaptchaBuilder::new();
312
+ assert!(!builder.noise);
313
+
314
+ builder = builder.noise(true);
315
+ assert!(builder.noise);
316
+ }
317
+
318
+ #[test]
319
+ fn test_difficulty() {
320
+ let mut builder = CaptchaBuilder::new();
321
+ assert_eq!(builder.complexity, 5);
322
+
323
+ builder = builder.complexity(10);
324
+ assert_eq!(builder.complexity, 10);
325
+
326
+ builder = builder.complexity(11);
327
+ assert_eq!(builder.complexity, 10);
328
+
329
+ builder = builder.complexity(0);
330
+ assert_eq!(builder.complexity, 1);
331
+ }
332
+
333
+ #[test]
334
+ fn test_length() {
335
+ let mut builder = CaptchaBuilder::new();
336
+ assert_eq!(builder.length, 4);
337
+
338
+ builder = builder.length(10);
339
+ assert_eq!(builder.length, 10);
340
+ }
341
+ }
@@ -2,9 +2,21 @@ use magnus::{define_class, function, Error, Object};
2
2
 
3
3
  mod captcha;
4
4
 
5
- pub fn create(len: usize, difficulty: usize) -> (String, Vec<u8>) {
5
+ pub fn create(
6
+ len: usize,
7
+ difficulty: usize,
8
+ line: bool,
9
+ noise: bool,
10
+ format: String,
11
+ ) -> (String, Vec<u8>) {
6
12
  let c = captcha::CaptchaBuilder::new();
7
- let out = c.complexity(difficulty).length(len).build();
13
+ let out = c
14
+ .complexity(difficulty)
15
+ .length(len)
16
+ .line(line)
17
+ .noise(noise)
18
+ .format(&format)
19
+ .build();
8
20
 
9
21
  (out.text, out.image)
10
22
  }
@@ -12,7 +24,7 @@ pub fn create(len: usize, difficulty: usize) -> (String, Vec<u8>) {
12
24
  #[magnus::init]
13
25
  fn init() -> Result<(), Error> {
14
26
  let class = define_class("RuCaptchaCore", Default::default())?;
15
- class.define_singleton_method("create", function!(create, 2))?;
27
+ class.define_singleton_method("create", function!(create, 5))?;
16
28
 
17
29
  Ok(())
18
30
  }
Binary file
Binary file
@@ -9,7 +9,15 @@ module RuCaptcha
9
9
  attr_accessor :length
10
10
  # Hard mode, default: 5, allows: [1..10]
11
11
  attr_accessor :difficulty
12
+ # Enable or disable strikethrough lines on captcha image, default: true
13
+ attr_accessor :line
14
+ # Enable or disable noise on captcha image, default: false
15
+ attr_accessor :noise
16
+ # Image format allow: ['jpeg', 'png', 'webp'], default: 'png'
17
+ attr_accessor :format
12
18
  # skip_cache_store_check, default: false
13
19
  attr_accessor :skip_cache_store_check
20
+ # custom rucaptcha mount path, default: '/rucaptcha'
21
+ attr_accessor :mount_path
14
22
  end
15
23
  end
@@ -6,7 +6,7 @@ module RuCaptcha
6
6
  # https://github.com/rails/rails/blob/3-2-stable/actionpack/lib/action_dispatch/routing/route_set.rb#L268
7
7
  # `app.routes.prepend` start from Rails 3.2 - 5.0
8
8
  app.routes.prepend do
9
- mount RuCaptcha::Engine => "/rucaptcha"
9
+ mount RuCaptcha::Engine => RuCaptcha.config.mount_path
10
10
  end
11
11
 
12
12
  RuCaptcha.check_cache_store! unless RuCaptcha.config.skip_cache_store_check
@@ -1,3 +1,3 @@
1
1
  module RuCaptcha
2
- VERSION = "3.1.4"
2
+ VERSION = "3.2.2"
3
3
  end
data/lib/rucaptcha.rb CHANGED
@@ -28,6 +28,10 @@ module RuCaptcha
28
28
  @config.difficulty = 3
29
29
  @config.expires_in = 2.minutes
30
30
  @config.skip_cache_store_check = false
31
+ @config.line = true
32
+ @config.noise = true
33
+ @config.format = "png"
34
+ @config.mount_path = "/rucaptcha"
31
35
 
32
36
  @config.cache_store = if Rails.application
33
37
  Rails.application.config.cache_store
@@ -47,7 +51,7 @@ module RuCaptcha
47
51
 
48
52
  raise RuCaptcha::Errors::Configuration, "length config error, value must in 3..7" unless length.in?(3..7)
49
53
 
50
- result = RuCaptchaCore.create(length, config.difficulty || 5)
54
+ result = RuCaptchaCore.create(length, config.difficulty || 5, config.line, config.noise, config.format)
51
55
  [result[0].downcase, result[1].pack("c*")]
52
56
  end
53
57
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rucaptcha
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.4
4
+ version: 3.2.2
5
5
  platform: x86_64-linux
6
6
  authors:
7
7
  - Jason Lee
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-01-11 00:00:00.000000000 Z
11
+ date: 2023-10-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties
@@ -93,7 +93,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
93
93
  - !ruby/object:Gem::Version
94
94
  version: '0'
95
95
  requirements: []
96
- rubygems_version: 3.4.3
96
+ rubygems_version: 3.4.4
97
97
  signing_key:
98
98
  specification_version: 4
99
99
  summary: Captcha Gem for Rails, which generates captcha image by Rust.