fast_thumbhash 0.7.0 → 0.7.2

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: 7ca1251a50f86a6d61d03d4aca11a98b30336a72c12f5d5e8a15992c8d694638
4
- data.tar.gz: e77931c369a56aec1f619b4da9ef822623d5e0f4e839aab43e88ebc80ad5b748
3
+ metadata.gz: e30e34927a692280eac28e7a1237d9964ad6899a29ab7268a321df8ea2b9d979
4
+ data.tar.gz: 39cd14b05a0d0a598ea3f48646c169935cbe17e17a4a2000450833347e4465b6
5
5
  SHA512:
6
- metadata.gz: 66332f36f6e8d43256725abeb3c6a0e1f59a0cf8601516a3d5d8f6c0820259e7a7c2fa00afa5ece7b7eb834d78fd156407726d135d61e31d16b06a1e33547d52
7
- data.tar.gz: cb3673f55f78c9a64b00d5ebe442ff44fa966df878f2bcc1f511a0d7a4ca672412510d55c891afeddf53e65c864f678ea87ffcdbd679f1bcc385d63acc8e78e0
6
+ metadata.gz: ee54e878ad7002544e568618281784baf2a565aa3f3ea44b0f0918c81b13ea56b849e12ea5c3a7baa7d36b5e94229b015bf256c0c4c23492789e0182bfc6457a
7
+ data.tar.gz: 9bd9096c25bf0a64999f6a484becae2e075018f3e9bc4a215dd94c4156e4c0319b7ad61ae7ff4d99d9c54cf5551c5e68b08d1d3f7000a1d1977f56816c043cac
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.7.0)
4
+ fast_thumbhash (0.7.2)
5
5
  ffi
6
6
 
7
7
  GEM
@@ -52,6 +52,8 @@ GEM
52
52
 
53
53
  PLATFORMS
54
54
  arm64-darwin-21
55
+ arm64-darwin-22
56
+ ruby
55
57
  x86_64-darwin-18
56
58
  x86_64-darwin-20
57
59
  x86_64-darwin-21
data/README.md CHANGED
@@ -1,3 +1,13 @@
1
+ <!--datocms-autoinclude-header start-->
2
+
3
+ <a href="https://www.datocms.com/"><img src="https://www.datocms.com/images/full_logo.svg" height="60"></a>
4
+
5
+ 👉 [Visit the DatoCMS homepage](https://www.datocms.com) or see [What is DatoCMS?](#what-is-datocms)
6
+
7
+ ---
8
+
9
+ <!--datocms-autoinclude-header end-->
10
+
1
11
  # FastThumbhash
2
12
 
3
13
  [![Ruby](https://github.com/datocms/fast_thumbhash/actions/workflows/main.yml/badge.svg)](https://github.com/datocms/fast_thumbhash/actions/workflows/main.yml)
@@ -124,3 +134,51 @@ The gem is available as open source under the terms of the [MIT License](https:/
124
134
  ## Code of Conduct
125
135
 
126
136
  Everyone interacting in the FastThumbhash project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/datocms/fast_thumbhash/blob/master/CODE_OF_CONDUCT.md).
137
+
138
+ <!--datocms-autoinclude-footer start-->
139
+
140
+ ---
141
+
142
+ # What is DatoCMS?
143
+
144
+ <a href="https://www.datocms.com/"><img src="https://www.datocms.com/images/full_logo.svg" height="60" alt="DatoCMS - The Headless CMS for the Modern Web"></a>
145
+
146
+ [DatoCMS](https://www.datocms.com/) is the REST & GraphQL Headless CMS for the modern web.
147
+
148
+ Trusted by over 25,000 enterprise businesses, agencies, and individuals across the world, DatoCMS users create online content at scale from a central hub and distribute it via API. We ❤️ our [developers](https://www.datocms.com/team/best-cms-for-developers), [content editors](https://www.datocms.com/team/content-creators) and [marketers](https://www.datocms.com/team/cms-digital-marketing)!
149
+
150
+ **Why DatoCMS?**
151
+
152
+ - **API-First Architecture**: Built for both REST and GraphQL, enabling flexible content delivery
153
+ - **Just Enough Features**: We believe in keeping things simple, and giving you [the right feature-set tools](https://www.datocms.com/features) to get the job done
154
+ - **Developer Experience**: First-class TypeScript support with powerful developer tools
155
+
156
+ **Getting Started:**
157
+
158
+ - ⚡️ [Create Free Account](https://dashboard.datocms.com/signup) - Get started with DatoCMS in minutes
159
+ - 🔖 [Documentation](https://www.datocms.com/docs) - Comprehensive guides and API references
160
+ - ⚙️ [Community Support](https://community.datocms.com/) - Get help from our team and community
161
+ - 🆕 [Changelog](https://www.datocms.com/product-updates) - Latest features and improvements
162
+
163
+ **Official Libraries:**
164
+
165
+ - [**Content Delivery Client**](https://github.com/datocms/cda-client) - TypeScript GraphQL client for content fetching
166
+ - [**REST API Clients**](https://github.com/datocms/js-rest-api-clients) - Node.js/Browser clients for content management
167
+ - [**CLI Tools**](https://github.com/datocms/cli) - Command-line utilities for schema migrations (includes [Contentful](https://github.com/datocms/cli/tree/main/packages/cli-plugin-contentful) and [WordPress](https://github.com/datocms/cli/tree/main/packages/cli-plugin-wordpress) importers)
168
+
169
+ **Official Framework Integrations**
170
+
171
+ Helpers to manage SEO, images, video and Structured Text coming from your DatoCMS projects:
172
+
173
+ - [**React Components**](https://github.com/datocms/react-datocms)
174
+ - [**Vue Components**](https://github.com/datocms/vue-datocms)
175
+ - [**Svelte Components**](https://github.com/datocms/datocms-svelte)
176
+ - [**Astro Components**](https://github.com/datocms/astro-datocms)
177
+
178
+ **Additional Resources:**
179
+
180
+ - [**Plugin Examples**](https://github.com/datocms/plugins) - Example plugins we've made that extend the editor/admin dashboard
181
+ - [**Starter Projects**](https://www.datocms.com/marketplace/starters) - Example website implementations for popular frameworks
182
+ - [**All Public Repositories**](https://github.com/orgs/datocms/repositories?q=&type=public&language=&sort=stargazers)
183
+
184
+ <!--datocms-autoinclude-footer end-->
@@ -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);
@@ -134,8 +140,8 @@ void rgba_to_thumbhash(uint8_t w, uint8_t h, uint8_t *rgba, uint8_t *thumbhash)
134
140
 
135
141
  // Write the constants
136
142
  bool is_landscape = w > h;
137
- u_int32_t header24 = (u_int32_t)roundf(63.0 * el.dc) | ((u_int32_t)roundf(31.5 + 31.5 * ep.dc) << 6) | ((u_int32_t)roundf(31.5 + 31.5 * eq.dc) << 12) | ((u_int32_t)roundf(31.0 * el.scale) << 18) | (has_alpha << 23);
138
- u_int32_t header16 = (is_landscape ? ly : lx) | ((u_int16_t)roundf(63.0 * ep.scale) << 3) | ((u_int16_t)roundf(63.0 * eq.scale) << 9) | (is_landscape << 15);
143
+ uint32_t header24 = (uint32_t)roundf(63.0 * el.dc) | ((uint32_t)roundf(31.5 + 31.5 * ep.dc) << 6) | ((uint32_t)roundf(31.5 + 31.5 * eq.dc) << 12) | ((uint32_t)roundf(31.0 * el.scale) << 18) | (has_alpha << 23);
144
+ uint32_t header16 = (is_landscape ? ly : lx) | ((uint16_t)roundf(63.0 * ep.scale) << 3) | ((uint16_t)roundf(63.0 * eq.scale) << 9) | (is_landscape << 15);
139
145
 
140
146
  thumbhash[0] = (uint8_t)(header24 & 0xff);
141
147
  thumbhash[1] = (uint8_t)((header24 >> 8) & 0xff);
@@ -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,19 +343,18 @@ 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
- u_int32_t header24 = hash[0] | (hash[1] << 8) | (hash[2] << 16);
336
- u_int32_t header16 = hash[3] | (hash[4] << 8);
356
+ uint32_t header24 = hash[0] | (hash[1] << 8) | (hash[2] << 16);
357
+ uint32_t header16 = hash[3] | (hash[4] << 8);
337
358
  double l_dc = (double)(header24 & 63) / 63;
338
359
  double p_dc = (double)((header24 >> 6) & 63) / 31.5 - 1;
339
360
  double q_dc = (double)((header24 >> 12) & 63) / 31.5 - 1;
@@ -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
 
@@ -359,7 +381,7 @@ void thumbhash_to_rgba(
359
381
  // Decode using the DCT into RGB
360
382
  double fx[7];
361
383
  double fy[7];
362
- u_int32_t i = 0;
384
+ uint32_t i = 0;
363
385
 
364
386
  for (uint8_t ry = 0; ry < h; ry++)
365
387
  {
@@ -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.7.0"
4
+ VERSION = "0.7.2"
5
5
  end
@@ -155,10 +155,9 @@ module FastThumbhash
155
155
 
156
156
  thumbhash_pointer = FFI::MemoryPointer.new(:uint8, 25)
157
157
 
158
- Library.rgba_to_thumbhash(width, height, rgba_pointer, thumbhash_pointer)
158
+ length = Library.rgba_to_thumbhash(width, height, rgba_pointer, thumbhash_pointer)
159
159
 
160
- result = thumbhash_pointer.read_array_of_uint8(25)
161
- result.pop while result.last.zero?
160
+ result = thumbhash_pointer.read_array_of_uint8(length)
162
161
 
163
162
  result.pack("C*")
164
163
  ensure
@@ -178,6 +177,6 @@ module FastThumbhash
178
177
 
179
178
  attach_function :thumb_size, %i[pointer uint8 pointer], :size_t
180
179
  attach_function :thumbhash_to_rgba, %i[pointer uint8 uint8 fill_mode pointer pointer int pointer], :void
181
- attach_function :rgba_to_thumbhash, %i[uint8 uint8 pointer pointer], :void
180
+ attach_function :rgba_to_thumbhash, %i[uint8 uint8 pointer pointer], :uint8
182
181
  end
183
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.7.0
4
+ version: 0.7.2
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-11 00:00:00.000000000 Z
11
+ date: 2025-04-23 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