simdope
v8.7.0
Published
SIMDope π¨ - Color trafficking library faster than tools not mentioning it, lighting fast and around 1700 lines of code (~34kB and 0 dep.)
Downloads
250
Maintainers
Readme
Introducing SIMDope 8.5.0: The Rocket-Fast Color Processing King-Size library in JavaScript
Knock, knock, unleash the Power of Exceptional Color Handling with -> Unparalleled Speed <-
π¨ Blend, Simplify, and Categorize Colors Like Never Before!
Bringing 250K colors (still manageable) down to a "BEST" manageable 25K with methods such as .simplify(ex: 1.6)
, or categorize skin tones using the (Boolean) property of Color's instances named .skin
and other ones into clusters of 64, 256, or even 4096 possibilities, utilizing the .rgbaon[6,8,12,16]bits
, and witness the magic of simplification and categorization like never before!
π Incomparable Speed and Efficiency!
Experience unparalleled speed with the ability to process 2M operations a second, reducing ~103K colors down to 624 in just 162ms on an average "Intel I5" (CPU) equipped computer - an achievement of 2M+ OPS / SEC. that redefines the boundaries of traditional JavaScript!
π Transform 3D Color Data (r, g, b) to 1D Arrays!
Employ Lebesgue, Hilbert, and Moore algorithms to convert complex 3D color sets into neatly ordered 1D arrays, navigating through various hues, tones, saturations, chroma, and luminosity with finesse. SIMDope offers the only authentic way to navigate through complex color sets with such ease and precision! See: colors.get_deduplicated_sorted_uint32a(limit=200, background="#FFFFFFFF", algorithm="lebesgue")
_get_most_used_color_sorted_well_html5 = (simdopeColors) => {
"use strict";
// Optional "but" faaaaster as it recycles it (being a sequencial operation, only one isntance of "Color" is needed).
var recycolor = new SIMDopeColor(new ArrayBuffer(4)), categories = new Map();
for(var i = 0; i < simdopeColors.length; i++) {
// Give you access to all properties and method of Color's instance
recycolor = simdopeColors.get_element(i, recycolor);
// Simplify the color of 320% (YEAH FAAAST)
recycolor.simplify(3.2);
// The color "i" is in the category being N (64 possibilities using 6 bits)
// 4, 6, 8, 12, 16 BITS RESULTS IN (16, 64, 256, 4096, 65536) CATEGORIES
categories.set(i, recycolor.rgbaon6bits);
// = CLUSTERING METHOD FASTER THAN A thunderbolt being faster than a "TR-3B"
}
// Constants like "limit" is simply ignoring less redundant ones before sorting them (after "background" enabling us to ignore alpha) with the fine tuned and chosen "algorithm".
var LIMIT = 999, BACKGROUND = "#FFFFFFFF", ALGORITHM = ["hilbert", "moore", "lebesgue"][Math.floor(Math.random() * 3 - 0.1)];
// List of colors, given a uint32array's buffer, we get a SIMDope's Colors' instance right back into our JS code
var colors = new SIMDopeColors(simdopeColors.get_deduplicated_sorted_uint32a(LIMIT, BACKGROUND, ALGORITHM).buffer);
// Array of hexadecimal colors in the starting block
var hexs1D = [], arrayTemp = [], hexs2D = new Array(64).fill([]);
// Filling the 2D "list" with our champion's hexadecimal outputs
for(var i = 0; i < LIMIT; i++) {
recycolor = colors.get_element(i, recycolor);
if(recycolor.is_not_skin()){ // Ignoring skin toned colours
arrayTemp = hexs2D[recycolor.rgbaon6bits]; // Select the color's cluster
arrayTemp.push(recycolor.hex); // Add color's "HEX" value to one of the 64 clusters
}
}
// Returning an array of HTML5/CSS3 (ready) colors from a two dimension array of clusters with hexadecimal colors
hexs1D = Array.prototype.concat.apply([], hexs2D);
return hexs1D;
};
How to Integrate SIMDope into Your Projects
npm install simdope
Importing the Library
Browser
// Use the file located in /dist/browser.min.js for proper polyfill support (pre-Chrome 61.0)
var Color = window.SIMDOPE.Color;
var Colors = window.SIMDOPE.Colors;
NodeJS
// simdope/dist/index.min.js is also available
import { Color, Colors } from "simdope";
NEW (AWESOME) FEATURE V.6+ => "SIMDopeCreate(mode)"
// simdope/dist/index.min.js is also available
import { SIMDopeCreate, SIMDopeCreateConfAdd, SIMDopeCreateConfRemove } from "simdope";
// Exemple
var MODE = SIMDopeCreateConfAdd({
"create": {
"new_of": true,
"new_uint32": true
},
"properties": {},
"methods": {
"get_use_element": true,
"set_tail": true,
"is_dark": true,
"blend_first_with": true,
"blend_first_with_tails": true
}
}), SIMDOPE = SIMDopeCreate(MODE), Color = SIMDOPE.Color;
var color = Color.new_uint32(0x0D00CDBF); // Blue 25% transparent
// DEFAULT (Slower because it is a big class)
var SIMDopeObjectConf = {
"create": {
"new_zero": true,
"new_splat": true,
"new_of": true,
"new_safe_of": true,
"new_from": true,
"new_array": true,
"new_array_safe": true,
"new_uint32": true,
"new_uint32b": true,
"new_hsla": true,
"new_hex": true,
"new_hex_name": true
},
"properties": {
"tail": true,
"pos": true,
"hilbert": true,
"lebesgue": true,
"moore": true,
"uint32": true,
"uint32b": true,
"hex": true,
"ycbcra": true,
"laba": true,
"hsla": true,
"rgbaon4bits": true,
"rgbaon6bits": true,
"rgbaon8bits": true,
"rgbaon12bits": true,
"rgbaon16bits": true,
"skin": true
},
"methods": {
"set": true,
"set_from_array": true,
"simplify": true,
"set_from_simdope": true,
"set_from_buffer": true,
"get_tail_opacity": true,
"get_tail_opacity_and_reset": true,
"get_tail": true,
"get_tail_and_reset": true,
"reset_tail": true,
"set_tail": true,
"normalize": true,
"set_out_of": true,
"get_subarray": true,
"get_slice": true,
"get_buffer": true,
"is_skin": true,
"is_not_skin": true,
"sum_rgba": true,
"sum_rgb": true,
"average_rgb": true,
"is_dark": true,
"is_fully_transparent": true,
"is_fully_opaque": true,
"is_not_fully_transparent": true,
"is_not_fully_opaque": true,
"match_with": true,
"euclidean_match_with": true,
"manhattan_match_with": true,
"cie76_match_with": true,
"set_r": true,
"set_g": true,
"set_b": true,
"set_a": true,
"to_greyscale": true,
"to_greyscale_luma": true,
"multiply_a_255": true,
"copy": true,
"get_difference_with": true,
"merge_with_a_fixed": true,
"blend_first_with": true,
"blend_all": true,
"blend_all_with_tails": true,
"blend_with": true,
"blend_first_with_tails": true,
"get_deduplicated_sorted_uint32a": true,
"get_element": true,
"get_new_element": true,
"get_use_element": true
}
};
How to use SIMDope.Color?
π§ Functions, Methods, and Properties of SIMDope.Color
Instantiate an object of the single color class
// We often use a uint32array just as: new Uint32Array(imagedata.data.buffer)
// Better just put the uint32array inside the constructor Colors using the class named: Color
Color(with_main_buffer, offset_4bytes_optional) // Uint8Array.of(127, 95, 0, 255) as "r, g, b, a" works too
Color.new_zero()
Color.new_of(r, g, b, a)
Color.new_safe_of(r, g, b, a)
Color.new_from(agbr_array)
Color.new_array(rgba_array)
Color.new_array_safe(rgba_array)
Color.new_uint32(uint32)
Color.new_uint32b(uint32b)
Color.new_hsla(h, s, l, a)
Color.new_hex(hex_anything)
π Color's Properties:
| Property | Description |
|------------------------|--------------------------------------------------------------|
|color.r
| Red component (readonly) |
|color.g
| Green component (readonly) |
|color.b
| Blue component (readonly) |
|color.a
| Alpha component (readonly) |
|color.uint32
| Integer representation (readonly) |
|color.uint32b
| Integer representation (readonly) |
|color.hex
| Hex representation (readonly) |
|color.hsla
| HSLA representation (readonly) |
|color.lab
| LAB color space (readonly) |
|color.ycbcra
| YCbCrA color representation (readonly) |
|color.skin
| Indicates if the color matches skin tones (Boolean) |
|color.tail
| Utility for chaining multiple colors before blending |
|color.hilbert
| Indicates the 1D (uint32) index of the RGB coordinates |
|color.moore
| Indicates the 1D (uint32) index of the RGB coordinates |
|color.lebesgue
| Indicates the 1D (uint32) index of the RGB coordinates |
|color.rgbaon4bits
| RGBA on 4 bits representation (readonly) |
|color.rgbaon6bits
| RGBA on 6 bits representation (readonly) |
|color.rgbaon8bits
| RGBA on 8 bits representation (readonly) |
|color.rgbaon12bits
| RGBA on 12 bits representation (readonly) |
|color.offset
| Offset of the color data (readonly) |
|color.buffer_
| Primary buffer (private; use methods for access) |
|color.subarray_
| Provides a "pointer" instance without copying data (private) |
|color.slice_
| Clones the data into a new Uint8Array (private) |
π Color's Methods:
Get:
| Method | Description |
| ------ | ----------- |
|color.get_buffer( )
| Retrieve the primary buffer |
|color.get_subarray( )
| Access the "pointer" instance of the color data |
|color.get_slice( )
| Clone and retrieve the color data |
|color.sum_rgba( )
| Sum of RGBA values |
|color.sum_rgb( )
| Sum of RGB values |
|color.is_dark( )
| Check if color is dark |
|color.is_skin( )
| Check if color matches skin tones |
|color.is_fully_transparent( )
| Check if color is fully transparent |
|color.is_fully_opaque( )
| Check if color is fully opaque |
|color.is_not_skin( )
| Check if color doesn't match skin tones |
|color.is_not_fully_transparent( )
| Check if color isn't fully transparent |
|color.is_not_fully_opaque( )
| Check if color isn't fully opaque |
Set:
| Method | Description |
|-------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------|
| color.set(with_buffer )
| Set the color using (Uint8Array or ArrayBuffer) |
| color.set_from_simdope(color )
| Set a color from a Color instance |
| color.set_from_array(new Uint8Array(4) )
| Set the color from an RGBA |
| color.set_from_buffer(with_buffer, offset_four_bytes )
| Reuse the instanced object |
| color.set_tail(simdope_instance, premultiply_alpha_255_optional )
| Set a tail |
| color.simplify(divider )
| Peg the color (e.g., 1.6, 2, 3.2) |
| color.blend_with(another_color, strength_on_255, should_return_transparent, is_alpha_addition )
| Blend |
| color.blend_first_with(another_color, strength_on_255, should_return_transparent, is_alpha_addition )
| Blend |
| color.blend_first_with_tails(is_alpha_addition )
| Blend color with tails then deletes tail links |
| color.match_with(another_color, threshold_on_255 )
| Match color |
| color.manhattan_match_with(another_color, threshold_float_optional )
| Match color using Manhattan algorithm (Return a Boolean or a Float if no threshold is given) |
| color.euclidean_match_with(another_color, threshold_float_optional )
| Match color using Euclidean algorithm (Return a Boolean or a Float if no threshold is given) |
| color.cie76_match_with(another_color, threshold_float_optional )
| Match color using CIE76 algorithm (Return a Boolean or a Float if no threshold is given) |
| color.set_r(r )
| Set red component to r
|
| color.set_g(g )
| Set green component to g
|
| color.set_b(b )
| Set blue component to b
|
| color.set_a(a )
| Set alpha component to a
|
| color.to_greyscale( )
| Convert color to greyscale |
| color.to_greyscale_luma( )
| Convert color to greyscale using luma |
π Color's Functions:
| Function | Description |
| -------- | ----------- |
|Color.with_r(color, r )
| Create a new color instance using color
with specified red component r
|
|Color.with_g(color, g )
| Create a new color instance using color
with specified green component g
|
|Color.with_b(color, b )
| Create a new color instance using color
with specified blue component b
|
|Color.with_a(color, a )
| Create a new color instance using color
with specified alpha component a
|
|Color.with_inverse(color )
| Create a new color instance with inverted colors of color
|
|Color.with_match(color_a, color_b, threshold_on_255 )
| Match two colors color_a
and color_b
with a threshold threshold_on_255
|
|Color.blend(color_a, color_b, strength_on_one, should_return_transparent, is_alpha_addition )
| Blend two colors color_a
and color_b
with strength_on_one
, should_return_transparent
, and is_alpha_addition
|
Please, look at the source code to know more about other cool ways of using it ...
How to use SIMDope.Colors?
π§ Functions, Methods, and Properties of SIMDope.Colors
π Colors' Properties:
| Property | Description |
| -------- | ----------- |
| colors.length
| Number of colors in the list (readonly) |
| colors.buffer
| Buffer containing the color data (readonly) |
π Colors' Methods:
Get:
| Method | Parameters | Description |
|-----------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------|
| colors.get_element(index, old_color_object_optional_faster )
| index
: Position of color in the list old_color_object_optional_faster
: (Optional) Previous color object for faster access | Retrieve the color at a specified index. When you get an element and apply changes, it updates the color within your list's buffer. |
| colors.get_new_element(index)
| index
: Position of color in the list | Retrieve the color at a specified index. When you get an element and apply changes, it updates the color within your list's buffer. |
| colors.get_use_element(index, old_color_object_optional_faster )
| index
: Position of color in the list old_color_object_optional_faster
: (Required) Previous color object for faster access | Retrieve the color at a specified index. When you get an element and apply changes, it updates the color within your list's buffer. |
| colors.subarray_uint32(start, end )
| start
: Start index end
: End index | Get a subarray from the Uint32Array representation. |
| colors.slice_uint32(start, end )
| start
: Start index end
: End index | Get a slice from the Uint32Array representation. |
| colors.subarray_uint8(start, end )
| start
: Start index end
: End index | Get a subarray from the Uint8Array representation. |
| colors.slice_uint8(start, end )
| start
: Start index end
: End index | Get a slice from the Uint8Array representation. |
| colors.get_hex()
| None | List all the hexadecimal values of each colors within the Colors' instance. |
| colors.get_properties(key)
| key
: ("hex", "r", "skin", or any other property...) | Return an array of the properties of all colors. |
| colors.get_deduplicated_uint32a( )
| None | Removes duplicate uint32 entries. May need polyfills for older browsers. |
| colors.get_deduplicated_sorted_uint32a(limit, background, algorithm )
| Optional | Use a high-performance 8bits curve algorithm (one of "hilbert", "moore", "lebesgue") |
Set:
| Method | Parameters | Description |
| ------ | ---------- | ----------- |
| colors.set_element(index, color_object )
| index
: Position in the list to set the color color_object
: The color object to set | Set a color at the specified index |
| colors.buffer_setUint8(index, number )
| index
: Position in the buffer to set the byte number
: Byte value to set | Set a byte in the buffer |
| colors.buffer_setUint32(index, number )
| index
: Position in the buffer to set the Uint32 value number
: Uint32 value to set | Set a Uint32 value in the buffer |
How it should be used (LOOK HERE)
var white = Color.new_of(255, 255, 255, 255);
var green = Color.new_of(0, 255, 0, 255);
var red = Color.new_of(255, 0, 0, 255);
var simdope_my_colors = Colors(imagedata);
// That rewrite the inner data of our array but also white if we don't copy it
simdope_my_colors.get_element(0).blend_with(white.copy(), 192, false, false);
simdope_my_colors.get_element(1).blend_with(white, 0.25*255, false, false) ;
simdope_my_colors.get_element(2)
.blend_with(white.copy(), 0.25*255, false, true)
.blend_with(green.copy(), 0.75*255, false, true)
.blend_with(red.copy(), 0.25*255, false, true)
var purple = simdope_my_colors.get_element(2);
var purple_copy = purple.copy();
var purple_hex = purple.hex;
var purple_uint32 = purple.uint32;
var is_purple_dark = purple.is_dark();
var is_purple_dark_but_from_hex = Color.new_hex(purple_hex).is_dark();
var purple_alpha_but_from_uint32 = Color.new_uint32(purple_uint32).a;
var some_uint32array_colors = simdope_my_colors.subarray_uint32(0, 3);
var some_colors = new Colors(some_uint32array_colors.buffer);
some_colors.set_uint32_element(0, purple.uint32);
some_colors.set_uint32_element(1, purple.uint32);
For more usage scenarios than those which follows, explore the source code.
- You can write a quantization algorithm using it that can detect skin tones quickly and simplify millions of colors fast benefiting clustering using rgbaonXbits.
- You can make a rendering engine which re-use Color's instance and link them through the tail property before blending them modifying the first one only as if you were using layers with a Colors' (list) + Color's (current) instance per layer.
- You can simply detect which contrast color to use depending on a given color
Color.new_hex("greenyellow").is_dark() ? "white": "black";
. - You can sort colors within a palette using
new Colors(colors.get_deduplicated_sorted_uint32a(200, Color.new_hex("white"), "lebesgue").buffer).get_properties("hex")
.
Please refer to the source code for additional information and advanced usage scenarios.
About me
"Philosophy is the science of estimating values, yet technology is the value of estimating science. My design is my voice while my code is my weapon of choice..."
I am (sometimes) open to work^^ ==> https://www.linkedin.com/in/matias-affolter/