File Coverage

lib/Data/Displaycolour.pm
Criterion Covered Total %
statement 137 234 58.5
branch 43 116 37.0
condition 13 72 18.0
subroutine 17 20 85.0
pod 7 7 100.0
total 217 449 48.3


line stmt bran cond sub pod time code
1             # Copyright (c) 2025 Philipp Schafft
2              
3             # licensed under Artistic License 2.0 (see LICENSE file)
4              
5             # ABSTRACT: Work with display colours
6              
7             package Data::Displaycolour;
8              
9 2     2   739517 use v5.20;
  2         10  
10 2     2   12 use strict;
  2         4  
  2         92  
11 2     2   12 use warnings;
  2         9  
  2         145  
12              
13 2     2   13 use Carp;
  2         45  
  2         212  
14              
15 2     2   1880 use Data::Identifier;
  2         465347  
  2         29  
16 2     2   1906 use Data::URIID;
  2         564692  
  2         166  
17 2     2   24 use Data::URIID::Colour;
  2         6  
  2         84  
18              
19 2     2   14 use parent qw(Data::Identifier::Interface::Userdata Data::Identifier::Interface::Subobjects Data::Identifier::Interface::Known);
  2         8  
  2         36  
20              
21             our $VERSION = v0.05;
22              
23             my %_abstract_names_to_ise = (
24             black => 'fade296d-c34f-4ded-abd5-d9adaf37c284',
25             white => '1a2c23fa-2321-47ce-bf4f-5f08934502de',
26             red => 'c9ec3bea-558e-4992-9b76-91f128b6cf29',
27             green => 'c0e957d0-b5cf-4e53-8e8a-ff0f5f2f3f03',
28             blue => '3dcef9a3-2ecc-482d-a98b-afffbc2f64b9',
29             cyan => 'abcbf48d-c302-4be1-8c5c-a8de4471bcbb',
30             magenta => 'a30d070d-9909-40d4-a33a-474c89e5cd45',
31             yellow => '2892c143-2ae7-48f1-95f4-279e059e7fc3',
32             grey => 'f9bb5cd8-d8e6-4f29-805f-cc6f2b74802d',
33             orange => '5c41829f-5062-4868-9c31-2ec98414c53d',
34             savannah => 'c90acb33-b8ea-4f55-bd86-beb7fa5cf80a',
35             );
36             my %_abstract_ise_to_name = map {$_abstract_names_to_ise{$_} => $_} keys %_abstract_names_to_ise;
37             my %_abstract_rgb_to_name = (
38             # this is filled later using palette data, so we only do corner cases here:
39             );
40              
41             my $_default_text_ops = [qw(trim fc)];
42             my %_text_types = (
43             name => $_default_text_ops,
44             username => $_default_text_ops,
45             displayname => $_default_text_ops,
46             text => $_default_text_ops,
47             email => $_default_text_ops,
48             _ise => [],
49             );
50              
51             my %_default_colours = (
52             black => '#000000',
53             white => '#ffffff',
54             red => '#ff0000',
55             green => '#008000',
56             blue => '#0000ff',
57             cyan => '#00ffff',
58             magenta => '#ff00ff',
59             yellow => '#ffff00',
60             grey => '#808080',
61             orange => '#ff8000',
62             savannah => '#decc9c',
63             );
64              
65             my %_palette = (
66             fallbacks => {%_default_colours},
67             v0 => {
68             black => '#2E3436',
69             white => '#EEEEEC',
70             red => '#EF2929',
71             green => '#8AE234',
72             blue => '#729FCF',
73             cyan => '#6BE5E5',
74             magenta => '#AD7FA8',
75             yellow => '#FCE94F',
76             grey => '#888A85',
77             orange => '#FCAF3E',
78             savannah => '#E9B96E',
79             },
80             vga => {
81             black => '#000000',
82             white => '#FFFFFF',
83             red => '#FF0000',
84             green => '#008000',
85             blue => '#0000FF',
86             cyan => '#00FFFF',
87             magenta => '#FF00FF',
88             yellow => '#FFFF00',
89             grey => '#808080',
90             _other => ['#800000', '#808000', '#000080', '#800080', '#008080', '#C0C0C0', '#00FF00'],
91             },
92             girlsandboys => {
93             blue => '#729FCF',
94             magenta => '#FF65C1',
95             },
96             roaraudio => {
97             _other => ['#ffbb55', '#cd6648'],
98             },
99             fun => {
100             blue => '#3465a4',
101             green => '#069a2e',
102             red => '#ce181e',
103             magenta => '#EE82EE',
104             _other => ['#04617b'],
105             },
106             neko_v0 => {
107             black => '#000000',
108             blue => '#0000ff',
109             green => '#00ff00',
110             cyan => '#00ffff',
111             red => '#ff0000',
112             magenta => '#ff00ff',
113             yellow => '#ffff00',
114             white => '#ffffff',
115             orange => '#ff8000',
116             grey => '#808080',
117             _other => ['#a52a2a'],
118             },
119             mirc_base => {
120             white => '#ffffff',
121             black => '#000000',
122             red => '#ff0000',
123             blue => '#00007f',
124             green => '#009300',
125             yellow => '#ffff00',
126             cyan => '#009393',
127             magenta => '#ff00ff',
128             orange => '#fc7f00',
129             grey => '#7f7f7f',
130             _other => ['#ff0000', '#7f0000', '#9c009c', '#00fc00', '#00ffff', '#0000fc', '#ff00ff', '#d2d2d2']
131             },
132             websafe => {
133             black => '#000000',
134             white => '#ffffff',
135             red => '#ff0000',
136             green => '#00FF00',
137             blue => '#0000ff',
138             cyan => '#00ffff',
139             magenta => '#ff00ff',
140             yellow => '#ffff00',
141             grey => '#999999',
142             orange => '#ff9000',
143             },
144             haiku_hrev58909_light => {
145             black => '#000000',
146             white => '#ffffff',
147             red => '#ff4136',
148             green => '#2ecc40',
149             blue => '#0000e5',
150             magenta => '#91709b',
151             grey => '#999999',
152             orange => '#ffcb00',
153             _other => ['#1b528c', '#3296ff', '#336698', '#3366bb', '#505050', '#6698cb', '#798ecb', '#acacac', '#bebebe', '#d8d8d8', '#e0e0e0', '#e8e8e8', '#f5f5f5', '#ffffd8'],
154             },
155             haiku_hrev58909_dark => {
156             black => '#000000',
157             white => '#ffffff',
158             red => '#ff2836',
159             green => '#2ecc40',
160             blue => '#0000e5',
161             magenta => '#91709b',
162             grey => '#c3c3c3',
163             orange => '#e34911',
164             _other => ['#1b528c', '#1c1c1c', '#1d1d1d', '#272727', '#2b2b2b', '#3296ff', '#336698', '#4b7ca8', '#4c444f', '#5a5a5a', '#6698cb', '#6a70d4', '#798ecb', '#cb2009', '#e6e6e6', '#eaeaea', '#fdfdfd'],
165             },
166             wfw_default => {
167             black => '#000000',
168             white => '#ffffff',
169             blue => '#000080',
170             grey => '#c0c0c0',
171             _other => ['#808080'],
172             },
173             vic2 => {
174             black => '#000000',
175             white => '#FFFFFF',
176             red => '#813338',
177             cyan => '#75CEC8',
178             magenta => '#8E3C97',
179             green => '#56AC4D',
180             blue => '#2E2C9B',
181             yellow => '#EDF171',
182             orange => '#8E5029',
183             gray => '#B2B2B2',
184             _other => ['#C46C71', '#4A4A4A', '#7B7B7B', '#A9FF9F', '#706DEB', '#553800'],
185             },
186             );
187              
188             {
189             my @colours;
190             my %got = map {$_ => 1} values %{$_palette{websafe}};
191             $_palette{websafe}{_other} = \@colours;
192             for (my $r = 0x00; $r <= 0xFF; $r += 0x33) {
193             for (my $g = 0x00; $g <= 0xFF; $g += 0x33) {
194             for (my $b = 0x00; $b <= 0xFF; $b += 0x33) {
195             my $c = sprintf('#%02x%02x%02x', $r, $g, $b);
196             next if $got{$c};
197             push(@colours, $c);
198             }
199             }
200             }
201             }
202              
203             foreach my $palette (values %_palette) {
204             my $other = $palette->{_other} // [];
205              
206             $other = [split/\s+/, $other] unless ref $other;
207              
208             $palette->{_all} = [(grep {defined} map {$palette->{$_}} sort keys %_default_colours), @{$other}];
209             }
210              
211             foreach my $palette (values(%_palette), \%_default_colours) {
212             foreach my $key (grep {!/^_/} keys %{$palette}) {
213             $_abstract_rgb_to_name{fc $palette->{$key}} = $key;
214             }
215             }
216              
217              
218              
219             sub new {
220 1     1 1 743 my ($pkg, %opts) = @_;
221 1         3 my $self = bless {}, $pkg;
222              
223 1 50       7 if (defined(my $so = delete $opts{subobjects})) {
224 0         0 $self->so_attach(%{$so});
  0         0  
225             }
226              
227             {
228 1   50     2 my $palette = delete($opts{palette}) // 'v0';
  1         6  
229              
230 1 50 33     6 if (ref($palette) eq 'ARRAY' && scalar(@{$palette}) >= 1) {
  0         0  
231 0 0       0 $palette = [map {ref ? Data::URIID::Colour->new(from => $_)->rgb : $_} @{$palette}];
  0         0  
  0         0  
232             my $p = $self->{palette} = {
233 0         0 _all => $palette,
234             };
235 0         0 foreach my $colour (@{$palette}) {
  0         0  
236 0 0       0 if (defined(my $name = $_abstract_rgb_to_name{fc($colour)})) {
237 0   0     0 $p->{$name} //= $colour;
238             }
239             }
240             } else {
241 1   33     11 $self->{palette} = $_palette{$palette} // croak 'Invalid palette: '.$palette;
242             }
243             }
244              
245 1 50 33     8 if (!defined($self->{origin}) && defined(my $for = delete $opts{for})) {
246 0         0 my $id = eval {Data::Identifier->new(from => $for)};
  0         0  
247 0 0 0     0 if (defined $_abstract_ise_to_name{eval {$id->ise} // ''}) {
  0 0       0  
248 0   0     0 $opts{from} //= $for;
249             } elsif ($for->isa('Data::URIID::Result')) {
250 0         0 eval {$self->so_attach(extractor => $for->extractor)};
  0         0  
251 0   0     0 $self->{origin} //= $for->attribute('displaycolour', as => 'Data::URIID::Colour', default => undef);
252 0   0     0 $opts{for__ise} //= $for->ise(default => undef);
253             } else {
254 0         0 my Data::URIID $extractor = $self->extractor;
255 0         0 my Data::URIID::Result $result = $extractor->lookup($for);
256              
257 0   0     0 $self->{origin} //= $result->attribute('displaycolour', as => 'Data::URIID::Colour', default => undef);
258 0   0     0 $opts{for__ise} //= $for->ise(default => undef);
259             }
260              
261 0 0 0     0 $opts{for_displayname} //= $id->displayname(default => undef, no_defaults => 1) if defined $id;
262             }
263              
264              
265 1         5 foreach my $key (keys %_text_types) {
266 6 100       16 if (defined(my $for = $opts{'for_'.$key})) {
267 1         2 foreach my $step (@{$_text_types{$key}}) {
  1         3  
268 2 100       8 if ($step eq 'fc') {
    50          
269 1         4 $for = fc($for);
270             } elsif ($step eq 'trim') {
271 1         7 $for =~ s/^\s+//;
272 1         4 $for =~ s/\s+$//;
273 1         2 $for =~ s/\s+/ /;
274             } else {
275 0         0 croak 'BUG';
276             }
277             }
278              
279 1 50       4 $opts{'for_'.$key} = length($for) ? $for : undef;
280             }
281             }
282              
283 1         5 foreach my $key (keys %_text_types) {
284 6 100       15 if (defined(my $for_text = $opts{'for_'.$key})) {
285 1         6 foreach my $for (split(/[\s\x20-\x2F\x5B-\x60\x7B-\x7F]+/, $for_text)) {
286 1         751 require Data::Displaycolour::Data;
287              
288 1         19 my %langs = %Data::Displaycolour::Data::_langs;
289 1         4 my @langs;
290             my %found;
291              
292 1 50       8 if (defined(my $list = delete $opts{language})) {
293 0         0 my $n = 0;
294 0         0 %langs = ();
295 0 0       0 $list = [split/\s*,\s*|\s+/, $list] unless ref $list;
296 0         0 $langs{$_} = $n++ foreach reverse @{$list};
  0         0  
297             }
298              
299 1 50       5 if (defined(my $list = delete $opts{preferred_language})) {
300 0         0 my $n = $Data::Displaycolour::Data::_lang_value;
301 0 0       0 $list = [split/\s*,\s*|\s+/, $list] unless ref $list;
302 0         0 $langs{$_} = $n++ foreach reverse @{$list};
  0         0  
303             }
304              
305 1 50       4 if (defined(my $list = delete $opts{blacklist_language})) {
306 0 0       0 $list = [split/\s*,\s*|\s+/, $list] unless ref $list;
307 0         0 delete $langs{$_} foreach @{$list};
  0         0  
308             }
309              
310 1         11 @langs = sort {$langs{$b} <=> $langs{$a}} keys %langs;
  101         170  
311              
312             outer:
313 1         6 foreach my $lang (@langs) {
314 28         56 my $l = $Data::Displaycolour::Data::_extra{$lang};
315 28         45 foreach my $name (@{$l->{__order__}}) {
  28         73  
316 113         174 my $v = _match_with_quality($for, $name);
317 113 50       259 $found{$l->{$name}} += $v if $v;
318             }
319              
320 28         12527 $l = $Data::Displaycolour::Data::_names{$lang};
321 28         38 foreach my $name (@{$l->{__order__}}) {
  28         78  
322 408         611 my $v = _match_with_quality($for, $name);
323 408 100       919 $found{$l->{$name}} += $v if $v;
324             }
325             }
326              
327             {
328 1         3 my $best_v = 0;
  1         3  
329 1         3 my $best;
330              
331 1         5 foreach my $key (keys %found) {
332 1         4 my $v = $found{$key};
333 1 50       6 if ($v > $best_v) {
334 1         17 $best = $key;
335 1         5 $best_v = $v;
336             }
337             }
338              
339 1 50 33     40 $opts{from} //= $_abstract_names_to_ise{$best} if defined $best;
340             }
341             }
342             }
343              
344 6 100       17 next if defined $opts{from};
345             }
346              
347 1 50 33     23 unless (delete($opts{no_defaults}) || defined $opts{from}) {
348 0         0 foreach my $key (keys %_text_types) {
349 0 0       0 if (defined(my $for = $opts{'for_'.$key})) {
350 0 0       0 unless (defined $self->{origin}) {
351 0         0 require Digest;
352 0         0 my $v = unpack('L', Digest->new('SHA-1')->add($key)->add(':')->add($for)->digest) & 0xFFFFFF;
353 0         0 my $palette = $self->{palette}{_all};
354 0         0 $v = $palette->[$v % scalar(@{$palette})];
  0         0  
355 0         0 $self->{specific} = $self->{origin} = Data::URIID::Colour->new(rgb => $v);
356             }
357             }
358             }
359             }
360              
361             # Delete keys after we used them.
362 1         6 foreach my $key (keys %_text_types) {
363 6         15 delete $opts{'for_'.$key};
364             }
365              
366 1 50       7 if (defined(my $from = delete $opts{from})) {
367 1         2 my $id;
368             my $ise;
369              
370 1         4 eval {
371 1         27 $id = Data::Identifier->new(from => $from);
372 1         154 $ise = $id->ise;
373             };
374              
375 1 50       25 if (defined $ise) {
376 1 50       7 if (defined(my $name = $_abstract_ise_to_name{$ise})) {
377 1         4 $self->{origin} = $from;
378 1         3 $self->{abstract} = $id;
379             }
380             }
381              
382 1 50       6 unless (defined $self->{origin}) {
383 0         0 $self->{origin} = Data::URIID::Colour->new(from => $from); # force a valid object.
384             }
385             }
386              
387 1 50       6 croak 'Stray options passed' if scalar keys %opts;
388              
389 1         9 return $self;
390             }
391              
392              
393             sub origin {
394 1     1 1 4 my ($self, @args) = @_;
395 1         15 return $self->_colour_getter(origin => @args);
396             }
397              
398              
399             sub abstract {
400 2     2 1 3502 my ($self, @args) = @_;
401 2         11 return $self->_colour_getter(abstract => @args);
402             }
403              
404              
405             sub specific {
406 3     3 1 1582 my ($self, @args) = @_;
407 3         10 return $self->_colour_getter(specific => @args);
408             }
409              
410              
411             sub rgb {
412 1     1 1 937 my ($self, %opts) = @_;
413 1         3 my $no_defaults = delete $opts{no_defaults};
414 1         3 my $exists_default = exists $opts{default};
415 1         3 my $value_default = delete $opts{default};
416 1         1 my $v;
417              
418 1 50       6 croak 'Stray options passed' if scalar keys %opts;
419              
420 1   33     7 $v //= eval { $self->origin( 'Data::URIID::Colour', no_defaults => 1, default => undef) };
  1         6  
421 1   33     8 $v //= eval { $self->specific('Data::URIID::Colour', no_defaults => 1, default => undef) };
  1         5  
422 1   33     40 $v //= eval { $self->abstract('Data::URIID::Colour', no_defaults => 1, default => undef) };
  0         0  
423              
424 1 0 33     5 if (!defined($v) && !$no_defaults) {
425 0   0     0 $v //= eval { $self->origin( 'Data::URIID::Colour', no_defaults => 0, default => undef) };
  0         0  
426 0   0     0 $v //= eval { $self->specific('Data::URIID::Colour', no_defaults => 0, default => undef) };
  0         0  
427 0   0     0 $v //= eval { $self->abstract('Data::URIID::Colour', no_defaults => 0, default => undef) };
  0         0  
428             }
429              
430 1 50       7 return $v->rgb if defined $v;
431              
432 0 0       0 return $value_default if $exists_default;
433 0         0 croak 'No value found';
434             }
435              
436              
437             sub list_colours {
438 0     0 1 0 my ($pkg, $palette) = @_;
439 0         0 my %res;
440              
441 0   0     0 $palette = $_palette{$palette} // croak 'Unknown palette: '.$palette;
442              
443 0         0 %res = map {fc($_) => undef} @{$palette->{_all}};
  0         0  
  0         0  
444              
445 0         0 foreach my $name (keys %_abstract_names_to_ise) {
446 0 0       0 if (defined(my $c = $palette->{$name})) {
447 0         0 $res{fc $c} = Data::Identifier->new(ise => $_abstract_names_to_ise{$name}, displayname => $name);
448             }
449             }
450              
451 0         0 return \%res;
452             }
453              
454             # ---- Private helpers ----
455              
456             sub _colour_getter {
457 6     6   24 my ($self, $key, $as, %opts) = @_;
458 6         12 my $no_defaults = delete $opts{no_defaults};
459 6         12 my $exists_default = exists $opts{default};
460 6         13 my $value_default = delete $opts{default};
461              
462 6 50       84 croak 'Stray options passed' if scalar keys %opts;
463              
464 6   50     21 $as //= 'Data::URIID::Colour';
465              
466 6 100       17 unless (exists $self->{$key}) {
467 1         3 $self->{$key} = undef; # break out of deep recursion.
468 1 50       12 if (defined(my $func = $self->can('_load_'.$key))) {
469 1         4 $self->{$key} = eval { $self->$func() };
  1         6  
470             }
471             }
472              
473 6 50       58 if (defined(my $val = $self->{$key})) {
474 6         18 return $val->as($as, extractor => $self->extractor);
475             }
476              
477 0 0       0 return $value_default if $exists_default;
478 0         0 croak 'No value found';
479             }
480              
481             #@returns Data::URIID
482             sub extractor {
483 6     6 1 12 my ($self) = @_;
484 6         44 my Data::URIID $extractor = $self->so_get('extractor', default => undef);
485              
486 6 100       133 return $extractor if defined $extractor;
487              
488 1         10 $extractor = Data::URIID->new;
489              
490 1         26 $self->so_attach(extractor => $extractor);
491              
492 1         122 return $extractor;
493             }
494              
495             # ---- Private loaders ----
496              
497             sub _match_with_quality {
498 521     521   5238 my ($haystack, $needle) = @_;
499 521         10646 my ($pre, $post) = $haystack =~ /^(.*)\Q$needle\E(.*)\z/;
500              
501 521 100 66     1533 return 0 unless defined($pre) && defined($post);
502 1 50       7 return 1 - (length($pre) ? 0.4 : 0) - (length($post) ? 0.4 : 0);
    50          
503 0         0 return 0;
504             }
505              
506             sub _load_abstract {
507 0     0   0 my ($self) = @_;
508 0         0 my $rgb = $self->rgb(default => undef);
509              
510 0 0 0     0 if (defined($rgb) && defined(my $name = $_abstract_rgb_to_name{fc($rgb)})) {
511 0 0       0 if (defined(my $ise = $_abstract_names_to_ise{$name})) {
512 0         0 return Data::Identifier->new(ise => $ise, displayname => $name);
513             }
514             }
515              
516 0         0 return undef;
517             }
518              
519             sub _load_specific {
520 1     1   4 my ($self) = @_;
521 1         4 my $abstract = $self->abstract('Data::Identifier');
522              
523 1 50       40 if (defined(my $ise = $abstract->ise(default => undef))) {
524 1 50       30 if (defined(my $name = $_abstract_ise_to_name{$ise})) {
525 1         2 my $c;
526              
527 1 50       9 if (defined($c = $self->{palette}{$name})) {
    0          
528 1         15 return Data::URIID::Colour->new(rgb => $c);
529             } elsif (defined($c = $_default_colours{$name})) {
530 0           return Data::URIID::Colour->new(rgb => $c);
531             }
532             }
533             }
534              
535 0           return $self->extractor->lookup($abstract)->attribute('displaycolour', as => 'Data::URIID::Colour');
536             }
537              
538             # ---- Private helpers for Data::Identifier::Interface::Known ----
539              
540              
541             sub _known_provider {
542 0     0     my ($pkg, $class, %opts) = @_;
543 0 0         croak 'Unsupported options passed' if scalar(keys %opts);
544              
545 0 0         if ($class eq 'abstract-colours') {
    0          
    0          
    0          
546 0           return ([keys %_abstract_ise_to_name], rawtype => 'ise');
547             } elsif ($class eq 'specific-colours') {
548 0           my %rgb;
549              
550 0           foreach my $palette (values %_palette) {
551 0           foreach my $value (values %{$palette}) {
  0            
552 0 0         if (ref $value) {
553 0           $rgb{$_} = undef foreach @{$value};
  0            
554             } else {
555 0           $rgb{$value} = undef;
556             }
557             }
558             }
559              
560 0           return ([map {Data::URIID::Colour->new(rgb => $_)} keys %rgb], rawtype => 'Data::URIID::Colour');
  0            
561             } elsif ($class eq 'palettes') {
562 0           return ([keys %_palette], not_identifiers => 1);
563             } elsif ($class eq ':all') {
564             return ([
565 0           @{(__SUB__->($pkg, 'specific-colours', %opts))[0]},
566             keys(%_palette),
567 0           (map {Data::Identifier->new(ise => $_)} keys %_abstract_ise_to_name),
  0            
568             ], not_identifiers => 1);
569             }
570              
571 0           croak 'Unsupported class';
572             }
573              
574             1;
575              
576             __END__
577              
578             =pod
579              
580             =encoding UTF-8
581              
582             =head1 NAME
583              
584             Data::Displaycolour - Work with display colours
585              
586             =head1 VERSION
587              
588             version v0.05
589              
590             =head1 SYNOPSIS
591              
592             use Data::Displaycolour;
593              
594             my Data::Displaycolour $dp = Data::Displaycolour->new(...);
595              
596             say $dp->rgb;
597              
598             This module supports working with display colours for arbitrary subjects.
599              
600             B<Note:>
601             This package is still a bit experimental.
602             While the API should be stable for use, the results may change over the next releases
603             as palette and matching code updates will take place.
604              
605             This package inherits from L<Data::Identifier::Interface::Userdata>, and L<Data::Identifier::Interface::Subobjects>, and
606             L<Data::Identifier::Interface::Known>.
607              
608             =head1 METHODS
609              
610             =head2 new
611              
612             my Data::Displaycolour $dc = Data::Displaycolour->new(%opts);
613              
614             Creates a new displaycolour object.
615              
616             The following options are supported:
617              
618             =over
619              
620             =item C<for>
621              
622             A blessed reference that represents the object we want the display colour for.
623             This might be anything L<Data::URIID/lookup> accepts as input.
624             (If it is a URI it must be a L<URI> object or similar.)
625              
626             =item C<for_displayname>
627              
628             A displayname for which a colour should be found.
629              
630             =item C<for_email>
631              
632             An e-mail address (without the name) for which a colour should be found.
633              
634             =item C<for_name>
635              
636             An name (such as a legal name) for which a colour should be found.
637              
638             =item C<for_text>
639              
640             Some portion of text (normally one sentence to a full paragraph) for which a colour should be found.
641              
642             =item C<for_username>
643              
644             Some username for which a colour should be found.
645              
646             =item C<from>
647              
648             A colour value this object should be constructed from.
649             This might be anything L<Data::URIID::Colour/new> accespts via C<from>.
650             Please also keep the notes in the documentation for that method in mind.
651              
652             =item C<palette>
653              
654             The palette to use. If this is a scalar it is the name of the palette.
655             If an array reference it must be a list of C<#rrggbb> values.
656             In this case the colours are matched to the abstract colours if possible,
657             with the default values used what what cannot be matched.
658             Other types of values might be supported.
659             Newer versions of this module might support more palette types.
660              
661             =item C<language>
662              
663             A language or list (arrayref or comma/space separated list) of languages as language tags (in order of preference) to use for lookups.
664              
665             Lookups will only performed with the listed languages.
666              
667             Defaults to a build in list.
668              
669             =item C<preferred_language>
670              
671             A list of langauges that are preferred. This will however not remove any languages from the list.
672              
673             The format is the same as for L</language>.
674              
675             Defaults to an empty list.
676              
677             B<Note:>
678             It is not defined what happens if both this and L</language> is given.
679              
680             =item C<blacklist_language>
681              
682             A list of languages that are never tried for lookups.
683              
684             The format is the same as for L</language>.
685              
686             Defaults to an empty list.
687              
688             B<Note:>
689             It is safe to combine with option with any other option.
690             If a language is specifically asked for and blacklisted, the blacklist wins.
691              
692             =item C<no_defaults>
693              
694             Do not try to use calculate fallback colours if no colour could be detected.
695              
696             =item C<subobjects>
697              
698             A unblessed hashref that is passed to L<Data::Identifier::Interface::Subobjects/so_attach>.
699              
700             =back
701              
702             =head2 origin
703              
704             my Data::URIID::Colour $origin = $dc->origin;
705             # or:
706             my $origin = $dc->origin($as [, %opts ] );
707              
708             Returns the origin colour of this object.
709             This value might be an abstract or specific colour and might or might not be set.
710              
711             If there is any problem or error this method C<die>s.
712              
713             C<$as> is to be understood the same way as in L<Data::Identifier/as>.
714             If not given, L<Data::URIID::Colour> is assumed.
715              
716             The following options are supported:
717              
718             =over
719              
720             =item C<default>
721              
722             The default value to return if no value is known.
723             When set to C<undef> this can be used to switch this method to returning C<undef> (not C<die>) in case no value is known.
724              
725             =item C<no_defaults>
726              
727             If a true value disables looking up a value based on other values.
728              
729             =back
730              
731             =head2 abstract
732              
733             my $abstract = $dc->abstract( [ $as [, %opst] ] );
734              
735             This method returns the abstract colour.
736             It works the same as L</origin> and takes the same arguments.
737              
738             =head2 specific
739              
740             my $specific = $dc->specific( [ $as [, %opst] ] );
741              
742             This method returns the specific colour.
743             It works the same as L</origin> and takes the same arguments.
744              
745             =head2 rgb
746              
747             my $rgb = $dc->rgb( [ %opts ] );
748              
749             Returns a single RGB value as per L<Data::URIID::Colour/rgb>.
750              
751             Takes the same options as L</origin>.
752              
753             =head2 list_colours
754              
755             my $colours = Data::Displaycolour->list_colours($palette_name);
756              
757             Returns a hashref with the keys being RGB (C<#rrggbb>) colour values of all colours present in the palette (fallbacks are not listed).
758             The values are a L<Data::Identifier> of the abstract colour this value represents (if any) or C<undef>.
759              
760             For discovery of known palettes see L</known>.
761              
762             =head2 known
763              
764             my @list = Data::Displaycolour->known($class [, %opts ] );
765              
766             Returns a list of well known items. See L<Data::Identifier::Interface::Known/known> for details.
767              
768             The following classes are supported:
769              
770             =over
771              
772             =item C<abstract-colours>
773              
774             The list of abstract colours known by this module.
775              
776             =item C<specific-colours>
777              
778             The list of specific colours known by this module for all palettes.
779              
780             See also:
781             L</list_colours>.
782              
783             =item C<palettes>
784              
785             The list of palettes known by this module. See L</new>.
786              
787             =back
788              
789             =head1 AUTHOR
790              
791             Philipp Schafft <lion@cpan.org>
792              
793             =head1 COPYRIGHT AND LICENSE
794              
795             This software is Copyright (c) 2025 by Philipp Schafft <lion@cpan.org>.
796              
797             This is free software, licensed under:
798              
799             The Artistic License 2.0 (GPL Compatible)
800              
801             =cut