tincture-apca 1.0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: '03519433f7f021e7c641da9814503f7175233ebab635f70599c419616ac18d15'
4
+ data.tar.gz: 58cb22824f9af6a9d99970e0213b8a761b8597fbcf65aa16b60d51a40ce61ca1
5
+ SHA512:
6
+ metadata.gz: 3014dc7a59b1deb07bc0686482cb4f2a077df8a73f9db6888f7e5abb140e0c9d391b35459e429ed70d232e91dd6445d9f38582a470f66450e221effb10e78c4e
7
+ data.tar.gz: 05b97f7f2f23d18296b530945be9fb9c5cfea664b5e3fc36dfc3340c96761572cc64a84bc116a8cd31546d6444180909f0b94db7b536a883d1bcb3a28c703d41
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ # Changelog
2
+
3
+ ## 1.0.0 (2026-10-21)
4
+
5
+ - `apca_contrast` and `contrast_color(method: :apca)` for `Tincture::Color`, ported from apca-w3 0.1.9.
data/LICENSE.md ADDED
@@ -0,0 +1,12 @@
1
+ # Licence
2
+
3
+ This gem is a port of [apca-w3](https://github.com/Myndex/apca-w3) 0.1.9 (base algorithm 0.0.98G-4g) and is distributed under the apca-w3 licence, not MIT: https://github.com/Myndex/apca-w3/blob/master/LICENSE.md
4
+
5
+ APCA is copyright © 2019-2023 Andrew Somers and Myndex Research, patent pending.
6
+
7
+ In short, and the licence itself governs:
8
+
9
+ - Use is allowed only for web content, in support of the WCAG accessibility guidelines. Other uses, such as print or PDF, fall under AGPL v3.
10
+ - A commercial product that uses it must give Myndex free access to audit the code on request.
11
+ - The algorithm and constants must not change, except to port them, and must be kept current.
12
+ - The name "APCA" may describe only a correct, current implementation.
data/README.md ADDED
@@ -0,0 +1,53 @@
1
+ # Tincture APCA
2
+
3
+ [![CI](https://github.com/andycroll/tincture-apca/actions/workflows/ci.yml/badge.svg)](https://github.com/andycroll/tincture-apca/actions/workflows/ci.yml)
4
+
5
+ APCA contrast for Tincture colours
6
+
7
+ > [!WARNING]
8
+ > APCA is © Andrew Somers and Myndex Research, patent pending. Its [licence](LICENSE.md) allows use only for web content, in support of the WCAG accessibility guidelines. Other uses, such as print or PDF, fall under AGPL v3. A commercial product that uses it must give Myndex free access to audit the code on request.
9
+
10
+ ## Installation
11
+
12
+ Add these lines to your Gemfile:
13
+
14
+ ```ruby
15
+ gem "tincture"
16
+ gem "tincture-apca", require: false
17
+ ```
18
+
19
+ Then require it where web content is built, not globally:
20
+
21
+ ```ruby
22
+ require "tincture/apca"
23
+ ```
24
+
25
+ ## Usage
26
+
27
+ Measure APCA lightness contrast (Lc) for text on a background
28
+
29
+ ```ruby
30
+ Tincture::Color.parse("#888").apca_contrast("#fff") # 63.06
31
+ Tincture::Color.parse("#fff").apca_contrast("#888") # -68.54
32
+ ```
33
+
34
+ Positive is dark text on light, negative is light on dark. For body text, Lc 75 is the minimum and Lc 90 preferred.
35
+
36
+ Pick black or white text by APCA
37
+
38
+ ```ruby
39
+ background.contrast_color(method: :apca)
40
+ background.contrast_color(among: ["#1f2937", "white"], method: :apca)
41
+ ```
42
+
43
+ This is a port of [apca-w3](https://github.com/Myndex/apca-w3) 0.1.9 (algorithm 0.0.98G-4g), checked against its test values.
44
+
45
+ ## Development
46
+
47
+ ```sh
48
+ bundle install
49
+ bundle exec rake # tests and RuboCop
50
+ bundle exec rake rdoc # API docs in doc/
51
+ ```
52
+
53
+ To release, set the version in `lib/tincture/apca/version.rb`, date the changelog entry, commit, and push a `vX.Y.Z` tag. GitHub Actions runs the checks and publishes the gem to rubygems.org through trusted publishing.
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tincture
4
+ module Apca
5
+ VERSION = '1.0.0' # :nodoc:
6
+ end
7
+ end
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'tincture'
4
+ require_relative 'apca/version'
5
+
6
+ module Tincture # :nodoc:
7
+ # [APCA](https://git.apcacontrast.com/) lightness contrast (Lc), the
8
+ # perceptual contrast method drafted for WCAG 3. Requiring
9
+ # `tincture/apca` adds ColorMethods#apca_contrast to Tincture::Color and
10
+ # `method: :apca` to Tincture::Color#contrast_color.
11
+ #
12
+ # A port of [apca-w3](https://github.com/Myndex/apca-w3) 0.1.9: base
13
+ # algorithm 0.0.98G-4g with its approved constants.
14
+ #
15
+ # **Licence restriction.** APCA is copyright © 2019–2023 Andrew Somers and
16
+ # Myndex Research, patent pending. Its licence allows use only for web
17
+ # content, in support of the WCAG accessibility guidelines. Other uses,
18
+ # such as print or PDF, fall under AGPL v3. A commercial product that uses
19
+ # it must give Myndex free access to audit the code on request. The
20
+ # algorithm and constants must not change, except to port them, and must
21
+ # be kept current. See the
22
+ # [licence](https://github.com/Myndex/apca-w3/blob/master/LICENSE.md).
23
+ module Apca
24
+ # Names match apca-w3's SA98G, so each value can be checked against it.
25
+ SA98G = {
26
+ mainTRC: 2.4,
27
+ sRco: 0.2126729,
28
+ sGco: 0.7151522,
29
+ sBco: 0.0721750,
30
+ normBG: 0.56,
31
+ normTXT: 0.57,
32
+ revTXT: 0.62,
33
+ revBG: 0.65,
34
+ blkThrs: 0.022,
35
+ blkClmp: 1.414,
36
+ scaleBoW: 1.14,
37
+ scaleWoB: 1.14,
38
+ loBoWoffset: 0.027,
39
+ loWoBoffset: 0.027,
40
+ deltaYmin: 0.0005,
41
+ loClip: 0.1
42
+ }.freeze
43
+
44
+ module_function
45
+
46
+ # Lc for text on a background, from their #luminance values. Positive for
47
+ # dark text on light, negative for light text on dark, up to about ±108.
48
+ # For body text, Lc 75 is the minimum and Lc 90 preferred.
49
+ #
50
+ #: (Float text_y, Float background_y) -> Float
51
+ def contrast(text_y, background_y)
52
+ text_y, background_y = [text_y, background_y].map { soft_clamped(it) }
53
+
54
+ lc =
55
+ if (background_y - text_y).abs < SA98G[:deltaYmin] then 0.0
56
+ elsif background_y > text_y then dark_on_light(text_y, background_y)
57
+ else light_on_dark(text_y, background_y)
58
+ end
59
+
60
+ lc * 100
61
+ end
62
+
63
+ # APCA's screen luminance (Y) for 0–255 sRGB channels. Not the same as
64
+ # WCAG 2 relative luminance.
65
+ #
66
+ #: ([Integer, Integer, Integer] rgb) -> Float
67
+ def luminance((red, green, blue))
68
+ (SA98G[:sRco] * linear(red)) + (SA98G[:sGco] * linear(green)) + (SA98G[:sBco] * linear(blue))
69
+ end
70
+
71
+ def linear(channel) = (channel / 255.0)**SA98G[:mainTRC] # :nodoc:
72
+
73
+ def soft_clamped(luminance) # :nodoc:
74
+ luminance > SA98G[:blkThrs] ? luminance : luminance + ((SA98G[:blkThrs] - luminance)**SA98G[:blkClmp])
75
+ end
76
+
77
+ def dark_on_light(text_y, background_y) # :nodoc:
78
+ sapc = ((background_y**SA98G[:normBG]) - (text_y**SA98G[:normTXT])) * SA98G[:scaleBoW]
79
+ sapc < SA98G[:loClip] ? 0.0 : sapc - SA98G[:loBoWoffset]
80
+ end
81
+
82
+ def light_on_dark(text_y, background_y) # :nodoc:
83
+ sapc = ((background_y**SA98G[:revBG]) - (text_y**SA98G[:revTXT])) * SA98G[:scaleWoB]
84
+ sapc > -SA98G[:loClip] ? 0.0 : sapc + SA98G[:loWoBoffset]
85
+ end
86
+
87
+ private_class_method :linear, :soft_clamped, :dark_on_light, :light_on_dark
88
+
89
+ # Added to Tincture::Color.
90
+ module ColorMethods
91
+ # APCA lightness contrast (Lc) of this colour as text on `background`.
92
+ # Positive for dark text on light, negative for light on dark.
93
+ # Translucent text is blended onto the background first.
94
+ #
95
+ # **Licence restriction:** web content only, in support of WCAG. See
96
+ # Apca.
97
+ #
98
+ # Tincture::Color.parse("#888").apca_contrast("#fff") # => 63.06…
99
+ #
100
+ #: (String | Color background) -> Float
101
+ def apca_contrast(background)
102
+ background = Color.parse(background)
103
+ text = opaque? ? self : blended_over(background)
104
+
105
+ Apca.contrast(Apca.luminance(text.rgb), Apca.luminance(background.rgb))
106
+ end
107
+
108
+ private
109
+
110
+ def blended_over(background)
111
+ Color.rgb(*rgb.zip(background.rgb).map { |mine, theirs| (theirs * (1 - alpha)) + (mine * alpha) })
112
+ end
113
+ end
114
+ end
115
+
116
+ Color.include(Apca::ColorMethods)
117
+ Color.contrast_scorers[:apca] = ->(text, background) { text.apca_contrast(background).abs }
118
+ end
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tincture-apca
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Andy Croll
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: tincture
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '1.0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '1.0'
26
+ description: Adds APCA lightness contrast (Lc) to Tincture::Color, ported from apca-w3.
27
+ Its licence restricts use to web content in support of WCAG.
28
+ email:
29
+ - andy@goodscary.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - CHANGELOG.md
35
+ - LICENSE.md
36
+ - README.md
37
+ - lib/tincture/apca.rb
38
+ - lib/tincture/apca/version.rb
39
+ homepage: https://github.com/andycroll/tincture-apca
40
+ licenses:
41
+ - LicenseRef-apca-w3
42
+ metadata:
43
+ source_code_uri: https://github.com/andycroll/tincture-apca
44
+ changelog_uri: https://github.com/andycroll/tincture-apca/blob/main/CHANGELOG.md
45
+ rubygems_mfa_required: 'true'
46
+ rdoc_options: []
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: '3.4'
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ requirements: []
60
+ rubygems_version: 4.0.20
61
+ specification_version: 4
62
+ summary: APCA contrast for Tincture colours, for WCAG web content only
63
+ test_files: []