Perceptual Color

doxygen.cpp
1// SPDX-FileCopyrightText: Lukas Sommer <sommerluk@gmail.com>
2// SPDX-License-Identifier: BSD-2-Clause OR MIT
3
4// This file contains the following documentation:
5// – All the @page documentation. Putting all @page documentation in this
6// single file allows that they show up in the documentation in
7// alphabetical order.
8// – The namespace documentation
9
10/** @page build Build instructions and requirements
11 *
12 * Build-time dependencies:
13 * - LittleCMS 2 (minimum version: 2.0)
14 * - Qt 5 (minimum version: 5.15) <!-- Qt 5.15 has an API that is close
15 * to Qt 6. It introduces some new functions we are using to avoid
16 * deprecated older functions. --> or Qt 6 (minimum version: 6.0.0).
17 Components: Core, Gui, Widgets, DBus, Concurrent, Test, Svg.
18 * - CMake
19 * - ECM (Extra CMake Modules from KDE)
20 * - C++17
21 * - Both, the input character set and the execution character set, have
22 * to be UTF8. (See @ref compilercharacterset for more details.)
23 * <!--
24 * Qt 5.6 (which is the minimum Qt version required
25 * by this library) only requires C++03. Only starting
26 * with Qt 5.7, Qt itself requires C++11. Source:
27 * https://doc.qt.io/qt-5.9/cmake-manual.html#using-qt-5-with-cmake-older-than-3-1-0
28 *
29 * Qt 6 requires minimum C++17, as
30 * https://doc-snapshots.qt.io/qt6-dev/cmake-get-started.html
31 * explains.
32 *
33 * Our library code uses C++11 features, for example “constexpr”.
34 *
35 * In the CMakeLists.txt file, we set -std=c++17 and we set
36 * also -Wpedantic and -pedantic-errors to enforce it. That is
37 * a useful option for this library if we decide to make it Qt-6-only.
38 * But it is even be useful if we support Qt 5, so we have future-proof
39 * requirements that we do not have to raise soon, and that are a
40 * good base for LTS.
41 * -->
42 * - Optional: There is also a LittleCMS plugin called
43 * <em>fast_float plug-in</em> that you can include into the
44 * source code of your application and load it in your main function
45 * before using this library. This can make color management faster.
46 * (Note that this plugin has a different license than LittleCMS itself.)
47 *
48 * Additional mandatory run-time dependencies:
49 * - QSvgIconEnginePlugin. Available plugins are loaded
50 * automatically by Qt. Therefore, just make sure that this plugin is
51 * present. On Linux, it seems possible to enforce this by linking
52 * dynamically to the plugin itself, if you want to. This forces Linux
53 * package managers to produce packages of your application that depend
54 * not only on Qt base, but also on the SVG plugin. A typical file name of
55 * the plugin is <tt>plugins/iconengines/libqsvgicon.so</tt>.
56 *
57 * Please make sure that you comply with the licences of used libraries.
58 *
59 * To prepare the build, run cmake. We provide plenty of CMake options
60 * that control the build type (shared/dynamic vs. static), IPO/LPO and
61 * much more. The options are self-documenting. When you run CMake,
62 * the options are listed with their values and a description of them.
63 *
64 * Then, to build and install the library:
65 * @code{.unparsed}
66 * make && sudo make install
67 * @endcode
68 *
69 * To do unit testing:
70 * @code{.unparsed}
71 * make build_test test
72 * @endcode */
73
74/** @internal
75 *
76 * @page codingstyle Coding style
77 *
78 * Always document your code.
79 *
80 * @section codingstylecpp C++
81 *
82 * - Provide unit tests for your code.
83 * - If working with children within Qt’s object hierarchy, allocate on the
84 * heap and use raw pointers or guarded pointers (`QPointer`). If not,
85 * allocate on the stack or use smart pointers. Prefer Qt’s smart pointers
86 * over the <tt>std</tt> smart pointers of C++.
87 * - Use KDE’s
88 * <a href="https://community.kde.org/Policies/Frameworks_Coding_Style">
89 * Frameworks Coding Style</a>. This can be done automatically with
90 * clang-format.
91 * - Comments within the code should have this form: <tt>// comment</tt>
92 * <br/> This allows to comment out quickly large parts of the code for
93 * testing purposes.
94 * - Comments for Doxygen should have this form: <tt>/⁠** Comment *⁠/</tt>
95 *
96 * @section codingstylecmake CMake
97 *
98 * @subsection codingstylecmakeusefuldocumentation Useful documentation
99 *
100 * - <a href="https://preshing.com/20170522/learn-cmakes-scripting-language-in-15-minutes/">
101 * Introduction to the CMake script language</a>
102 * - <a href="https://github.com/onqtam/awesome-cmake">
103 * Curated list of awesome CMake scripts, modules, examples and others</a>
104 * - <a href="https://llvm.org/docs/CMakePrimer.html">General introduction
105 * into CMake (both, the script language and the commands)</a>
106 *
107 * @subsection codingstylecmakemodern Use “Modern CMake”
108 *
109 * Use <em>Modern CMake</em>: Avoid global settings like
110 * <tt>include_directories()</tt>. Use target-based commands like
111 * <tt>target_include_directories()</tt> instead. Use
112 * <tt>target_link_libraries()</tt> to pull in dependencies, which gives you
113 * automatically the correct include directories, compile options etc.
114 * When using <tt>target_link_libraries()</tt>, always specify
115 * <tt>PUBLIC</tt> or <tt>PRIVATE</tt> or <tt>INTERFACE</tt> explicitly.
116 *
117 * @subsection codingstylecmakeindent Indent
118 *
119 * Use 4 spaces for indenting. Do not use tabs.
120 *
121 * @subsection codingstylecmakequotationmarks Quotation marks
122 *
123 * Use quotation marks when you want to represent a string.
124 * Do not use quotation marks when you mean a keyword. Example:
125 *
126 * @code{.unparsed}
127 * set(myvar "foo")
128 * @endcode
129 *
130 * Particularly, always quote strings within control structures:
131 *
132 * @code{.unparsed}
133 * if("${myvar}" STREQUAL "bar")
134 * @endcode
135 *
136 * @subsection codingstylecmakeboolean Boolean
137 *
138 * CMake allows various representations of boolean. Use only the forms
139 * <tt>TRUE</tt> and <tt>FALSE</tt>. Do not quote them.
140 *
141 * @subsection codingstylevariablecheck Check if a variable exists
142 *
143 * Check if a variable exists like this:
144 *
145 * @code{.unparsed}
146 * if(DEFINED varname)
147 * @endcode
148 *
149 * @subsection codingstylecmakenaming Naming
150 *
151 * Functions and macros:
152 *
153 * @code{.unparsed}
154 * lower_case()
155 * @endcode
156 *
157 * Control structures: <tt>lower_case()</tt>, with empty <tt>else()</tt>,
158 * <tt>endif()</tt>, <tt>endfunction()</tt>…
159 *
160 * Operators/keywords/directives/extra options: <tt>UPPER_CASE</tt> without
161 * quotes. Examples:
162 *
163 * @code{.unparsed}
164 * if(condition STREQUAL "")
165 * @endcode
166 *
167 * @code{.unparsed}
168 * do_something(... USE_THIS)
169 * @endcode
170 *
171 * @code{.unparsed}
172 * file(COPY ...)
173 * @endcode
174 *
175 * @subsection codingstyleparenthesis Parenthesis
176 *
177 * Multi-line calls have trailing parenthesis on the same line as
178 * last parameter, not on separate line:
179 *
180 * @code{.unparsed}
181 * set(my_variable
182 * "value1"
183 * "value2"
184 * "value3)
185 * @endcode
186 *
187 * @subsection codingstyleorder Order
188 *
189 * Source and header lists should be ordered alphabetically,
190 * subdirectories last, preferably separated by a single empty line.
191 *
192 * @subsection codingstylelinelength Line length
193 *
194 * Keep the length of the line below 80 characters when possible.
195 * No trailing whitespace.
196 *
197 * @subsection codingstyledirectories Directories
198 *
199 * A directory path may not have a trailing <tt>/</tt>. This is to avoid
200 * duplicates like <tt>//</tt> when composing paths:
201 *
202 * @code{.unparsed}
203 * set(my_path "/usr/bin/") # BAD
204 * set(my_path "/usr/bin") # GOOD
205 * set(my_file "${my_path}/my_file")
206 * @endcode
207 *
208 * @subsection codingstylelists Lists
209 *
210 * Declaring an empty list:
211 *
212 * @code{.unparsed}
213 * set(mylist)
214 * @endcode
215 *
216 * Declaring and initializing a list at the same time:
217 *
218 * @code{.unparsed}
219 * set(mylist
220 * "first item"
221 * "second item"
222 * "third item")
223 * @endcode
224 *
225 * Append to a list:
226 *
227 * @code{.unparsed}
228 * list(APPEND mylist "last item")
229 * @endcode
230 *
231 * @subsection codingstyleprojectname ${PROJECT_NAME}
232 *
233 * Use <tt>${PROJECT_NAME}</tt> for global variables, targets and labels
234 * instead of repeating the project name manually or using fixed names:
235 *
236 * @code{.unparsed}
237 * add_executable(${PROJECT_NAME} …)
238 * @endcode */
239
240/** @page compilercharacterset Compiler character sets
241 *
242 * @section compilercharacterset_ Compiler character sets
243 *
244 * Compilers have three different character sets:
245 * - Input character set (the character set of the source code)
246 * - Narrow execution character set
247 * (for <tt>char</tt> and for string literals without prefix)
248 * - Wide execution character set
249 * (for <tt>wchar_t</tt> and for string literals with <tt>L</tt> prefix)
250 *
251 * @subsection inputcharacterset Input character set
252 *
253 * This source code of this library is encoded in UTF8. Therefore, your
254 * compiler must treat is also as UTF-8.
255 *
256 * Why are we using UTF-8 instead of ASCII?
257 * - UTF-8 is more complete than ASCII. ASCII does not even provide basic
258 * typographic symbols like en-dash, em-dash or non-breaking space
259 * characters or quotes.
260 * - Unicode exists since 1991, UTF-8 since 1993. It’s time to get rid of
261 * the insufficient ASCII character. It’s time to use Unicode.
262 * - We use non-ASCII characters for (typographically
263 * correct) Doxygen documentation and partially also for non-Doxygen
264 * source code comments. It would be quite annoying to use HTML
265 * entities for each non-ASCII character in the Doxygen documentation;
266 * and it would be pointless to do it for non-Doxygen source code
267 * comments.
268 * - <tt>i18n()</tt> and <tt>ki18n()</tt> and <tt>tr()</tt> require both,
269 * the source file and <tt>char*</tt> to be encoded in UTF-8; no other
270 * encodings are supported. (Only ASCII would be UTF-8 compatible,
271 * but in practice this encoding is not supported, but only 8859-Latin
272 * encodings, which allow code points higher than 127, which risks to
273 * introduce incompatibilities. Therefore, this would not be a good
274 * option.)
275 * - The C++ identifiers of library symbols are however (currently)
276 * ASCII-only.
277 *
278 * So we use a <tt>static_assert</tt> statement to control this.
279 *
280 * @subsection narowexecutioncharacterset Narrow execution character set
281 *
282 * Why are we using UTF-8 as narrow execution character set?
283 * - <tt>i18n()</tt> and <tt>ki18n()</tt> and <tt>tr()</tt> require both,
284 * the source file and <tt>char*</tt> to be encoded in UTF-8; no other
285 * encodings are supported.
286 * - Implicit conversion from <tt>char*</tt> to <tt>QString</tt> assumes
287 * that <tt>char*</tt> is UTF-8 encoded. Thus we disable this implicit
288 * conversion in <tt>CMakeLists.txt</tt>, it’s wise to stay compatible.
289 *
290 * Therefore, a static assert controls that really UTF-8 is used
291 * as narrow execution character set.
292 *
293 * @subsection wideexecutioncharacterset Wide execution character set
294 *
295 * We do not use actively the wide execution character set. There is
296 * a usage when communicating with LittleCMS, but there we depend anyway
297 * from LittleCMS. Therefore, currently, no static assert forces a specific
298 * wide execution character set.
299 *
300 * @internal
301 *
302 * @note The static asserts that enforce the character sets are located
303 * in @ref staticasserts.cpp. */
304
305/** @internal
306 *
307 * @page datatypes Data types
308 *
309 * The library uses in general <tt>int</tt> for integer values, because
310 * <tt>QSize()</tt> and <tt>QPoint()</tt> also do. As the library relies
311 * heavily on the usage of <tt>QSize()</tt> and <tt>QPoint()</tt>, this
312 * seems reasonable.
313 *
314 * For the same reason, it uses generally <tt>qreal</tt>
315 * for floating point values, because <tt>QPointF()</tt> also does.
316 *
317 * Output colors that are shown on the screen, are usually 8-bit-per-channel
318 * colors. For internal transformation, usually <tt>qreal</tt>
319 * is used for each channel, giving a better precision and reducing rounding
320 * errors. */
321
322/** @internal
323 *
324 * @page generaltodolist General TODO list
325 *
326 * This is a TODO list that contains general ideas or issues of this
327 * library.
328 *
329 * @todo Use words as hints for color ranges? Muted/dull colors have a low
330 * chroma value. The dark ones (getrübte/gebrochene Farben) are created by
331 * adding black (and possibly a bit of white) and include warm tones (the
332 * browns) and cool tones (the olives). The light ones are called Pastel
333 * colors and are created by adding white (and possibly a bit of
334 * black) and include warm tones (like baby pink) and cool
335 * tones (like baby blue). Warm colors are located at a color angle of
336 * about 45°, cool colors at about 225°. Could we mark this in the diagrams?
337 * Cold and warm could be marked by a text outside the color wheel at the
338 * given position. The other ones seem to be more complicated: These specific
339 * color terms do not have a translation in all languages. (For “muted colors”,
340 * there is no good German translation, and for “getrübte Farben”, there is
341 * no good English translation.
342 *
343 * @todo A design question: Following KDE’s HIG, if the command requires
344 * additional user interaction to complete, at the end its label there
345 * should be an elipsis sfs (…). Currently, this only seems to apply
346 * to @ref PerceptualColor::ColorDialogPrivate::m_screenColorPickerButton.
347 *
348 * @todo https://invent.kde.org/plasma/kdeplasma-addons/-/merge_requests/249
349 * allows the user to drag and drop an image file. The image’s average color
350 * is calculated and set as current color of Plasma’s color picker widget.
351 * Furthermore, it seems that Plasma’s color picker widget also accepts
352 * color codes for drag-and-drop. (Which ones? Maybe the #128945 style?)
353 * Would this make sense also for our library?
354 *
355 * @todo ITUR profile: Minimum widget size must be smaller! On high sizes, the
356 * inner focus indicator of color wheel too narrow to hue circle.
357 * On RGB 255 0 0 no value indicator is visible. The high-chroma values
358 * are empty in the diagram!
359 *
360 * @todo Touch friendly: @ref PerceptualColor::ColorPatch,
361 * @ref PerceptualColor::GradientSlider etc. at least
362 * as thick as (normal) buttons. Qt6 replaces QTouchDevice by
363 * QInputDevice::devices()…
364 *
365 * @todo For all diagram images: No abort during first interlacing pass. (See
366 * @ref PerceptualColor::AsyncImageProvider for details.)
367 *
368 * @todo All scripts (both, local and CI scripts) should break and stop
369 * on every error. When implementing this, be beware of side effects
370 * (some local scripts are also called from the CI and so on…).
371 *
372 * @todo Review @ref PerceptualColor::RgbColorSpace. And change
373 * it in order to allow support for Oklab. And maybe Googles
374 * <a href="https://github.com/material-foundation/material-color-utilities">
375 * HTC</a>.
376 *
377 * @todo A design question: In the chroma-lightness diagram, the color
378 * wheel is a slider and reacts as such. However, in the chroma-hue-diagram,
379 * the same color wheel is just decoration (for orientation). Isn’t this
380 * different behaviour of two visually identical elements confusing?
381 *
382 * @todo A design question: Should we use
383 * <a href="https://doc.qt.io/qt-6/qt.html#CursorShape-enum">
384 * <tt>Qt::CrossCursor</tt></a> for two-dimensional selections like
385 * @ref PerceptualColor::ChromaHueDiagram? And should we use
386 * <a href="https://doc.qt.io/qt-6/qt.html#CursorShape-enum"><tt>
387 * Qt::UpArrowCursor</tt></a> for one-dimensional selections like
388 * @ref PerceptualColor::GradientSlider?
389 *
390 * @todo Remove things form the public API, leaving only the absolutely
391 * minimal API that is required by the user.
392 *
393 * @todo Avoid “final” in the public API (or even altogether?). Implement
394 * a codecheck for this.
395 *
396 * @todo <a href="https://valgrind.org/docs/manual/quick-start.html"> Test with
397 * valgrind.org</a>
398 *
399 * @todo Most widgets of this library allocate in each paint event a new
400 * buffer to paint on, before painting on the widget. This is also done
401 * because only <tt>QImage</tt> guarantees the same result on all platforms,
402 * while <tt>QPixmap</tt> is platform-dependent and Qt does not guarantee that
403 * for example <tt>QPainter::Antialiasing</tt> is available on all platforms.
404 * However, not using a buffer would save memory! Can we know if the current
405 * platform supports <tt>QPainter::Antialiasing</tt> and buffer only if
406 * necessary? Or could we at least instantiate only one single buffer per
407 * application, that is than shared between all the widgets of our library?
408 * This buffer would never be freed, so it will always occupy memory. But
409 * this avoids the time-consuming memory allocations at each paint event!
410 *
411 * @todo Use <tt>QCache</tt> where is makes sense. Maybe
412 * @ref PerceptualColor::RgbColorSpace::reduceCielchD50ChromaToFitIntoGamut() or
413 * @ref PerceptualColor::RgbColorSpace::isCielchD50InGamut() or
414 * @ref PerceptualColor::RgbColorSpace::isCielabD50InGamut() or
415 * @ref PerceptualColor::ChromaLightnessDiagramPrivate::nearestInGamutCielchD50ByAdjustingChromaLightness(().
416 *
417 * @todo Switch AbstractDiagram::handleOutlineThickness() and
418 * handleRadius() and spaceForFocusIndicator() to use PM_DefaultFrameWidth.
419 * (PM_DefaultFrameWidth seems to be used yet in ColorPatch.)
420 *
421 * @todo QColor is ambiguous: It allows different types of color system,
422 * or even various versions of the same color system at different
423 * precisions (RGB). This makes it difficult to communicate in the API
424 * which is the type of color (model) it contains. Therefore, we should
425 * eliminate all its usage within this library (except where it is necessary
426 * for API compatibility with Qt).
427 *
428 * @todo If using the Motif style, the @ref PerceptualColor::ChromaHueDiagram
429 * widget, which has circular look-and-feel, has a rectangular focus
430 * indicator corresponding the rectangular widget geometry, which looks
431 * quite ugly. On the other hand, @ref PerceptualColor::WheelColorPicker
432 * has also circular look-and-feel, but no rectangular focus indicator
433 * corresponding the rectangular widget geometry, which looks better.
434 * Why doesn’t @ref PerceptualColor::ChromaHueDiagram also behave
435 * like @ref PerceptualColor::WheelColorPicker? And
436 * how does @ref PerceptualColor::ColorWheel behave?
437 *
438 * @todo Idea: Provide QColorWidget (like QColorDialog, but inheriting
439 * from QWidget, and no buttons). Does this make sense?
440 *
441 * @todo Use implicit data sharing in @ref PerceptualColor::RgbColorSpace
442 * instead of <tt>QSharedPointer< @ref PerceptualColor::RgbColorSpace ></tt>.
443 * But: Wouldn’t this require to make the declaration
444 * of @ref PerceptualColor::RgbColorSpace, which was secret until today,
445 * public? If so, this would not be good…
446 *
447 * @todo Dual-Licence with Apache2 and/or Boost licence?
448 *
449 * @todo Reduce number of exported symbols.
450 *
451 * @todo Rename main.cpp.
452 *
453 * @todo Currently, we consider that a mouse clicks click a pixel, but mean
454 * the coordinate point in the middle of this pixel. This seems an approach
455 * that other widgets (including Qt itself) do not use. And maybe is meant also
456 * the coordinate at the top of the mouse cursor, so no offset by (0.5, 0.5)
457 * would be necessary. This would give better results (at least on LTR
458 * mouse cursors, but what's about crosshair cursors and RTL cursors?)
459 *
460 * @todo We do some hacks to get circle-like (instead of rectangular)
461 * feeling for our circular widgets, which is not perfect when talking
462 * about mouse events. It seems that QWidget::setMask() offers an
463 * alternative, restricting mouse events (and painting) to a given
464 * mask. Does this actually work also for mouse focus management?
465 * If so: Has it performance penalties? If not, we should probably use
466 * it! And document that those widgets are circular widgets and from
467 * a user perspective behave like circular widgets (both paint event
468 * and mouse cursor reactions/usage feeling), though from an application
469 * programmer (that uses this library) perspective, they are of course
470 * rectangular in the layout system. And: Post the results on
471 * <a href="https://forum.qt.io/topic/118547/accept-reject-focus-coming-by-mouse-click-based-on-coordinates">
472 * this Qt Forum thread</a>.
473 *
474 * @todo Support more of Qt Style Sheets, for example allow
475 * customizing the neutral-gray background of diagrams? If
476 * so, @ref PerceptualColor::drawQWidgetStyleSheetAware()
477 * is available. Otherwise, remove the currently not used
478 * @ref PerceptualColor::drawQWidgetStyleSheetAware() from
479 * this library.
480 *
481 * @todo Unit tests for endianess. Maybe QtEndian can help…
482 *
483 * @todo General library properties:
484 * - test cross-platform support and different byte-orders
485 * - Could we integrate more with QStyle? Apparently
486 * <a href="https://api.kde.org/frameworks/frameworkintegration/html/classKStyle.html">
487 * KStyle</a> is a QCommonStyle-based class that provides
488 * support for QString-based query for custom style hints,
489 * control elements and sub elements. There is also
490 * <a href="https://api.kde.org/frameworks/kwidgetsaddons/html/namespaceKStyleExtensions.html">
491 * KStyleExtensions</a> that allows apparently custom widgets to query
492 * for these QString-based custom support, which allows to make the same
493 * query independently of the actual style, without the need to hard-code
494 * individual custom enum values for QStyle::ControlElement (and similar
495 * enum) for each individual style. KStyleExtensions works for all
496 * styles, also for these that are <em>not</em> subclasses of
497 * <tt>KStyle</tt>. It reports if a given query is supported or not
498 * by the underlying style. However, even Breeze, KDE’s default style,
499 * seems not to inherit from KStyle, so the question is if KStyle is
500 * not rather deprecated yet. An alternative would be if a style
501 * has special functions just for PerceptualColor rendering, like
502 * <tt>renderColorWheel</tt>. Than, we could cast the current QStyle
503 * of the application to this style (if the actual current
504 * style <em>is</em> this style), and call these functions. Big
505 * disadvantage: We would have to <em>link</em> against all styles
506 * that we want to support, which makes our library <em>depend</em>
507 * on them, which is not reasonable.
508 * - More work on accessibility. [This includes to work well with bigger
509 * fonts. Should then the gradient be thicker and the marker
510 * thicker? setAccessibleName().] The application Accerciser provides
511 * inspection possibilities.
512 *
513 * @todo From KDE’s binary compatibility info page: In order to make a class
514 * to extend in the future you should follow these rules:
515 * - add non-inline virtual destructor even if the body is empty.
516 * - re-implement event in QObject-derived classes, even if the body for
517 * the function is just calling the base class' implementation. This is
518 * specifically to avoid problems caused by adding a reimplemented virtual
519 * function as discussed below.
520 *
521 * @todo Following the recommendation of the C++ core guidelines, all
522 * destructors should be noexcept.
523 *
524 * @todo Make genereatescreenshots and the unit tests run on hardware
525 * without graphic card. This would be good for Continuous Integration.
526 * The XVFB Virtual framebuffer (https://de.m.wikipedia.org/wiki/Xvfb)
527 * can do this for X apps. Also, it is possible to start X apps on
528 * terminal without a window manager, see
529 * https://linuxconfig.org/how-to-run-x-applications-without-a-desktop-or-a-wm
530 * but I suppose an X server is still required? There seem to exist also
531 * possibilities for Wayland
532 * https://unix.stackexchange.com/questions/653672/virtual-wayland-display-server-possible
533 * Also, there seems to be a Qt Platform Abstraction called “minimal”
534 * (https://doc.qt.io/qt-6/qpa.html) for testing purposes. Elsewhere,
535 * if I remember correctly, it was described as useful for testing without X.
536 *
537 * @todo The missing 3rd diagram (hue-lightness? But: Impossible to model
538 * the circular behaviour of the LCH color space: It cannot be a cut through
539 * the gamut body, but has to be a curve within the gamut body – not so
540 * nice. And: The diagram width has to change with the selected hue if we want
541 * to have correct scaling between x axis and y axis…
542 *
543 * @todo In https://phabricator.kde.org/T12359 is recommended to provide
544 * RESET statements for all properties for better compatibility with QML.
545 * As we provide widgets, this should not be too important. Are there also
546 * good arguments for widgets to provide RESET?
547 *
548 * @todo Provide an init() function that calls qRegisterMetaType() for
549 * all our types?
550 *
551 * @todo We prevent division by 0 in
552 * @ref PerceptualColor::ChromaLightnessDiagramPrivate::fromWidgetPixelPositionToCielchD50().
553 * We should make sure this happens also in the other diagram widgets!
554 *
555 * @todo Add a @ref PerceptualColor::ConstPropagatingUniquePointer to
556 * all classes, including the non-pimpl classes, to allow for later
557 * enhancements.
558 *
559 * @todo Remove setDevicePixelRatioF from all *Image classes. (It is
560 * confusing, and at the same time there is no real need/benefit.)
561 * Complete list: @ref PerceptualColor::ChromaHueImageParameters,
562 * @ref PerceptualColor::ColorWheelImage,
563 * @ref PerceptualColor::GradientImageParameters.
564 *
565 * @todo Test also on Windows. (Does it work well with VisualStudio?)
566 *
567 * @todo Test also Big-Endian compatibility using s390x Linux via Qemu?
568 * KDE Invent does not support this out-of-the-box, but with a custom
569 * script?
570 *
571 * @todo Test opaque RGB color space object with a non-export-all version
572 * of this library to make sure it actually works for third-party developers.
573 *
574 * @todo Sometimes, on dual-screen setup, one screen has another DPI than
575 * the other screen. Does this library behave correctly in these situations?
576 *
577 * @todo Would it make sense for @ref PerceptualColor::ChromaHueDiagram and
578 * @ref PerceptualColor::ChromaLightnessDiagram to split up their property
579 * <tt>currentColor</tt> into two properties: A two-dimensional property
580 * for what the user can change, and a one-dimensional property
581 * for what only the programmer can change? Or at least provide
582 * a Q_INVOKABLE getter and maybe also setter support? So
583 * @ref PerceptualColor::WheelColorPicker could use this
584 * instead of a lambda expression to set the hue of the
585 * @ref PerceptualColor::ChromaLightnessDiagram. And: Also when we don’t do
586 * that: When setting <tt>currentColor</tt> to an out-of-gamut color,
587 * what happens? Does @ref PerceptualColor::ChromaHueDiagram preserve
588 * lightness, while @ref PerceptualColor::ChromaLightnessDiagram preserves
589 * hue? Would this make sense?
590 *
591 * @todo Paint grayed-out handles for all widgets when setEnabled(false)
592 * is used! For example 25% lightness instead of black. And 75% lightness
593 * instead of white. But: Provide this information
594 * in @ref PerceptualColor::AbstractDiagram!
595 *
596 * @todo It might be interesting to use <tt>QStyle::PM_FocusFrameHMargin</tt>
597 * <em>(Horizontal margin that the focus frame will outset the widget
598 * by.)</em> Or: <tt>QStyle::PM_FocusFrameVMargin</tt>. Using this for the
599 * distance between the focus indicator and the actual content of the widget
600 * maybe give a more <tt>QStyle</tt> compliant look. But: If using this,
601 * ensurePolished() must be called before!
602 *
603 * @todo Use <tt>explicit</tt> on all constructors?
604 *
605 * @todo Screen picker with magnifier glass in two steps
606 * similar to https://colorsnapper.com ? Or like in Firefox
607 * (Menu → Weitere Werkzeuge → Farbpalette)?
608 *
609 * @todo Multi-licensing? Add Boost licence and Unlicense as an additional
610 * choice?
611 *
612 * @todo The image cache for the gamut widgets should be updated
613 * asynchronously (in its own thread or even various own threads
614 * in parallel). While waiting for the result, an empty image could be used.
615 * Or it might be useful to provide first a low-resolution version, and only
616 * later-on a high-resolution version. Anyway, KDE provides an interesting
617 * recommendation: <tt>int Units::humanMoment = 2000;</tt> <em>Time in
618 * milliseconds equivalent to the theoretical human moment, which can be
619 * used to determine whether how long to wait until the user should be
620 * informed of something, or can be used as the limit for how long something
621 * should wait before being automatically initiated. / Some examples: /
622 * When the user types text in a search field, wait no longer than this
623 * duration after the user completes typing before starting the search /
624 * When loading data which would commonly arrive rapidly enough to not
625 * require interaction, wait this long before showing a spinner</em> See
626 * https://api.kde.org/frameworks/plasma-framework/html/classUnits.html#ab22ad7033b2e3d00a862650e82f5ba5e
627 * for details.
628 *
629 * @todo HLC @ref PerceptualColor::MultiSpinBox Allow entering (on the
630 * keyboard) of too big hues (361°), negative hues (-1°), negative chroma (-20)
631 * and too big chroma (201 or 256) – but do not allow this with the arrows
632 * (and how do the arrows react when currently one of these values is
633 * shown?). Does this make sense? Anyway do <em>not</em> allow this for
634 * lightness, because the lightness is <em>by definition</em> bound
635 * to <tt>[0, 100]</tt>.
636 *
637 * @todo Multi-threaded application of color transforms. It seems okay to
638 * create the color transforms in one thread and use the same color
639 * transform (once created) from various other threads at the same time
640 * as long as the flag <tt>cmsFLAGS_NOCACHE</tt> is used to create the
641 * transform.
642 *
643 * @todo Automatically scale the thickness of the wheel (and maybe even the
644 * handle) with varying widget size?
645 *
646 * @todo Support more color spaces? https://pypi.org/project/colorio/ for
647 * example supports a lot of (also perceptually uniform) color spaces…
648 *
649 * @todo Export less symbols?
650 *
651 * @todo Check in all classes that take a @ref PerceptualColor::RgbColorSpace
652 * that the shared pointer is actually not a <tt>nullptr</tt>. If is
653 * <em>is</em> a <tt>nullptr</tt> than throw an exception. Throwing the
654 * exception early might make error detection easier for users of the library.
655 *
656 * * @todo Avoid default arguments like <tt>void test(int i = 0)</tt> in
657 * public headers, as changes require re-compilation of the client application
658 * to take effect, which might lead to a miss-match of behaviour between
659 * application and library, if compile-time and run-time version of the
660 * library are not the same. Is the problem for default constructors
661 * like <tt>ClassName() = default</tt> similar?
662 *
663 * @todo mark all public non-slot functions with Q_INVOKABLE (except property
664 * setters and getters)
665 *
666 * @todo A good widget library should also be touchscreen-ready. Find
667 * an alternative to @ref PerceptualColor::MultiSpinBox? How, for up
668 * to 360 values (degrees in step by 1)? Or should the steps simply be bigger?
669 *
670 * @todo KDE Frameworks / https://marketplace.qt.io/ ?
671 * https://community.kde.org/Incubator
672 *
673 * @todo Provide property bindings as described in
674 * https://www.qt.io/blog/property-bindings-in-qt-6 or not? It is worth
675 * when we do not support QML? What are the pitfalls? Imagine a property
676 * that holds a percent value from 0 to 100; the setter enforces this
677 * range; the binding bypasses the setter and allows every value? And:
678 * How can callbacks know about when a setter was called in C++? See
679 * also: https://doc.qt.io/qt-5/qtqml-cppintegration-exposecppattributes.html
680 * and https://doc.qt.io/qt-5/qtqml-tutorials-extending-qml-example.html and
681 * http://blog.aeguana.com/2015/12/12/writing-a-gui-using-qml-for-a-c-project/
682 * for interaction between QML and C++. Pitfalls: Example of color() property
683 * stored internally at m_color: Much implementation code of the class will
684 * access directly m_color instead of color(), so when using bindings,
685 * this code is broken?
686 *
687 * @todo Provide QML support so that for
688 * https://doc.qt.io/qt-5/qml-qtquick-dialogs-colordialog.html (or its
689 * Qt6 counterpart) we provide a source compatible alternative, like for
690 * QColorWidget? Split the library in three parts (Common, Widgets, QML)?
691 * Support <a href="https://mauikit.org/">MauiKit</a>?
692 *
693 * @todo Apparently QWidget cannot be used from QML. (Though there is
694 * https://www.kdab.com/declarative-widgets/ – how does that work?) Is it
695 * therefore worth to have complete support for signals in all our QWidget
696 * code if this is not really necessary for QWidget (for example for
697 * properties that can only be changed by the library user and not by the
698 * end user)?
699 *
700 * @todo Comply with <a href="https://community.kde.org/Policies">KDE
701 * policies</a>.
702 *
703 * @todo Remove all qDebug calls from the source
704 *
705 * @todo Qt Designer support for the widgets. Quote from a blog from Viking
706 * about Qt Designer plugins:
707 * The problem is that you have to build it with exactly the same compiler
708 * tool chain as designer was built with, and you have to do it in release
709 * mode. Unless your Qt is built in debug, then your plugin needs to be
710 * built in debug mode as well. So you can’t just always use the same
711 * compiler as you build the application with, if you use the system Qt or
712 * a downloaded Qt version.
713 *
714 * @todo Use <a href="https://lvc.github.io/abi-compliance-checker/">
715 * abi-compliance-checker</a> to control ABI compatibility.
716 *
717 * @todo Follow KDE’s <a href="https://hig.kde.org/index.html">HIG</a>
718 *
719 * @todo Test linking against lcms.h in version 2.0.0 for compatibility
720 * (or require more recent version?)
721 *
722 * @todo Require (by static cast additional to CMake conditions) a minimum
723 * Qt version?
724 *
725 * @todo Would it be a good idea to implement Q_PROPERTY RESET overall? See
726 * also https://phabricator.kde.org/T12359
727 *
728 * @todo Better design on small widget sizes for the whole library.
729 *
730 * @todo Anti-aliasing the gamut diagrams? Wouldn't this be bad for
731 * performance?
732 *
733 * @todo Use a cross-hair cursor on @ref PerceptualColor::ChromaHueDiagram
734 * and @ref PerceptualColor::ChromaLightnessDiagram when the mouse is
735 * hovering over the gamut, to show that this surface can be clicked?
736 *
737 * @todo Touch-friendly interface: Would it be good to have buttons for
738 * plus and minus on the various LCH axis which would be companions
739 * for @ref PerceptualColor::ChromaHueDiagram and
740 * @ref PerceptualColor::ChromaLightnessDiagram and would allow
741 * more exactly choose colors also on touch devices?
742 *
743 * @todo Would it be a good idea to have plus and minus buttons that
744 * manipulate the current color along the depth and vividness axis
745 * as proposed in “Extending CIELAB - Vividness, V, depth, D, and clarity, T”
746 * by Roy S. Berns?
747 *
748 * @todo Spell checking for the documentation, if possible also grammar
749 * checking with LanguageTool */
750
751/** @page hidpisupport High DPI support
752 *
753 * This library supports High DPI out of the box.
754 *
755 * The only thing that requires special attention are icons.
756 *
757 * @section iconsupport Icon support
758 *
759 * This library uses by default a possibly existing icon theme
760 * if available in Qt. Windows and Mac do not provide icon themes by
761 * default, while Linux usually provides them. SVG is pretty much the standard
762 * nowadays and the only reliably way to have crisp icons also on desktop
763 * scales like 1.25 or 1.5. If high-DPI icons are available depends finally
764 * on your operation system. Only if no icon at all is provided by the
765 * operation system, the library falls back to built-in high-DPI SVG icons.
766 *
767 * Note that QSvgIconEnginePlugin is a mandatory run-time
768 * dependency (see @ref build for details).
769 *
770 * @section qt5icons Qt5 legacy
771 *
772 * While <a href="https://bugreports.qt.io/browse/QTBUG-89279">Qt6
773 * renders icons always with high-DPI</a> (if available),
774 * Qt5 renders icons by default in low resolution. This applies even
775 * for SVG icons on high-DPI displays! Application developers have to enable
776 * high-DPI icon rendering manually with the following code (which should be
777 * put by convention <em>before</em> creating the <tt>QCoreApplication</tt>
778 * object):
779 * <br/><tt>QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);</tt> */
780
781/** @page howtogetstarted How to get started
782 *
783 * How to get started? @ref PerceptualColor::ColorDialog provides a
784 * perceptual replacement for QColorDialog:
785 * @snippet testcolordialog.cpp ColorDialog Get color
786 *
787 * This is a minimal, but complete example project showing how to use
788 * this library:
789 *
790 * CMakeLists.txt:
791 * @include examples/CMakeLists.txt
792 *
793 * example.cpp:
794 * @include examples/example.cpp */
795
796/** @page i18nl10n Internationalization and localization
797 *
798 * @section Internationalization
799 *
800 * This library is internationalized (i18n). This include also support
801 * for right-to-left layouts in the widgets.
802 *
803 * @section Localization
804 *
805 * This library is also localized (l10n). The localization is divided
806 * into two separate areas, which behave differently and independently
807 * of each other.
808 *
809 * 1. Translation.
810 * 2. Everything else.
811 *
812 * @subsection localizationtranslation Translation
813 *
814 * The translation of user-visible strings is a global setting for the whole
815 * library. The language for the translation is auto-detected depending on
816 * the settings of the current computer. You can specify the translation
817 * explicitly with @ref PerceptualColor::setTranslation(), which can also
818 * be used to change the translation dynamically (during program execution).
819 * The various translations are build directly into the library binary;
820 * no external files need to be available or loaded.
821 *
822 * @subsection localizationeverythingelse Everything else
823 *
824 * All other localization settings (like which decimal separator to use or
825 * which date format to use) are individual per widget, depending on the
826 * <tt><a href="https://doc.qt.io/qt-6/qwidget.html#locale-prop">
827 * QWidget::locale()</a></tt> property. Changing the localization dynamically
828 * (during program execution) is currently not supported.
829 *
830 * @internal
831 *
832 * @todo Support changing the localization dynamically (during program
833 * execution). This affects also @ref PerceptualColor::MultiSpinBox and
834 * the <tt>QSpinBox</tt> in @ref PerceptualColor::ColorDialog that is
835 * used for the opacity and maybe also the RGB-Hex-LineEdit.
836 *
837 * @todo Provide more localizations! */
838
839/** @page licenseinfo License
840 *
841 * @copyright
842 * - We follow the <a href="https://reuse.software/">“Reuse”
843 * specification</a>.
844 * - The files from which the library (and this documentation as well)
845 * are generated do not all have the same license; instead, each file
846 * is subject to one of the following permissive licenses:
847 * - BSD-2-Clause OR MIT (for example, some C++ source code files)
848 * - MIT (for example, some icons)
849 * - BSD-3-Clause (for example, some CMake files)
850 * - CC0-1.0 (for example, some color profiles)
851 * - Other parts of the codebase (which will
852 * <em>not</em> be installed by CMake, examples include <em>autotests</em>
853 * and <em>utils</em>) might have different licenses and/or include
854 * compiled-in resources that have different licenses. */
855
856/** @internal
857 *
858 * @page measurementdetails Measurement details
859 *
860 * When this library deals with raster graphics, it simultaneously uses
861 * concepts concerning measurement. This page describes the terminology
862 * used within the documentation of this library.
863 *
864 * @section introduction Introduction
865 * Today’s displays have a wide range of physical pixel density (pixels
866 * per length). Displays with a high physical pixel density are called
867 * <b>High-DPI displays</b> or <b>HiDPI displays</b> or <b>Retina displays</b>.
868 *
869 * @section unitsofmeasurement Units of measurement
870 * As Qt documentation says:
871 * “<em>Qt uses a model where the application coordinate system is
872 * independent of the display device resolution. The application
873 * operates in </em>device-independent pixels<em>, which are then
874 * mapped to the physical pixels of the display via a scale
875 * factor, known as the </em>device pixel ratio<em>.</em>”
876 *
877 * So when rendering widgets, there are two different units of measurement
878 * to consider:
879 * - <b>Device-independent pixels</b> are the unit of measurement for
880 * widgets, windows, screens, mouse events and so on in Qt.
881 * - <b>Physical pixels</b> are the unit that measures actual physical
882 * display pixels.
883 *
884 * The conversion factor between these two units of measurement is
885 * <tt>QPaintDevice::devicePixelRatioF()</tt>, a floating point number.
886 * It is usually <tt>1.00</tt> on classic low-resolution screens. It could be
887 * for example <tt>1.25</tt> or <tt>2.00</tt> on displays with a higher
888 * pixel density.
889 *
890 * @section coordinatepointsversuspixelpositions Coordinate points versus pixel positions
891 *
892 * - <b>Coordinate points</b> are points in the mathematical sense, that
893 * means they have zero surface. Coordinate points should be stored as
894 * <em>floating point numbers</em>.
895 * - <b>Pixel positions</b> describe the position of a particular pixel
896 * within the pixel grid. Pixels are surfaces, not points. A pixel is a
897 * square of the width and length <tt>1</tt>. The pixel at position
898 * <tt>QPoint(x, y)</tt> is the square with the top-left edge at coordinate
899 * point <tt>QPoint(x, y)</tt> and the bottom-right edge at coordinate
900 * point <tt>QPoint(x+1, y+1)</tt>. Pixel positions should be stored
901 * as <em>integer numbers</em>.
902 *
903 * Some functions (like mouse events) work with pixel positions, other
904 * functions (like antialiased floating-point drawing operations) work
905 * with coordinate points. It’s important to always distinguish correctly
906 * these two different concepts. See https://doc.qt.io/qt-6/coordsys.html
907 * for more details about integer precision vs floating point precision
908 * on drawing operations. */
909
910/** @page namespacepollution Name⁠space pollution
911 *
912 * This library avoids namespace pollution and collisions:
913 *
914 * - Macros are prefixed with <tt>PERCEPTUALCOLOR_</tt>.
915 * - Symbols that have external linkage are within the
916 * namespace <tt>PerceptualColor</tt>. (Exception: The
917 * <a href="https://doc.qt.io/qt-5/resources.html">
918 * Qt resource system</a> generates functions prefixed
919 * with <tt>qInitResources_</tt> and <tt>qCleanupResources_</tt>
920 * that are not within the previously mentioned namespace.)
921 * - Resources within the <a href="https://doc.qt.io/qt-5/resources.html">Qt
922 * resource system</a> are within the folder <tt>:/PerceptualColor/</tt>. */
923
924/** @internal
925 *
926 * @page pimpl Pointer to implementation idiom
927 *
928 * This library uses the <em>pointer to implementation</em> idiom
929 * (also known as pimpl idiom, d-pointer idiom or opaque-pointer idiom)
930 * in almost all classes that are part of the public API, and also in
931 * some classes that are part of the private API. The idiom is described
932 * in detail in the Internet. The following flavour of the idiom is used
933 * in our library:
934 *
935 * - The pointer to the implementation is called <tt>d_pointer</tt>. It’s of
936 * type @ref PerceptualColor::ConstPropagatingUniquePointer which provides
937 * const-correctness.
938 * - The back pointer is called <tt>q_pointer</tt>. (A “q” is just a “d”
939 * pointing in a different direction, get it?). It’s
940 * of type @ref PerceptualColor::ConstPropagatingRawPointer which provides
941 * const-correctness.
942 * - <a href="https://euroquis.nl//kde/2022/01/31/dptr.html"> The
943 * <tt>q_pointer</tt> <em>must not</em> ever be used in the destructor
944 * of the private implementation.</a> Rationale: All functions of the
945 * public class could potentially use the d_pointer. However, at the moment
946 * the destructor of the private class has started, the use of the d_pointer
947 * is already undefined behaviour. With some compilers this leads to an
948 * immediate crash, with other compilers it leads to
949 * silent undefined behaviour.
950 *
951 * The private classes are <em>not</em> nested
952 * classes of their public counterpart. This is also
953 * <a href="https://community.kde.org/Policies/Binary_Compatibility_Issues_With_C%2B%2B#Using_a_d-Pointer">
954 * what the the KDE community recommends</a>:
955 * > It is also possible (but not recommended) to declare the private
956 * > class […] as a nested private class (e.g. Foo::Private). […] remember
957 * > that the nested private class will inherit the public symbol visibility
958 * > of the containing exported class. This will cause the functions
959 * > of the private class to be named in the dynamic library's symbol
960 * > table. […] Other downsides […] include […] the fact that it can't be
961 * > forward-declared in unrelated headers anymore (which can be useful to
962 * > declare it as a friend class).
963 *
964 * @note This idiom is also used by Qt itself, and Qt even provides some macros
965 * and extension points (<tt>Q_DECLARE_PRIVATE</tt>, <tt>Q_D</tt>, a protected
966 * member called <tt>d_ptr</tt> in almost all classes…), that help dealing
967 * with the pimpl idiom. Though available, these Qt features are not
968 * officially documented; and they would also interfere with private
969 * implementations of Qt itself without documented behaviour, which seems
970 * inappropriate. Furthermore, the Qt pimpl idiom is complicate because
971 * it uses (for performance reasons) inheritance between the private
972 * implementation classes. This breaks, however, the encapsulation, because
973 * all formerly private elements of a class become protected now. Our class
974 * hierarchy is not that deep, so the performance gain might not be worth
975 * the additional code complexity. Therefore, this library uses a more simple
976 * pimpl idiom without inheritance of the private implementation. It has
977 * however all the other features of the Qt pimpl idiom, including
978 * <tt>const</tt> propagating access to the private implementation
979 * thanks to @ref PerceptualColor::ConstPropagatingUniquePointer and
980 * @ref PerceptualColor::ConstPropagatingRawPointer. And, at difference
981 * to Qt’s pimpl idiom, it keeps private code strictly private.
982 * Note however, that switching later from our current pimpl idiom to
983 * the polymorphic Qt pimpl idiom would break the binary
984 * compatibility. See also the document <em>
985 * <a href="https://accu.org/journals/overload/18/100/love_1718/">Interface
986 * Versioning in C++</a></em> and KDE’s information document <em>
987 * <a
988 * href="https://community.kde.org/Policies/Binary_Compatibility_Issues_With_C%2B%2B">
989 * Binary Compatibility Issues With C++</a></em> and for details.
990 *
991 * @note It would be nice to have the d_pointer and q_pointer
992 * be themselves be declared <tt>const</tt>, because this would
993 * clearly communicate that those pointers are not expected to change
994 * the address they point to. Unfortunately, apparently this does not
995 * work with neither @ref PerceptualColor::ConstPropagatingUniquePointer nor
996 * @ref PerceptualColor::ConstPropagatingRawPointer as it would change also
997 * all the access rights to the pointed object to always <tt>const</tt>. */
998
999/** @page qtstylesheetssupport Qt Style Sheets support
1000 *
1001 * The widget of this library supports the Qt Style Sheet
1002 * <a href="https://doc.qt.io/qt-6/stylesheet-reference.html#list-of-stylable-widgets">
1003 * properties of the Qt class they are derived from</a> only where it
1004 * makes sense. So you set the <tt>background-color</tt> of
1005 * a @ref PerceptualColor::MultiSpinBox. But you should not set
1006 * it for a @ref PerceptualColor::GradientSlider because the point
1007 * of this widget is to always use the gradient as the background;
1008 * the same applies for most widgets that showcase colors.
1009 *
1010 * When using class names of this library as
1011 * selectors in Qt Style Sheets, you have to
1012 * <a href="https://doc.qt.io/Qt-6/stylesheet-syntax.html#widgets-inside-c-namespaces">
1013 * substitute the namespace separator <tt>::</tt> by <tt>\--</tt></a>
1014 * to get a working selector: To select the class
1015 * @ref PerceptualColor::ColorDialog, use the selector
1016 * <tt>PerceptualColor\--ColorDialog</tt>. */
1017
1018/** @page lchrange Range of LCH values
1019 *
1020 *
1021 * The LCH values in this library are implemented with the following range:
1022 *
1023 * | | l | a | b | c | h |
1024 * | :------------ | :------: | :------: | :------: |:-------: | :------: |
1025 * | CIELab/CIELCh | [0, 100] | [0, 255] | [0, 255] | [0, 255] | [0, 360[ |
1026 * | Oklab/Oklch | [0, 1] | [0, 2] | [0, 2] | [0, 2] | [0, 360[ |
1027 *
1028 * This range is enough to cover the hole range of human perception. (Note
1029 * that the actual range of human perception has an irregular shape and
1030 * covers only parts of all possible combinations of LCH values. And
1031 * the actual gamut of real-word output devices is smaller than the
1032 * human perception.)
1033 *
1034 * @internal
1035 *
1036 * @section lchrangerationale Rationale
1037 *
1038 * The gamut of actual human perception within the LAB color model (and
1039 * its alternative representation LCH) has an irregular shape. Its maximum
1040 * extensions:
1041 *
1042 * <b>Lightness (L)</b>
1043 * The maximum range for LAB/LCH lightness is limited by
1044 * definition: <tt>[0, 100]</tt> for CIELch and <tt>[0, 1]</tt> for Oklch.
1045 *
1046 * <b>Hue (H)</b>
1047 * The maximum range for LCH hue is limited by definition to
1048 * the full circle: <tt>[0°, 360°[</tt>.
1049 *
1050 * <b>a, b, Chroma (C)</b>
1051 * The maximum range for a, b and Chroma (C) is complex. It is <em>not</em>
1052 * limited by definition. A useful limit is the actual human perception.
1053 *
1054 * | CIELab/CIELCh | a | b | C |
1055 * | :---------------------------- |:----------------: | :---------------: | :---------: |
1056 * | Usual implementation¹ | [−128, 127] | [−128, 127] | |
1057 * | Human perception (Wikipedia)² | [−170, 100] | [−100, 150] | |
1058 * | Human perception (2° D50)³ | [−165.39, 129.05] | [−132.62, 146.69] | [0, 183.42] |
1059 * | Human perception (2° D65)³ | [−170.84, 147.84] | [−129.66, 146.78] | [0, 194.84] |
1060 * | Human perception (10° D65)³ | [−164.29, 115.14] | [−116.10, 145.53] | [0, 186.17] |
1061 *
1062 * 1. The range of  <tt>[−128, 127]</tt> is in C++ a signed 8‑bit integer. But
1063 * this data type usually used in software implementations is (as the table
1064 * clearly shows) not enough to cover the hole range of actual human
1065 * color perception.
1066 * 2. Ranges of CIELAB coordinates according to the
1067 * <a href="https://de.wikipedia.org/w/index.php?title=Lab-Farbraum&oldid=197156292">
1068 * German Wikipedia</a>.
1069 * 3. The German association <em>Freie Farbe e. V.</em> has
1070 * published a calculation of the
1071 * <a href="https://www.freiefarbe.de/artikel/grenzen-des-cielab-farbraums/">
1072 * shape of actual human perception</a> for various observation angles
1073 * and illuminants. This data contains only the CIELAB coordinates
1074 * (L, a, b). From this data, the chroma (C) component can be calculated
1075 * easily as Pythagoras of the a axis and b axis value pairs:
1076 * √(a² + b²) = C.
1077 *
1078 * Logically, the chroma value can reach higher values than a and b, however,
1079 * for simplicity it seems appropriate to use the same range for chroma, a and
1080 * b. Following these tables, the maximum chroma in human perception in CIELCh
1081 * is <tt>194.84</tt>. As apparently this depends on viewing conditions,
1082 * it might be a good idea to use a slightly higher limit, to be sure that the
1083 * value will never be too small. Here, <tt>200</tt> might be a good candidate.
1084 * However, some gamuts are wider. The <em>LargeRGB-elle-V2-g22.icc</em>
1085 * profile goes up to a chroma value of 245. Finally, we have fixed the valid
1086 * range to 255, because this is for sure enough to cover the human
1087 * perception, and it will cover almost all existing profiles.
1088 *
1089 * For Oklch we have observed up to 1.52 as chroma values when using the
1090 * <em>LargeRGB-elle-V2-g22.icc</em> profile. As with CIELCh chroma, we have
1091 * added a safety margin, rounded up to the next integer, and finally
1092 * chosen 2 as maximum.
1093 *
1094 * @internal
1095 *
1096 * @sa @ref PerceptualColor::CielchD50Values::maximumChroma
1097 * @sa @ref PerceptualColor::OklchValues::maximumChroma
1098 *
1099 * @todo Why is the exact extend of non-imaginary colors unknown? Could it be
1100 * deduced from the <a href="https://en.m.wikipedia.org/wiki/CIE_1931_color_space#CIE_xy_chromaticity_diagram_and_the_CIE_xyY_color_space">
1101 * CIE xy chromacity diagram</a>? And: Is 255 enough even for large color
1102 * spaces like <a href="https://en.m.wikipedia.org/wiki/Rec._2020">
1103 * Rec. 2020</a> or <a href="https://en.m.wikipedia.org/wiki/DCI-P3">
1104 * DCI-P3</a>?
1105 */
1106
1107/** @page versioninfo Version information at compiletime and runtime
1108 *
1109 * This library uses
1110 * <a href="https://semver.org/">Semantic Versioning 2.0.0</a>.
1111 *
1112 * Version information is provided by the header <tt>version.h</tt>
1113 *
1114 * To know against which version of this library you are <em>running</em>, use
1115 * - @ref PerceptualColor::perceptualColorRunTimeVersion
1116 *
1117 * To know against which version of this library you are <em>compiling</em>,
1118 * use
1119 * - @ref PERCEPTUALCOLOR_COMPILE_TIME_VERSION
1120 * - @ref PERCEPTUALCOLOR_COMPILE_TIME_VERSION_MAJOR
1121 * - @ref PERCEPTUALCOLOR_COMPILE_TIME_VERSION_MINOR
1122 * - @ref PERCEPTUALCOLOR_COMPILE_TIME_VERSION_PATCH */
1123
1124/** @brief The namespace of this library.
1125 *
1126 * All symbols that are provided in this library are encapsulated within this
1127 * namespace. */
1128namespace PerceptualColor
1129{
1130} // namespace PerceptualColor
The namespace of this library.
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sat Dec 21 2024 16:57:18 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.