blitz-pdf 0.0.0-stage → 0.1.0
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.
- package/LICENSE +21 -0
- package/README.md +355 -2
- package/THIRD_PARTY_NOTICES.md +25 -0
- package/assets/icon.svg +4 -0
- package/dist/api.d.ts +7 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +46 -0
- package/dist/api.js.map +1 -0
- package/dist/assets.d.ts +7 -0
- package/dist/assets.d.ts.map +1 -0
- package/dist/assets.js +52 -0
- package/dist/assets.js.map +1 -0
- package/dist/browser.d.ts +3 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +3 -0
- package/dist/browser.js.map +1 -0
- package/dist/node.d.ts +3 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/node.js +10 -0
- package/dist/node.js.map +1 -0
- package/dist/options.d.ts +24 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +135 -0
- package/dist/options.js.map +1 -0
- package/dist/types.d.ts +51 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/examples/bun.ts +8 -0
- package/examples/german-invoice/README.md +70 -0
- package/examples/german-invoice/data.mjs +83 -0
- package/examples/german-invoice/invoice.css +59 -0
- package/examples/german-invoice/template.mjs +49 -0
- package/examples/german-invoice.mjs +20 -0
- package/examples/invoice.html +29 -0
- package/examples/node.mjs +8 -0
- package/examples/pagination.html +40 -0
- package/examples/pagination.mjs +8 -0
- package/licenses/DejaVu.txt +187 -0
- package/licenses/RUST_DEPENDENCIES.txt +11577 -0
- package/package.json +89 -4
- package/src/api.ts +44 -0
- package/src/assets.ts +43 -0
- package/src/browser.ts +6 -0
- package/src/node.ts +12 -0
- package/src/options.ts +101 -0
- package/src/types.ts +49 -0
- package/vendor/README.md +17 -0
- package/vendor/stylo/.cargo-ok +1 -0
- package/vendor/stylo/.cargo_vcs_info.json +6 -0
- package/vendor/stylo/Cargo.lock +1485 -0
- package/vendor/stylo/Cargo.toml +274 -0
- package/vendor/stylo/LICENSE +373 -0
- package/vendor/stylo/README.md +6 -0
- package/vendor/stylo/applicable_declarations.rs +328 -0
- package/vendor/stylo/author_styles.rs +79 -0
- package/vendor/stylo/bezier.rs +176 -0
- package/vendor/stylo/bloom.rs +414 -0
- package/vendor/stylo/build.rs +91 -0
- package/vendor/stylo/build_gecko.rs +393 -0
- package/vendor/stylo/color/color_function.rs +601 -0
- package/vendor/stylo/color/component.rs +207 -0
- package/vendor/stylo/color/convert.rs +935 -0
- package/vendor/stylo/color/gamut/raytrace.rs +265 -0
- package/vendor/stylo/color/gamut.rs +227 -0
- package/vendor/stylo/color/mix.rs +645 -0
- package/vendor/stylo/color/mod.rs +750 -0
- package/vendor/stylo/color/parsing.rs +770 -0
- package/vendor/stylo/color/to_css.rs +297 -0
- package/vendor/stylo/context.rs +716 -0
- package/vendor/stylo/counter_style/mod.rs +754 -0
- package/vendor/stylo/counter_style/predefined.rs +61 -0
- package/vendor/stylo/counter_style/update_predefined.py +35 -0
- package/vendor/stylo/custom_properties.rs +2023 -0
- package/vendor/stylo/custom_properties_map.rs +220 -0
- package/vendor/stylo/data.rs +693 -0
- package/vendor/stylo/device/gecko.rs +486 -0
- package/vendor/stylo/device/mod.rs +304 -0
- package/vendor/stylo/device/servo.rs +507 -0
- package/vendor/stylo/dom.rs +1164 -0
- package/vendor/stylo/dom_apis.rs +937 -0
- package/vendor/stylo/driver.rs +172 -0
- package/vendor/stylo/error_reporting.rs +484 -0
- package/vendor/stylo/font_face.rs +558 -0
- package/vendor/stylo/font_metrics.rs +124 -0
- package/vendor/stylo/gecko/anon_boxes.toml +113 -0
- package/vendor/stylo/gecko/arc_types.rs +211 -0
- package/vendor/stylo/gecko/conversions.rs +59 -0
- package/vendor/stylo/gecko/data.rs +222 -0
- package/vendor/stylo/gecko/media_features.rs +971 -0
- package/vendor/stylo/gecko/mod.rs +20 -0
- package/vendor/stylo/gecko/non_ts_pseudo_class_list.rs +119 -0
- package/vendor/stylo/gecko/pseudo_element.rs +640 -0
- package/vendor/stylo/gecko/pseudo_element_definition.mako.rs +298 -0
- package/vendor/stylo/gecko/pseudo_elements.py +137 -0
- package/vendor/stylo/gecko/pseudo_elements.toml +197 -0
- package/vendor/stylo/gecko/regen_pseudo_elements.py +33 -0
- package/vendor/stylo/gecko/restyle_damage.rs +127 -0
- package/vendor/stylo/gecko/selector_parser.rs +627 -0
- package/vendor/stylo/gecko/snapshot.rs +202 -0
- package/vendor/stylo/gecko/snapshot_helpers.rs +334 -0
- package/vendor/stylo/gecko/traversal.rs +52 -0
- package/vendor/stylo/gecko/wrapper.rs +2258 -0
- package/vendor/stylo/gecko_bindings/mod.rs +34 -0
- package/vendor/stylo/gecko_bindings/sugar/mod.rs +12 -0
- package/vendor/stylo/gecko_bindings/sugar/ns_com_ptr.rs +15 -0
- package/vendor/stylo/gecko_bindings/sugar/ns_compatibility.rs +19 -0
- package/vendor/stylo/gecko_bindings/sugar/ns_style_auto_array.rs +111 -0
- package/vendor/stylo/gecko_bindings/sugar/origin_flags.rs +31 -0
- package/vendor/stylo/gecko_bindings/sugar/ownership.rs +70 -0
- package/vendor/stylo/gecko_bindings/sugar/refptr.rs +299 -0
- package/vendor/stylo/gecko_string_cache/mod.rs +543 -0
- package/vendor/stylo/gecko_string_cache/namespace.rs +106 -0
- package/vendor/stylo/global_style_data.rs +224 -0
- package/vendor/stylo/invalidation/element/document_state.rs +156 -0
- package/vendor/stylo/invalidation/element/element_wrapper.rs +432 -0
- package/vendor/stylo/invalidation/element/invalidation_map.rs +1631 -0
- package/vendor/stylo/invalidation/element/invalidator.rs +1470 -0
- package/vendor/stylo/invalidation/element/mod.rs +13 -0
- package/vendor/stylo/invalidation/element/relative_selector.rs +1399 -0
- package/vendor/stylo/invalidation/element/restyle_hints.rs +226 -0
- package/vendor/stylo/invalidation/element/state_and_attributes.rs +756 -0
- package/vendor/stylo/invalidation/media_queries.rs +144 -0
- package/vendor/stylo/invalidation/mod.rs +10 -0
- package/vendor/stylo/invalidation/stylesheets.rs +745 -0
- package/vendor/stylo/invalidation/viewport_units.rs +71 -0
- package/vendor/stylo/lib.rs +336 -0
- package/vendor/stylo/logical_geometry.rs +1684 -0
- package/vendor/stylo/macros.rs +70 -0
- package/vendor/stylo/matching.rs +1226 -0
- package/vendor/stylo/media_queries/media_list.rs +168 -0
- package/vendor/stylo/media_queries/media_query.rs +190 -0
- package/vendor/stylo/media_queries/mod.rs +13 -0
- package/vendor/stylo/parallel.rs +205 -0
- package/vendor/stylo/parser.rs +276 -0
- package/vendor/stylo/piecewise_linear.rs +282 -0
- package/vendor/stylo/prefs.rs +33 -0
- package/vendor/stylo/properties/build.py +119 -0
- package/vendor/stylo/properties/cascade.rs +2704 -0
- package/vendor/stylo/properties/computed_value_flags.rs +206 -0
- package/vendor/stylo/properties/counted_unknown_properties.py +104 -0
- package/vendor/stylo/properties/counter_style_descriptors.toml +45 -0
- package/vendor/stylo/properties/data.py +1375 -0
- package/vendor/stylo/properties/declaration_block.rs +1788 -0
- package/vendor/stylo/properties/font_face_descriptors.toml +50 -0
- package/vendor/stylo/properties/gecko.mako.rs +1555 -0
- package/vendor/stylo/properties/helpers/animated_properties.mako.rs +800 -0
- package/vendor/stylo/properties/helpers.mako.rs +812 -0
- package/vendor/stylo/properties/longhands.toml +4305 -0
- package/vendor/stylo/properties/mod.rs +1857 -0
- package/vendor/stylo/properties/properties.html.mako +31 -0
- package/vendor/stylo/properties/properties.mako.rs +3103 -0
- package/vendor/stylo/properties/property_descriptors.toml +18 -0
- package/vendor/stylo/properties/shorthands.rs +4241 -0
- package/vendor/stylo/properties/shorthands.toml +575 -0
- package/vendor/stylo/properties/vendored_python/mako-1.3.10-py3-none-any.whl +0 -0
- package/vendor/stylo/properties/vendored_python/markupsafe/LICENSE.txt +28 -0
- package/vendor/stylo/properties/vendored_python/markupsafe/__init__.py +384 -0
- package/vendor/stylo/properties/vendored_python/toml-0.10.2-py2.py3-none-any.whl +0 -0
- package/vendor/stylo/properties/view_transition_descriptors.toml +11 -0
- package/vendor/stylo/properties_and_values/mod.rs +12 -0
- package/vendor/stylo/properties_and_values/registry.rs +65 -0
- package/vendor/stylo/properties_and_values/rule.rs +331 -0
- package/vendor/stylo/properties_and_values/syntax/ascii.rs +60 -0
- package/vendor/stylo/properties_and_values/syntax/data_type.rs +146 -0
- package/vendor/stylo/properties_and_values/syntax/mod.rs +437 -0
- package/vendor/stylo/properties_and_values/value.rs +758 -0
- package/vendor/stylo/queries/condition.rs +996 -0
- package/vendor/stylo/queries/feature.rs +199 -0
- package/vendor/stylo/queries/feature_expression.rs +1170 -0
- package/vendor/stylo/queries/mod.rs +19 -0
- package/vendor/stylo/queries/values.rs +46 -0
- package/vendor/stylo/rule_cache.rs +267 -0
- package/vendor/stylo/rule_collector.rs +554 -0
- package/vendor/stylo/rule_tree/core.rs +787 -0
- package/vendor/stylo/rule_tree/level.rs +396 -0
- package/vendor/stylo/rule_tree/map.rs +201 -0
- package/vendor/stylo/rule_tree/mod.rs +427 -0
- package/vendor/stylo/rule_tree/source.rs +80 -0
- package/vendor/stylo/rule_tree/unsafe_box.rs +78 -0
- package/vendor/stylo/scoped_tls.rs +80 -0
- package/vendor/stylo/selector_map.rs +1050 -0
- package/vendor/stylo/selector_parser.rs +305 -0
- package/vendor/stylo/servo/animation.rs +1922 -0
- package/vendor/stylo/servo/attr.rs +714 -0
- package/vendor/stylo/servo/encoding_support.rs +81 -0
- package/vendor/stylo/servo/media_features.rs +254 -0
- package/vendor/stylo/servo/mod.rs +16 -0
- package/vendor/stylo/servo/restyle_damage.rs +215 -0
- package/vendor/stylo/servo/selector_parser.rs +1036 -0
- package/vendor/stylo/servo/shadow_parts.rs +207 -0
- package/vendor/stylo/shared_lock.rs +271 -0
- package/vendor/stylo/sharing/checks.rs +281 -0
- package/vendor/stylo/sharing/mod.rs +1000 -0
- package/vendor/stylo/simple_buckets_map.rs +52 -0
- package/vendor/stylo/str.rs +168 -0
- package/vendor/stylo/style_adjuster.rs +1086 -0
- package/vendor/stylo/style_resolver.rs +658 -0
- package/vendor/stylo/stylesheet_set.rs +658 -0
- package/vendor/stylo/stylesheets/appearance_base_rule.rs +51 -0
- package/vendor/stylo/stylesheets/container_rule.rs +769 -0
- package/vendor/stylo/stylesheets/counter_style_rule.rs +7 -0
- package/vendor/stylo/stylesheets/document_rule.rs +272 -0
- package/vendor/stylo/stylesheets/font_face_rule.rs +7 -0
- package/vendor/stylo/stylesheets/font_feature_values_rule.rs +481 -0
- package/vendor/stylo/stylesheets/font_palette_values_rule.rs +304 -0
- package/vendor/stylo/stylesheets/import_rule.rs +259 -0
- package/vendor/stylo/stylesheets/keyframes_rule.rs +733 -0
- package/vendor/stylo/stylesheets/layer_rule.rs +221 -0
- package/vendor/stylo/stylesheets/loader.rs +29 -0
- package/vendor/stylo/stylesheets/margin_rule.rs +190 -0
- package/vendor/stylo/stylesheets/media_rule.rs +191 -0
- package/vendor/stylo/stylesheets/mod.rs +918 -0
- package/vendor/stylo/stylesheets/namespace_rule.rs +43 -0
- package/vendor/stylo/stylesheets/nested_declarations_rule.rs +51 -0
- package/vendor/stylo/stylesheets/origin.rs +249 -0
- package/vendor/stylo/stylesheets/page_rule.rs +354 -0
- package/vendor/stylo/stylesheets/position_try_rule.rs +68 -0
- package/vendor/stylo/stylesheets/property_rule.rs +5 -0
- package/vendor/stylo/stylesheets/rule_list.rs +167 -0
- package/vendor/stylo/stylesheets/rule_parser.rs +1189 -0
- package/vendor/stylo/stylesheets/rules_iterator.rs +397 -0
- package/vendor/stylo/stylesheets/scope_rule.rs +511 -0
- package/vendor/stylo/stylesheets/starting_style_rule.rs +54 -0
- package/vendor/stylo/stylesheets/style_rule.rs +80 -0
- package/vendor/stylo/stylesheets/stylesheet.rs +570 -0
- package/vendor/stylo/stylesheets/supports_rule.rs +486 -0
- package/vendor/stylo/stylesheets/view_transition_rule.rs +81 -0
- package/vendor/stylo/stylist.rs +5076 -0
- package/vendor/stylo/thread_state.rs +87 -0
- package/vendor/stylo/traversal.rs +765 -0
- package/vendor/stylo/traversal_flags.rs +68 -0
- package/vendor/stylo/typed_om/mod.rs +981 -0
- package/vendor/stylo/typed_om/numeric.rs +128 -0
- package/vendor/stylo/typed_om/numeric_declaration.rs +93 -0
- package/vendor/stylo/typed_om/numeric_type.rs +640 -0
- package/vendor/stylo/typed_om/sum_value.rs +426 -0
- package/vendor/stylo/url/gecko.rs +367 -0
- package/vendor/stylo/url/mod.rs +71 -0
- package/vendor/stylo/url/servo.rs +239 -0
- package/vendor/stylo/use_counters/mod.rs +137 -0
- package/vendor/stylo/values/animated/color.rs +103 -0
- package/vendor/stylo/values/animated/effects.rs +26 -0
- package/vendor/stylo/values/animated/font.rs +37 -0
- package/vendor/stylo/values/animated/grid.rs +161 -0
- package/vendor/stylo/values/animated/lists.rs +141 -0
- package/vendor/stylo/values/animated/mod.rs +550 -0
- package/vendor/stylo/values/animated/svg.rs +46 -0
- package/vendor/stylo/values/animated/text.rs +58 -0
- package/vendor/stylo/values/animated/transform.rs +1592 -0
- package/vendor/stylo/values/computed/align.rs +90 -0
- package/vendor/stylo/values/computed/angle.rs +130 -0
- package/vendor/stylo/values/computed/animation.rs +124 -0
- package/vendor/stylo/values/computed/background.rs +13 -0
- package/vendor/stylo/values/computed/basic_shape.rs +267 -0
- package/vendor/stylo/values/computed/border.rs +163 -0
- package/vendor/stylo/values/computed/box.rs +267 -0
- package/vendor/stylo/values/computed/calc.rs +334 -0
- package/vendor/stylo/values/computed/color.rs +161 -0
- package/vendor/stylo/values/computed/column.rs +11 -0
- package/vendor/stylo/values/computed/corner_shape.rs +155 -0
- package/vendor/stylo/values/computed/counters.rs +26 -0
- package/vendor/stylo/values/computed/easing.rs +109 -0
- package/vendor/stylo/values/computed/effects.rs +30 -0
- package/vendor/stylo/values/computed/flex.rs +19 -0
- package/vendor/stylo/values/computed/font.rs +1517 -0
- package/vendor/stylo/values/computed/image.rs +273 -0
- package/vendor/stylo/values/computed/length.rs +576 -0
- package/vendor/stylo/values/computed/length_percentage.rs +1055 -0
- package/vendor/stylo/values/computed/list.rs +16 -0
- package/vendor/stylo/values/computed/mod.rs +1141 -0
- package/vendor/stylo/values/computed/motion.rs +73 -0
- package/vendor/stylo/values/computed/outline.rs +7 -0
- package/vendor/stylo/values/computed/page.rs +77 -0
- package/vendor/stylo/values/computed/param.rs +9 -0
- package/vendor/stylo/values/computed/percentage.rs +143 -0
- package/vendor/stylo/values/computed/position.rs +273 -0
- package/vendor/stylo/values/computed/ratio.rs +88 -0
- package/vendor/stylo/values/computed/rect.rs +19 -0
- package/vendor/stylo/values/computed/resolution.rs +76 -0
- package/vendor/stylo/values/computed/svg.rs +66 -0
- package/vendor/stylo/values/computed/table.rs +7 -0
- package/vendor/stylo/values/computed/text.rs +199 -0
- package/vendor/stylo/values/computed/time.rs +83 -0
- package/vendor/stylo/values/computed/transform.rs +559 -0
- package/vendor/stylo/values/computed/tree_counting.rs +30 -0
- package/vendor/stylo/values/computed/ui.rs +23 -0
- package/vendor/stylo/values/computed/url.rs +12 -0
- package/vendor/stylo/values/distance.rs +139 -0
- package/vendor/stylo/values/generics/animation.rs +363 -0
- package/vendor/stylo/values/generics/background.rs +65 -0
- package/vendor/stylo/values/generics/basic_shape.rs +1389 -0
- package/vendor/stylo/values/generics/border.rs +303 -0
- package/vendor/stylo/values/generics/box.rs +552 -0
- package/vendor/stylo/values/generics/calc.rs +2986 -0
- package/vendor/stylo/values/generics/color.rs +318 -0
- package/vendor/stylo/values/generics/column.rs +44 -0
- package/vendor/stylo/values/generics/counters.rs +320 -0
- package/vendor/stylo/values/generics/easing.rs +132 -0
- package/vendor/stylo/values/generics/effects.rs +131 -0
- package/vendor/stylo/values/generics/flex.rs +34 -0
- package/vendor/stylo/values/generics/font.rs +376 -0
- package/vendor/stylo/values/generics/grid.rs +962 -0
- package/vendor/stylo/values/generics/image.rs +653 -0
- package/vendor/stylo/values/generics/length.rs +656 -0
- package/vendor/stylo/values/generics/mod.rs +303 -0
- package/vendor/stylo/values/generics/motion.rs +274 -0
- package/vendor/stylo/values/generics/page.rs +167 -0
- package/vendor/stylo/values/generics/position.rs +669 -0
- package/vendor/stylo/values/generics/ratio.rs +88 -0
- package/vendor/stylo/values/generics/rect.rs +147 -0
- package/vendor/stylo/values/generics/size.rs +102 -0
- package/vendor/stylo/values/generics/svg.rs +226 -0
- package/vendor/stylo/values/generics/text.rs +268 -0
- package/vendor/stylo/values/generics/transform.rs +1157 -0
- package/vendor/stylo/values/generics/ui.rs +147 -0
- package/vendor/stylo/values/generics/url.rs +51 -0
- package/vendor/stylo/values/mod.rs +820 -0
- package/vendor/stylo/values/resolved/animation.rs +33 -0
- package/vendor/stylo/values/resolved/color.rs +53 -0
- package/vendor/stylo/values/resolved/counters.rs +45 -0
- package/vendor/stylo/values/resolved/mod.rs +316 -0
- package/vendor/stylo/values/specified/align.rs +711 -0
- package/vendor/stylo/values/specified/angle.rs +407 -0
- package/vendor/stylo/values/specified/animation.rs +921 -0
- package/vendor/stylo/values/specified/background.rs +270 -0
- package/vendor/stylo/values/specified/basic_shape.rs +986 -0
- package/vendor/stylo/values/specified/border.rs +430 -0
- package/vendor/stylo/values/specified/box.rs +2231 -0
- package/vendor/stylo/values/specified/calc.rs +1657 -0
- package/vendor/stylo/values/specified/color.rs +1210 -0
- package/vendor/stylo/values/specified/column.rs +11 -0
- package/vendor/stylo/values/specified/corner_shape.rs +152 -0
- package/vendor/stylo/values/specified/counters.rs +242 -0
- package/vendor/stylo/values/specified/easing.rs +225 -0
- package/vendor/stylo/values/specified/effects.rs +421 -0
- package/vendor/stylo/values/specified/flex.rs +42 -0
- package/vendor/stylo/values/specified/font.rs +2103 -0
- package/vendor/stylo/values/specified/frequency.rs +39 -0
- package/vendor/stylo/values/specified/grid.rs +407 -0
- package/vendor/stylo/values/specified/image.rs +1385 -0
- package/vendor/stylo/values/specified/intersection_observer.rs +80 -0
- package/vendor/stylo/values/specified/length.rs +2024 -0
- package/vendor/stylo/values/specified/list.rs +190 -0
- package/vendor/stylo/values/specified/mod.rs +531 -0
- package/vendor/stylo/values/specified/motion.rs +316 -0
- package/vendor/stylo/values/specified/number.rs +603 -0
- package/vendor/stylo/values/specified/outline.rs +69 -0
- package/vendor/stylo/values/specified/page.rs +94 -0
- package/vendor/stylo/values/specified/param.rs +121 -0
- package/vendor/stylo/values/specified/percentage.rs +364 -0
- package/vendor/stylo/values/specified/position.rs +2247 -0
- package/vendor/stylo/values/specified/ratio.rs +29 -0
- package/vendor/stylo/values/specified/rect.rs +28 -0
- package/vendor/stylo/values/specified/resolution.rs +237 -0
- package/vendor/stylo/values/specified/source_size_list.rs +135 -0
- package/vendor/stylo/values/specified/svg.rs +427 -0
- package/vendor/stylo/values/specified/svg_path.rs +1115 -0
- package/vendor/stylo/values/specified/table.rs +38 -0
- package/vendor/stylo/values/specified/text.rs +1561 -0
- package/vendor/stylo/values/specified/time.rs +313 -0
- package/vendor/stylo/values/specified/transform.rs +599 -0
- package/vendor/stylo/values/specified/tree_counting.rs +32 -0
- package/vendor/stylo/values/specified/ui.rs +344 -0
- package/vendor/stylo/values/specified/url.rs +12 -0
- package/vendor/stylo/values/tagged_numeric.rs +253 -0
- package/wasm/blitz_pdf.d.ts +67 -0
- package/wasm/blitz_pdf.js +699 -0
- package/wasm/blitz_pdf_bg.wasm +0 -0
- package/wasm/blitz_pdf_bg.wasm.d.ts +20 -0
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
|
|
5
|
+
//! Gamut mapping - Raytrace algorithm.
|
|
6
|
+
//! <https://drafts.csswg.org/css-color-4/#gamut-mapping>
|
|
7
|
+
|
|
8
|
+
use crate::color::{gamut::MIN_PRECISION, AbsoluteColor, ColorComponents, ColorSpace};
|
|
9
|
+
|
|
10
|
+
impl AbsoluteColor {
|
|
11
|
+
/// 13.2.5. The Ray Trace Gamut Mapping
|
|
12
|
+
/// <https://drafts.csswg.org/css-color-4/#GMA-Raytrace>
|
|
13
|
+
pub fn gamut_map_raytrace(&self, dest_color_space: ColorSpace) -> Self {
|
|
14
|
+
macro_rules! in_range {
|
|
15
|
+
($l:expr, $c:expr, $h:expr) => {{
|
|
16
|
+
$c >= $l && $c <= $h
|
|
17
|
+
}};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const MIN_L: f32 = MIN_PRECISION;
|
|
21
|
+
const MAX_L: f32 = 1.0;
|
|
22
|
+
|
|
23
|
+
// Get the linear version of the destination color space;
|
|
24
|
+
// else, use the same space for the destination.
|
|
25
|
+
// NOTE that this will cause temporary approximations for wide-gamut
|
|
26
|
+
// RGB spaces beyond DisplayP3 (A98RGB, ProPhoto, and Rec2020) that
|
|
27
|
+
// currently don't have linear versions built-out for them.
|
|
28
|
+
// See comments/notes on [`ColorSpace::get_linear_color_space()`].
|
|
29
|
+
let dest_linear_color_space = dest_color_space
|
|
30
|
+
.get_linear_color_space()
|
|
31
|
+
.unwrap_or(dest_color_space);
|
|
32
|
+
|
|
33
|
+
// 1. if destination has no gamut limits (XYZ-D65, XYZ-D50, Lab, LCH,
|
|
34
|
+
// Oklab, OkLCh) convert origin to destination and return it as the
|
|
35
|
+
// gamut mapped color
|
|
36
|
+
if matches!(
|
|
37
|
+
dest_color_space,
|
|
38
|
+
ColorSpace::Lab
|
|
39
|
+
| ColorSpace::Lch
|
|
40
|
+
| ColorSpace::Oklab
|
|
41
|
+
| ColorSpace::Oklch
|
|
42
|
+
| ColorSpace::XyzD50
|
|
43
|
+
| ColorSpace::XyzD65
|
|
44
|
+
) {
|
|
45
|
+
return self.to_color_space(dest_color_space);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// 2. let `origin_OkLCh` be `origin` converted from `origin color
|
|
49
|
+
// space` to the OkLCh color space
|
|
50
|
+
let origin_oklch = self.to_color_space(ColorSpace::Oklch);
|
|
51
|
+
|
|
52
|
+
// 3. if the Lightness of `origin_OkLCh` is greater than or equal to
|
|
53
|
+
// 100%, convert `oklab(1 0 0 / origin.alpha)` to `destination` and
|
|
54
|
+
// return it as the gamut mapped color
|
|
55
|
+
if origin_oklch.components.0 >= MAX_L {
|
|
56
|
+
return AbsoluteColor::new(ColorSpace::Oklab, 1.0, 0.0, 0.0, self.alpha)
|
|
57
|
+
.to_color_space(dest_color_space);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// 4. if the Lightness of `origin_OkLCh` is less than than or equal to
|
|
61
|
+
// 0%, convert `oklab(0 0 0 / origin.alpha)` to `destination` and
|
|
62
|
+
// return it as the gamut mapped color
|
|
63
|
+
if origin_oklch.components.0 <= MIN_L {
|
|
64
|
+
return AbsoluteColor::new(ColorSpace::Oklab, 0.0, 0.0, 0.0, self.alpha)
|
|
65
|
+
.to_color_space(dest_color_space);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// 5. let `l_origin` be the OkLCh lightness component of `origin_OkLCh`
|
|
69
|
+
// 6. let `h_origin` be the OkLCh hue component of `origin_OkLCh`
|
|
70
|
+
let ColorComponents(l_origin, _, h_origin) = origin_oklch.components;
|
|
71
|
+
|
|
72
|
+
// 7. let `anchor` be an achromatic OkLCh color formed with `l_origin`
|
|
73
|
+
// as lightness, 0 as chroma, and `h_origin` as hue, converted to
|
|
74
|
+
// the linear-light form of destination
|
|
75
|
+
let mut anchor = AbsoluteColor::new(ColorSpace::Oklch, l_origin, 0.0, h_origin, self.alpha)
|
|
76
|
+
.to_color_space(dest_linear_color_space);
|
|
77
|
+
|
|
78
|
+
// 8. let `origin_rgb` be `origin_OkLCh` converted to the linear-light
|
|
79
|
+
// form of destination
|
|
80
|
+
let mut origin_rgb = origin_oklch.to_color_space(dest_linear_color_space);
|
|
81
|
+
|
|
82
|
+
// 9. if origin_rgb is not in gamut
|
|
83
|
+
if !origin_rgb.in_gamut() {
|
|
84
|
+
// 9.1. let `low` be 1E-6 [^1]
|
|
85
|
+
const LOW: f32 = 1.0e-6;
|
|
86
|
+
|
|
87
|
+
// 9.2 let `high` be 1.0 - `low` [^2]
|
|
88
|
+
const HIGH: f32 = 1.0 - LOW;
|
|
89
|
+
|
|
90
|
+
// 9.3 let `last` be `origin_rgb`
|
|
91
|
+
let mut last = origin_rgb;
|
|
92
|
+
|
|
93
|
+
// We're doing 4 cycles of ray tracing.
|
|
94
|
+
// 9.4 `for (i=0; i<4; i++)`:
|
|
95
|
+
for i in 0..4 {
|
|
96
|
+
// 9.4.1. if (`i > 0`)
|
|
97
|
+
if i > 0 {
|
|
98
|
+
// 9.4.1.1. let `current_OkLCh` be `origin_rgb` converted to OkLCh
|
|
99
|
+
let mut current_oklch = origin_rgb.to_color_space(ColorSpace::Oklch);
|
|
100
|
+
|
|
101
|
+
// 9.4.1.2. let the lightness of `current_OkLCh` be `l_origin`
|
|
102
|
+
current_oklch.components.0 = l_origin;
|
|
103
|
+
// 9.4.1.3. let the hue of `current_OkLCh` be `h_origin` [^3]
|
|
104
|
+
current_oklch.components.2 = h_origin;
|
|
105
|
+
|
|
106
|
+
// 9.4.1.4. let `origin_rgb` be `current_OkLCh` converted to the
|
|
107
|
+
// linear-light form of destination
|
|
108
|
+
origin_rgb = current_oklch.to_color_space(dest_linear_color_space);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// 9.4.2. **Cast a ray** from `anchor` to `origin_rgb` and let
|
|
112
|
+
// `intersection` be the intersection of this ray with the
|
|
113
|
+
// gamut boundary
|
|
114
|
+
let intersection = Self::cast_ray(&anchor.components, &origin_rgb.components);
|
|
115
|
+
|
|
116
|
+
// 9.4.3. if an intersection was not found, let `origin_rgb` be
|
|
117
|
+
// `last` and exit the loop [^5]
|
|
118
|
+
let Some(intersection) = intersection else {
|
|
119
|
+
origin_rgb = last;
|
|
120
|
+
break;
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
// 9.4.4. if (`i > 0`) AND (each component of `origin_rgb` is
|
|
124
|
+
// between `low` and `high`) then let `anchor` be
|
|
125
|
+
// `origin_rgb` [^4]
|
|
126
|
+
if (i > 0)
|
|
127
|
+
&& in_range!(LOW, origin_rgb.components.0, HIGH)
|
|
128
|
+
&& in_range!(LOW, origin_rgb.components.1, HIGH)
|
|
129
|
+
&& in_range!(LOW, origin_rgb.components.2, HIGH)
|
|
130
|
+
{
|
|
131
|
+
anchor = origin_rgb;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// 9.4.5. let `origin_rgb` be `intersection`
|
|
135
|
+
origin_rgb.components = intersection;
|
|
136
|
+
|
|
137
|
+
// 9.4.6. let `last` be `intersection`
|
|
138
|
+
last.components = intersection;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// 10. let clip(color) be a function which converts color to
|
|
143
|
+
// destination, clamps each component to the bounds of the
|
|
144
|
+
// reference range for that component, and returns the result
|
|
145
|
+
// See [`Self::clip`] and [`Self::clip_to_dest_space`].
|
|
146
|
+
|
|
147
|
+
// NOTE: in the 2026-02-27 draft, this line doesn't make sense.
|
|
148
|
+
// I've posted a question/issue to the CSS Color 4 team about it.
|
|
149
|
+
// See <https://github.com/w3c/csswg-drafts/issues/10579#issuecomment-4122677476>
|
|
150
|
+
// Isaac (@facelessuser) replied that it is ambiguous, but ATOW this hasn't
|
|
151
|
+
// been fixed in the working copy pseudo-code.
|
|
152
|
+
// See <https://github.com/w3c/csswg-drafts/issues/10579#issuecomment-4123490623>
|
|
153
|
+
// 11. set clipped to clip(current)
|
|
154
|
+
//
|
|
155
|
+
// In the meantime, this was the logic from the 2026-02-02 draft that worked:
|
|
156
|
+
// 13. let `clipped` be `origin_rgb` clipped to gamut (components in
|
|
157
|
+
// the range 0 to 1), thus trimming off any noise due to floating
|
|
158
|
+
// point inaccuracy
|
|
159
|
+
let clipped = origin_rgb.clip_to_dest_space(dest_color_space);
|
|
160
|
+
|
|
161
|
+
// 12. return `clipped` as the gamut mapped color
|
|
162
|
+
clipped
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/// To **cast a ray** through a linear-light RGB space from `start` to
|
|
166
|
+
/// `end` (in gamut mapping, `start` is an anchor within the RGB gamut and
|
|
167
|
+
/// `end` is the gamut mapped color, on the cubical gamut surface)
|
|
168
|
+
/// <https://drafts.csswg.org/css-color-4/#GMA-Raytrace>
|
|
169
|
+
fn cast_ray(start: &ColorComponents, end: &ColorComponents) -> Option<ColorComponents> {
|
|
170
|
+
// 1. let `bmin` and `bmax` be 3-element arrays with the gamut’s lower
|
|
171
|
+
// and upper bounds, respectively [^6]
|
|
172
|
+
// NOTE: assuming these are always tied to RGB bounds [0.0, 1.0]
|
|
173
|
+
let bmin = [0.0, 0.0, 0.0];
|
|
174
|
+
let bmax = [1.0, 1.0, 1.0];
|
|
175
|
+
|
|
176
|
+
// 2. let `tfar` be `infinity` (or some very large number)
|
|
177
|
+
let mut tfar = f32::INFINITY;
|
|
178
|
+
|
|
179
|
+
// 3. let `tnear` be `-infinity` (or some very large, negative number)
|
|
180
|
+
let mut tnear = f32::NEG_INFINITY;
|
|
181
|
+
|
|
182
|
+
// 4. let `direction` be a 3-element array
|
|
183
|
+
let mut direction = [0.0, 0.0, 0.0];
|
|
184
|
+
|
|
185
|
+
// reshape start and end so we can iterate over them
|
|
186
|
+
let start_array = start.to_array();
|
|
187
|
+
let end_array = end.to_array();
|
|
188
|
+
|
|
189
|
+
// 5. `for (i = 0; i < 3; i++)`:
|
|
190
|
+
for i in 0..3 {
|
|
191
|
+
// 5.1. let `a` be `start[i]`
|
|
192
|
+
let a = start_array[i];
|
|
193
|
+
|
|
194
|
+
// 5.2. let `b` be `end[i]`
|
|
195
|
+
let b = end_array[i];
|
|
196
|
+
|
|
197
|
+
// 5.3. let `d` be `b - a`
|
|
198
|
+
let d = b - a;
|
|
199
|
+
|
|
200
|
+
// 5.4. let `direction[i]` be `d`
|
|
201
|
+
direction[i] = d;
|
|
202
|
+
|
|
203
|
+
// 5.5. if abs(d) > MIN_THRESHOLD:
|
|
204
|
+
// NOTE the 2026-02-27 spec is incorrect; it uses less-than -- should be greater-than.
|
|
205
|
+
// Reference impls colorjs.io and ColorAide both use greater-than.
|
|
206
|
+
// Issue reported to CSS Color 4 team; yet to be fixed in working draft ATOW.
|
|
207
|
+
// See <https://github.com/w3c/csswg-drafts/issues/10579#issuecomment-4122988782>
|
|
208
|
+
// NOTE the spec and reference implementations all assume f64 precision, where
|
|
209
|
+
// MIN_THRESHOLD is 1e-12 currently in the spec. This is too precise for f32.
|
|
210
|
+
// Testing by working group members revealed the issue, and recommended
|
|
211
|
+
// loosening the precision to accommodate f32 properly by using 1e-6.
|
|
212
|
+
// See <https://github.com/w3c/csswg-drafts/issues/10579#issuecomment-4666657910>.
|
|
213
|
+
const MIN_THRESHOLD: f32 = 1e-6;
|
|
214
|
+
if d.abs() > MIN_THRESHOLD {
|
|
215
|
+
// 5.5.1. let `inv_d` be `1 / d`
|
|
216
|
+
let inv_d = 1.0 / d;
|
|
217
|
+
|
|
218
|
+
// 5.5.2. let `t1` be `(bmin[i] - a) * inv_d`
|
|
219
|
+
let t1 = (bmin[i] - a) * inv_d;
|
|
220
|
+
|
|
221
|
+
// 5.5.3. let `t2` be `(bmax[i] - a) * inv_d`
|
|
222
|
+
let t2 = (bmax[i] - a) * inv_d;
|
|
223
|
+
|
|
224
|
+
// 5.5.4. let `tnear` be `max(min(t1, t2), tnear)`
|
|
225
|
+
tnear = t1.min(t2).max(tnear);
|
|
226
|
+
|
|
227
|
+
// 5.5.5. let `tfar` be `min(max(t1, t2), tfar)`
|
|
228
|
+
tfar = t1.max(t2).min(tfar);
|
|
229
|
+
}
|
|
230
|
+
// 5.6. else if (`a < bmin[i]` or `a > bmax[i]`)
|
|
231
|
+
// * return `INTERSECTION NOT FOUND`
|
|
232
|
+
else if a < bmin[i] || a > bmax[i] {
|
|
233
|
+
return None;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// 6. if (`tnear > tfar` or `tfar < 0`)
|
|
238
|
+
// * return `INTERSECTION NOT FOUND`
|
|
239
|
+
if (tnear > tfar) || (tfar < 0.0) {
|
|
240
|
+
return None;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// 7. if `tnear < 0`
|
|
244
|
+
// * let `tnear` be `tfar` [^7]
|
|
245
|
+
if tnear < 0.0 {
|
|
246
|
+
tnear = tfar;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// 8. if tnear is infinite (or matches the initial very large value)
|
|
250
|
+
// * return `INTERSECTION NOT FOUND`
|
|
251
|
+
if tnear.is_infinite() {
|
|
252
|
+
return None;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
let mut result = [0.0, 0.0, 0.0];
|
|
256
|
+
// 9. for (`i = 0; i < 3; i++`):
|
|
257
|
+
// * let `result[i]` be `start[i] + direction[i] * tnear`
|
|
258
|
+
for i in 0..3 {
|
|
259
|
+
result[i] = start_array[i] + direction[i] * tnear;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// 10. return `result`
|
|
263
|
+
Some(ColorComponents(result[0], result[1], result[2]))
|
|
264
|
+
}
|
|
265
|
+
}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
4
|
+
|
|
5
|
+
//! Gamut mapping.
|
|
6
|
+
//! <https://drafts.csswg.org/css-color-4/#gamut-mapping>
|
|
7
|
+
|
|
8
|
+
use super::{AbsoluteColor, ColorSpace};
|
|
9
|
+
|
|
10
|
+
/// Gamut-mapping min precision
|
|
11
|
+
const MIN_PRECISION: f32 = 1.0 / (i32::MAX as f32);
|
|
12
|
+
|
|
13
|
+
pub mod raytrace;
|
|
14
|
+
|
|
15
|
+
impl AbsoluteColor {
|
|
16
|
+
/// 13.2.1. Binary Search Gamut Mapping with Local MINDE
|
|
17
|
+
/// <https://drafts.csswg.org/css-color-4/#GMA-Binary-local-MINDE>
|
|
18
|
+
pub fn gamut_map_binary_search(&self, dest_color_space: ColorSpace) -> Self {
|
|
19
|
+
const MIN_L: f32 = MIN_PRECISION;
|
|
20
|
+
const MAX_L: f32 = 1.0;
|
|
21
|
+
|
|
22
|
+
// 1. if destination has no gamut limits (XYZ-D65, XYZ-D50, Lab, LCH,
|
|
23
|
+
// Oklab, OkLCh) convert origin to destination and return it as the
|
|
24
|
+
// gamut mapped color
|
|
25
|
+
if matches!(
|
|
26
|
+
dest_color_space,
|
|
27
|
+
ColorSpace::Lab
|
|
28
|
+
| ColorSpace::Lch
|
|
29
|
+
| ColorSpace::Oklab
|
|
30
|
+
| ColorSpace::Oklch
|
|
31
|
+
| ColorSpace::XyzD50
|
|
32
|
+
| ColorSpace::XyzD65
|
|
33
|
+
) {
|
|
34
|
+
return self.to_color_space(dest_color_space);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// 2. let origin_OkLCh be origin converted from origin color space to
|
|
38
|
+
// the OkLCh color space
|
|
39
|
+
let origin_oklch = self.to_color_space(ColorSpace::Oklch);
|
|
40
|
+
|
|
41
|
+
// 3. if the Lightness of origin_OkLCh is greater than or equal to
|
|
42
|
+
// 100%, convert `oklab(1 0 0 / origin.alpha)` to destination and
|
|
43
|
+
// return it as the gamut mapped color
|
|
44
|
+
if origin_oklch.components.0 >= MAX_L {
|
|
45
|
+
return AbsoluteColor::new(ColorSpace::Oklab, 1.0, 0.0, 0.0, self.alpha)
|
|
46
|
+
.to_color_space(dest_color_space);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// 4. if the Lightness of origin_OkLCh is less than than or equal to
|
|
50
|
+
// 0%, convert `oklab(0 0 0 / origin.alpha)` to destination and
|
|
51
|
+
// return it as the gamut mapped color
|
|
52
|
+
if origin_oklch.components.0 <= MIN_L {
|
|
53
|
+
return AbsoluteColor::new(ColorSpace::Oklab, 0.0, 0.0, 0.0, self.alpha)
|
|
54
|
+
.to_color_space(dest_color_space);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// 5. let inGamut(color) be a function which returns true if, when
|
|
58
|
+
// passed a color, that color is inside the gamut of destination.
|
|
59
|
+
// For HSL and HWB, it returns true if the color is inside the
|
|
60
|
+
// gamut of sRGB.
|
|
61
|
+
// See [`Self::in_gamut`] and [`Self::in_gamut_for_dest_space`].
|
|
62
|
+
|
|
63
|
+
// 6. if inGamut(origin_OkLCh) is true, convert origin_OkLCh to
|
|
64
|
+
// destination and return it as the gamut mapped color
|
|
65
|
+
if origin_oklch.in_gamut_for_dest_space(dest_color_space) {
|
|
66
|
+
return origin_oklch.to_color_space(dest_color_space);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// 7. otherwise, let delta(one, two) be a function which returns the
|
|
70
|
+
// deltaEOK of color one compared to color two
|
|
71
|
+
// See the [`delta_eok`] function.
|
|
72
|
+
|
|
73
|
+
// 8. let JND be 0.02
|
|
74
|
+
const JND: f32 = 0.02;
|
|
75
|
+
|
|
76
|
+
// 9. let epsilon be 0.0001
|
|
77
|
+
const EPSILON: f32 = 0.0001;
|
|
78
|
+
|
|
79
|
+
// 10. let clip(color) be a function which converts color to
|
|
80
|
+
// destination, clamps each component to the bounds of the
|
|
81
|
+
// reference range for that component, and returns the result.
|
|
82
|
+
// See [`Self::clip`] and [`Self::clip_to_dest_space`].
|
|
83
|
+
|
|
84
|
+
// 11. set current to origin_OkLCh
|
|
85
|
+
let mut current_oklch = origin_oklch;
|
|
86
|
+
|
|
87
|
+
// 12. set clipped to clip(current)
|
|
88
|
+
let mut clipped = current_oklch.clip_to_dest_space(dest_color_space);
|
|
89
|
+
|
|
90
|
+
// 13. set E to delta(clipped, current)
|
|
91
|
+
let mut e = delta_eok(&clipped, ¤t_oklch);
|
|
92
|
+
|
|
93
|
+
// 14. if E < JND, return clipped as the gamut mapped color
|
|
94
|
+
if e < JND {
|
|
95
|
+
return clipped;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// 15. set min to zero
|
|
99
|
+
let mut min = 0.0;
|
|
100
|
+
|
|
101
|
+
// 16. set max to the Oklch chroma of origin_Oklch.
|
|
102
|
+
let mut max = origin_oklch.components.1;
|
|
103
|
+
|
|
104
|
+
// 17. let min_inGamut be a boolean that represents when min is still
|
|
105
|
+
// in gamut, and set it to true
|
|
106
|
+
let mut min_in_gamut = true;
|
|
107
|
+
|
|
108
|
+
// 18. while (max - min is greater than epsilon) repeat the following
|
|
109
|
+
// steps.
|
|
110
|
+
while max - min > EPSILON {
|
|
111
|
+
// 18.1. set chroma to (min + max) / 2
|
|
112
|
+
let chroma = (min + max) / 2.0;
|
|
113
|
+
|
|
114
|
+
// 18.2. set the chroma component of current to chroma
|
|
115
|
+
current_oklch.components.1 = chroma;
|
|
116
|
+
|
|
117
|
+
// 18.3. if min_inGamut is true and also if inGamut(current) is
|
|
118
|
+
// true, set min to chroma and continue to repeat these steps.
|
|
119
|
+
if min_in_gamut && current_oklch.in_gamut_for_dest_space(dest_color_space) {
|
|
120
|
+
min = chroma;
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// 18.4. otherwise, if inGamut(current) is false carry out these
|
|
125
|
+
// steps:
|
|
126
|
+
// 18.4.1. set clipped to clip(current)
|
|
127
|
+
clipped = current_oklch.clip_to_dest_space(dest_color_space);
|
|
128
|
+
|
|
129
|
+
// 18.4.2. set E to delta(clipped, current)
|
|
130
|
+
e = delta_eok(&clipped, ¤t_oklch);
|
|
131
|
+
|
|
132
|
+
// 18.4.3. if E < JND
|
|
133
|
+
if e < JND {
|
|
134
|
+
// 18.4.3.1. if (JND - E < epsilon), return clipped as the
|
|
135
|
+
// gamut mapped color
|
|
136
|
+
if JND - e < EPSILON {
|
|
137
|
+
return clipped;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// 18.4.3.2. otherwise:
|
|
141
|
+
// 18.4.3.2.1. set min_inGamut to false
|
|
142
|
+
min_in_gamut = false;
|
|
143
|
+
|
|
144
|
+
// 18.4.3.2.2. set min to chroma
|
|
145
|
+
min = chroma;
|
|
146
|
+
} else {
|
|
147
|
+
// 18.4.4. otherwise, set max to chroma and continue to repeat
|
|
148
|
+
// these steps
|
|
149
|
+
max = chroma;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// 19. return clipped as the gamut mapped color
|
|
154
|
+
clipped
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/// Clamp this color to within the [0..1] range.
|
|
158
|
+
/// NOTE this assumes RGB ranges and will not work for Lab, Oklab, or
|
|
159
|
+
/// other color spaces with different ranges, or limitless ranges
|
|
160
|
+
fn clip(&self) -> Self {
|
|
161
|
+
let mut result = *self;
|
|
162
|
+
result.components = result.components.map(|c| c.clamp(0.0, 1.0));
|
|
163
|
+
result
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/// ^10. let clip(color) be a function which converts color to destination,
|
|
167
|
+
/// clamps each component to the bounds of the reference range for
|
|
168
|
+
/// that component, and returns the result
|
|
169
|
+
/// Clip/clamp this color to the supplied destination color space
|
|
170
|
+
fn clip_to_dest_space(&self, dest_color_space: ColorSpace) -> Self {
|
|
171
|
+
self.to_color_space(dest_color_space).clip()
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/// Returns true if this color is within its gamut limits.
|
|
175
|
+
fn in_gamut(&self) -> bool {
|
|
176
|
+
macro_rules! in_range {
|
|
177
|
+
($c:expr) => {{
|
|
178
|
+
$c >= MIN_PRECISION && $c <= 1.0
|
|
179
|
+
}};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
match self.color_space {
|
|
183
|
+
ColorSpace::Hsl | ColorSpace::Hwb => self.to_color_space(ColorSpace::Srgb).in_gamut(),
|
|
184
|
+
ColorSpace::Srgb
|
|
185
|
+
| ColorSpace::SrgbLinear
|
|
186
|
+
| ColorSpace::DisplayP3
|
|
187
|
+
| ColorSpace::DisplayP3Linear
|
|
188
|
+
| ColorSpace::A98Rgb
|
|
189
|
+
| ColorSpace::ProphotoRgb
|
|
190
|
+
| ColorSpace::Rec2020 => {
|
|
191
|
+
in_range!(self.components.0)
|
|
192
|
+
&& in_range!(self.components.1)
|
|
193
|
+
&& in_range!(self.components.2)
|
|
194
|
+
},
|
|
195
|
+
ColorSpace::Lab
|
|
196
|
+
| ColorSpace::Lch
|
|
197
|
+
| ColorSpace::Oklab
|
|
198
|
+
| ColorSpace::Oklch
|
|
199
|
+
| ColorSpace::XyzD50
|
|
200
|
+
| ColorSpace::XyzD65 => true,
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/// ^5. let inGamut(color) be a function which returns true if, when passed
|
|
205
|
+
/// a color, that color is inside the gamut of destination. For HSL and
|
|
206
|
+
/// HWB, it returns true if the color is inside the gamut of sRGB.
|
|
207
|
+
/// Check if this color is in-gamut for the destination color space
|
|
208
|
+
fn in_gamut_for_dest_space(&self, dest_color_space: ColorSpace) -> bool {
|
|
209
|
+
if self.color_space == ColorSpace::Hsl || self.color_space == ColorSpace::Hwb {
|
|
210
|
+
self.to_color_space(ColorSpace::Srgb).in_gamut()
|
|
211
|
+
} else {
|
|
212
|
+
self.to_color_space(dest_color_space).in_gamut()
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/// Calculate deltaE OK (simple root sum of squares).
|
|
218
|
+
/// <https://drafts.csswg.org/css-color-4/#color-difference-OK>
|
|
219
|
+
fn delta_eok(reference: &AbsoluteColor, sample: &AbsoluteColor) -> f32 {
|
|
220
|
+
// Delta is calculated in the oklab color space.
|
|
221
|
+
let reference = reference.to_color_space(ColorSpace::Oklab);
|
|
222
|
+
let sample = sample.to_color_space(ColorSpace::Oklab);
|
|
223
|
+
|
|
224
|
+
let diff = reference.components - sample.components;
|
|
225
|
+
let diff = diff * diff;
|
|
226
|
+
(diff.0 + diff.1 + diff.2).sqrt()
|
|
227
|
+
}
|