fast_thumbhash 0.6.0 → 0.7.1

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
2
  SHA256:
3
- metadata.gz: 3dd0e9e710dfa53775b6c718fd674fdc26fb0a17932058ca18e495b229d43e30
4
- data.tar.gz: dc6e6c4203596d64bb3fb7e84fa63b72dda92cd5b7612a97371cb4ae418ae2af
3
+ metadata.gz: '029bcedcfcff9aeabbd3d052759f165228798ba5a4599747866b80c0e7cb2267'
4
+ data.tar.gz: c0284c796f2541a68ba0ce5d5f6d39362abc487d443ea92fe34f1cae84e49da2
5
5
  SHA512:
6
- metadata.gz: 29c037a813de79ec9a791484823fc42291e2bbc6dd5c8c6a8ecc4d5e17b9de52dfcc64cd554372604bd8068cc5239e898b982f875e0f1efd62cac53967dabf05
7
- data.tar.gz: 2d0f21baac23f3c28e024d6755a45cdae2c9f4b1dd78243ccd98e6fa6e9b01520f1ff28f9c113d4ab0a9c2ecc0988a0fa801c141310d760337c8f1ec37cc002b
6
+ metadata.gz: 8305727fad3e3d55f31265f05f3bad5931f6a6cb90787e896a8aacde19d3fa5aa75c122a3d6a7a977b0f0703c95323556527401816641148f69c25001b5b30e9
7
+ data.tar.gz: 77e126d32164ec0531b0ee450a950e59e7f872ca18d2fbb46e5544171f35f44066835817fb0f6cccce2625e806e5af9a280c238e7bd104de2125065e6b6e3cb8
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.7.8
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- fast_thumbhash (0.6.0)
4
+ fast_thumbhash (0.7.1)
5
5
  ffi
6
6
 
7
7
  GEM
@@ -52,6 +52,7 @@ GEM
52
52
 
53
53
  PLATFORMS
54
54
  arm64-darwin-21
55
+ arm64-darwin-22
55
56
  x86_64-darwin-18
56
57
  x86_64-darwin-20
57
58
  x86_64-darwin-21
@@ -67,14 +67,20 @@ encoded_channel encode_channel(double *channel, uint8_t nx, uint8_t ny, uint8_t
67
67
  return (encoded_channel){dc, ac, ac_length, scale};
68
68
  }
69
69
 
70
- void write_varying_factors(double *ac, int ac_size, uint8_t *thumbhash, uint8_t *ac_index) {
71
- for (int i = 0; i < ac_size; i++) {
72
- uint8_t index = (*ac_index) >> 1;
73
- thumbhash[index] |= (uint8_t) roundf(15.0 * ac[i]) << (((*ac_index)++ & 1) << 2);
70
+ uint8_t write_varying_factors(double *ac, int ac_size, uint8_t *thumbhash, uint8_t *ac_index)
71
+ {
72
+ uint8_t index;
73
+
74
+ for (int i = 0; i < ac_size; i++)
75
+ {
76
+ index = (*ac_index) >> 1;
77
+ thumbhash[index] |= (uint8_t)roundf(15.0 * ac[i]) << (((*ac_index)++ & 1) << 2);
74
78
  }
79
+
80
+ return index;
75
81
  }
76
82
 
77
- void rgba_to_thumbhash(uint8_t w, uint8_t h, uint8_t *rgba, uint8_t *thumbhash)
83
+ uint8_t rgba_to_thumbhash(uint8_t w, uint8_t h, uint8_t *rgba, uint8_t *thumbhash)
78
84
  {
79
85
  assert(w <= 100);
80
86
  assert(h <= 100);
@@ -143,28 +149,44 @@ void rgba_to_thumbhash(uint8_t w, uint8_t h, uint8_t *rgba, uint8_t *thumbhash)
143
149
  thumbhash[3] = (uint8_t)(header16 & 0xff);
144
150
  thumbhash[4] = (uint8_t)(header16 >> 8);
145
151
 
146
- if (has_alpha) {
147
- thumbhash[5] = (uint8_t) roundf(15.0 * ea.dc) | ((uint8_t) roundf(15.0 * ea.scale) << 4);
152
+ if (has_alpha)
153
+ {
154
+ thumbhash[5] = (uint8_t)roundf(15.0 * ea.dc) | ((uint8_t)roundf(15.0 * ea.scale) << 4);
148
155
  }
149
156
 
150
157
  uint8_t ac_start = has_alpha ? 6 : 5;
151
158
  uint8_t ac_index = 0;
152
159
 
153
- write_varying_factors(el.ac, el.ac_size, thumbhash + ac_start, &ac_index);
154
- write_varying_factors(ep.ac, ep.ac_size, thumbhash + ac_start, &ac_index);
155
- write_varying_factors(eq.ac, eq.ac_size, thumbhash + ac_start, &ac_index);
160
+ uint8_t max_written_indexes[] = {0, 0, 0, 0};
161
+
162
+ max_written_indexes[0] = write_varying_factors(el.ac, el.ac_size, thumbhash + ac_start, &ac_index);
163
+ max_written_indexes[1] = write_varying_factors(ep.ac, ep.ac_size, thumbhash + ac_start, &ac_index);
164
+ max_written_indexes[2] = write_varying_factors(eq.ac, eq.ac_size, thumbhash + ac_start, &ac_index);
156
165
 
157
- if (has_alpha) {
158
- write_varying_factors(ea.ac, ea.ac_size, thumbhash + ac_start, &ac_index);
166
+ if (has_alpha)
167
+ {
168
+ max_written_indexes[3] = write_varying_factors(ea.ac, ea.ac_size, thumbhash + ac_start, &ac_index);
159
169
  }
160
170
 
161
171
  free(el.ac);
162
172
  free(ep.ac);
163
173
  free(eq.ac);
164
174
 
165
- if (has_alpha) {
175
+ if (has_alpha)
176
+ {
166
177
  free(ea.ac);
167
178
  }
179
+
180
+ // store the largest number at max_written_indexes[0]
181
+ for (int i = 1; i < 4; ++i)
182
+ {
183
+ if (max_written_indexes[0] < max_written_indexes[i])
184
+ {
185
+ max_written_indexes[0] = max_written_indexes[i];
186
+ }
187
+ }
188
+
189
+ return max_written_indexes[0] + ac_start + 1;
168
190
  }
169
191
 
170
192
  double *decode_channel(uint8_t nx, uint8_t ny, double scale, uint8_t *hash, uint8_t ac_start, uint8_t *ac_index)
@@ -321,15 +343,14 @@ void hsv2rgb(float *hsv, uint8_t *rgb)
321
343
  * Decodes a ThumbHash to an RGBA image. RGB is not be premultiplied by A.
322
344
  */
323
345
  void thumbhash_to_rgba(
324
- uint8_t *hash,
325
- uint8_t w,
326
- uint8_t h,
327
- enum FillMode fill_mode,
328
- uint8_t *fill_color,
329
- double *homogeneous_transform,
330
- int saturation,
331
- uint8_t *rgba
332
- )
346
+ uint8_t *hash,
347
+ uint8_t w,
348
+ uint8_t h,
349
+ enum FillMode fill_mode,
350
+ uint8_t *fill_color,
351
+ double *homogeneous_transform,
352
+ int saturation,
353
+ uint8_t *rgba)
333
354
  {
334
355
  // Read the constants
335
356
  u_int32_t header24 = hash[0] | (hash[1] << 8) | (hash[2] << 16);
@@ -343,7 +364,8 @@ void thumbhash_to_rgba(
343
364
  double q_scale = (double)((header16 >> 9) & 63) / 63;
344
365
  bool is_landscape = (header16 >> 15) != 0;
345
366
  uint8_t lx = fmax(3, is_landscape ? has_alpha ? 5 : 7 : header16 & 7);
346
- uint8_t ly = fmax(3, is_landscape ? header16 & 7 : has_alpha ? 5 : 7);
367
+ uint8_t ly = fmax(3, is_landscape ? header16 & 7 : has_alpha ? 5
368
+ : 7);
347
369
  double a_dc = (double)has_alpha ? (hash[5] & 15) / 15 : 1;
348
370
  double a_scale = (double)(hash[5] >> 4) / 15;
349
371
 
@@ -380,7 +402,8 @@ void thumbhash_to_rgba(
380
402
 
381
403
  double r, g, b, a;
382
404
 
383
- if (fill_mode == CLAMP || fill_mode == BLUR) {
405
+ if (fill_mode == CLAMP || fill_mode == BLUR)
406
+ {
384
407
  if (x < 0)
385
408
  {
386
409
  x = 0;
@@ -401,7 +424,8 @@ void thumbhash_to_rgba(
401
424
 
402
425
  bool inside_image = x >= 0 && x <= 1.0 && y >= 0 && y <= 1.0;
403
426
 
404
- if (inside_image) {
427
+ if (inside_image)
428
+ {
405
429
  double l = l_dc, p = p_dc, q = q_dc;
406
430
  a = a_dc;
407
431
 
@@ -455,7 +479,9 @@ void thumbhash_to_rgba(
455
479
  b = l - 2.0 / 3.0 * p;
456
480
  r = (3.0 * l - b + q) / 2.0;
457
481
  g = r - q;
458
- } else {
482
+ }
483
+ else
484
+ {
459
485
  r = 255;
460
486
  g = 255;
461
487
  b = 255;
@@ -463,35 +489,37 @@ void thumbhash_to_rgba(
463
489
  }
464
490
 
465
491
  uint_fast8_t top[4] = {
466
- fmax(0, 255 * fmin(1, r)),
467
- fmax(0, 255 * fmin(1, g)),
468
- fmax(0, 255 * fmin(1, b)),
469
- fmax(0, 255 * fmin(1, a))
470
- };
471
-
472
- if (fill_color && fill_color[3] > 0) {
473
- double top_a = (double) top[3] / 255.0;
474
- double fill_color_a = (double) fill_color[3] / 255.0;
492
+ fmax(0, 255 * fmin(1, r)),
493
+ fmax(0, 255 * fmin(1, g)),
494
+ fmax(0, 255 * fmin(1, b)),
495
+ fmax(0, 255 * fmin(1, a))};
496
+
497
+ if (fill_color && fill_color[3] > 0)
498
+ {
499
+ double top_a = (double)top[3] / 255.0;
500
+ double fill_color_a = (double)fill_color[3] / 255.0;
475
501
  double inverse_top_a = 1.0 - top_a;
476
502
  double sum_a = top_a + fill_color_a * inverse_top_a;
477
503
 
478
504
  // Alpha compositing (top over fill_color)
479
- rgba[i] = roundf(((double) top[0] * top_a + (double) fill_color[0] * fill_color_a * inverse_top_a) / sum_a);
480
- rgba[i+1] = roundf(((double) top[1] * top_a + (double) fill_color[1] * fill_color_a * inverse_top_a) / sum_a);
481
- rgba[i+2] = roundf(((double) top[2] * top_a + (double) fill_color[2] * fill_color_a * inverse_top_a) / sum_a);
482
- rgba[i+3] = roundf(sum_a * 255.0);
483
- } else {
484
- rgba[i] = top[0];
485
- rgba[i+1] = top[1];
486
- rgba[i+2] = top[2];
487
- rgba[i+3] = top[3];
505
+ rgba[i] = roundf(((double)top[0] * top_a + (double)fill_color[0] * fill_color_a * inverse_top_a) / sum_a);
506
+ rgba[i + 1] = roundf(((double)top[1] * top_a + (double)fill_color[1] * fill_color_a * inverse_top_a) / sum_a);
507
+ rgba[i + 2] = roundf(((double)top[2] * top_a + (double)fill_color[2] * fill_color_a * inverse_top_a) / sum_a);
508
+ rgba[i + 3] = roundf(sum_a * 255.0);
509
+ }
510
+ else
511
+ {
512
+ rgba[i] = top[0];
513
+ rgba[i + 1] = top[1];
514
+ rgba[i + 2] = top[2];
515
+ rgba[i + 3] = top[3];
488
516
  }
489
517
 
490
518
  if (saturation)
491
519
  {
492
520
  float hsv[3] = {0};
493
521
  rgb2hsv(rgba + i, hsv);
494
- float mult = ((float) saturation + 100.0f) / 200.0f * 1.4f;
522
+ float mult = ((float)saturation + 100.0f) / 200.0f * 1.4f;
495
523
  hsv[1] = fminf(fmaxf(hsv[1] * mult, 0), 1.0f);
496
524
  hsv2rgb(hsv, rgba + i);
497
525
  }
@@ -3,34 +3,32 @@
3
3
 
4
4
  #include <stdint.h>
5
5
 
6
- enum FillMode {
6
+ enum FillMode
7
+ {
7
8
  SOLID = 0,
8
9
  BLUR = 1,
9
10
  CLAMP = 2,
10
11
  };
11
12
 
12
- void rgba_to_thumbhash(
13
- uint8_t w,
14
- uint8_t h,
15
- uint8_t *rgba,
16
- uint8_t *thumbhash
17
- );
13
+ uint8_t rgba_to_thumbhash(
14
+ uint8_t w,
15
+ uint8_t h,
16
+ uint8_t *rgba,
17
+ uint8_t *thumbhash);
18
18
 
19
19
  void thumb_size(
20
- uint8_t *hash,
21
- uint8_t max_size,
22
- uint8_t *size
23
- );
20
+ uint8_t *hash,
21
+ uint8_t max_size,
22
+ uint8_t *size);
24
23
 
25
24
  void thumbhash_to_rgba(
26
- uint8_t *hash,
27
- uint8_t w,
28
- uint8_t h,
29
- enum FillMode fill_mode,
30
- uint8_t *fill_color,
31
- double *homogeneous_transform,
32
- int saturation,
33
- uint8_t *rgba
34
- );
25
+ uint8_t *hash,
26
+ uint8_t w,
27
+ uint8_t h,
28
+ enum FillMode fill_mode,
29
+ uint8_t *fill_color,
30
+ double *homogeneous_transform,
31
+ int saturation,
32
+ uint8_t *rgba);
35
33
 
36
34
  #endif
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module FastThumbhash
4
- VERSION = "0.6.0"
4
+ VERSION = "0.7.1"
5
5
  end
@@ -33,29 +33,66 @@ module FastThumbhash
33
33
  homogeneous_transform: nil,
34
34
  saturation: 0
35
35
  )
36
+ %i[solid blur clamp].include?(fill_mode) or
37
+ raise ArgumentError, "Invalid `fill_mode` option"
38
+
39
+ if fill_color
40
+ fill_color.length == 4 or
41
+ raise ArgumentError, "You need to pass [r, g, b, a] to the `fill_color` option"
42
+ end
43
+
44
+ raise ArgumentError, "Option `fill_color` is required for :solid fill_mode" if fill_mode == :solid && fill_color.nil?
45
+
46
+ if homogeneous_transform
47
+ (homogeneous_transform.size == 3 && homogeneous_transform.all? { |row| row.size == 3 }) or
48
+ raise ArgumentError, "`homogeneous_transform` option must be a 3x3 matrix"
49
+ end
50
+
51
+ if size
52
+ size.length == 2 or
53
+ raise ArgumentError, "You need to pass [width, height] to the `size` option"
54
+
55
+ size.all? { |dimension| dimension < 100 } or
56
+ raise ArgumentError, "Cannot generate images bigger then 100 pixels"
57
+ end
58
+
59
+ if max_size
60
+ max_size <= 100 or
61
+ raise ArgumentError, "Cannot generate images bigger then 100 pixels"
62
+ end
63
+
36
64
  !max_size.nil? ^ !size.nil? or
37
65
  raise ArgumentError, "Pass either the `max_size` option, or an explicit `size`"
38
66
 
39
- %i[solid blur clamp].include?(fill_mode) or
40
- raise ArgumentError, "Invalid `fill_mode` option"
67
+ binary_thumbhash_to_rgba!(
68
+ binary_thumbhash,
69
+ max_size: max_size,
70
+ size: size,
71
+ fill_mode: fill_mode,
72
+ fill_color: fill_color,
73
+ homogeneous_transform: homogeneous_transform,
74
+ saturation: saturation
75
+ )
76
+ end
41
77
 
78
+ def self.binary_thumbhash_to_rgba!(
79
+ binary_thumbhash,
80
+ max_size: nil,
81
+ size: nil,
82
+ fill_mode: :solid,
83
+ fill_color: [255, 255, 255, 0],
84
+ homogeneous_transform: nil,
85
+ saturation: 0
86
+ )
42
87
  fill_color_pointer =
43
88
  if fill_color
44
- fill_color.length == 4 or
45
- raise ArgumentError, "You need to pass [r, g, b, a] to the `fill_color` option"
46
-
47
89
  FFI::MemoryPointer.new(:uint8, 4).tap do |p|
48
90
  p.write_array_of_uint8(fill_color)
49
91
  end
50
92
  end
51
93
 
52
- raise ArgumentError, "Option `fill_color` is required for :solid fill_mode" if fill_mode == :solid && fill_color.nil?
53
-
54
94
  transform_pointer =
55
95
  if homogeneous_transform
56
- (homogeneous_transform.size == 3 && homogeneous_transform.all? { |row| row.size == 3 }) or
57
- raise ArgumentError, "`homogeneous_transform` option must be a 3x3 matrix"
58
-
59
96
  FFI::MemoryPointer.new(:double, 6).tap do |p|
60
97
  p.write_array_of_double(
61
98
  [
@@ -75,17 +112,8 @@ module FastThumbhash
75
112
 
76
113
  width, height =
77
114
  if size
78
- size.length == 2 or
79
- raise ArgumentError, "You need to pass [width, height] to the `size` option"
80
-
81
- size.all? { |dimension| dimension < 100 } or
82
- raise ArgumentError, "Cannot generate images bigger then 100 pixels"
83
-
84
115
  size
85
116
  else
86
- max_size <= 100 or
87
- raise ArgumentError, "Cannot generate images bigger then 100 pixels"
88
-
89
117
  thumb_size_pointer = FFI::MemoryPointer.new(:uint8, 2)
90
118
  Library.thumb_size(thumbhash_pointer, max_size, thumb_size_pointer)
91
119
  thumb_size_pointer.read_array_of_uint8(2)
@@ -93,6 +121,7 @@ module FastThumbhash
93
121
 
94
122
  rgba_size = width * height * 4
95
123
  rgba_pointer = FFI::MemoryPointer.new(:uint8, rgba_size)
124
+
96
125
  Library.thumbhash_to_rgba(
97
126
  thumbhash_pointer,
98
127
  width,
@@ -100,7 +129,7 @@ module FastThumbhash
100
129
  fill_mode.to_sym,
101
130
  fill_color_pointer,
102
131
  transform_pointer,
103
- saturation,
132
+ saturation.clamp(-100, 100),
104
133
  rgba_pointer
105
134
  )
106
135
 
@@ -126,10 +155,9 @@ module FastThumbhash
126
155
 
127
156
  thumbhash_pointer = FFI::MemoryPointer.new(:uint8, 25)
128
157
 
129
- Library.rgba_to_thumbhash(width, height, rgba_pointer, thumbhash_pointer)
158
+ length = Library.rgba_to_thumbhash(width, height, rgba_pointer, thumbhash_pointer)
130
159
 
131
- result = thumbhash_pointer.read_array_of_uint8(25)
132
- result.pop while result.last.zero?
160
+ result = thumbhash_pointer.read_array_of_uint8(length)
133
161
 
134
162
  result.pack("C*")
135
163
  ensure
@@ -149,6 +177,6 @@ module FastThumbhash
149
177
 
150
178
  attach_function :thumb_size, %i[pointer uint8 pointer], :size_t
151
179
  attach_function :thumbhash_to_rgba, %i[pointer uint8 uint8 fill_mode pointer pointer int pointer], :void
152
- attach_function :rgba_to_thumbhash, %i[uint8 uint8 pointer pointer], :void
180
+ attach_function :rgba_to_thumbhash, %i[uint8 uint8 pointer pointer], :uint8
153
181
  end
154
182
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fast_thumbhash
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stefano Verna
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-04-07 00:00:00.000000000 Z
11
+ date: 2023-11-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
@@ -35,6 +35,7 @@ extra_rdoc_files: []
35
35
  files:
36
36
  - ".rspec"
37
37
  - ".rubocop.yml"
38
+ - ".ruby-version"
38
39
  - CODE_OF_CONDUCT.md
39
40
  - Gemfile
40
41
  - Gemfile.lock