From c8a37f940652f23bfecf4040af1095048f7260b4 Mon Sep 17 00:00:00 2001 From: Jeremy Bicha Date: Mon, 5 Oct 2020 02:46:57 +0100 Subject: [PATCH] Import babl_0.1.82.orig.tar.xz [dgit import orig babl_0.1.82.orig.tar.xz] --- .kateconfig | 4 + AUTHORS | 99 + COPYING | 165 + INSTALL.in | 24 + MAINTAINERS | 3 + NEWS | 61 + TODO | 12 + babl.doap | 38 + babl.pc.in | 11 + babl/babl-cache.c | 387 ++ babl/babl-class.h | 57 + babl/babl-classes.h | 97 + babl/babl-component.c | 155 + babl/babl-component.h | 36 + babl/babl-conversion.c | 557 ++ babl/babl-conversion.h | 63 + babl/babl-core.c | 164 + babl/babl-cpuaccel.c | 541 ++ babl/babl-cpuaccel.h | 50 + babl/babl-db.c | 220 + babl/babl-db.h | 76 + babl/babl-extension.c | 377 ++ babl/babl-extension.h | 40 + babl/babl-fish-path.c | 1070 +++ babl/babl-fish-reference.c | 1454 ++++ babl/babl-fish-simple.c | 66 + babl/babl-fish.c | 362 + babl/babl-fish.h | 93 + babl/babl-format.c | 789 +++ babl/babl-format.h | 49 + babl/babl-hash-table.c | 190 + babl/babl-hash-table.h | 68 + babl/babl-icc.c | 1496 +++++ babl/babl-ids.h | 135 + babl/babl-image.c | 254 + babl/babl-image.h | 61 + babl/babl-internal.c | 132 + babl/babl-internal.h | 470 ++ babl/babl-introspect.c | 253 + babl/babl-introspect.h | 33 + babl/babl-list.c | 131 + babl/babl-list.h | 64 + babl/babl-macros.h | 33 + babl/babl-main.h | 0 babl/babl-matrix.h | 222 + babl/babl-memory.c | 368 + babl/babl-memory.h | 49 + babl/babl-model.c | 497 ++ babl/babl-model.h | 38 + babl/babl-mutex.c | 87 + babl/babl-mutex.h | 40 + babl/babl-palette.c | 989 +++ babl/babl-polynomial.c | 539 ++ babl/babl-polynomial.h | 79 + babl/babl-ref-pixels.c | 81 + babl/babl-ref-pixels.h | 34 + babl/babl-ref-pixels.inc | 4140 ++++++++++++ babl/babl-sampling.c | 81 + babl/babl-sampling.h | 35 + babl/babl-sanity.c | 144 + babl/babl-space.c | 1456 ++++ babl/babl-space.h | 175 + babl/babl-trc.c | 708 ++ babl/babl-trc.h | 107 + babl/babl-type.c | 248 + babl/babl-type.h | 50 + babl/babl-types.h | 55 + babl/babl-util.c | 150 + babl/babl-util.h | 29 + babl/babl-version.c | 36 + babl/babl-version.h.in | 51 + babl/babl.c | 192 + babl/babl.h | 737 +++ babl/base/babl-base.c | 75 + babl/base/babl-base.h | 40 + babl/base/formats.c | 228 + babl/base/meson.build | 23 + babl/base/model-cmyk.c | 1183 ++++ babl/base/model-gray.c | 1741 +++++ babl/base/model-rgb.c | 1501 +++++ babl/base/model-ycbcr.c | 308 + babl/base/pow-24.c | 156 + babl/base/pow-24.h | 182 + babl/base/type-float.c | 115 + babl/base/type-half.c | 434 ++ babl/base/type-u15.c | 238 + babl/base/type-u16.c | 234 + babl/base/type-u32.c | 234 + babl/base/type-u8.c | 310 + babl/base/util.h | 135 + babl/gettimeofday.c | 71 + babl/git-version.h | 6 + babl/git-version.h.in | 6 + babl/identfilter.py | 37 + babl/meson.build | 177 + babl/test-clang.map | 1 + babl/test-gnu.map | 6 + build/archlinux/PKGBUILD | 48 + build/buildbot/suppressed-warnings.txt | 9 + build/mingw/PKGBUILD | 49 + docs/CMYK-static.html | 61 + docs/COPYING | 674 ++ docs/COPYING.LESSER | 165 + docs/ColorManagement-static.html | 64 + docs/Glossary-static.html | 98 + docs/OldNews-static.html | 236 + docs/Reference-static.html | 107 + docs/UnifiedAlpha-static.html | 110 + docs/babl.css | 324 + docs/graphics/babl-16x16.svg | 524 ++ docs/graphics/babl-48x48.svg | 695 ++ docs/graphics/babl-a4poster.svg | 8107 +++++++++++++++++++++++ docs/graphics/index.html | 56 + docs/graphics/meson.build | 42 + docs/index-static.html.in | 292 + docs/meson.build | 111 + docs/toc | 28 + docs/tools/changelog2rss | 117 + export-symbols | 87 + extensions/CIE.c | 3570 ++++++++++ extensions/HCY.c | 394 ++ extensions/HSL.c | 307 + extensions/HSV.c | 370 ++ extensions/avx2-int8-tables.h | 4617 +++++++++++++ extensions/avx2-int8.c | 610 ++ extensions/cairo.c | 753 +++ extensions/double.c | 293 + extensions/fast-float.c | 727 ++ extensions/float.c | 627 ++ extensions/gegl-fixups.c | 625 ++ extensions/gggl-lies.c | 1017 +++ extensions/gggl-table-lies.c | 565 ++ extensions/gggl-table.c | 563 ++ extensions/gggl.c | 1302 ++++ extensions/gimp-8bit.c | 531 ++ extensions/grey.c | 175 + extensions/half.c | 621 ++ extensions/meson.build | 69 + extensions/naive-CMYK.c | 42 + extensions/simple.c | 830 +++ extensions/sse-half.c | 319 + extensions/sse2-float.c | 742 +++ extensions/sse2-int16.c | 216 + extensions/sse2-int8.c | 334 + extensions/sse4-int8.c | 228 + extensions/two-table-tables.h | 3444 ++++++++++ extensions/two-table.c | 254 + extensions/u16.c | 115 + extensions/u32.c | 436 ++ extensions/util.h | 56 + extensions/ycbcr.c | 259 + gen_babl_map.py | 19 + meson.build | 492 ++ meson_options.txt | 55 + tests/alpha_symmetric_transform.c | 111 + tests/babl_class_name.c | 74 + tests/cairo-RGB24.c | 95 + tests/cairo_cmyk_hack.c | 80 + tests/chromaticities.c | 77 + tests/cmyk.c | 56 + tests/common.inc | 53 + tests/concurrency-stress-test.c | 82 + tests/conversions.c | 73 + tests/extract.c | 48 + tests/float-to-8bit.c | 102 + tests/floatclamp.c | 46 + tests/format_with_space.c | 109 + tests/grayscale_to_rgb.c | 86 + tests/hsl.c | 86 + tests/hsva.c | 93 + tests/meson.build | 54 + tests/models.c | 34 + tests/n_components.c | 116 + tests/n_components_cast.c | 97 + tests/nop.c | 29 + tests/palette-concurrency-stress-test.c | 133 + tests/palette.c | 161 + tests/rgb_to_bgr.c | 90 + tests/rgb_to_ycbcr.c | 97 + tests/sanity.c | 31 + tests/srgb_to_lab_u8.c | 77 + tests/transparent.c | 80 + tests/types.c | 28 + tools/babl-benchmark.c | 196 + tools/babl-gen-test-pixels.c | 204 + tools/babl-html-dump.c | 293 + tools/babl-icc-dump.c | 719 ++ tools/babl-icc-rewrite.c | 197 + tools/babl-verify.c | 127 + tools/babl-verify.sh | 47 + tools/babl_fish_path_fitness.c | 339 + tools/conversions.c | 37 + tools/formats.c | 29 + tools/introspect.c | 30 + tools/meson.build | 27 + tools/trc-validator.c | 225 + tools/xml-insert.py | 110 + 197 files changed, 71757 insertions(+) create mode 100644 .kateconfig create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 INSTALL.in create mode 100644 MAINTAINERS create mode 100644 NEWS create mode 100644 TODO create mode 100644 babl.doap create mode 100644 babl.pc.in create mode 100644 babl/babl-cache.c create mode 100644 babl/babl-class.h create mode 100644 babl/babl-classes.h create mode 100644 babl/babl-component.c create mode 100644 babl/babl-component.h create mode 100644 babl/babl-conversion.c create mode 100644 babl/babl-conversion.h create mode 100644 babl/babl-core.c create mode 100644 babl/babl-cpuaccel.c create mode 100644 babl/babl-cpuaccel.h create mode 100644 babl/babl-db.c create mode 100644 babl/babl-db.h create mode 100644 babl/babl-extension.c create mode 100644 babl/babl-extension.h create mode 100644 babl/babl-fish-path.c create mode 100644 babl/babl-fish-reference.c create mode 100644 babl/babl-fish-simple.c create mode 100644 babl/babl-fish.c create mode 100644 babl/babl-fish.h create mode 100644 babl/babl-format.c create mode 100644 babl/babl-format.h create mode 100644 babl/babl-hash-table.c create mode 100644 babl/babl-hash-table.h create mode 100644 babl/babl-icc.c create mode 100644 babl/babl-ids.h create mode 100644 babl/babl-image.c create mode 100644 babl/babl-image.h create mode 100644 babl/babl-internal.c create mode 100644 babl/babl-internal.h create mode 100644 babl/babl-introspect.c create mode 100644 babl/babl-introspect.h create mode 100644 babl/babl-list.c create mode 100644 babl/babl-list.h create mode 100644 babl/babl-macros.h create mode 100644 babl/babl-main.h create mode 100644 babl/babl-matrix.h create mode 100644 babl/babl-memory.c create mode 100644 babl/babl-memory.h create mode 100644 babl/babl-model.c create mode 100644 babl/babl-model.h create mode 100644 babl/babl-mutex.c create mode 100644 babl/babl-mutex.h create mode 100644 babl/babl-palette.c create mode 100644 babl/babl-polynomial.c create mode 100644 babl/babl-polynomial.h create mode 100644 babl/babl-ref-pixels.c create mode 100644 babl/babl-ref-pixels.h create mode 100644 babl/babl-ref-pixels.inc create mode 100644 babl/babl-sampling.c create mode 100644 babl/babl-sampling.h create mode 100644 babl/babl-sanity.c create mode 100644 babl/babl-space.c create mode 100644 babl/babl-space.h create mode 100644 babl/babl-trc.c create mode 100644 babl/babl-trc.h create mode 100644 babl/babl-type.c create mode 100644 babl/babl-type.h create mode 100644 babl/babl-types.h create mode 100644 babl/babl-util.c create mode 100644 babl/babl-util.h create mode 100644 babl/babl-version.c create mode 100644 babl/babl-version.h.in create mode 100644 babl/babl.c create mode 100644 babl/babl.h create mode 100644 babl/base/babl-base.c create mode 100644 babl/base/babl-base.h create mode 100644 babl/base/formats.c create mode 100644 babl/base/meson.build create mode 100644 babl/base/model-cmyk.c create mode 100644 babl/base/model-gray.c create mode 100644 babl/base/model-rgb.c create mode 100644 babl/base/model-ycbcr.c create mode 100644 babl/base/pow-24.c create mode 100644 babl/base/pow-24.h create mode 100644 babl/base/type-float.c create mode 100644 babl/base/type-half.c create mode 100644 babl/base/type-u15.c create mode 100644 babl/base/type-u16.c create mode 100644 babl/base/type-u32.c create mode 100644 babl/base/type-u8.c create mode 100644 babl/base/util.h create mode 100644 babl/gettimeofday.c create mode 100644 babl/git-version.h create mode 100644 babl/git-version.h.in create mode 100644 babl/identfilter.py create mode 100644 babl/meson.build create mode 100644 babl/test-clang.map create mode 100644 babl/test-gnu.map create mode 100644 build/archlinux/PKGBUILD create mode 100644 build/buildbot/suppressed-warnings.txt create mode 100644 build/mingw/PKGBUILD create mode 100644 docs/CMYK-static.html create mode 100644 docs/COPYING create mode 100644 docs/COPYING.LESSER create mode 100644 docs/ColorManagement-static.html create mode 100644 docs/Glossary-static.html create mode 100644 docs/OldNews-static.html create mode 100644 docs/Reference-static.html create mode 100644 docs/UnifiedAlpha-static.html create mode 100644 docs/babl.css create mode 100644 docs/graphics/babl-16x16.svg create mode 100644 docs/graphics/babl-48x48.svg create mode 100644 docs/graphics/babl-a4poster.svg create mode 100644 docs/graphics/index.html create mode 100644 docs/graphics/meson.build create mode 100644 docs/index-static.html.in create mode 100644 docs/meson.build create mode 100644 docs/toc create mode 100755 docs/tools/changelog2rss create mode 100644 export-symbols create mode 100644 extensions/CIE.c create mode 100644 extensions/HCY.c create mode 100644 extensions/HSL.c create mode 100644 extensions/HSV.c create mode 100644 extensions/avx2-int8-tables.h create mode 100644 extensions/avx2-int8.c create mode 100644 extensions/cairo.c create mode 100644 extensions/double.c create mode 100644 extensions/fast-float.c create mode 100644 extensions/float.c create mode 100644 extensions/gegl-fixups.c create mode 100644 extensions/gggl-lies.c create mode 100644 extensions/gggl-table-lies.c create mode 100644 extensions/gggl-table.c create mode 100644 extensions/gggl.c create mode 100644 extensions/gimp-8bit.c create mode 100644 extensions/grey.c create mode 100644 extensions/half.c create mode 100644 extensions/meson.build create mode 100644 extensions/naive-CMYK.c create mode 100644 extensions/simple.c create mode 100644 extensions/sse-half.c create mode 100644 extensions/sse2-float.c create mode 100644 extensions/sse2-int16.c create mode 100644 extensions/sse2-int8.c create mode 100644 extensions/sse4-int8.c create mode 100644 extensions/two-table-tables.h create mode 100644 extensions/two-table.c create mode 100644 extensions/u16.c create mode 100644 extensions/u32.c create mode 100644 extensions/util.h create mode 100644 extensions/ycbcr.c create mode 100644 gen_babl_map.py create mode 100644 meson.build create mode 100644 meson_options.txt create mode 100644 tests/alpha_symmetric_transform.c create mode 100644 tests/babl_class_name.c create mode 100644 tests/cairo-RGB24.c create mode 100644 tests/cairo_cmyk_hack.c create mode 100644 tests/chromaticities.c create mode 100644 tests/cmyk.c create mode 100644 tests/common.inc create mode 100644 tests/concurrency-stress-test.c create mode 100644 tests/conversions.c create mode 100644 tests/extract.c create mode 100644 tests/float-to-8bit.c create mode 100644 tests/floatclamp.c create mode 100644 tests/format_with_space.c create mode 100644 tests/grayscale_to_rgb.c create mode 100644 tests/hsl.c create mode 100644 tests/hsva.c create mode 100644 tests/meson.build create mode 100644 tests/models.c create mode 100644 tests/n_components.c create mode 100644 tests/n_components_cast.c create mode 100644 tests/nop.c create mode 100644 tests/palette-concurrency-stress-test.c create mode 100644 tests/palette.c create mode 100644 tests/rgb_to_bgr.c create mode 100644 tests/rgb_to_ycbcr.c create mode 100644 tests/sanity.c create mode 100644 tests/srgb_to_lab_u8.c create mode 100644 tests/transparent.c create mode 100644 tests/types.c create mode 100644 tools/babl-benchmark.c create mode 100644 tools/babl-gen-test-pixels.c create mode 100644 tools/babl-html-dump.c create mode 100644 tools/babl-icc-dump.c create mode 100644 tools/babl-icc-rewrite.c create mode 100644 tools/babl-verify.c create mode 100755 tools/babl-verify.sh create mode 100644 tools/babl_fish_path_fitness.c create mode 100644 tools/conversions.c create mode 100644 tools/formats.c create mode 100644 tools/introspect.c create mode 100644 tools/meson.build create mode 100644 tools/trc-validator.c create mode 100644 tools/xml-insert.py diff --git a/.kateconfig b/.kateconfig new file mode 100644 index 0000000..e4b8336 --- /dev/null +++ b/.kateconfig @@ -0,0 +1,4 @@ +kate: indent-mode cstyle; +kate: indent-width 2; tab-width 8; +kate: tab-indents off; replace-tabs on; +kate: remove-trailing-spaces modified; diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..8b4ea71 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,99 @@ +
+
Øyvind Kolås pippin at gimp.org
+
Original author.
+
Sven Neumann sven at gimp.org
+
Build sanity and optimizations.
+
Michael Natterer mitch at gimp.org
+
Build sanity.
+
Kevin Cozens kcozens at cvs.gnome.org
+
Build sanity.
+
Tim Mooney
+
Portability fixes.
+
Michael Schumacher schumaml at cvs.gnome.org
+
win32 support for dynamic extensions.
+
Portability fixes.
+
Jan Heller jheller at svn.gnome.org
+
Optimizations, refactoring and documentation.
+
Mukund Sivaraman muks at mukund.org
+
Sparse fixes and sanity.
+
dmacks at netspace.org
+
Build sanity
+
Sam Hocevar
+
Build sanity.
+
Zhang Junbo
+
Frequency domain color model.
+
Martin Nordholts
+
Optimizations and API overhaul.
+
Gary V. Vaughan
+
Multiplatform build support.
+
Stanislav Brabec
+
Portability patch.
+
Hubert Figuiere
+
C++ friendliness patch.
+
Danny Robson
+
Code cleanups.
+
Fryderyk Dziarmagowski freetz at gmx.net
+
Code cleanups.
+
Daniel Paredes García danipga at gmail.com
+
Initial work to make babl threadsafe
+
Rupert Weber gimp at leguanease.org
+
Documentation and other improvements
+
Jehan jehan at girinstud.io
+
win32 portabilitiy
+
Sven Claussner
+
Update DOAP file
+
Alexander Larsson
+
Math optimizations
+
Nils Philippsen
+
code cleanups
+
Simon Budig
+
cleanups
+ +
Micheal Muré +
portability fixes
+ +
Edward E
+
win32 platform adaptations
+ +
Maxime Nicco
+
HSV color model extension
+
Teo Mazars
+
Color spaces/models in extensions
+
Daniel Sabo
+
Dead code elimination, general cleanups,
+
Michael Henning
+
Conversion fixes
+
Elle Stone
+
CIE xyY color space
+
Verification and improvements to accuracy of color space + conversions.
+
Thomas Manni
+
CIE related fixups
+
Roman Lebedev
+
Stability/crasher fixes
+
Jon Nordby
+
Portability, Stability and more
+
Massimo Valentini
+
stability fixes
+
Ell
+
fast paths
+
Guiu Rocafort
+
sanity crash fix
+
Tobias Stoeckmann
+
bug fixes for leaks and crashers
+
Debarshi Ray
+
SSE2 version of CIE code paths
+
Félix Piédallu
+
Meson build; original port, and improvements.
+
Yaakov Selkowitz
+
Cygwin patch
+
Étienne Bersac
+
build/packaging
+
Nuno Ferreira
+
coding style fixes
+
John Marshall
+
meson build improvements
+ + + +
diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..fc8a5de --- /dev/null +++ b/COPYING @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/INSTALL.in b/INSTALL.in new file mode 100644 index 0000000..1581a3d --- /dev/null +++ b/INSTALL.in @@ -0,0 +1,24 @@ + +babl @BABL_VERSION@ + + Dynamic; any to any, pixel format conversion library. + +----------------------------------------------------------------------- + +Installation instructions: +-------------------------- + +From a released version the following is the expected method of +installation (or a variation on this theme): + + ------------------------------------------------------------ + foo$ wget ftp://ftp.gtk.org/pub/babl/0.1/babl-@BABL_VERSION@.tar.bz2 + foo$ tar xvf babl-@BABL_VERSION@.tar.gz + foo$ cd babl-@BABL_VERSION@ + foo/babl-@BABL_VERSION@$ meson build + foo/babl-@BABL_VERSION@$ cd build + foo/babl-@BABL_VERSION@/build$ ninja && ninja install + + ------------------------------------------------------------ + + diff --git a/MAINTAINERS b/MAINTAINERS new file mode 100644 index 0000000..b2a2c20 --- /dev/null +++ b/MAINTAINERS @@ -0,0 +1,3 @@ +Øyvind Kolås +E-mail: pippin@gimp.org +Userid: ok diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..d4bfec0 --- /dev/null +++ b/NEWS @@ -0,0 +1,61 @@ +
+ +2020-10-04 babl-0.1.82
+Handle the parametric ICCv4 types that are not strictly the same type as core +sRGB curve. +
+2020-08-02 babl-0.1.80
+meson build cleanups, depend on meson 0.54 +
+2020-06-07 babl-0.1.78
+Bugfix release - mutex and atomicity related issues. +
+2020-05-27 babl-0.1.76
+Wrap hue in HSV, HSL, HCY. Fix black pullout in non ICC CMYK +conversion. Added AV2 gamme u8->linear float conversions. VAPI file generation +for vala integration. Adjusted strategy for conversion selection, trades back +warm-up time for missing some fast multi-step conversions. +
+2019-08-22 babl-0.1.74
+Build fixes, improved host cpu detection, OSX fixes, clang warning squelches. +2019-08-22 babl-0.1.72
+
+Added handling for grayscale ICC profiles and gobject introspection support. +Optimizations for many format conversions for u8, u16 and half formats. And +fixed a crash for NANs in float to u8 conversions. +
+2019-08-02 babl-0.1.70
+Build fixes making the meson build work with more architectures. +
+2019-07-25 babl-0.1.68
+Added Yu'v' (CIE 1976 UCS) color model. Fixed a severe non-initialised memory +issue - that kept us from using fast paths for many babl spaces loaded from +profile. More fully symmetric conversions between associated and separate +alpha. Added more converters, both SSE2 and non-SSE2 for matrix-conversion +between different RGB spaces. Improvements to website/documentation; babl is +now using the terms associated alpha and separate alpha, all of: +nonpremultiplied-, premultiplied- and nonassociated- alpha are now considered +deprecated API. HCY luminance is now relative to the RGB space used - no change +for sRGB related pixel formats. AVX2 acceleration for some linear to float +conversions. +
+2019-06-12 babl-0.1.66
+Added API call, babl_space_get_rgb_luminance, +Make most SIMD code-paths optional again on i686. +
+2019-05-25 babl-0.1.64
+Support for Hygon Dhyana, and Y~aA formats for symmetric completeness. +Code consistency, gitlab CI, autotools and meson build improvements. + +
+2019-02-01 babl-0.1.62
+Continuous integration with gitlab. +Initial CMYK spaces with lcms2 based ICC support, much room for optimization. +Improved custom space support for palette formats. +scRGB space, works like sRGB but always with linear TRCs. +Model introspection API permitting low overhead checks whether a format/model +is RGB, CMYK type of alpha and similar. +
diff --git a/TODO b/TODO new file mode 100644 index 0000000..b83bb34 --- /dev/null +++ b/TODO @@ -0,0 +1,12 @@ +

TODO

+ +

These are among desired or expected changes to babl, that are missing.

+ +
    +
  • extensions for many SIMD variants for many archiectures.
  • +
  • Spectral pixel formats - with configurable spectral mapping to tristimulus with configurable illuminant + observer
  • +
  • Spectral substrate + ink/paint job configuration as a pixel format, +combined with above to achieve soft proofing, and stochastic sparse LUT for +separation.
  • +
  • Support for datatypes that are not a multiple of 8bit.
  • +
diff --git a/babl.doap b/babl.doap new file mode 100644 index 0000000..d97f35b --- /dev/null +++ b/babl.doap @@ -0,0 +1,38 @@ + + + babl + + babl is a pixel encoding and color space conversion engine. + babl ist eine dynamische Bibliothek zur direkten Umwandlung von Pixelformaten. + + babl is a pixel encoding and color space conversions engine. + babl ist eine dynamische Bibliothek zur direkten Umwandlung von Pixelformaten. + + + + + + + + + /> + + C + + + + Øyvind Kolås + ok + + + + + + diff --git a/babl.pc.in b/babl.pc.in new file mode 100644 index 0000000..3f2049f --- /dev/null +++ b/babl.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: babl +Description: Dynamic, any to any, pixel format conversion library +Version: @BABL_REAL_VERSION@ +Cflags: -I${includedir}/@PACKAGE_NAME@-@BABL_API_VERSION@ +Libs: -L${libdir} -l@PACKAGE_NAME@-@BABL_API_VERSION@ +Libs.private: @MATH_LIB@ @THREAD_LIB@ diff --git a/babl/babl-cache.c b/babl/babl-cache.c new file mode 100644 index 0000000..63ae19e --- /dev/null +++ b/babl/babl-cache.c @@ -0,0 +1,387 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2016 Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#ifdef _WIN32 +#include +#endif + +#include +#include +#include "config.h" +#include "babl-internal.h" +#include "git-version.h" + +#ifdef _WIN32 +#define FALLBACK_CACHE_PATH "C:/babl-fishes.txt" +#else +#define FALLBACK_CACHE_PATH "/tmp/babl-fishes.txt" +#endif + +static int +mk_ancestry_iter (const char *path) +{ + char copy[4096]; + strncpy (copy, path, 4096); + copy[sizeof (copy) - 1] = '\0'; + if (strrchr (copy, '/')) + { + *strrchr (copy, '/') = '\0'; + if (copy[0]) + { + struct stat stat_buf; + if ( ! (stat (copy, &stat_buf)==0 && S_ISDIR(stat_buf.st_mode))) + { + if (mk_ancestry_iter (copy) != 0) + return -1; +#ifndef _WIN32 + return mkdir (copy, S_IRWXU); +#else + return mkdir (copy); +#endif + } + } + } + return 0; +} + +static int +mk_ancestry (const char *path) +{ + char copy[4096]; + strncpy (copy, path, 4096); + copy[sizeof (copy) - 1] = '\0'; +#ifdef _WIN32 + for (char *c = copy; *c; c++) + if (*c == '\\') + *c = '/'; +#endif + return mk_ancestry_iter (copy); +} + +static const char * +fish_cache_path (void) +{ + struct stat stat_buf; + static char path[4096]; + + strncpy (path, FALLBACK_CACHE_PATH, 4096); + path[sizeof (path) - 1] = '\0'; +#ifndef _WIN32 + if (getenv ("XDG_CACHE_HOME")) + snprintf (path, sizeof (path), "%s/babl/babl-fishes", getenv("XDG_CACHE_HOME")); + else if (getenv ("HOME")) + snprintf (path, sizeof (path), "%s/.cache/babl/babl-fishes", getenv("HOME")); +#else +{ + char win32path[4096]; + if (SHGetFolderPathA (NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, win32path) == S_OK) + snprintf (path, sizeof (path), "%s\\%s\\babl-fishes.txt", win32path, BABL_LIBRARY); + else if (getenv ("TEMP")) + snprintf (path, sizeof (path), "%s\\babl-fishes.txt", getenv("TEMP")); +} +#endif + + if (stat (path, &stat_buf)==0 && S_ISREG(stat_buf.st_mode)) + return path; + + if (mk_ancestry (path) != 0) + return FALLBACK_CACHE_PATH; + + return path; +} + +static char * +babl_fish_serialize (Babl *fish, char *dest, int n) +{ + char *d = dest; + if (fish->class_type != BABL_FISH && + fish->class_type != BABL_FISH_PATH) + { + return NULL; + } + + snprintf (d, n, "%s\n%s\n", + babl_get_name (fish->fish.source), + babl_get_name (fish->fish.destination)); + n -= strlen (d);d += strlen (d); + + snprintf (d, n, "\tpixels=%li", fish->fish.pixels); + n -= strlen (d);d += strlen (d); + + if (fish->class_type == BABL_FISH_PATH) + { + snprintf (d, n, " cost=%d", (int)fish->fish_path.cost); + n -= strlen (d);d += strlen (d); + } + + snprintf (d, n, " error=%.10f", fish->fish.error); + n -= strlen (d);d += strlen (d); + + if (fish->class_type == BABL_FISH) + { + snprintf (d, n, " [reference]"); + n -= strlen (d);d += strlen (d); + } + + snprintf (d, n, "\n"); + n -= strlen (d);d += strlen (d); + + if (fish->class_type == BABL_FISH_PATH) + { + for (int i = 0; i < fish->fish_path.conversion_list->count; i++) + { + snprintf (d, n, "\t%s\n", + babl_get_name(fish->fish_path.conversion_list->items[i] )); + n -= strlen (d);d += strlen (d); + } + } + + return dest; +} + +static int +compare_fish_pixels (const void *a, const void *b) +{ + const Babl **fa = (void*)a; + const Babl **fb = (void*)b; + return ((*fb)->fish.pixels - (*fa)->fish.pixels); +} + +static const char * +cache_header (void) +{ + static char buf[2048]; + if (strchr (BABL_GIT_VERSION, ' ')) // we must be building from tarball + snprintf (buf, sizeof (buf), + "#%i.%i.%i BABL_PATH_LENGTH=%d BABL_TOLERANCE=%f", + BABL_MAJOR_VERSION, BABL_MINOR_VERSION, BABL_MICRO_VERSION, + _babl_max_path_len (), _babl_legal_error ()); + else + snprintf (buf, sizeof (buf), "#%s BABL_PATH_LENGTH=%d BABL_TOLERANCE=%f", + BABL_GIT_VERSION, _babl_max_path_len (), _babl_legal_error ()); + return buf; +} + +void +babl_store_db (void) +{ + BablDb *db = babl_fish_db (); + int i; + char *tmpp = calloc(8000,1); + FILE *dbfile; + + if (!tmpp) + return; + snprintf (tmpp, 8000, "%s~", fish_cache_path ()); + dbfile = fopen (tmpp, "w"); + if (!dbfile) + { + free (tmpp); + return; + } + fprintf (dbfile, "%s\n", cache_header ()); + + /* sort the list of fishes by usage, making next run more efficient - + * and the data easier to approach as data for targeted optimization + */ + qsort (db->babl_list->items, db->babl_list->count, + sizeof (Babl*), compare_fish_pixels); + + for (i = 0; i< db->babl_list->count; i++) + { + Babl *fish = db->babl_list->items[i]; + char tmp[8192]; + if (babl_fish_serialize (fish, tmp, 4096)) + fprintf (dbfile, "%s----\n", tmp); + } + fclose (dbfile); + +#ifdef _WIN32 + remove (fish_cache_path ()); +#endif + rename (tmpp, fish_cache_path()); + free (tmpp); +} + +int +_babl_fish_path_destroy (void *data); + +char * +_babl_fish_create_name (char *buf, + const Babl *source, + const Babl *destination, + int is_reference); + +void +babl_init_db (void) +{ + const char *path = fish_cache_path (); + long length = -1; + char seps[] = "\n\r"; + Babl *babl = NULL; + char *contents = NULL; + char *token; + char *tokp; + const Babl *from_format = NULL; + const Babl *to_format = NULL; + time_t tim = time (NULL); + + if (getenv ("BABL_DEBUG_CONVERSIONS")) + return; + + _babl_file_get_contents (path, &contents, &length, NULL); + if (!contents) + return; + + token = strtok_r (contents, seps, &tokp); + while( token != NULL ) + { + switch (token[0]) + { + case '-': /* finalize */ + if (babl) + { + if ((babl->fish.pixels) == (tim % 100)) + { + /* 1% chance of individual cached conversions being dropped - + * making sure mis-measured conversions do not + stick around for a long time*/ + babl_free (babl); + } + else + babl_db_insert (babl_fish_db(), babl); + } + from_format = NULL; + to_format = NULL; + babl=NULL; + break; + case '#': + /* if babl has changed in git .. drop whole cache */ + { + if (strcmp ( token, cache_header ())) + { + free (contents); + return; + } + } + break; + case '\t': + if (to_format && strchr (token, '=')) + { + char seps2[] = " "; + char *tokp2; + char *token2; + char name[4096]; + + _babl_fish_create_name (name, from_format, to_format, 1); + babl = babl_db_exist_by_name (babl_fish_db (), name); + if (babl) + { + fprintf (stderr, "%s:%i: loading of cache failed\n", + __FUNCTION__, __LINE__); + free (contents); + return; + } + + if (strstr (token, "[reference]")) + { + /* there isn't a suitable path for requested formats, + * let's create a dummy BABL_FISH instance and insert + * it into the fish database to indicate that such path + * does not exist. + */ + const char *name = "X"; /* name does not matter */ + babl = babl_calloc (1, sizeof (BablFish) + strlen (name) + 1); + + babl->class_type = BABL_FISH; + babl->instance.id = babl_fish_get_id (from_format, + to_format); + babl->instance.name = ((char *) babl) + sizeof (BablFish); + strcpy (babl->instance.name, name); + babl->fish.source = from_format; + babl->fish.destination = to_format; + babl->fish.data = (void*) 1; /* signals babl_fish() to + * show a "missing fash path" + * warning upon the first + * lookup + */ + } + else + { + babl = babl_calloc (1, sizeof (BablFishPath) + + strlen (name) + 1); + babl_set_destructor (babl, _babl_fish_path_destroy); + + babl->class_type = BABL_FISH_PATH; + babl->instance.id = babl_fish_get_id (from_format, to_format); + babl->instance.name = ((char *) babl) + sizeof (BablFishPath); + strcpy (babl->instance.name, name); + babl->fish.source = from_format; + babl->fish.destination = to_format; + babl->fish_path.conversion_list = babl_list_init_with_size (10); + _babl_fish_prepare_bpp (babl); + _babl_fish_rig_dispatch (babl); + } + + token2 = strtok_r (&token[1], seps2, &tokp2); + while( token2 != NULL ) + { + if (!strncmp (token2, "error=", 6)) + { + babl->fish.error = babl_parse_double (token2 + 6); + } + else if (!strncmp (token2, "cost=", 5)) + { + if (babl->class_type == BABL_FISH_PATH) + babl->fish_path.cost = babl_parse_double (token2 + 5); + } + else if (!strncmp (token2, "pixels=", 7)) + { + babl->fish.pixels = strtol (token2 + 7, NULL, 10); + } + token2 = strtok_r (NULL, seps2, &tokp2); + } + } + else if (to_format && babl && babl->class_type == BABL_FISH_PATH) + { + Babl *conv = (void*)babl_db_find(babl_conversion_db(), &token[1]); + if (!conv) + { + babl_free (babl); + babl = NULL; + } + else + babl_list_insert_last (babl->fish_path.conversion_list, conv); + } + break; + default: + if (!from_format) + { + from_format = (void*)babl_db_find(babl_format_db(), token); + } + else + { + to_format = (void*)babl_db_find(babl_format_db(), token); + } + break; + } + token = strtok_r (NULL, seps, &tokp); + } + if (contents) + free (contents); +} diff --git a/babl/babl-class.h b/babl/babl-class.h new file mode 100644 index 0000000..ceada22 --- /dev/null +++ b/babl/babl-class.h @@ -0,0 +1,57 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005-2008, Øyvind Kolås and others. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#ifndef _BABL_CLASS_H +#define _BABL_CLASS_H + +#include "babl.h" + + +typedef struct _BablList BablList; + +typedef int BablClassType; + +typedef int (*BablEachFunction) (Babl *entry, + void *data); + +/* All Classes in babl have common functionality like the ability + * to be iterated over, common functionality is defined through these + * macros. + */ +#define BABL_CLASS_DECLARE(klass) \ + \ +BablDb * babl_##klass##_db (void); \ +const Babl * babl_##klass##_from_id (int id); \ +void babl_##klass##_class_for_each (BablEachFunction each_fun, \ + void *user_data) + +/* common header for any item inserted into database, the actual + * implementation of babl-instance is in babl-internal + */ +typedef struct +{ + BablClassType class_type; + int id; /*< a numerical id, look at 'babl-ids.h' for the reserved + ones */ + void *creator; + char *name; /*< the name this type exists under */ + const char *doc; /*< the name this type exists under */ +} BablInstance; + + +#endif diff --git a/babl/babl-classes.h b/babl/babl-classes.h new file mode 100644 index 0000000..c25172a --- /dev/null +++ b/babl/babl-classes.h @@ -0,0 +1,97 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005-2008, Øyvind Kolås and others. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#ifndef _BABL_CLASSES_H +#define _BABL_CLASSES_H + +#include "babl-class.h" +#include "babl-db.h" + +/* magic number used at the start of all babl objects, used to do + * differentiation in polymorphic functions. (as well as manual type + * check assertions). + */ +#define BABL_MAGIC 0xbab100 + +/* class types */ +enum { + BABL_INSTANCE = BABL_MAGIC, + BABL_TYPE, + BABL_TYPE_INTEGER, + BABL_TYPE_FLOAT, + BABL_SAMPLING, + BABL_TRC, + BABL_COMPONENT, + BABL_MODEL, + BABL_FORMAT, + BABL_SPACE, + + BABL_CONVERSION, + BABL_CONVERSION_LINEAR, + BABL_CONVERSION_PLANE, + BABL_CONVERSION_PLANAR, + + BABL_FISH, + BABL_FISH_REFERENCE, + BABL_FISH_SIMPLE, + BABL_FISH_PATH, + BABL_IMAGE, + + BABL_EXTENSION, + + BABL_SKY +}; + +#include "babl-type.h" +#include "babl-sampling.h" +#include "babl-trc.h" +#include "babl-space.h" +#include "babl-component.h" +#include "babl-model.h" +#include "babl-format.h" +#include "babl-image.h" +#include "babl-conversion.h" +#include "babl-fish.h" +#include "babl-extension.h" + + +/* This union can be used for convenient access to any field without + * the need to cast if the variable already is of the type Babl* + */ +typedef union _Babl +{ + BablClassType class_type; + BablInstance instance; + BablType type; + BablSampling sampling; + BablSpace space; + BablTRC trc; + BablComponent component; + BablModel model; + BablFormat format; + BablConversion conversion; + BablImage image; + BablFish fish; + BablFishReference fish_reference; + BablFishSimple fish_simple; + BablFishPath fish_path; + BablExtension extension; +} _Babl; + + +#endif diff --git a/babl/babl-component.c b/babl/babl-component.c new file mode 100644 index 0000000..514ad26 --- /dev/null +++ b/babl/babl-component.c @@ -0,0 +1,155 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#define NEEDS_BABL_DB +#include "babl-internal.h" +#include "babl-db.h" +#include + +#include + +static Babl * +component_new (const char *name, + int id, + int luma, + int chroma, + int alpha, + const char *doc) +{ + Babl *babl; + + babl = babl_malloc (sizeof (BablComponent) + strlen (name) + 1); + babl->instance.name = (char *) babl + sizeof (BablComponent); + strcpy (babl->instance.name, name); + + babl->class_type = BABL_COMPONENT; + babl->instance.id = id; + babl->instance.doc = doc; + babl->component.luma = luma; + babl->component.chroma = chroma; + babl->component.alpha = alpha; + return babl; +} + + +static int +is_component_duplicate (Babl *babl, + int luma, + int chroma, + int alpha) +{ + if (babl->component.luma != luma || + babl->component.chroma != chroma || + babl->component.alpha != alpha) + return 0; + + return 1; +} + + +const Babl * +babl_component_new (void *first_arg, + ...) +{ + va_list varg; + Babl *babl; + int id = 0; + int luma = 0; + int chroma = 0; + int alpha = 0; + const char *name = first_arg; + const char *arg; + const char *doc = NULL; + + va_start (varg, first_arg); + + while (1) + { + arg = va_arg (varg, char *); + if (!arg) + break; + + /* first, we assume arguments to be strings */ + if (!strcmp (arg, "id")) + { + id = va_arg (varg, int); + } + else if (!strcmp (arg, "doc")) + { + doc = va_arg (varg, const char *); + } + + else if (!strcmp (arg, "luma")) + { + luma = 1; + } + + else if (!strcmp (arg, "chroma")) + { + chroma = 1; + } + + else if (!strcmp (arg, "alpha")) + { + alpha = 1; + } + + /* if we didn't point to a known string, we assume argument to be babl */ + else if (BABL_IS_BABL (arg)) + { +#ifdef BABL_LOG + Babl *babl = (Babl *) arg; + babl_log ("%s unexpected", babl_class_name (babl->class_type)); +#endif + } + + else + { + babl_fatal ("unhandled argument '%s' for component '%s'", arg, name); + } + } + + va_end (varg); + + babl = babl_db_exist (db, id, name); + if (id && !babl && babl_db_exist (db, 0, name)) + babl_fatal ("Trying to reregister BablComponent '%s' with different id!", + name); + + if (babl) + { + /* There is an instance already registered by the required id/name, + * returning the preexistent one instead if it doesn't differ. + */ + if (!is_component_duplicate (babl, luma, chroma, alpha)) + babl_fatal ("BablComponent '%s' already registered " + "with different attributes!", name); + return babl; + } + + babl = component_new (name, id, luma, chroma, alpha, doc); + + /* Since there is not an already registered instance by the required + * id/name, inserting newly created class into database. + */ + babl_db_insert (db, babl); + return babl; +} + +BABL_CLASS_IMPLEMENT (component) diff --git a/babl/babl-component.h b/babl/babl-component.h new file mode 100644 index 0000000..483b840 --- /dev/null +++ b/babl/babl-component.h @@ -0,0 +1,36 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005-2008, Øyvind Kolås and others. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#ifndef _BABL_COMPONENT_H +#define _BABL_COMPONENT_H + + +/****************************************************************/ +/* BablComponent */ +BABL_CLASS_DECLARE (component); + + +typedef struct +{ + BablInstance instance; + int luma; + int chroma; + int alpha; +} BablComponent; + +#endif diff --git a/babl/babl-conversion.c b/babl/babl-conversion.c new file mode 100644 index 0000000..6c5d4f1 --- /dev/null +++ b/babl/babl-conversion.c @@ -0,0 +1,557 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + + +#include "config.h" +#include +#include +#include +#define NEEDS_BABL_DB +#include "babl-internal.h" +#include "babl-db.h" +#include "babl-ref-pixels.h" + +static void +babl_conversion_plane_process (BablConversion *conversion, + const void *source, + void *destination, + int src_pitch, + int dst_pitch, + long n, + void *user_data) +{ + conversion->function.plane ((void*)conversion, source, destination, + src_pitch, dst_pitch, + n, + user_data); +} + +static void +babl_conversion_planar_process (const Babl *babl, + const char *src, + char *dst, + long n, + void *user_data) +{ + BablConversion *conversion = (void*)babl; + const BablImage *source = (void*)src; + BablImage *destination = (void*)dst; +#ifdef USE_ALLOCA + const char **src_data = alloca (sizeof (void *) * source->components); + char **dst_data = alloca (sizeof (void *) * destination->components); +#else + const char *src_data[BABL_MAX_COMPONENTS]; + char *dst_data[BABL_MAX_COMPONENTS]; +#endif + + memcpy (src_data, source->data, sizeof (void *) * source->components); + memcpy (dst_data, destination->data, sizeof (void *) * destination->components); + conversion->function.planar ((void*)conversion, + source->components, + src_data, + source->pitch, + destination->components, + dst_data, + destination->pitch, + n, + user_data); +} + +static void dispatch_plane (const Babl *babl, + const char *source, + char *destination, + long n, + void *user_data) +{ + const BablConversion *conversion = &babl->conversion; + const void *src_data = NULL; + void *dst_data = NULL; + int src_pitch = 0; + int dst_pitch = 0; + + if (BABL_IS_BABL (source)) + { + BablImage *img; + + img = (BablImage *) source; + src_data = img->data[0]; + src_pitch = img->pitch[0]; + } + if (BABL_IS_BABL (destination)) + { + BablImage *img = (BablImage *) destination; + + dst_data = img->data[0]; + dst_pitch = img->pitch[0]; + } + + if (!src_data) + src_data = source; + if (!src_pitch) + src_pitch = BABL (conversion->source)->type.bits / 8; + if (!dst_data) + dst_data = destination; + if (!dst_pitch) + dst_pitch = BABL (conversion->destination)->type.bits / 8; + + babl_conversion_plane_process ((void*)conversion, + src_data, dst_data, + src_pitch, dst_pitch, + n, user_data); +} + +static inline void +babl_conversion_rig_dispatch (const Babl *babl) +{ + BablConversion *conversion = (BablConversion *) babl; + switch (BABL (conversion)->class_type) + { + case BABL_CONVERSION_PLANE: + conversion->dispatch = dispatch_plane; + break; + case BABL_CONVERSION_PLANAR: + conversion->dispatch = babl_conversion_planar_process; + break; + case BABL_CONVERSION_LINEAR: + conversion->dispatch = conversion->function.linear; + break; + } +} + +Babl * +_conversion_new (const char *name, + int id, + const Babl *source, + const Babl *destination, + BablFuncLinear linear, + BablFuncPlane plane, + BablFuncPlanar planar, + void *user_data, + int allow_collision) +{ + Babl *babl = NULL; + + babl_assert (source->class_type == + destination->class_type); + + babl = babl_malloc (sizeof (BablConversion) + strlen (name) + 1); + babl->instance.name = (char *) babl + sizeof (BablConversion); + strcpy (babl->instance.name, name); + + if (linear) + { + babl->class_type = BABL_CONVERSION_LINEAR; + babl->conversion.function.linear = linear; + } + else if (plane) + { + babl->class_type = BABL_CONVERSION_PLANE; + babl->conversion.function.plane = plane; + } + else if (planar) + { + babl->class_type = BABL_CONVERSION_PLANAR; + babl->conversion.function.planar = planar; + } + switch (source->class_type) + { + case BABL_TYPE: + if (linear) /* maybe linear could take a special argument, passed as an + additional key/value pair in the constructor. To cast it + as a generic N-element conversion, thus making it applicable + to being generic for any within model conversion of plain + buffers. + */ + { + babl_fatal ("linear conversions not supported for %s", + babl_class_name (source->class_type)); + } + else if (planar) + { + babl_fatal ("planar conversions not supported for %s", + babl_class_name (source->class_type)); + } + break; + + case BABL_MODEL: + if (plane) + { + babl_fatal ("plane conversions not supported for %s", + babl_class_name (source->class_type)); + } + break; + + case BABL_FORMAT: + break; + + default: + babl_fatal ("%s unexpected", babl_class_name (babl->class_type)); + break; + } + + babl->instance.id = id; + babl->conversion.source = source; + babl->conversion.destination = destination; + babl->conversion.error = -1.0; + babl->conversion.cost = 69L; + + babl->conversion.pixels = 0; + + babl->conversion.data = user_data; + + if (babl->class_type == BABL_CONVERSION_LINEAR && + BABL (babl->conversion.source)->class_type == BABL_MODEL) + { + const Babl *src_format = NULL; + const Babl *dst_format = NULL; + + src_format = babl_format_with_model_as_type ( + BABL (babl->conversion.source), + babl_type_from_id (BABL_DOUBLE)); + dst_format = babl_format_with_model_as_type ( + BABL (babl->conversion.destination), + babl_type_from_id (BABL_DOUBLE)); + + if(allow_collision){ + const Babl *fish = babl_conversion_find (src_format, dst_format); + if (fish) + return (void*)fish; + } + babl_conversion_new ( + src_format, + dst_format, + "linear", linear, + "data", user_data, + allow_collision?"allow-collision":NULL, + NULL); + babl->conversion.error = 0.0; + } + + babl_conversion_rig_dispatch (babl); + return babl; +} + +static char buf[512] = ""; +static int collisions = 0; + +static char * +create_name (Babl *source, + Babl *destination, + int type) +{ + if (babl_extender ()) + { + snprintf (buf, sizeof (buf), "%s %i: %s%s to %s", + BABL (babl_extender ())->instance.name, + collisions, + type == BABL_CONVERSION_LINEAR ? "" : + type == BABL_CONVERSION_PLANE ? "plane " : + type == BABL_CONVERSION_PLANAR ? "planar " : "Eeeek! ", + source->instance.name, + destination->instance.name); + } + else + { + snprintf (buf, sizeof (buf), "%s %s to %s %i", + type == BABL_CONVERSION_LINEAR ? "" : + type == BABL_CONVERSION_PLANE ? "plane " : + type == BABL_CONVERSION_PLANAR ? "planar " : "Eeeek! ", + source->instance.name, + destination->instance.name, + collisions); + } + return buf; +} + +const char * +babl_conversion_create_name (Babl *source, + Babl *destination, + int type, + int allow_collision) +{ + Babl *babl; + char *name; + int id = 0; + collisions = 0; + name = create_name (source, destination, type); + + if (allow_collision == 0) + { + babl = babl_db_exist (db, id, name); + while (babl) + { + /* we allow multiple conversions to be registered per extender, each + of them ending up with their own unique name + */ + collisions++; + name = create_name (source, destination, type); + babl = babl_db_exist (db, id, name); + } + } + return name; +} + +const Babl * +babl_conversion_new (const void *first_arg, + ...) +{ + va_list varg; + Babl *babl; + + int id = 0; + BablFuncLinear linear = NULL; + BablFuncPlane plane = NULL; + BablFuncPlanar planar = NULL; + int type = 0; + int got_func = 0; + const char *arg = first_arg; + void *user_data= NULL; + + Babl *source; + Babl *destination; + char *name; + int allow_collision = 0; + + va_start (varg, first_arg); + source = (Babl *) arg; + destination = va_arg (varg, Babl *); + arg = va_arg (varg, char *); + + assert (BABL_IS_BABL (source)); + assert (BABL_IS_BABL (destination)); + + + while (arg) + { + if (!strcmp (arg, "id")) + { + id = va_arg (varg, int); + } + + else if (!strcmp (arg, "data")) + { + user_data = va_arg (varg, void*); + } + + else if (!strcmp (arg, "allow-collision")) + { + allow_collision = 1; + } + else if (!strcmp (arg, "linear")) + { + if (got_func++) + { + babl_fatal ("already got a conversion func\n"); + } + linear = va_arg (varg, BablFuncLinear); + } + + else if (!strcmp (arg, "plane")) + { + if (got_func++) + { + babl_fatal ("already got a conversion func\n"); + } + plane = va_arg (varg, BablFuncPlane); + } + + else if (!strcmp (arg, "planar")) + { + if (got_func++) + { + babl_fatal ("already got a conversion func\n"); + } + planar = va_arg (varg, BablFuncPlanar); + } + + else + { + babl_fatal ("unhandled argument '%s'", arg); + } + + arg = va_arg (varg, char *); + } + + va_end (varg); + + assert (source); + assert (destination); + + if (linear) + { + type = BABL_CONVERSION_LINEAR; + } + else if (plane) + { + type = BABL_CONVERSION_PLANE; + } + else if (planar) + { + type = BABL_CONVERSION_PLANAR; + } + + name = (void*) babl_conversion_create_name (source, destination, type, allow_collision); + + babl = _conversion_new (name, id, source, destination, linear, plane, planar, + user_data, allow_collision); + + /* Since there is not an already registered instance by the required + * id/name, inserting newly created class into database. + */ + babl_db_insert (db, babl); + if (!source->type.from_list) + source->type.from_list = babl_list_init_with_size (BABL_CONVERSIONS); + babl_list_insert_last (source->type.from_list, babl); + return babl; +} + + +long +babl_conversion_cost (BablConversion *conversion) +{ + if (!conversion) + return 100000000L; + if (conversion->error == -1.0) + babl_conversion_error (conversion); + return conversion->cost; +} + +double +babl_conversion_error (BablConversion *conversion) +{ + Babl *fmt_source; + Babl *fmt_destination; + + const Babl *fmt_rgba_double = babl_format_with_space ("RGBA double", + conversion->destination->format.space); + double error = 0.0; + long ticks_start = 0; + long ticks_end = 0; + + const int test_pixels = babl_get_num_conversion_test_pixels (); + const double *test = babl_get_conversion_test_pixels (); + + void *source; + void *destination; + double *destination_rgba_double; + void *ref_destination; + double *ref_destination_rgba_double; + + Babl *fish_rgba_to_source; + Babl *fish_reference; + Babl *fish_destination_to_rgba; + + if (!conversion) + return 0.0; + + if (conversion->error != -1.0) /* double conversion against a set value should work */ + { + return conversion->error; + } + + fmt_source = BABL (conversion->source); + fmt_destination = BABL (conversion->destination); + + fish_rgba_to_source = babl_fish_reference (fmt_rgba_double, fmt_source); + fish_reference = babl_fish_reference (fmt_source, fmt_destination); + fish_destination_to_rgba = babl_fish_reference (fmt_destination, fmt_rgba_double); + + if (fmt_source == fmt_destination) + { + conversion->error = 0.0; + return 0.0; + } + + if (!(fmt_source->instance.id != BABL_RGBA && + fmt_destination->instance.id != BABL_RGBA && + fmt_source->instance.id != BABL_DOUBLE && + fmt_destination->instance.id != BABL_DOUBLE && + fmt_source->class_type == BABL_FORMAT && + fmt_destination->class_type == BABL_FORMAT)) + { + conversion->error = 0.0000042; + } + + source = babl_calloc (test_pixels+1, fmt_source->format.bytes_per_pixel); + /* +1 is masking valgrind Invalid read of 16 + * false positives */ + destination = babl_calloc (test_pixels, fmt_destination->format.bytes_per_pixel); + ref_destination = babl_calloc (test_pixels, fmt_destination->format.bytes_per_pixel); + destination_rgba_double = babl_calloc (test_pixels, fmt_rgba_double->format.bytes_per_pixel); + ref_destination_rgba_double = babl_calloc (test_pixels, fmt_rgba_double->format.bytes_per_pixel); + + babl_process (fish_rgba_to_source, + test, source, test_pixels); + + if (BABL(conversion)->class_type == BABL_CONVERSION_LINEAR) + { + ticks_start = babl_ticks (); + babl_process (babl_fish_simple (conversion), + source, destination, test_pixels); + ticks_end = babl_ticks (); + } + else + { + /* we could still measure it, but for the paths we only really consider + * the linear ones anyways */ + ticks_end = 1000; + } + + babl_process (fish_reference, + source, ref_destination, test_pixels); + + babl_process (fish_destination_to_rgba, + ref_destination, ref_destination_rgba_double, test_pixels); + babl_process (fish_destination_to_rgba, + destination, destination_rgba_double, test_pixels); + + error = babl_rel_avg_error (destination_rgba_double, + ref_destination_rgba_double, + test_pixels * 4); + + fish_rgba_to_source->fish.pixels -= test_pixels; + fish_reference->fish.pixels -= test_pixels; + fish_destination_to_rgba->fish.pixels -= 2 * test_pixels; + + babl_free (source); + babl_free (destination); + babl_free (destination_rgba_double); + babl_free (ref_destination); + babl_free (ref_destination_rgba_double); + + conversion->error = error; + conversion->cost = ticks_end - ticks_start; + + return error; +} + +const Babl * +babl_conversion_get_source_space (const Babl *conversion) +{ + return conversion->conversion.source->format.space; +} + +const Babl * +babl_conversion_get_destination_space (const Babl *conversion) +{ + return conversion->conversion.destination->format.space; +} + + + +BABL_CLASS_IMPLEMENT (conversion) diff --git a/babl/babl-conversion.h b/babl/babl-conversion.h new file mode 100644 index 0000000..c187223 --- /dev/null +++ b/babl/babl-conversion.h @@ -0,0 +1,63 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005-2008, Øyvind Kolås and others. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#ifndef _BABL_CONVERSION_H +#define _BABL_CONVERSION_H + +BABL_CLASS_DECLARE (conversion); + +const Babl * babl_conversion (const char *name); + +typedef struct _BablConversion BablConversion; + + +/* Signature of functions registered for reference type + * conversions, + */ +typedef void (*BablFuncPlane) (BablConversion *conversion, + const char *src, + char *dst, + int src_pitch, + int dst_pitch, + long n, + void *user_data); + +struct +_BablConversion { + BablInstance instance; + const Babl *source; + const Babl *destination; + void (*dispatch) (const Babl *babl, const char *src, char *dst, long n, + void *user_data); + void *data; /* user data */ + + long cost; + double error; + union + { + BablFuncLinear linear; + BablFuncPlane plane; + BablFuncPlanar planar; + } function; + long pixels; +}; + + + + +#endif diff --git a/babl/babl-core.c b/babl/babl-core.c new file mode 100644 index 0000000..d78b5e5 --- /dev/null +++ b/babl/babl-core.c @@ -0,0 +1,164 @@ +/* babl - dynamically extendable universal pixel conversion library. + + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include +#include "babl-internal.h" +#include "babl-ids.h" +#include "util.h" + +static long +convert_double_double (const Babl *babl, + char *src, + char *dst, + int src_pitch, + int dst_pitch, + long n) +{ + if (src_pitch == 64 && + dst_pitch == 64) + { + memcpy (dst, src, n / 8); + return n; + } + + while (n--) + { + (*(double *) dst) = (*(double *) src); + dst += dst_pitch; + src += src_pitch; + } + return n; +} + +/* + static long + copy_strip_1 (int src_bands, + char **src, + int *src_pitch, + int dst_bands, + char **dst, + int *dst_pitch, + long n) + { + BABL_PLANAR_SANITY + while (n--) + { + int i; + + for (i=0;i. + */ + +/* + * x86 bits Copyright (C) Manish Singh + */ + +/* + * PPC CPU acceleration detection was taken from DirectFB but seems to be + * originating from mpeg2dec with the following copyright: + * + * Copyright (C) 1999-2001 Aaron Holtzman + */ + +#include "config.h" +#include +#include +#include + +#include "babl-cpuaccel.h" + +typedef unsigned int gboolean; +typedef unsigned int guint32; +typedef int gint; +typedef char gchar; +typedef size_t gsize; +#define TRUE 1 +#define FALSE 0 +#define G_GNUC_CONST + +static BablCpuAccelFlags cpu_accel (void) G_GNUC_CONST; + +static gboolean use_cpu_accel = TRUE; + + +/** + * babl_cpu_accel_get_support: + * + * Query for CPU acceleration support. + * + * Return value: #BablCpuAccelFlags as supported by the CPU. + */ +BablCpuAccelFlags +babl_cpu_accel_get_support (void) +{ + return use_cpu_accel ? cpu_accel () : BABL_CPU_ACCEL_NONE; +} + +/** + * babl_cpu_accel_set_use: + * @use: whether to use CPU acceleration features or not + * + * This function is for internal use only. + */ +void +babl_cpu_accel_set_use (gboolean use) +{ + use_cpu_accel = use ? TRUE : FALSE; +} + + +#if defined(ARCH_X86) && defined(USE_MMX) && defined(__GNUC__) + +#define HAVE_ACCEL 1 + + +typedef enum +{ + ARCH_X86_VENDOR_NONE, + ARCH_X86_VENDOR_INTEL, + ARCH_X86_VENDOR_AMD, + ARCH_X86_VENDOR_CENTAUR, + ARCH_X86_VENDOR_CYRIX, + ARCH_X86_VENDOR_NSC, + ARCH_X86_VENDOR_TRANSMETA, + ARCH_X86_VENDOR_NEXGEN, + ARCH_X86_VENDOR_RISE, + ARCH_X86_VENDOR_UMC, + ARCH_X86_VENDOR_SIS, + ARCH_X86_VENDOR_HYGON, + ARCH_X86_VENDOR_UNKNOWN = 0xff +} X86Vendor; + +enum +{ + ARCH_X86_INTEL_FEATURE_MMX = 1 << 23, + ARCH_X86_INTEL_FEATURE_XMM = 1 << 25, + ARCH_X86_INTEL_FEATURE_XMM2 = 1 << 26, + + ARCH_X86_AMD_FEATURE_MMXEXT = 1 << 22, + ARCH_X86_AMD_FEATURE_3DNOW = 1 << 31, + + ARCH_X86_CENTAUR_FEATURE_MMX = 1 << 23, + ARCH_X86_CENTAUR_FEATURE_MMXEXT = 1 << 24, + ARCH_X86_CENTAUR_FEATURE_3DNOW = 1 << 31, + + ARCH_X86_CYRIX_FEATURE_MMX = 1 << 23, + ARCH_X86_CYRIX_FEATURE_MMXEXT = 1 << 24 +}; + +enum +{ + ARCH_X86_INTEL_FEATURE_PNI = 1 << 0, + ARCH_X86_INTEL_FEATURE_SSSE3 = 1 << 9, + ARCH_X86_INTEL_FEATURE_SSE4_1 = 1 << 19, + ARCH_X86_INTEL_FEATURE_SSE4_2 = 1 << 20, + ARCH_X86_INTEL_FEATURE_AVX = 1 << 28, + ARCH_X86_INTEL_FEATURE_F16C = 1 << 29, + + /* extended features */ + ARCH_X86_INTEL_FEATURE_AVX2 = 1 << 5 +}; + +#if !defined(ARCH_X86_64) && (defined(PIC) || defined(__PIC__)) +#define cpuid(op,eax,ebx,ecx,edx) \ + __asm__ ("movl %%ebx, %%esi\n\t" \ + "xor %%ecx, %%ecx\n\t" \ + "cpuid\n\t" \ + "xchgl %%ebx,%%esi" \ + : "=a" (eax), \ + "=S" (ebx), \ + "=c" (ecx), \ + "=d" (edx) \ + : "0" (op)) +#else +#define cpuid(op,eax,ebx,ecx,edx) \ + __asm__ ("xor %%ecx, %%ecx\n\t" \ + "cpuid" \ + : "=a" (eax), \ + "=b" (ebx), \ + "=c" (ecx), \ + "=d" (edx) \ + : "0" (op)) +#endif + + +static X86Vendor +arch_get_vendor (void) +{ + guint32 eax, ebx, ecx, edx; + guint32 intid[4]; + char *id = (char *) intid; + +#ifndef ARCH_X86_64 + /* Only need to check this on ia32 */ + __asm__ ("pushfl\n\t" + "pushfl\n\t" + "popl %0\n\t" + "movl %0,%1\n\t" + "xorl $0x200000,%0\n\t" + "pushl %0\n\t" + "popfl\n\t" + "pushfl\n\t" + "popl %0\n\t" + "popfl" + : "=a" (eax), + "=c" (ecx) + : + : "cc"); + + if (eax == ecx) + return ARCH_X86_VENDOR_NONE; +#endif + + cpuid (0, eax, ebx, ecx, edx); + + if (eax == 0) + return ARCH_X86_VENDOR_NONE; + + intid[0] = ebx; + intid[1] = edx; + intid[2] = ecx; + + id[12] = '\0'; + +#ifdef ARCH_X86_64 + if (strcmp (id, "AuthenticAMD") == 0) + return ARCH_X86_VENDOR_AMD; + else if (strcmp (id, "HygonGenuine") == 0) + return ARCH_X86_VENDOR_HYGON; + else if (strcmp (id, "GenuineIntel") == 0) + return ARCH_X86_VENDOR_INTEL; +#else + if (strcmp (id, "GenuineIntel") == 0) + return ARCH_X86_VENDOR_INTEL; + else if (strcmp (id, "AuthenticAMD") == 0) + return ARCH_X86_VENDOR_AMD; + else if (strcmp (id, "HygonGenuine") == 0) + return ARCH_X86_VENDOR_HYGON; + else if (strcmp (id, "CentaurHauls") == 0) + return ARCH_X86_VENDOR_CENTAUR; + else if (strcmp (id, "CyrixInstead") == 0) + return ARCH_X86_VENDOR_CYRIX; + else if (strcmp (id, "Geode by NSC") == 0) + return ARCH_X86_VENDOR_NSC; + else if (strcmp (id, "GenuineTMx86") == 0 || + strcmp (id, "TransmetaCPU") == 0) + return ARCH_X86_VENDOR_TRANSMETA; + else if (strcmp (id, "NexGenDriven") == 0) + return ARCH_X86_VENDOR_NEXGEN; + else if (strcmp (id, "RiseRiseRise") == 0) + return ARCH_X86_VENDOR_RISE; + else if (strcmp (id, "UMC UMC UMC ") == 0) + return ARCH_X86_VENDOR_UMC; + else if (strcmp (id, "SiS SiS SiS ") == 0) + return ARCH_X86_VENDOR_SIS; +#endif + + return ARCH_X86_VENDOR_UNKNOWN; +} + +static guint32 +arch_accel_intel (void) +{ + guint32 caps = 0; + +#ifdef USE_MMX + { + guint32 eax, ebx, ecx, edx; + + cpuid (1, eax, ebx, ecx, edx); + + if ((edx & ARCH_X86_INTEL_FEATURE_MMX) == 0) + return 0; + + caps = BABL_CPU_ACCEL_X86_MMX; + +#ifdef USE_SSE + if (edx & ARCH_X86_INTEL_FEATURE_XMM) + caps |= BABL_CPU_ACCEL_X86_SSE | BABL_CPU_ACCEL_X86_MMXEXT; + + if (edx & ARCH_X86_INTEL_FEATURE_XMM2) + caps |= BABL_CPU_ACCEL_X86_SSE2; + + if (ecx & ARCH_X86_INTEL_FEATURE_PNI) + caps |= BABL_CPU_ACCEL_X86_SSE3; + + if (ecx & ARCH_X86_INTEL_FEATURE_SSSE3) + caps |= BABL_CPU_ACCEL_X86_SSSE3; + + if (ecx & ARCH_X86_INTEL_FEATURE_SSE4_1) + caps |= BABL_CPU_ACCEL_X86_SSE4_1; + + if (ecx & ARCH_X86_INTEL_FEATURE_F16C) + caps |= BABL_CPU_ACCEL_X86_F16C; + + cpuid (0, eax, ebx, ecx, edx); + + if (eax >= 7) + { + cpuid (7, eax, ebx, ecx, edx); + + if (ebx & ARCH_X86_INTEL_FEATURE_AVX2) + caps |= BABL_CPU_ACCEL_X86_AVX2; + } +#endif /* USE_SSE */ + } +#endif /* USE_MMX */ + + return caps; +} + +static guint32 +arch_accel_amd (void) +{ + guint32 caps; + + caps = arch_accel_intel (); + +#ifdef USE_MMX + { + guint32 eax, ebx, ecx, edx; + + cpuid (0x80000000, eax, ebx, ecx, edx); + + if (eax < 0x80000001) + return caps; + +#ifdef USE_SSE + cpuid (0x80000001, eax, ebx, ecx, edx); + + if (edx & ARCH_X86_AMD_FEATURE_3DNOW) + caps |= BABL_CPU_ACCEL_X86_3DNOW; + + if (edx & ARCH_X86_AMD_FEATURE_MMXEXT) + caps |= BABL_CPU_ACCEL_X86_MMXEXT; +#endif /* USE_SSE */ + } +#endif /* USE_MMX */ + + return caps; +} + +static guint32 +arch_accel_centaur (void) +{ + guint32 caps; + + caps = arch_accel_intel (); + +#ifdef USE_MMX + { + guint32 eax, ebx, ecx, edx; + + cpuid (0x80000000, eax, ebx, ecx, edx); + + if (eax < 0x80000001) + return caps; + + cpuid (0x80000001, eax, ebx, ecx, edx); + + if (edx & ARCH_X86_CENTAUR_FEATURE_MMX) + caps |= BABL_CPU_ACCEL_X86_MMX; + +#ifdef USE_SSE + if (edx & ARCH_X86_CENTAUR_FEATURE_3DNOW) + caps |= BABL_CPU_ACCEL_X86_3DNOW; + + if (edx & ARCH_X86_CENTAUR_FEATURE_MMXEXT) + caps |= BABL_CPU_ACCEL_X86_MMXEXT; +#endif /* USE_SSE */ + } +#endif /* USE_MMX */ + + return caps; +} + +static guint32 +arch_accel_cyrix (void) +{ + guint32 caps; + + caps = arch_accel_intel (); + +#ifdef USE_MMX + { + guint32 eax, ebx, ecx, edx; + + cpuid (0, eax, ebx, ecx, edx); + + if (eax != 2) + return caps; + + cpuid (0x80000001, eax, ebx, ecx, edx); + + if (edx & ARCH_X86_CYRIX_FEATURE_MMX) + caps |= BABL_CPU_ACCEL_X86_MMX; + +#ifdef USE_SSE + if (edx & ARCH_X86_CYRIX_FEATURE_MMXEXT) + caps |= BABL_CPU_ACCEL_X86_MMXEXT; +#endif /* USE_SSE */ + } +#endif /* USE_MMX */ + + return caps; +} + +#ifdef USE_SSE +static jmp_buf sigill_return; + +static void +sigill_handler (gint n) +{ + longjmp (sigill_return, 1); +} + +static gboolean +arch_accel_sse_os_support (void) +{ + if (setjmp (sigill_return)) + { + return FALSE; + } + else + { + signal (SIGILL, sigill_handler); + __asm__ __volatile__ ("xorps %xmm0, %xmm0"); + signal (SIGILL, SIG_DFL); + } + + return TRUE; +} +#endif /* USE_SSE */ + +static guint32 +arch_accel (void) +{ + guint32 caps; + X86Vendor vendor; + + vendor = arch_get_vendor (); + + switch (vendor) + { + case ARCH_X86_VENDOR_NONE: + caps = 0; + break; + + case ARCH_X86_VENDOR_AMD: + case ARCH_X86_VENDOR_HYGON: + caps = arch_accel_amd (); + break; + + case ARCH_X86_VENDOR_CENTAUR: + caps = arch_accel_centaur (); + break; + + case ARCH_X86_VENDOR_CYRIX: + case ARCH_X86_VENDOR_NSC: + caps = arch_accel_cyrix (); + break; + + /* check for what Intel speced, even if UNKNOWN */ + default: + caps = arch_accel_intel (); + break; + } + +#ifdef USE_SSE + if ((caps & BABL_CPU_ACCEL_X86_SSE) && !arch_accel_sse_os_support ()) + caps &= ~(BABL_CPU_ACCEL_X86_SSE | + BABL_CPU_ACCEL_X86_SSE2 | + BABL_CPU_ACCEL_X86_SSE3 | + BABL_CPU_ACCEL_X86_SSSE3 | + BABL_CPU_ACCEL_X86_SSE4_1); +#endif + + return caps; +} + +#endif /* ARCH_X86 && USE_MMX && __GNUC__ */ + + +#if defined(ARCH_PPC) && defined (USE_ALTIVEC) + +#if defined(HAVE_ALTIVEC_SYSCTL) + +#include + +#define HAVE_ACCEL 1 + +static guint32 +arch_accel (void) +{ + gint sels[2] = { CTL_HW, HW_VECTORUNIT }; + gboolean has_vu = FALSE; + gsize length = sizeof(has_vu); + gint err; + + err = sysctl (sels, 2, &has_vu, &length, NULL, 0); + + if (err == 0 && has_vu) + return BABL_CPU_ACCEL_PPC_ALTIVEC; + + return 0; +} + +#elif defined(__GNUC__) + +#define HAVE_ACCEL 1 + +static sigjmp_buf jmpbuf; +static volatile sig_atomic_t canjump = 0; + +static void +sigill_handler (gint sig) +{ + if (!canjump) + { + signal (sig, SIG_DFL); + raise (sig); + } + + canjump = 0; + siglongjmp (jmpbuf, 1); +} + +static guint32 +arch_accel (void) +{ + signal (SIGILL, sigill_handler); + + if (sigsetjmp (jmpbuf, 1)) + { + signal (SIGILL, SIG_DFL); + return 0; + } + + canjump = 1; + + asm volatile ("mtspr 256, %0\n\t" + "vand %%v0, %%v0, %%v0" + : + : "r" (-1)); + + signal (SIGILL, SIG_DFL); + + return BABL_CPU_ACCEL_PPC_ALTIVEC; +} +#endif /* __GNUC__ */ + +#endif /* ARCH_PPC && USE_ALTIVEC */ + + +static BablCpuAccelFlags +cpu_accel (void) +{ +#ifdef HAVE_ACCEL + static guint32 accel = ~0U; + + if (accel != ~0U) + return accel; + + accel = arch_accel (); + +#if defined(ARCH_X86_64) + accel |= BABL_CPU_ACCEL_X86_64; +#endif + + return (BablCpuAccelFlags) accel; + +#else /* !HAVE_ACCEL */ + return BABL_CPU_ACCEL_NONE; +#endif +} diff --git a/babl/babl-cpuaccel.h b/babl/babl-cpuaccel.h new file mode 100644 index 0000000..b8a6855 --- /dev/null +++ b/babl/babl-cpuaccel.h @@ -0,0 +1,50 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005-2008, Øyvind Kolås and others. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#ifndef _BABL_CPU_ACCEL_H +#define _BABL_CPU_ACCEL_H + +typedef enum +{ + BABL_CPU_ACCEL_NONE = 0x0, + + /* x86 accelerations */ + BABL_CPU_ACCEL_X86_MMX = 0x01000000, + BABL_CPU_ACCEL_X86_3DNOW = 0x40000000, + BABL_CPU_ACCEL_X86_MMXEXT = 0x20000000, + BABL_CPU_ACCEL_X86_SSE = 0x10000000, + BABL_CPU_ACCEL_X86_SSE2 = 0x08000000, + BABL_CPU_ACCEL_X86_SSE3 = 0x02000000, + BABL_CPU_ACCEL_X86_SSSE3 = 0x00800000, + BABL_CPU_ACCEL_X86_SSE4_1 = 0x00400000, + /* BABL_CPU_ACCEL_X86_SSE4_2 = 0x00200000, */ + /* BABL_CPU_ACCEL_X86_AVX = 0x00080000, */ + BABL_CPU_ACCEL_X86_F16C = 0x00040000, + BABL_CPU_ACCEL_X86_AVX2 = 0x00020000, + + /* powerpc accelerations */ + BABL_CPU_ACCEL_PPC_ALTIVEC = 0x04000000, + BABL_CPU_ACCEL_X86_64 = 0x00100000 +} BablCpuAccelFlags; + + +BablCpuAccelFlags babl_cpu_accel_get_support (void); +void babl_cpu_accel_set_use (unsigned int use); + + +#endif /* _BABL_CPU_ACCEL_H */ diff --git a/babl/babl-db.c b/babl/babl-db.c new file mode 100644 index 0000000..2ae47a4 --- /dev/null +++ b/babl/babl-db.c @@ -0,0 +1,220 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +/* Reimplementation of database code using redundant hash tables + * for faster searching by id/name and using list for fast item enumeration. + * Copyright (C) 2008, Jan Heller + */ + +#define _BABL_DB_C + +#include "config.h" +#include +#include "babl-internal.h" + +static int +_babl_hash_by_str (BablHashTable *htab, + const char *str) +{ + int hash = 0; + + while (*str) + { + hash += *str++; + hash += (hash << 10); + hash ^= (hash >> 6); + } + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + + return (hash & htab->mask); +} + +int +babl_hash_by_str (BablHashTable *htab, + const char *str) +{ + return _babl_hash_by_str (htab, str); +} + + +static int +_babl_hash_by_int (BablHashTable *htab, + int id) +{ + int hash = 0; + hash += id & 0xFF; + hash += (hash << 10); + hash ^= (hash >> 6); + id >>= 8; + hash += id & 0xFF; + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + + return (hash & htab->mask); +} + +int +babl_hash_by_int (BablHashTable *htab, + int id) +{ + return _babl_hash_by_int (htab, id); +} + +static int +db_find_by_name (Babl *item, + void *data) +{ + if (!strcmp (item->instance.name, (char *) data)) + return 1; + return 0; +} + +static int +db_find_by_id (Babl *item, + void *data) +{ + if (item->instance.id == *((int *) data)) + return 1; + return 0; +} + +static int +db_hash_by_name (BablHashTable *htab, + Babl *item) +{ + return _babl_hash_by_str (htab, item->instance.name); +} + +static int +db_hash_by_id (BablHashTable *htab, + Babl *item) +{ + return _babl_hash_by_int (htab, item->instance.id); +} + +static int +each_free (Babl *data, + void *foo) +{ + babl_free (data); + return 0; +} + +static int +babl_db_destroy (void *data) +{ + BablDb *db = data; + babl_assert (db); + + babl_db_each (db, each_free, NULL); + babl_mutex_destroy (db->mutex); + babl_free (db->name_hash); + babl_free (db->id_hash); + babl_free (db->babl_list); + return 0; +} + +BablDb * +babl_db_init (void) +{ + BablDb *db = babl_calloc (sizeof (BablDb), 1); + babl_set_destructor (db, babl_db_destroy); + + db->name_hash = babl_hash_table_init (db_hash_by_name, db_find_by_name); + db->id_hash = babl_hash_table_init (db_hash_by_id, db_find_by_id); + db->babl_list = babl_list_init_with_size (512); + db->mutex = babl_mutex_new (); + + return db; +} + + +Babl * +babl_db_find (BablDb *db, + const char *name) +{ + return babl_hash_table_find (db->name_hash, _babl_hash_by_str (db->name_hash, name), + NULL, (void *) name); +} + +int +babl_db_count (BablDb *db) +{ + return db->babl_list->count; +} + +Babl * +babl_db_insert (BablDb *db, + Babl *item) +{ + babl_mutex_lock (db->mutex); + if (item->instance.id) + babl_hash_table_insert (db->id_hash, item); + babl_hash_table_insert (db->name_hash, item); + babl_list_insert_last (db->babl_list, item); + + /* this point all registered items pass through, a nice + * place to brand them with where the item came from. */ + item->instance.creator = babl_extender (); + babl_mutex_unlock (db->mutex); + return item; +} + +void +babl_db_each (BablDb *db, + BablEachFunction each_fun, + void *user_data) +{ + babl_list_each (db->babl_list, each_fun, user_data); +} + + +Babl * +babl_db_exist (BablDb *db, + int id, + const char *name) +{ + Babl *ret; + if (id) + ret = babl_hash_table_find (db->id_hash, _babl_hash_by_int (db->id_hash, id), NULL, &id); + else + ret = babl_hash_table_find (db->name_hash, _babl_hash_by_str (db->name_hash, name), NULL, (void *) name); + return ret; +} + +Babl * +babl_db_exist_by_id (BablDb *db, + int id) +{ + Babl *ret; + ret = babl_hash_table_find (db->id_hash, _babl_hash_by_int (db->id_hash, id), NULL, &id); + return ret; +} + +Babl * +babl_db_exist_by_name (BablDb *db, + const char *name) +{ + Babl *ret; + ret = babl_hash_table_find (db->name_hash, _babl_hash_by_str (db->name_hash, name), + NULL, (void *) name); + return ret; +} diff --git a/babl/babl-db.h b/babl/babl-db.h new file mode 100644 index 0000000..9b170d1 --- /dev/null +++ b/babl/babl-db.h @@ -0,0 +1,76 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#ifndef _BABL_DB_H +#define _BABL_DB_H + +#ifndef _BABL_H +#error babl-db.h is only to be included after babl.h +#endif + +#include "babl-list.h" +#include "babl-hash-table.h" +#include "babl-memory.h" +#include "babl-mutex.h" + +typedef struct _BablDb BablDb; + +typedef struct _BablDb +{ + BablHashTable *name_hash; + BablHashTable *id_hash; + BablList *babl_list; + BablMutex *mutex; +} _BablDb; + +#ifdef NEEDS_BABL_DB +static BablDb *db = NULL; +#endif /* NEEDS_BABL_DB */ + +BablDb * +babl_db_init (void); + +void +babl_db_each (BablDb *db, + BablEachFunction each_fun, + void *user_data); + +int +babl_db_count (BablDb *db); + +Babl * +babl_db_insert (BablDb *db, + Babl *entry); + +Babl * +babl_db_exist (BablDb *db, + int id, + const char *name); + +Babl * +babl_db_exist_by_name (BablDb *db, + const char *name); +Babl * +babl_db_exist_by_id (BablDb *db, + int id); + +Babl * +babl_db_find (BablDb *db, + const char *name); + +#endif diff --git a/babl/babl-extension.c b/babl/babl-extension.c new file mode 100644 index 0000000..41edb8e --- /dev/null +++ b/babl/babl-extension.c @@ -0,0 +1,377 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#define BABL_DYNAMIC_EXTENSIONS + +#include "config.h" + + +#ifdef BABL_DYNAMIC_EXTENSIONS +/* must be defined before inclusion of babl-internal.h */ +#undef BABL_INIT_HOOK +#define BABL_INIT_HOOK init_hook (); dynamic_init_hook (); +#endif + +#define NEEDS_BABL_DB +#include "babl-internal.h" +#include "babl-db.h" +#include "babl-base.h" +#include +#include + +static Babl *babl_extension_current_extender = NULL; + +Babl * +babl_extender (void) +{ + if (babl_extension_current_extender) + return babl_extension_current_extender; + return NULL; +} + +void +babl_set_extender (Babl *new_extender) +{ + babl_extension_current_extender = new_extender; +} + +static int +babl_extension_destroy (void *data); + +static Babl * +extension_new (const char *path, + void *dl_handle, + void (*destroy)(void)) +{ + Babl *babl; + + babl = babl_malloc (sizeof (BablExtension) + strlen (path) + 1); + babl_set_destructor (babl, babl_extension_destroy); + babl->instance.name = (char *) babl + sizeof (BablExtension); + strcpy (babl->instance.name, path); + babl->instance.id = 0; + babl->class_type = BABL_EXTENSION; + babl->extension.dl_handle = dl_handle; + babl->extension.destroy = destroy; + + return babl; +} + +static Babl *babl_quiet = NULL; + +Babl * +babl_extension_quiet_log (void) +{ + if (babl_quiet) + return babl_quiet; + babl_quiet = extension_new ("", NULL, NULL); + return babl_quiet; +} + +Babl * +babl_extension_base (void) +{ + Babl *babl; + void *dl_handle = NULL; + + void (*destroy)(void) = NULL; + + if (!db) + { + babl_extension_quiet_log (); + babl_set_extender (NULL); + db = babl_db_init (); + } + babl = extension_new ("BablBase", + dl_handle, + destroy); + babl_set_extender (babl); + + { + Babl *ret = babl_db_insert (db, babl); + if (ret != babl) + babl_free (babl); + else + babl_base_init (); + babl = ret; + } + babl_set_extender (NULL); + return babl; +} + +void +babl_extension_deinit (void) +{ + babl_free (babl_quiet); + babl_quiet = NULL; +} + +#ifdef BABL_DYNAMIC_EXTENSIONS + +#include +#include +#include +#include + +#ifdef HAVE_DLFCN_H +#ifndef WIN32 + +#include +#define HLIB void * + +#endif /* WIN32 */ +#elif HAVE_DL_H + + +#include +#include +#if !defined(DYNAMIC_PATH) +# define DYNAMIC_PATH 0 +#endif +#if !defined(BIND_RESTRICTED) +# define BIND_RESTRICTED 0 +#endif +#define RTLD_NOW (BIND_IMMEDIATE|BIND_NONFATAL|DYNAMIC_PATH) +#define HLIB shl_t +#define dlopen(path, flags) shl_load (path, flags, 0L) +#define dlclose(handle) shl_unload (handle) +#define dlerror() strerror (errno) + +static void * +dlsym (HLIB handle, + const char *name) +{ + void *address = 0; + shl_findsym(&handle, name, TYPE_UNDEFINED, &address); + return address; +} + +#endif + +#ifndef RTLD_NOW +#define RTLD_NOW 0 +#endif + +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#define HLIB HINSTANCE + +#define dlopen(a, b) LoadLibrary (a) +#define dlsym(l, s) GetProcAddress (l, s) +#define dlclose(l) FreeLibrary (l) +#define dlerror() GetLastError () +#endif + +typedef int (*BablExtensionInitFunc) (void); +typedef void (*BablExtensionDestroyFunc)(void); + + +static Babl * +load_failed (Babl *babl) +{ + if (babl) + { + babl_free (babl); + } + babl_set_extender (NULL); + return NULL; +} + +static Babl * +babl_extension_load (const char *path) +{ + Babl *babl = NULL; + /* do the actual loading thing */ + HLIB dl_handle = NULL; + + BablExtensionInitFunc init = NULL; + BablExtensionDestroyFunc destroy = NULL; + + dl_handle = dlopen (path, RTLD_NOW); + if (!dl_handle) + { + babl_log ("dlopen() failed:\n\t%s", dlerror ()); + return load_failed (babl); + } + init = (BablExtensionInitFunc) dlsym (dl_handle, "init"); + if (!init) + { + babl_log ("\n\tint babl_extension_init() function not found in extension '%s'", path); + dlclose (dl_handle); + return load_failed (babl); + } + + destroy = (BablExtensionDestroyFunc) dlsym (dl_handle, "destroy"); + babl = extension_new (path, + dl_handle, + destroy); + + babl_set_extender (babl); + if (init ()) + { + babl_log ("babl_extension_init() in extension '%s' failed (return!=0)", path); + dlclose (dl_handle); + return load_failed (babl); + } + + babl_db_insert (db, babl); + if (babl == babl_db_exist_by_name (db, path)) + { + babl_set_extender (NULL); + return babl; + } + else + { + return load_failed (babl); + } +} + +static void +babl_extension_load_dir (const char *base_path) +{ + DIR *dir; + + if ((dir = opendir (base_path))) + { + struct dirent *dentry; + + while ((dentry = readdir (dir)) != NULL) + { + if (dentry->d_name[0] != '.') + { + char *path = NULL; + char *extension; + + path = babl_strcat (path, base_path); + path = babl_strcat (path, BABL_DIR_SEPARATOR); + path = babl_strcat (path, dentry->d_name); + + if ((extension = strrchr (dentry->d_name, '.')) != NULL && + !strcmp (extension, SHREXT)) + { + babl_extension_load (path); + } + + babl_free (path); + } + } + closedir (dir); + } +} + +static char * +expand_path (char *path) +{ + char *src; + char *dst; + + dst = NULL; + + src = path; + + while (*src) + { + char *home; + switch (*src) + { + case '~': + home = getenv ("HOME"); + if (NULL != home) + dst = babl_strcat (dst, home); + break; + + default: + { + char tmp[2] = "?"; + tmp[0] = *src; + dst = babl_strcat (dst, tmp); + } + } + src++; + } + return dst; +} + + +/* parse the provided colon seperated list of paths to search + */ +void +babl_extension_load_dir_list (const char *dir_list) +{ + int eos = 0; + const char *src; + char *path, *dst; + + + path = babl_strdup (dir_list); + src = dir_list; + dst = path; + + while (!eos) + { + switch (*src) + { + case '\0': + eos = 1; + /* don't break here, the path needs to be processed */ + + case BABL_PATH_SEPARATOR: + { + char *expanded_path = expand_path (path); + if (expanded_path) { + babl_extension_load_dir (expanded_path); + babl_free (expanded_path); + } + } + dst = path; + src++; + *dst = '\0'; + break; + + default: + *(dst++) = *(src++); + *dst = '\0'; + break; + } + } + babl_free (path); + if (babl_db_count (db) <= 1) + { + babl_log ("WARNING: the babl installation seems broken, no extensions found in queried\n" + "BABL_PATH (%s) this means no SIMD/instructions/special case fast paths and\n" + "only slow reference conversions are available, applications might still\n" + "run but software relying on babl for conversions will be slow\n", dir_list); + } +} + +#endif + + +static int +babl_extension_destroy (void *data) +{ + Babl *babl = data; + if (babl->extension.destroy) + babl->extension.destroy (); + if (babl->extension.dl_handle) + dlclose (babl->extension.dl_handle); + return 0; +} + +BABL_CLASS_IMPLEMENT (extension) diff --git a/babl/babl-extension.h b/babl/babl-extension.h new file mode 100644 index 0000000..82e1d7e --- /dev/null +++ b/babl/babl-extension.h @@ -0,0 +1,40 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005-2008, Øyvind Kolås and others. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#ifndef _BABL_EXTENSION_H +#define _BABL_EXTENSION_H + + +/****************************************************************/ +/* BablExtension */ +BABL_CLASS_DECLARE (extension); +/* + * BablExtension objects are only used internally in babl. + */ + +const Babl * babl_extension (const char *name); +void babl_extension_load_dir_list (const char *dir_list); + +typedef struct +{ + BablInstance instance; /* path to .so / .dll is stored in instance name */ + void *dl_handle; + void (*destroy) (void); +} BablExtension; + +#endif diff --git a/babl/babl-fish-path.c b/babl/babl-fish-path.c new file mode 100644 index 0000000..b0396db --- /dev/null +++ b/babl/babl-fish-path.c @@ -0,0 +1,1070 @@ +/* babl - dynamically extendable universal pixel fish library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include +#include "babl-internal.h" +#include "babl-ref-pixels.h" + +#define BABL_TOLERANCE 0.0000047 +#define BABL_MAX_COST_VALUE 2000000 +#define BABL_HARD_MAX_PATH_LENGTH 8 +#define BABL_MAX_NAME_LEN 1024 + +#define BABL_TEST_ITER 16 + +#ifndef MIN +#define MIN(a, b) (((a) > (b)) ? (b) : (a)) +#endif + +#define MAX_BUFFER_SIZE 512 +#define ITERATIONS 4 + +int babl_in_fish_path = 0; + +typedef struct _FishPathInstrumentation +{ + const Babl *fmt_rgba_double; + int num_test_pixels; + void *source; + void *destination; + void *ref_destination; + double *destination_rgba_double; + double *ref_destination_rgba_double; + const Babl *fish_rgba_to_source; + const Babl *fish_reference; + const Babl *fish_destination_to_rgba; + double reference_cost; + int init_instrumentation_done; +} FishPathInstrumentation; + +typedef struct PathContext { + Babl *fish_path; + Babl *to_format; + BablList *current_path; +} PathContext; + +static void +init_path_instrumentation (FishPathInstrumentation *fpi, + Babl *fmt_source, + Babl *fmt_destination); + +static void +destroy_path_instrumentation (FishPathInstrumentation *fpi); + +static void +get_path_instrumentation (FishPathInstrumentation *fpi, + BablList *path, + double *path_cost, + double *ref_cost, + double *path_error); + + +static inline void +process_conversion_path (BablList *path, + const void *source_buffer, + int source_bpp, + void *destination_buffer, + int dest_bpp, + long n); + +static void +get_conversion_path (PathContext *pc, + Babl *current_format, + int current_length, + int max_length, + double legal_error); + +char * +_babl_fish_create_name (char *buf, + const Babl *source, + const Babl *destination, + int is_reference); + + +static int max_path_length (void); + +static int debug_conversions = 0; +int _babl_instrument = 0; + +double +_babl_legal_error (void) +{ + static double error = 0.0; + const char *env; + + if (error != 0.0) + return error; + + env = getenv ("BABL_TOLERANCE"); + if (env && env[0] != '\0') + error = babl_parse_double (env); + else + error = BABL_TOLERANCE; + + env = getenv ("BABL_DEBUG_CONVERSIONS"); + if (env && env[0] != '\0') + debug_conversions = 1; + else + debug_conversions = 0; + + env = getenv ("BABL_INSTRUMENT"); + if (env && env[0] != '\0') + _babl_instrument = 1; + else + _babl_instrument = 0; + + return error; +} + +static int +max_path_length (void) +{ + static int max_length = 0; + const char *env; + + if (max_length != 0) + return max_length; + + env = getenv ("BABL_PATH_LENGTH"); + if (env) + max_length = atoi (env); + else + max_length = 2; /* reducing this number makes finding short fishes much + faster - even if we lose out on some of the fast + bigger fish, the fishes we can get with a max_length of 2 + is actually 5, since we deepen the search to that + depth if none are found within two steps in the + initial search. + */ + if (max_length > BABL_HARD_MAX_PATH_LENGTH) + max_length = BABL_HARD_MAX_PATH_LENGTH; + else if (max_length <= 0) + max_length = 1; + return max_length; +} + +int +_babl_max_path_len (void) +{ + return max_path_length (); +} + +static int +bad_idea (const Babl *from, const Babl *to, const Babl *format) +{ + if (babl_format_has_alpha (from) && + babl_format_has_alpha (to) && + !babl_format_has_alpha (format)) + { + return 1; + } + if (from->format.components > format->format.components && + to->format.components > format->format.components) + { + return 1; + } + if (from->format.type[0]->bits > format->format.type[0]->bits && + to->format.type[0]->bits > format->format.type[0]->bits) + { + /* XXX: perhaps we especially avoid going to half-float, when + * going between u16 formats as well? */ + return 1; + } + + return 0; +} + + +/* The task of BablFishPath construction is to compute + * the shortest path in a graph where formats are the vertices + * and conversions are the edges. However, there is an additional + * constraint to the shortest path, that limits conversion error + * introduced by such a path to be less than BABL_TOLERANCE. This + * prohibits usage of any reasonable shortest path construction + * algorithm such as Dijkstra's algorithm. The shortest path is + * constructed by enumerating all available paths that are less + * than BABL_PATH_LENGTH long, computing their costs and + * conversion errors and backtracking. The backtracking is + * implemented by recursive function get_conversion_path (). + */ + +static void +get_conversion_path (PathContext *pc, + Babl *current_format, + int current_length, + int max_length, + double legal_error) +{ + if (current_length > max_length) + { + /* We have reached the maximum recursion + * depth, let's bail out */ + return; + } + else if ((current_length > 0) && (current_format == pc->to_format)) + { + /* We have found a candidate path, let's + * see about it's properties */ + double path_cost = 0.0; + double ref_cost = 0.0; + double path_error = 1.0; +#if 1 + int i; + for (i = 0; i < babl_list_size (pc->current_path); i++) + { + path_error *= (1.0 + babl_conversion_error ((BablConversion *) pc->current_path->items[i])); + } + + if (path_error - 1.0 <= legal_error ) + /* check this before the more accurate measurement of error - + to bail earlier, this also leads to a stricter + discarding of bad fast paths */ +#endif + { + FishPathInstrumentation fpi; + memset (&fpi, 0, sizeof (fpi)); + + fpi.source = (Babl*) babl_list_get_first (pc->current_path)->conversion.source; + fpi.destination = pc->to_format; + + get_path_instrumentation (&fpi, pc->current_path, &path_cost, &ref_cost, &path_error); + if(debug_conversions && current_length == 1) + fprintf (stderr, "%s error:%f cost:%f \n", + babl_get_name (pc->current_path->items[0]), path_error, path_cost); + + if ((path_cost < ref_cost) && /* do not use paths that took longer to compute than reference */ + (path_cost < pc->fish_path->fish_path.cost) && // best thus far + (path_error <= legal_error ) // within tolerance + ) + { + /* We have found the best path so far, + * let's copy it into our new fish */ + pc->fish_path->fish_path.cost = path_cost; + pc->fish_path->fish.error = path_error; + babl_list_copy (pc->current_path, + pc->fish_path->fish_path.conversion_list); + } + + destroy_path_instrumentation (&fpi); + } + } + else + { + /* + * we have to search deeper... + */ + BablList *list; + int i; + + list = current_format->format.from_list; + if (list) + { + /* Mark the current format in conversion path as visited */ + current_format->format.visited = 1; + + /* Iterate through unvisited formats from the current format ...*/ + for (i = 0; i < babl_list_size (list); i++) + { + Babl *next_conversion = BABL (list->items[i]); + Babl *next_format = BABL (next_conversion->conversion.destination); + if (!next_format->format.visited && !bad_idea (current_format, pc->to_format, next_format)) + { + /* next_format is not in the current path, we can pay a visit */ + babl_list_insert_last (pc->current_path, next_conversion); + get_conversion_path (pc, next_format, current_length + 1, max_length, legal_error); + babl_list_remove_last (pc->current_path); + } + } + + /* Remove the current format from current path */ + current_format->format.visited = 0; + } + } +} + +char * +_babl_fish_create_name (char *buf, + const Babl *source, + const Babl *destination, + int is_reference) +{ + /* fish names are intentionally kept short */ + snprintf (buf, BABL_MAX_NAME_LEN, "%s %p %p %i", "", + source, destination, is_reference); + return buf; +} + +int +_babl_fish_path_destroy (void *data); + +int +_babl_fish_path_destroy (void *data) +{ + Babl *babl=data; + if (babl->fish_path.conversion_list) + babl_free (babl->fish_path.conversion_list); + babl->fish_path.conversion_list = NULL; + return 0; +} + +static int +show_item (Babl *babl, + void *user_data) +{ + BablConversion *conv = (void *)babl; + + if (conv->destination->class_type == BABL_FORMAT) + { + fprintf (stderr, "%s : %.12f\n", babl_get_name (babl), babl_conversion_error(conv)); + } + + return 0; +} + +static int +alias_conversion (Babl *babl, + void *user_data) +{ + const Babl *sRGB = babl_space ("sRGB"); + BablConversion *conv = (void *)babl; + BablSpace *space = user_data; + + if ((conv->source->class_type == BABL_FORMAT) && + (conv->destination->class_type == BABL_FORMAT) && + (!babl_format_is_palette (conv->source)) && + (!babl_format_is_palette (conv->destination))) + { + if ((conv->source->format.space == sRGB) && + (conv->destination->format.space == sRGB)) + { + switch (conv->instance.class_type) + { + case BABL_CONVERSION_LINEAR: + babl_conversion_new ( + babl_format_with_space ( + (void*)conv->source->instance.name, (void*)space), + babl_format_with_space ( + (void*)conv->destination->instance.name, (void*)space), + "linear", conv->function.linear, + "data", conv->data, + NULL); + break; + case BABL_CONVERSION_PLANAR: + babl_conversion_new ( + babl_format_with_space ( + (void*)conv->source->instance.name, (void*)space), + babl_format_with_space ( + (void*)conv->destination->instance.name, (void*)space), + "planar", conv->function.planar, + "data", conv->data, + NULL); + break; + case BABL_CONVERSION_PLANE: + babl_conversion_new ( + babl_format_with_space ( + (void*)conv->source->instance.name, (void*)space), + babl_format_with_space ( + (void*)conv->destination->instance.name, (void*)space), + "plane", conv->function.plane, + "data", conv->data, + NULL); + break; + default: + break; + } + } + } + else + if ((conv->source->class_type == BABL_MODEL) && + (conv->destination->class_type == BABL_MODEL)) + { + if ((conv->source->model.space == sRGB) && + (conv->destination->model.space == sRGB)) + { + switch (conv->instance.class_type) + { + case BABL_CONVERSION_LINEAR: + babl_conversion_new ( + babl_remodel_with_space ( + (void*)conv->source, (void*)space), + babl_remodel_with_space ( + (void*)conv->destination, (void*)space), + "linear", conv->function.linear, + NULL); + break; + case BABL_CONVERSION_PLANAR: + babl_conversion_new ( + babl_remodel_with_space ( + (void*)conv->source, (void*)space), + babl_remodel_with_space ( + (void*)conv->destination, (void*)space), + "planar", conv->function.planar, + NULL); + break; + case BABL_CONVERSION_PLANE: + babl_conversion_new ( + babl_remodel_with_space ( + (void*)conv->source, (void*)space), + babl_remodel_with_space ( + (void*)conv->destination, (void*)space), + "plane", conv->function.plane, + NULL); + break; + default: + break; + } + } + } + else + if ((conv->source->class_type == BABL_TYPE) && + (conv->destination->class_type == BABL_TYPE)) + { + } + return 0; +} + +void +_babl_fish_prepare_bpp (Babl *babl) +{ + const Babl *babl_source = babl->fish.source; + const Babl *babl_dest = babl->fish.destination; + + switch (babl_source->instance.class_type) + { + case BABL_FORMAT: + babl->fish_path.source_bpp = babl_source->format.bytes_per_pixel; + break; + case BABL_TYPE: + babl->fish_path.source_bpp = babl_source->type.bits / 8; + break; + default: + babl_log ("=eeek{%i}\n", + babl_source->instance.class_type - BABL_MAGIC); + } + + switch (babl_dest->instance.class_type) + { + case BABL_FORMAT: + babl->fish_path.dest_bpp = babl_dest->format.bytes_per_pixel; + break; + case BABL_TYPE: + babl->fish_path.dest_bpp = babl_dest->type.bits / 8; + break; + default: + babl_log ("-eeek{%i}\n", babl_dest->instance.class_type - BABL_MAGIC); + } +} + +void +_babl_fish_missing_fast_path_warning (const Babl *source, + const Babl *destination) +{ +#ifndef BABL_UNSTABLE + if (debug_conversions) +#endif + { + static int warnings = 0; + + if (_babl_legal_error() <= 0.0000000001) + return; + + if (warnings++ == 0) + fprintf (stderr, +"Missing fast-path babl conversion detected, Implementing missing babl fast paths\n" +"accelerates GEGL, GIMP and other software using babl, warnings are printed on\n" +"first occurance of formats used where a conversion has to be synthesized\n" +"programmatically by babl based on format description\n" +"\n"); + + fprintf (stderr, "*WARNING* missing babl fast path(s): \"%s\" to \"%s\"\n", + babl_get_name (source), + babl_get_name (destination)); + + } +} + + +static Babl * +babl_fish_path2 (const Babl *source, + const Babl *destination, + double tolerance) +{ + Babl *babl = NULL; + const Babl *sRGB = babl_space ("sRGB"); + char name[BABL_MAX_NAME_LEN]; + int is_fast = 0; + static int debug_missing = -1; + if (debug_missing < 0) + { + const char *val = getenv ("BABL_DEBUG_MISSING"); + if (val && strcmp (val, "0")) + debug_missing = 1; + else + debug_missing = 0; + } + + _babl_fish_create_name (name, source, destination, 1); + babl_mutex_lock (babl_format_mutex); + babl = babl_db_exist_by_name (babl_fish_db (), name); + + if (tolerance <= 0.0) + { + is_fast = 0; + tolerance = _babl_legal_error (); + } + else + is_fast = 1; + + if (!is_fast) + { + if (babl) + { + /* There is an instance already registered by the required name, + * returning the preexistent one instead. + */ + babl_mutex_unlock (babl_format_mutex); + return babl; + } + } + + if ((source->format.space != sRGB) || + (destination->format.space != sRGB)) + { + static const Babl *run_once[512]={NULL}; + int i; + int done = 0; + for (i = 0; run_once[i]; i++) + { + if (run_once[i] == source->format.space) + done |= 1; + else if (run_once[i] == destination->format.space) + done |= 2; + } + + /* source space not in initialization array */ + if ((done & 1) == 0 && (source->format.space != sRGB)) + { + run_once[i++] = source->format.space; + babl_conversion_class_for_each (alias_conversion, (void*)source->format.space); + + _babl_space_add_universal_rgb (source->format.space); + } + + /* destination space not in initialization array */ + if ((done & 2) == 0 && (destination->format.space != source->format.space) && (destination->format.space != sRGB)) + { + run_once[i++] = destination->format.space; + babl_conversion_class_for_each (alias_conversion, (void*)destination->format.space); + + _babl_space_add_universal_rgb (destination->format.space); + } + + if (!done && 0) + { + babl_conversion_class_for_each (show_item, (void*)source->format.space); + } + + } + + babl = babl_calloc (1, sizeof (BablFishPath) + + strlen (name) + 1); + babl_set_destructor (babl, _babl_fish_path_destroy); + + babl->class_type = BABL_FISH_PATH; + babl->instance.id = babl_fish_get_id (source, destination); + babl->instance.name = ((char *) babl) + sizeof (BablFishPath); + strcpy (babl->instance.name, name); + babl->fish.source = source; + babl->fish.destination = destination; + babl->fish.pixels = 0; + babl->fish.error = BABL_MAX_COST_VALUE; + babl->fish_path.cost = BABL_MAX_COST_VALUE; + babl->fish_path.conversion_list = babl_list_init_with_size (BABL_HARD_MAX_PATH_LENGTH); + + + { + PathContext pc; + int start_depth = max_path_length (); + int end_depth = start_depth + 2 + ((destination->format.space != sRGB)?1:0); + end_depth = MIN(end_depth, BABL_HARD_MAX_PATH_LENGTH); + + pc.current_path = babl_list_init_with_size (BABL_HARD_MAX_PATH_LENGTH); + pc.fish_path = babl; + pc.to_format = (Babl *) destination; + + /* we hold a global lock whilerunning get_conversion_path since + * it depends on keeping the various format.visited members in + * a consistent state, this code path is not performance critical + * since created fishes are cached. + */ + babl_in_fish_path++; + + for (int max_depth = start_depth; + babl->fish_path.conversion_list->count == 0 && max_depth <= end_depth; + max_depth++) + { + get_conversion_path (&pc, (Babl *) source, 0, max_depth, tolerance); + } + + if (debug_missing) + { + if (babl->fish_path.conversion_list->count == 0) + fprintf (stderr, "babl: WARNING lacking conversion path for %s to %s\n", + babl_get_name (source), babl_get_name (destination)); + else if (babl->fish_path.conversion_list->count == end_depth) + fprintf (stderr, "babl: WARNING need %i step conversion for %s to %s\n", end_depth, + babl_get_name (source), babl_get_name (destination)); + else + fprintf (stderr, "babl: found %i step conversion for %s to %s\n", + babl->fish_path.conversion_list->count, + babl_get_name (source), babl_get_name (destination)); + } + + babl_in_fish_path--; + babl_free (pc.current_path); + } + + if (babl_list_size (babl->fish_path.conversion_list) == 0) + { + babl_free (babl); + babl_mutex_unlock (babl_format_mutex); + + return NULL; + } + + _babl_fish_prepare_bpp (babl); + _babl_fish_rig_dispatch (babl); + /* Since there is not an already registered instance by the required + * name, inserting newly created class into database. + */ + if (!is_fast) + { + babl_db_insert (babl_fish_db (), babl); + } + babl_mutex_unlock (babl_format_mutex); + return babl; +} + +const Babl * +babl_fast_fish (const void *source_format, + const void *destination_format, + const char *performance) +{ + double tolerance = 0.0; + + if (!performance || !strcmp (performance, "default")) + tolerance = 0.0; // note: not _babl_legal_error() to trigger, + // right code paths in babl_fish_path2 + else if (!strcmp (performance, "exact")) + tolerance=0.0000000001; + else if (!strcmp (performance, "precise")) + tolerance=0.00001; + if (!strcmp (performance, "fast")) + tolerance=0.001; + else if (!strcmp (performance, "glitch")) + tolerance=0.01; + else { + tolerance = babl_parse_double (performance); + } + + return babl_fish_path2 (source_format, destination_format, tolerance); +} + +Babl * +babl_fish_path (const Babl *source, + const Babl *destination) +{ + return babl_fish_path2 (source, destination, 0.0); +} + + +static void +babl_fish_path_process (const Babl *babl, + const char *source, + char *destination, + long n, + void *data) +{ + process_conversion_path (babl->fish_path.conversion_list, + source, + babl->fish_path.source_bpp, + destination, + babl->fish_path.dest_bpp, + n); +} + +static void +babl_fish_memcpy_process (const Babl *babl, + const char *source, + char *destination, + long n, + void *data) +{ + memcpy (destination, source, n * babl->fish.source->format.bytes_per_pixel); +} + +void +_babl_fish_rig_dispatch (Babl *babl) +{ + babl->fish.data = (void*)&(babl->fish.data); + + if (babl->fish.source == babl->fish.destination) + { + babl->fish.dispatch = babl_fish_memcpy_process; + return; + } + + switch (babl->class_type) + { + case BABL_FISH_REFERENCE: + babl->fish.dispatch = babl_fish_reference_process; + break; + + case BABL_FISH_SIMPLE: + if (BABL (babl->fish_simple.conversion)->class_type == BABL_CONVERSION_LINEAR) + { + /* lift out conversion from single step conversion and make it be the dispatch function + * itself + */ + babl->fish.data = &(babl->fish_simple.conversion->data); + babl->fish.dispatch = babl->fish_simple.conversion->dispatch; + } + else + { + babl_fatal ("Cannot use a simple fish to process without a linear conversion"); + } + break; + + case BABL_FISH_PATH: + if (babl_list_size(babl->fish_path.conversion_list) == 1) + { + BablConversion *conversion = (void*)babl_list_get_first(babl->fish_path.conversion_list); + + /* do same short-circuit optimization as for simple fishes */ + babl->fish.dispatch = conversion->dispatch; + babl->fish.data = &conversion->data; + } + else + { + babl->fish.dispatch = babl_fish_path_process; + } + break; + + case BABL_CONVERSION: + case BABL_CONVERSION_LINEAR: + case BABL_CONVERSION_PLANE: + case BABL_CONVERSION_PLANAR: + babl_assert (0); + break; + + default: + babl_log ("NYI"); + break; + } +} + +static inline long +_babl_process (const Babl *cbabl, + const void *source, + void *destination, + long n) +{ + Babl *babl = (void*)cbabl; + babl->fish.dispatch (babl, source, destination, n, *babl->fish.data); + if (_babl_instrument) + babl->fish.pixels += n; + return n; +} + +long +babl_process (const Babl *babl, + const void *source, + void *destination, + long n) +{ + return _babl_process ((void*)babl, source, destination, n); +} + +long +babl_process_rows (const Babl *fish, + const void *source, + int source_stride, + void *dest, + int dest_stride, + long n, + int rows) +{ + Babl *babl = (Babl*)fish; + const uint8_t *src = source; + uint8_t *dst = dest; + int row; + + babl_assert (babl && BABL_IS_BABL (babl) && source && dest); + + if (n <= 0) + return 0; + + if (_babl_instrument) + babl->fish.pixels += n * rows; + for (row = 0; row < rows; row++) + { + babl->fish.dispatch (babl, (void*)src, (void*)dst, n, *babl->fish.data); + + src += source_stride; + dst += dest_stride; + } + return n * rows; +} + +#include + +#define BABL_ALIGN 16 +static void inline *align_16 (unsigned char *ret) +{ + int offset = BABL_ALIGN - ((uintptr_t) ret) % BABL_ALIGN; + ret = ret + offset; + return ret; +} + +static inline void +process_conversion_path (BablList *path, + const void *source_buffer, + int source_bpp, + void *destination_buffer, + int dest_bpp, + long n) +{ + int conversions = babl_list_size (path); + + if (conversions == 1) + { + babl_conversion_process (BABL (babl_list_get_first (path)), + source_buffer, + destination_buffer, + n); + } + else + { + long j; + + void *temp_buffer = align_16 (alloca (MIN(n, MAX_BUFFER_SIZE) * + sizeof (double) * 5 + 16)); + void *temp_buffer2 = NULL; + + if (conversions > 2) + { + /* We'll need one more auxiliary buffer */ + temp_buffer2 = align_16 (alloca (MIN(n, MAX_BUFFER_SIZE) * + sizeof (double) * 5 + 16)); + } + + for (j = 0; j < n; j+= MAX_BUFFER_SIZE) + { + long c = MIN (n - j, MAX_BUFFER_SIZE); + int i; + + void *aux1_buffer = temp_buffer; + void *aux2_buffer = temp_buffer2; + + /* The first conversion goes from source_buffer to aux1_buffer */ + babl_conversion_process (babl_list_get_first (path), + (void*)(((unsigned char*)source_buffer) + + (j * source_bpp)), + aux1_buffer, + c); + + /* Process, if any, conversions between the first and the last + * conversion in the path, in a loop */ + for (i = 1; i < conversions - 1; i++) + { + babl_conversion_process (path->items[i], + aux1_buffer, + aux2_buffer, + c); + { + /* Swap the auxiliary buffers */ + void *swap_buffer = aux1_buffer; + aux1_buffer = aux2_buffer; + aux2_buffer = swap_buffer; + } + } + + /* The last conversion goes from aux1_buffer to destination_buffer */ + babl_conversion_process (babl_list_get_last (path), + aux1_buffer, + (void*)((unsigned char*)destination_buffer + + (j * dest_bpp)), + c); + } + } +} + +static void +init_path_instrumentation (FishPathInstrumentation *fpi, + Babl *fmt_source, + Babl *fmt_destination) +{ + long ticks_start = 0; + long ticks_end = 0; + + const double *test_pixels = babl_get_path_test_pixels (); + + if (!fpi->fmt_rgba_double) + { + fpi->fmt_rgba_double = + babl_format_with_space ("RGBA double", + fmt_destination->format.space); + } + + fpi->num_test_pixels = babl_get_num_path_test_pixels (); + + fpi->fish_rgba_to_source = + babl_fish_reference (fpi->fmt_rgba_double, fmt_source); + + fpi->fish_reference = + babl_fish_reference (fmt_source, fmt_destination); + + fpi->fish_destination_to_rgba = + babl_fish_reference (fmt_destination, fpi->fmt_rgba_double); + + fpi->source = + babl_calloc (fpi->num_test_pixels, + fmt_source->format.bytes_per_pixel); + + fpi->destination = + babl_calloc (fpi->num_test_pixels, + fmt_destination->format.bytes_per_pixel); + + fpi->ref_destination = + babl_calloc (fpi->num_test_pixels, + fmt_destination->format.bytes_per_pixel); + + fpi->destination_rgba_double = + babl_calloc (fpi->num_test_pixels, + fpi->fmt_rgba_double->format.bytes_per_pixel); + + fpi->ref_destination_rgba_double = + babl_calloc (fpi->num_test_pixels, + fpi->fmt_rgba_double->format.bytes_per_pixel); + + /* create sourcebuffer from testbuffer in the correct format */ + _babl_process (fpi->fish_rgba_to_source, + test_pixels, fpi->source,fpi->num_test_pixels); + + /* calculate the reference buffer of how it should be */ + ticks_start = babl_ticks (); + _babl_process (fpi->fish_reference, + fpi->source, fpi->ref_destination, + fpi->num_test_pixels); + ticks_end = babl_ticks (); + fpi->reference_cost = (ticks_end - ticks_start) * BABL_TEST_ITER; + + /* transform the reference destination buffer to RGBA */ + _babl_process (fpi->fish_destination_to_rgba, + fpi->ref_destination, fpi->ref_destination_rgba_double, + fpi->num_test_pixels); +} + +static void +destroy_path_instrumentation (FishPathInstrumentation *fpi) +{ + if (fpi->init_instrumentation_done) + { + babl_free (fpi->source); + babl_free (fpi->destination); + babl_free (fpi->destination_rgba_double); + babl_free (fpi->ref_destination); + babl_free (fpi->ref_destination_rgba_double); + + /* nulify the flag for potential new search */ + fpi->init_instrumentation_done = 0; + } +} + +static void +get_path_instrumentation (FishPathInstrumentation *fpi, + BablList *path, + double *path_cost, + double *ref_cost, + double *path_error) +{ + long ticks_start = 0; + long ticks_end = 0; + + Babl *babl_source = fpi->source; + Babl *babl_destination = fpi->destination; + + int source_bpp = 0; + int dest_bpp = 0; + + switch (babl_source->instance.class_type) + { + case BABL_FORMAT: + source_bpp = babl_source->format.bytes_per_pixel; + break; + case BABL_TYPE: + source_bpp = babl_source->type.bits / 8; + break; + default: + babl_log ("=eeek{%i}\n", babl_source->instance.class_type - BABL_MAGIC); + } + + switch (babl_destination->instance.class_type) + { + case BABL_FORMAT: + dest_bpp = babl_destination->format.bytes_per_pixel; + break; + case BABL_TYPE: + dest_bpp = babl_destination->type.bits / 8; + break; + default: + babl_log ("-eeek{%i}\n", + babl_destination->instance.class_type - BABL_MAGIC); + } + + if (!fpi->init_instrumentation_done) + { + /* this initialization can be done only once since the + * source and destination formats do not change during + * the search */ + init_path_instrumentation (fpi, babl_source, babl_destination); + fpi->init_instrumentation_done = 1; + } + + /* calculate this path's view of what the result should be */ + ticks_start = babl_ticks (); + for (int i = 0; i < BABL_TEST_ITER; i ++) + process_conversion_path (path, fpi->source, source_bpp, fpi->destination, + dest_bpp, fpi->num_test_pixels); + ticks_end = babl_ticks (); + *path_cost = (ticks_end - ticks_start); + + /* transform the reference and the actual destination buffers to RGBA + * for comparison with each other + */ + _babl_process (fpi->fish_destination_to_rgba, + fpi->destination, fpi->destination_rgba_double, + fpi->num_test_pixels); + + *path_error = babl_rel_avg_error (fpi->destination_rgba_double, + fpi->ref_destination_rgba_double, + fpi->num_test_pixels * 4); + + *ref_cost = fpi->reference_cost; +} diff --git a/babl/babl-fish-reference.c b/babl/babl-fish-reference.c new file mode 100644 index 0000000..a62f32a --- /dev/null +++ b/babl/babl-fish-reference.c @@ -0,0 +1,1454 @@ +/* babl - dynamically extendable universal pixel fish library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include "babl-internal.h" +#ifdef HAVE_LCMS +#include "lcms2.h" +#endif + + +static Babl * +assert_conversion_find (const void *source, + const void *destination) +{ + Babl *ret = babl_conversion_find (source, destination); + + if (!ret) + babl_fatal ("failed finding conversion between %s and %s aborting", + babl_get_name (source), babl_get_name (destination)); + + return ret; +} + +static int +create_name_internal (char *buf, + size_t maxlen, + const Babl *source, + const Babl *destination, + int is_reference) +{ + return snprintf (buf, maxlen, "%s %p %p", + is_reference ? "ref " + : "", + source, destination); +} + +#ifdef HAVE_TLS + +static __thread char buf[1024]; + +static char * +create_name (const Babl *source, + const Babl *destination, + int is_reference) +{ + int size = 0; + + size = create_name_internal (buf, sizeof(buf), source, destination, is_reference); + + if (size < 0) + return NULL; + + return buf; +} + + +#else + +static char * +create_name (const Babl *source, + const Babl *destination, + int is_reference) +{ + int size = 0; + char *buf = NULL; + + size = create_name_internal (buf, size, source, destination, is_reference); + + if (size < 0) + return NULL; + + size++; /* For '\0' */ + buf = malloc (size); + if (buf == NULL) + return NULL; + + size = create_name_internal (buf, size, source, destination, is_reference); + + if (size < 0) + { + free (buf); + return NULL; + } + + return buf; +} + +#endif + +/* need an internal version that only ever does double, + * for use in path evaluation? and perhaps even self evaluation of float code path? + */ +Babl * +babl_fish_reference (const Babl *source, + const Babl *destination) +{ + Babl *babl = NULL; + char *name = create_name (source, destination, 1); + + babl_assert (name); + + babl = babl_db_exist_by_name (babl_fish_db (), name); + if (babl) + { + /* There is an instance already registered by the required name, + * returning the preexistent one instead. + */ +#ifndef HAVE_TLS + free (name); +#endif + _babl_fish_rig_dispatch (babl); + return babl; + } + + babl_assert (BABL_IS_BABL (source)); + babl_assert (BABL_IS_BABL (destination)); + + babl_assert (source->class_type == BABL_FORMAT); + babl_assert (destination->class_type == BABL_FORMAT); + + babl = babl_calloc (1, sizeof (BablFishReference) + + strlen (name) + 1); + babl->class_type = BABL_FISH_REFERENCE; + babl->instance.id = babl_fish_get_id (source, destination); + babl->instance.name = ((char *) babl) + sizeof (BablFishReference); + strcpy (babl->instance.name, name); + babl->fish.source = source; + babl->fish.destination = destination; + + babl->fish.pixels = 0; + babl->fish.error = 0.0; /* assuming the provided reference conversions for types + and models are as exact as possible + */ + _babl_fish_rig_dispatch (babl); + + /* Since there is not an already registered instance by the required + * name, inserting newly created class into database. + */ + babl_db_insert (babl_fish_db (), babl); +#ifndef HAVE_TLS + free (name); +#endif + return babl; +} + + +static void +convert_to_double (BablFormat *source_fmt, + const char *source_buf, + char *double_buf, + int n) +{ + int i; + + BablImage *src_img; + BablImage *dst_img; + + src_img = (BablImage *) babl_image_new ( + babl_component_from_id (BABL_GRAY_LINEAR), NULL, 1, 0, NULL); + dst_img = (BablImage *) babl_image_new ( + babl_component_from_id (BABL_GRAY_LINEAR), NULL, 1, 0, NULL); + + dst_img->type[0] = (BablType *) babl_type_from_id (BABL_DOUBLE); + dst_img->pitch[0] = + (dst_img->type[0]->bits / 8) * source_fmt->model->components; + dst_img->stride[0] = 0; + + src_img->type[0] = (BablType *) babl_type_from_id (BABL_DOUBLE); + src_img->pitch[0] = source_fmt->bytes_per_pixel; + src_img->stride[0] = 0; + + { + /* i is dest position */ + for (i = 0; i < source_fmt->model->components; i++) + { + int j; + int found = 0; + + dst_img->data[0] = + double_buf + (dst_img->type[0]->bits / 8) * i; + + src_img->data[0] = (char *)source_buf; + + /* j is source position */ + for (j = 0; j < source_fmt->components; j++) + { + src_img->type[0] = source_fmt->type[j]; + + if (source_fmt->component[j] == + source_fmt->model->component[i]) + { + babl_conversion_process (assert_conversion_find (src_img->type[0], dst_img->type[0]), + (void*)src_img, (void*)dst_img, n); + found = 1; + break; + } + + src_img->data[0] += src_img->type[0]->bits / 8; + } + + if (!found) + { + char *dst_ptr = dst_img->data[0]; + double value; + + value = source_fmt->model->component[i]->instance.id == BABL_ALPHA ? 1.0 : 0.0; + + for (j = 0; j < n; j++) + { + double *dst_component = (double *) dst_ptr; + + *dst_component = value; + dst_ptr += dst_img->pitch[0]; + } + } + } + } + babl_free (src_img); + babl_free (dst_img); +} + + +static void +convert_from_double (BablFormat *source_fmt, + BablFormat *destination_fmt, + char *destination_double_buf, + char *destination_buf, + int n) +{ + int i; + + BablImage *src_img; + BablImage *dst_img; + + src_img = (BablImage *) babl_image_new ( + babl_component_from_id (BABL_GRAY_LINEAR), NULL, 1, 0, NULL); + dst_img = (BablImage *) babl_image_new ( + babl_component_from_id (BABL_GRAY_LINEAR), NULL, 1, 0, NULL); + + src_img->type[0] = (BablType *) babl_type_from_id (BABL_DOUBLE); + src_img->pitch[0] = (src_img->type[0]->bits / 8) * destination_fmt->model->components; + src_img->stride[0] = 0; + + dst_img->data[0] = destination_buf; + dst_img->pitch[0] = destination_fmt->bytes_per_pixel; + dst_img->stride[0] = 0; + + for (i = 0; i < destination_fmt->components; i++) + { + int j; + int can_be_used = 1; + + dst_img->type[0] = destination_fmt->type[i]; + + if (source_fmt->model == destination_fmt->model) + { + can_be_used = 0; + for (j = 0; j < source_fmt->components; j++) + { + if (destination_fmt->component[i] == source_fmt->component[j]) + { + can_be_used = 1; + } + } + } + else + { + } + //fprintf (stderr, "%s %s %i\n", babl_get_name (source_fmt), babl_get_name (destination_fmt), can_be_used); + + if (can_be_used) + for (j = 0; j < destination_fmt->model->components; j++) + { + if (destination_fmt->component[i] == + destination_fmt->model->component[j]) + { + src_img->data[0] = + destination_double_buf + (src_img->type[0]->bits / 8) * j; + + babl_conversion_process (assert_conversion_find (src_img->type[0], + dst_img->type[0]), + (void*)src_img, (void*)dst_img, n); + break; + } + } + + dst_img->data[0] += dst_img->type[0]->bits / 8; + } + babl_free (src_img); + babl_free (dst_img); +} + + +static void +ncomponent_convert_to_double (BablFormat *source_fmt, + char *source_buf, + char *source_double_buf, + int n) +{ + BablImage *src_img; + BablImage *dst_img; + + src_img = (BablImage *) babl_image_new ( + babl_component_from_id (BABL_GRAY_LINEAR), NULL, 1, 0, NULL); + dst_img = (BablImage *) babl_image_new ( + babl_component_from_id (BABL_GRAY_LINEAR), NULL, 1, 0, NULL); + + dst_img->type[0] = (BablType *) babl_type_from_id (BABL_DOUBLE); + dst_img->pitch[0] = (dst_img->type[0]->bits / 8); + dst_img->stride[0] = 0; + + src_img->data[0] = source_buf; + src_img->type[0] = source_fmt->type[0]; + src_img->pitch[0] = source_fmt->type[0]->bits / 8; + src_img->stride[0] = 0; + + dst_img->data[0] = source_double_buf; + + babl_conversion_process ( + assert_conversion_find (src_img->type[0], dst_img->type[0]), + (void*)src_img, (void*)dst_img, + n * source_fmt->components); + babl_free (src_img); + babl_free (dst_img); +} + +static void +ncomponent_convert_from_double (BablFormat *destination_fmt, + char *destination_double_buf, + char *destination_buf, + int n) +{ + BablImage *src_img; + BablImage *dst_img; + + src_img = (BablImage *) babl_image_new ( + babl_component_from_id (BABL_GRAY_LINEAR), NULL, 1, 0, NULL); + dst_img = (BablImage *) babl_image_new ( + babl_component_from_id (BABL_GRAY_LINEAR), NULL, 1, 0, NULL); + + src_img->type[0] = (BablType *) babl_type_from_id (BABL_DOUBLE); + src_img->pitch[0] = (src_img->type[0]->bits / 8); + src_img->stride[0] = 0; + + dst_img->data[0] = destination_buf; + dst_img->type[0] = (BablType *) babl_type_from_id (BABL_DOUBLE); + dst_img->pitch[0] = destination_fmt->type[0]->bits/8; + dst_img->stride[0] = 0; + + dst_img->type[0] = destination_fmt->type[0]; + src_img->data[0] = destination_double_buf; + + babl_conversion_process ( + assert_conversion_find (src_img->type[0], dst_img->type[0]), + (void*)src_img, (void*)dst_img, + n * destination_fmt->components); + + dst_img->data[0] += dst_img->type[0]->bits / 8; + babl_free (src_img); + babl_free (dst_img); +} + + +static int +process_to_n_component (const Babl *babl, + const char *source, + char *destination, + long n) +{ + void *double_buf; +#ifndef MAX +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif + int components = MAX(BABL (babl->fish.source)->format.model->components, + BABL (babl->fish.source)->format.components); + components = MAX(components, BABL (babl->fish.destination)->format.components); + components = MAX(components, BABL (babl->fish.destination)->model.components); + + double_buf = babl_malloc (sizeof (double) * n * components); + memset (double_buf, 0,sizeof (double) * n * components); + + /* a single precision path could be added here*/ + { + ncomponent_convert_to_double ( + (BablFormat *) BABL (babl->fish.source), + (char *) source, + double_buf, + n + ); + + ncomponent_convert_from_double ( + (BablFormat *) BABL (babl->fish.destination), + double_buf, + (char *) destination, + n + ); + } + + babl_free (double_buf); + return 0; +} + +static int compatible_components (const BablFormat *a, + const BablFormat *b) +{ + int i; + if (a->components != b->components) + return 0; + for (i = 0; i < a->components; i++) + if (a->component[i] != b->component[i]) + return 0; + return 1; +} + +static void +ncomponent_convert_to_float (BablFormat *source_fmt, + char *source_buf, + char *source_float_buf, + int n) +{ + BablImage *src_img; + BablImage *dst_img; + + src_img = (BablImage *) babl_image_new ( + babl_component_from_id (BABL_GRAY_LINEAR), NULL, 1, 0, NULL); + dst_img = (BablImage *) babl_image_new ( + babl_component_from_id (BABL_GRAY_LINEAR), NULL, 1, 0, NULL); + + dst_img->type[0] = (BablType *) babl_type_from_id (BABL_FLOAT); + dst_img->pitch[0] = (dst_img->type[0]->bits / 8); + dst_img->stride[0] = 0; + + src_img->data[0] = source_buf; + src_img->type[0] = source_fmt->type[0]; + src_img->pitch[0] = source_fmt->type[0]->bits / 8; + src_img->stride[0] = 0; + + dst_img->data[0] = source_float_buf; + + babl_conversion_process ( + assert_conversion_find (src_img->type[0], dst_img->type[0]), + (void*)src_img, (void*)dst_img, + n * source_fmt->components); + babl_free (src_img); + babl_free (dst_img); +} + +static void +ncomponent_convert_from_float (BablFormat *source_fmt, + BablFormat *destination_fmt, + char *destination_float_buf, + char *destination_buf, + int n) +{ + BablImage *src_img; + BablImage *dst_img; + + src_img = (BablImage *) babl_image_new ( + babl_component_from_id (BABL_GRAY_LINEAR), NULL, 1, 0, NULL); + dst_img = (BablImage *) babl_image_new ( + babl_component_from_id (BABL_GRAY_LINEAR), NULL, 1, 0, NULL); + + src_img->type[0] = (BablType *) babl_type_from_id (BABL_FLOAT); + src_img->pitch[0] = (src_img->type[0]->bits / 8); + src_img->stride[0] = 0; + + dst_img->data[0] = destination_buf; + dst_img->type[0] = (BablType *) babl_type_from_id (BABL_FLOAT); + dst_img->pitch[0] = destination_fmt->type[0]->bits/8; + dst_img->stride[0] = 0; + + dst_img->type[0] = destination_fmt->type[0]; + src_img->data[0] = destination_float_buf; + + babl_conversion_process ( + assert_conversion_find (src_img->type[0], dst_img->type[0]), + (void*)src_img, (void*)dst_img, + n * destination_fmt->components); + + dst_img->data[0] += dst_img->type[0]->bits / 8; + babl_free (src_img); + babl_free (dst_img); +} + +static void +convert_to_float (BablFormat *source_fmt, + const char *source_buf, + char *float_buf, + int n) +{ + int i; + + BablImage *src_img; + BablImage *dst_img; + + src_img = (BablImage *) babl_image_new ( + babl_component_from_id (BABL_GRAY_LINEAR), NULL, 1, 0, NULL); + dst_img = (BablImage *) babl_image_new ( + babl_component_from_id (BABL_GRAY_LINEAR), NULL, 1, 0, NULL); + + dst_img->type[0] = (BablType *) babl_type_from_id (BABL_FLOAT); + dst_img->pitch[0] = + (dst_img->type[0]->bits / 8) * source_fmt->model->components; + dst_img->stride[0] = 0; + + src_img->type[0] = (BablType *) babl_type_from_id (BABL_FLOAT); + src_img->pitch[0] = source_fmt->bytes_per_pixel; + src_img->stride[0] = 0; + + { + /* i is dest position */ + for (i = 0; i < source_fmt->model->components; i++) + { + int j; + int found = 0; + + dst_img->data[0] = + float_buf + (dst_img->type[0]->bits / 8) * i; + + src_img->data[0] = (char *)source_buf; + + /* j is source position */ + for (j = 0; j < source_fmt->components; j++) + { + src_img->type[0] = source_fmt->type[j]; + + if (source_fmt->component[j] == + source_fmt->model->component[i]) + { + babl_conversion_process (assert_conversion_find (src_img->type[0], dst_img->type[0]), + (void*)src_img, (void*)dst_img, n); + found = 1; + break; + } + + src_img->data[0] += src_img->type[0]->bits / 8; + } + + if (!found) + { + char *dst_ptr = dst_img->data[0]; + float value; + + value = source_fmt->model->component[i]->instance.id == BABL_ALPHA ? 1.0 : 0.0; + + for (j = 0; j < n; j++) + { + float *dst_component = (float *) dst_ptr; + + *dst_component = value; + dst_ptr += dst_img->pitch[0]; + } + } + } + } + babl_free (src_img); + babl_free (dst_img); +} + + +static void +convert_from_float (BablFormat *source_fmt, + BablFormat *destination_fmt, + char *destination_float_buf, + char *destination_buf, + int n) +{ + int i; + + BablImage *src_img; + BablImage *dst_img; + + src_img = (BablImage *) babl_image_new ( + babl_component_from_id (BABL_GRAY_LINEAR), NULL, 1, 0, NULL); + dst_img = (BablImage *) babl_image_new ( + babl_component_from_id (BABL_GRAY_LINEAR), NULL, 1, 0, NULL); + + src_img->type[0] = (BablType *) babl_type_from_id (BABL_FLOAT); + src_img->pitch[0] = (src_img->type[0]->bits / 8) * destination_fmt->model->components; + src_img->stride[0] = 0; + + dst_img->data[0] = destination_buf; + dst_img->type[0] = (BablType *) babl_type_from_id (BABL_FLOAT); + dst_img->pitch[0] = destination_fmt->bytes_per_pixel; + dst_img->stride[0] = 0; + + for (i = 0; i < destination_fmt->components; i++) + { + int j; + int can_be_used = 1; + + dst_img->type[0] = destination_fmt->type[i]; + + if (source_fmt->model == destination_fmt->model) + { + can_be_used = 0; + for (j = 0; j < source_fmt->components; j++) + { + if (destination_fmt->component[i] == source_fmt->component[j]) + { + can_be_used = 1; + } + } + } + + if (can_be_used) + for (j = 0; j < destination_fmt->model->components; j++) + { + if (destination_fmt->component[i] == + destination_fmt->model->component[j]) + { + src_img->data[0] = + destination_float_buf + (src_img->type[0]->bits / 8) * j; + + babl_conversion_process (assert_conversion_find (src_img->type[0], + dst_img->type[0]), + (void*)src_img, (void*)dst_img, n); + break; + } + } + + dst_img->data[0] += dst_img->type[0]->bits / 8; + } + babl_free (src_img); + babl_free (dst_img); +} + + + +static void +process_same_model (const Babl *babl, + const char *source, + char *destination, + long n) +{ + const void *type_float = babl_type_from_id (BABL_FLOAT); +#define MAX(a, b) ((a) > (b) ? (a) : (b)) + + if ((babl->fish.source->format.type[0]->bits < 32 || + babl->fish.source->format.type[0] == type_float) && + (babl->fish.destination->format.type[0]->bits < 32 || + babl->fish.destination->format.type[0] == type_float)) + { + void *float_buf = babl_malloc (sizeof (float) * n * + MAX (BABL (babl->fish.source)->format.model->components, + BABL (babl->fish.source)->format.components)); + if (compatible_components ((void*)babl->fish.source, + (void*)babl->fish.destination)) + { + ncomponent_convert_to_float ( + (BablFormat *) BABL (babl->fish.source), + (char *) source, + float_buf, + n); + ncomponent_convert_from_float ( + (BablFormat *) BABL (babl->fish.source), + (BablFormat *) BABL (babl->fish.destination), + float_buf, + (char *) destination, + n); + } + else + { + convert_to_float ( + (BablFormat *) BABL (babl->fish.source), + (char *) source, + float_buf, + n); + + convert_from_float ( + (BablFormat *) BABL (babl->fish.source), + (BablFormat *) BABL (babl->fish.destination), + float_buf, + (char *) destination, + n); + } + babl_free (float_buf); + } + else + { + void *double_buf = babl_malloc (sizeof (double) * n * + MAX (BABL (babl->fish.source)->format.model->components, + BABL (babl->fish.source)->format.components)); +#undef MAX + if (compatible_components ((void*)babl->fish.source, + (void*)babl->fish.destination)) + { + ncomponent_convert_to_double ( + (BablFormat *) BABL (babl->fish.source), + (char *) source, + double_buf, + n); + ncomponent_convert_from_double ( + (BablFormat *) BABL (babl->fish.destination), + double_buf, + (char *) destination, + n); + } + else + { + convert_to_double ( + (BablFormat *) BABL (babl->fish.source), + (char *) source, + double_buf, + n); + + convert_from_double ( + (BablFormat *) BABL (babl->fish.source), + (BablFormat *) BABL (babl->fish.destination), + double_buf, + (char *) destination, + n); + } + babl_free (double_buf); + } +} + +typedef enum _Kind Kind; +enum _Kind { KIND_RGB, KIND_CMYK}; + +static int format_has_cmyk_model (const Babl *format) +{ + return format->format.model->flags & BABL_MODEL_FLAG_CMYK; +} + +static void +babl_fish_reference_process_double (const Babl *babl, + const char *source, + char *destination, + long n, + void *data) +{ + Kind source_kind = KIND_RGB; + Kind destination_kind = KIND_RGB; + Babl *source_image = NULL; + Babl *rgba_image = NULL; + Babl *cmyka_image = NULL; + Babl *destination_image = NULL; + + + + void *source_double_buf_alloc = NULL; + void *source_double_buf = NULL; + void *rgba_double_buf_alloc = NULL; + void *rgba_double_buf = NULL; + void *cmyka_double_buf_alloc = NULL; + void *cmyka_double_buf = NULL; + void *destination_double_buf_alloc = NULL; + void *destination_double_buf; + const void *type_double = babl_type_from_id (BABL_DOUBLE); + + const Babl *source_space = BABL (BABL ((babl->fish.source))->format.space); + const Babl *destination_space = BABL (BABL ((babl->fish.destination))->format.space); + + /* This is not the full/only condition XXX */ + + /* XXX : sometimes is_cmyk is neither 0 or 1 */ + + if (format_has_cmyk_model (babl->fish.source)) + source_kind = KIND_CMYK; + if (format_has_cmyk_model (babl->fish.destination)) + destination_kind = KIND_CMYK; + + if (babl->fish.source->format.type[0] == type_double && + BABL(babl->fish.source)->format.components == + BABL(babl->fish.source)->format.model->components) + { + source_double_buf = (void*)source; + source_image = babl_image_from_linear ( + source_double_buf, BABL (BABL ((babl->fish.source))->format.model)); + } + else + { + source_double_buf = + source_double_buf_alloc = babl_malloc (sizeof (double) * n * + BABL (babl->fish.source)->format.model->components); + + source_image = babl_image_from_linear ( + source_double_buf, BABL (BABL ((babl->fish.source))->format.model)); + convert_to_double ( + (BablFormat *) BABL (babl->fish.source), + source, + source_double_buf, + n + ); + } + + babl_mutex_lock (babl_reference_mutex); + switch (source_kind) + { + case KIND_RGB: + { + Babl *conv = assert_conversion_find ( + BABL (babl->fish.source)->format.model, + babl_remodel_with_space (babl_model_from_id (BABL_RGBA), + source_space)); + + rgba_double_buf = + rgba_double_buf_alloc = babl_malloc (sizeof (double) * n * 4); + + rgba_image = babl_image_from_linear ( + rgba_double_buf, babl_remodel_with_space (babl_model_from_id (BABL_RGBA), source_space)); + + if (conv->class_type == BABL_CONVERSION_PLANAR) + { + babl_conversion_process (conv, + (void*)source_image, (void*)rgba_image, n); + } + else if (conv->class_type == BABL_CONVERSION_LINEAR) + { + babl_conversion_process (conv, source_double_buf, rgba_double_buf, n); + } + else babl_fatal ("oops"); + } + break; + case KIND_CMYK: + if (babl_model_is ((void*)babl->fish.source->format.model, "cmykA")) + { + cmyka_double_buf = source_double_buf; + cmyka_image = babl_image_from_linear (cmyka_double_buf, + (void*)babl->fish.source->format.model); + } + else + { + Babl *conv = assert_conversion_find ( + BABL (babl->fish.source)->format.model, + babl_remodel_with_space (babl_model ("cmykA"), + source_space)); + + cmyka_double_buf = + cmyka_double_buf_alloc = babl_malloc (sizeof (double) * n * 5); + + cmyka_image = babl_image_from_linear ( + cmyka_double_buf, babl_remodel_with_space (babl_model ("cmykA"), + source_space)); + + if (conv->class_type == BABL_CONVERSION_PLANAR) + { + babl_conversion_process (conv, + (void*)source_image, (void*)cmyka_image, n); + } + else if (conv->class_type == BABL_CONVERSION_LINEAR) + { + babl_conversion_process (conv,source_double_buf, cmyka_double_buf, n); + } + else babl_fatal ("oops"); + } + break; + } + + if (source_kind == KIND_RGB && + destination_kind == KIND_RGB) + { + if (source_space != destination_space) + { + double matrix[9]; + double *rgba = rgba_double_buf; + babl_matrix_mul_matrix ( + destination_space->space.XYZtoRGB, + source_space->space.RGBtoXYZ, + matrix); + + babl_matrix_mul_vector_buf4 (matrix, rgba, rgba, n); + } + } + else if (source_kind == KIND_RGB && + destination_kind == KIND_CMYK) + { + cmyka_double_buf = + cmyka_double_buf_alloc = babl_malloc (sizeof (double) * n * 5); + cmyka_image = babl_image_from_linear ( + cmyka_double_buf, babl_remodel_with_space (babl_model ("cmykA"), + destination_space)); + +#if HAVE_LCMS + if (destination_space->space.cmyk.lcms_profile) + { + /* lcms expect floats with normalized range 0.0-100.0 for CMYK data, + we also do our inversion from profile here. + */ + double *rgba=rgba_double_buf; + double *cmyka=cmyka_double_buf; + int i; + /* use lcms for doing conversion from RGBA */ + cmsDoTransform (destination_space->space.cmyk.lcms_from_rgba, + rgba_double_buf, cmyka_double_buf, n); + + for (i = 0; i < n; i++) + { + cmyka[i * 5 + 0] = 1.0-(cmyka[i * 5 + 0])/100.0; + cmyka[i * 5 + 1] = 1.0-(cmyka[i * 5 + 1])/100.0; + cmyka[i * 5 + 2] = 1.0-(cmyka[i * 5 + 2])/100.0; + cmyka[i * 5 + 3] = 1.0-(cmyka[i * 5 + 3])/100.0; + cmyka[i * 5 + 4] = rgba[i * 4 + 3]; + } + } + else +#endif + { + double *rgba=rgba_double_buf; + double *cmyka=cmyka_double_buf; + int i; + for (i = 0; i < n; i++) + { + /* A very naive conversion - but it is usable */ + double key=1.0; + cmyka[i * 5 + 0] = 1.0 - rgba[i * 4 + 0]; + cmyka[i * 5 + 1] = 1.0 - rgba[i * 4 + 1]; + cmyka[i * 5 + 2] = 1.0 - rgba[i * 4 + 2]; + + if (cmyka[i * 5 + 0] < key) key = cmyka[i*5+0]; + if (cmyka[i * 5 + 1] < key) key = cmyka[i*5+1]; + if (cmyka[i * 5 + 2] < key) key = cmyka[i*5+2]; + + key *= 1.0; // pullout - XXX tune default pullout?; + + if (key < 1.0) + { + cmyka[i * 5 + 0] = (cmyka[i * 5 + 0] - key) / (1.0-key); + cmyka[i * 5 + 1] = (cmyka[i * 5 + 1] - key) / (1.0-key); + cmyka[i * 5 + 2] = (cmyka[i * 5 + 2] - key) / (1.0-key); + } + cmyka[i * 5 + 0] = 1.0-cmyka[i * 5 + 0]; + cmyka[i * 5 + 1] = 1.0-cmyka[i * 5 + 1]; + cmyka[i * 5 + 2] = 1.0-cmyka[i * 5 + 2]; + cmyka[i * 5 + 3] = 1.0-key; + cmyka[i * 5 + 4] = rgba[i * 4 + 3]; + } + } + } + else if (source_kind == KIND_CMYK && + destination_kind == KIND_RGB) + { + /* */ + rgba_double_buf_alloc = babl_malloc (sizeof (double) * n * 4); + rgba_double_buf = rgba_double_buf_alloc; + rgba_image = babl_image_from_linear ( + rgba_double_buf, babl_remodel_with_space (babl_model_from_id (BABL_RGBA), + destination_space)); + +#if HAVE_LCMS + if (source_space->space.cmyk.lcms_profile) + { + { + /* lcms expect floats with normalized range 0.0-100.0 for CMYK data, + we also do our inversion from profile here. + */ + double *cmyka=cmyka_double_buf; + int i; + for (i = 0; i < n; i++) + { + cmyka[i * 5 + 0] = (1.0-cmyka[i * 5 + 0])*100.0; + cmyka[i * 5 + 1] = (1.0-cmyka[i * 5 + 1])*100.0; + cmyka[i * 5 + 2] = (1.0-cmyka[i * 5 + 2])*100.0; + cmyka[i * 5 + 3] = (1.0-cmyka[i * 5 + 3])*100.0; + } + } + /* use lcms for doing conversion to RGBA */ + cmsDoTransform (source_space->space.cmyk.lcms_to_rgba, + cmyka_double_buf, rgba_double_buf, n); + + { + double *rgba=rgba_double_buf; + double *cmyka=cmyka_double_buf; + int i; + for (i = 0; i < n; i++) + { + rgba[i * 4 + 3] = cmyka[i * 5 + 4]; + } + } + } + else +#endif + { + double *rgba=rgba_double_buf; + double *cmyka=cmyka_double_buf; + int i; + for (i = 0; i < n; i++) + { + /* A very naive conversion - but it is usable */ + rgba[i * 4 + 0] = cmyka[i * 5 + 0]*cmyka[i*5+3]; + rgba[i * 4 + 1] = cmyka[i * 5 + 1]*cmyka[i*5+3]; + rgba[i * 4 + 2] = cmyka[i * 5 + 2]*cmyka[i*5+3]; + rgba[i * 4 + 3] = cmyka[i * 5 + 4]; + } + } + + /* color space conversions */ + if ((babl_space ("scRGB")!= + ((babl->fish.destination)->format.space))) + { + double matrix[9]; + double *rgba = rgba_double_buf; + babl_matrix_mul_matrix ( + (babl->fish.destination)->format.space->space.XYZtoRGB, + babl_space("scRGB")->space.RGBtoXYZ, + matrix); + + babl_matrix_mul_vector_buf4 (matrix, rgba, rgba, n); + } + } + else if (source_kind == KIND_CMYK && + destination_kind == KIND_CMYK) + { + if (source_space != destination_space +#if HAVE_LCMS + && source_space->space.cmyk.lcms_profile + && destination_space->space.cmyk.lcms_profile +#endif + ) + { +#if HAVE_LCMS + +#define MAX_CMYK_CMYK 64 + static int cmyk_cmyk_count = 0; + static const Babl *cmyk_cmyk_source[MAX_CMYK_CMYK]; + static const Babl *cmyk_cmyk_destination[MAX_CMYK_CMYK]; + static cmsHTRANSFORM cmyk_cmyk_transform[MAX_CMYK_CMYK]; + + int cmyk_cmyk_no; + double *cmyka = cmyka_double_buf; + for (cmyk_cmyk_no = 0; cmyk_cmyk_no < cmyk_cmyk_count; cmyk_cmyk_no++) + { + if (cmyk_cmyk_source[cmyk_cmyk_no] == source_space && + cmyk_cmyk_destination[cmyk_cmyk_no] == destination_space) + break; + } + +/* these are not defined by lcms2.h we hope that following the existing pattern of pixel-format definitions work */ +#ifndef TYPE_CMYKA_DBL +#define TYPE_CMYKA_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_CMYK)|EXTRA_SH(1)|CHANNELS_SH(4)|BYTES_SH(0)) +#endif + + if (cmyk_cmyk_no >= cmyk_cmyk_count) + { + cmsHPROFILE src_profile = cmsOpenProfileFromMem(source_space->space.icc_profile, source_space->space.icc_length); + cmsHPROFILE dst_profile = cmsOpenProfileFromMem(destination_space->space.icc_profile, source_space->space.icc_length); + + cmyk_cmyk_source[cmyk_cmyk_no] = source_space; + cmyk_cmyk_destination[cmyk_cmyk_no] = destination_space; + cmyk_cmyk_transform[cmyk_cmyk_no] = cmsCreateTransform(src_profile, TYPE_CMYKA_DBL, + dst_profile, TYPE_CMYKA_DBL, + INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_BLACKPOINTCOMPENSATION); + cmsCloseProfile (src_profile); + cmsCloseProfile (dst_profile); + + cmyk_cmyk_count ++; + } + for (int i = 0; i < n; i++) + { + cmyka[i * 5 + 0] = (1.0-cmyka[i * 5 + 0])*100.0; + cmyka[i * 5 + 1] = (1.0-cmyka[i * 5 + 1])*100.0; + cmyka[i * 5 + 2] = (1.0-cmyka[i * 5 + 2])*100.0; + cmyka[i * 5 + 3] = (1.0-cmyka[i * 5 + 3])*100.0; + } + + cmsDoTransform (cmyk_cmyk_transform[cmyk_cmyk_no], + cmyka_double_buf, cmyka_double_buf, n); + + for (int i = 0; i < n; i++) + { + cmyka[i * 5 + 0] = 1.0-(cmyka[i * 5 + 0])/100.0; + cmyka[i * 5 + 1] = 1.0-(cmyka[i * 5 + 1])/100.0; + cmyka[i * 5 + 2] = 1.0-(cmyka[i * 5 + 2])/100.0; + cmyka[i * 5 + 3] = 1.0-(cmyka[i * 5 + 3])/100.0; + } + +#endif + } + } + + + switch (destination_kind) /* XXX: the cases can share logic */ + { + case KIND_CMYK: + { + const Babl *destination_cmyka_format = + babl_remodel_with_space (babl_model ("cmykA"), destination_space); + if(BABL (babl->fish.destination)->format.model == (void*)destination_cmyka_format) + { + destination_double_buf = cmyka_double_buf; + } + else + { + Babl *conv = + assert_conversion_find (destination_cmyka_format, + BABL (babl->fish.destination)->format.model); + destination_double_buf = + destination_double_buf_alloc = babl_malloc (sizeof (double) * n * + BABL (babl->fish.destination)->format.model->components); + if (conv->class_type == BABL_CONVERSION_PLANAR) + { + destination_image = babl_image_from_linear ( + destination_double_buf, BABL (BABL ((babl->fish.destination))->format.model)); + babl_conversion_process (conv, + (void*)cmyka_image, (void*)destination_image, n); + } + else if (conv->class_type == BABL_CONVERSION_LINEAR) + { + babl_conversion_process (conv, + cmyka_double_buf, destination_double_buf, n); + } + else + { + babl_fatal ("oops"); + } + } + } + break; + case KIND_RGB: + { + const Babl *destination_rgba_format = + babl_remodel_with_space (babl_model_from_id (BABL_RGBA), + destination_space); + + if(BABL (babl->fish.destination)->format.model == (void*)destination_rgba_format) + { + destination_double_buf = rgba_double_buf; + } + else + { + Babl *conv = + assert_conversion_find (destination_rgba_format, + BABL (babl->fish.destination)->format.model); + destination_double_buf_alloc = babl_malloc (sizeof (double) * n * + BABL (babl->fish.destination)->format.model->components); + destination_double_buf = destination_double_buf_alloc; + + if (conv->class_type == BABL_CONVERSION_PLANAR) + { + destination_image = babl_image_from_linear ( + destination_double_buf, BABL (BABL ((babl->fish.destination))->format.model)); + babl_conversion_process ( + conv, + (void*)rgba_image, (void*)destination_image, + n); + } + else if (conv->class_type == BABL_CONVERSION_LINEAR) + { + babl_conversion_process ( + conv, + rgba_double_buf, destination_double_buf, + n); + } + else + { + babl_fatal ("oops"); + } + } + } + break; + } + babl_mutex_unlock (babl_reference_mutex); + + /* convert from double model backing target pixel format to final representation */ + convert_from_double ( + (BablFormat *) BABL (babl->fish.source), + (BablFormat *) BABL (babl->fish.destination), + destination_double_buf, + destination, + n + ); + + if (destination_double_buf_alloc) + babl_free (destination_double_buf_alloc); + if (rgba_double_buf_alloc) + babl_free (rgba_double_buf_alloc); + if (cmyka_double_buf_alloc) + babl_free (cmyka_double_buf_alloc); + if (source_double_buf_alloc) + babl_free (source_double_buf_alloc); + if (source_image) + babl_free (source_image); + if (rgba_image) + babl_free (rgba_image); + if (cmyka_image) + babl_free (cmyka_image); + if (destination_image) + babl_free (destination_image); +} + +static void +babl_fish_reference_process_float (const Babl *babl, + const char *source, + char *destination, + long n, + void *data) +{ + const void *type_float = babl_type_from_id (BABL_FLOAT); + Babl *source_image = NULL; + Babl *rgba_image = NULL; + Babl *destination_image = NULL; + void *source_float_buf_alloc = NULL; + void *source_float_buf; + void *rgba_float_buf_alloc = NULL; + void *rgba_float_buf; + void *destination_float_buf_alloc = NULL; + void *destination_float_buf; + const Babl *destination_float_format; + Babl *conv_to_rgba; + Babl *conv_from_rgba; + char dst_name[256]; + + + { + char src_name[256]; + sprintf (src_name, "%s float", babl_get_name((void*)babl->fish.source->format.model)); + conv_to_rgba = + babl_conversion_find ( + babl_format_with_space (src_name, + BABL (BABL ((babl->fish.source))->format.space)), + babl_format_with_space ("RGBA float", + BABL (BABL ((babl->fish.source))->format.space))); + } + { + sprintf (dst_name, "%s float", babl_get_name((void*)babl->fish.destination->format.model)); + destination_float_format = + babl_format_with_space (dst_name, + BABL (BABL ((babl->fish.destination))->format.space)); + conv_from_rgba = + babl_conversion_find ( + babl_format_with_space ("RGBA float", + BABL (BABL ((babl->fish.destination))->format.space)), + destination_float_format); + } + + if (!conv_to_rgba || !conv_from_rgba) + { + /* needed float conversions not found, using double code path instead */ + babl_fish_reference_process_double (babl, source, destination, n, data); + return; + } + + babl_mutex_lock (babl_reference_mutex); + if (babl->fish.source->format.type[0] == type_float && + BABL(babl->fish.source)->format.components == + BABL(babl->fish.source)->format.model->components && 0) + { + source_float_buf = (void*)source; + source_image = babl_image_from_linear ( + source_float_buf, + babl_format_with_model_as_type ((void*)((babl->fish.source))->format.model, + type_float)); + } + else + { + /* the +1 is to mask a valgrind 'invalid read of size 16' false positive */ + source_float_buf_alloc = babl_malloc (sizeof (float) * (n+1) * + (BABL (babl->fish.source)->format.model->components)); + + source_float_buf = source_float_buf_alloc; + source_image = babl_image_from_linear ( + source_float_buf, + babl_format_with_model_as_type (BABL(BABL ((babl->fish.source))->format.model), + type_float)); + convert_to_float ( + (BablFormat *) BABL (babl->fish.source), + source, + source_float_buf, + n + ); + } + + if (babl_model_is ((void*)babl->fish.source->format.model, "RGBA") && 0) + { + rgba_float_buf = source_float_buf; + rgba_image = babl_image_from_linear ( + rgba_float_buf, + (void*)babl->fish.source->format.model); + } + else + { + rgba_float_buf_alloc = babl_malloc (sizeof (float) * n * 4); + rgba_float_buf = rgba_float_buf_alloc; + + rgba_image = babl_image_from_linear ( + rgba_float_buf, + babl_format_with_space ("RGBA float", + BABL (BABL ((babl->fish.source))->format.space))); + + + if (conv_to_rgba->class_type == BABL_CONVERSION_PLANAR) + { + babl_conversion_process ( + conv_to_rgba, + (void*)source_image, (void*)rgba_image, + n); + } + else if (conv_to_rgba->class_type == BABL_CONVERSION_LINEAR) + { + babl_conversion_process ( + conv_to_rgba, + source_float_buf, rgba_float_buf, + n); + } + } + babl_mutex_unlock (babl_reference_mutex); + + if (((babl->fish.source)->format.space != + ((babl->fish.destination)->format.space))) + { + float matrix[9]; + float *rgba = rgba_float_buf; + babl_matrix_mul_matrixf ( + (babl->fish.destination)->format.space->space.XYZtoRGBf, + (babl->fish.source)->format.space->space.RGBtoXYZf, + matrix); + + babl_matrix_mul_vectorff_buf4 (matrix, rgba, rgba, n); + } + + { + if(babl_format_with_space ("RGBA float", + BABL (BABL ((babl->fish.destination))->format.space)) == + babl_format_with_space (dst_name, + BABL (BABL ((babl->fish.destination))->format.space))) + { + destination_float_buf = rgba_float_buf; + } + else + { + destination_float_buf_alloc = babl_malloc (sizeof (float) * n * + BABL (babl->fish.destination)->format.model->components); + destination_float_buf = destination_float_buf_alloc; + + if (conv_from_rgba->class_type == BABL_CONVERSION_PLANAR) + { + destination_image = babl_image_from_linear ( + destination_float_buf, destination_float_format); + babl_conversion_process ( + conv_from_rgba, + (void*)rgba_image, (void*)destination_image, + n); + } + else if (conv_from_rgba->class_type == BABL_CONVERSION_LINEAR) + { + babl_conversion_process (conv_from_rgba, rgba_float_buf, + destination_float_buf, n); + } + } + } + + convert_from_float ( + (BablFormat *) BABL (babl->fish.source), + (BablFormat *) BABL (babl->fish.destination), + destination_float_buf, + destination, + n + ); + + if (destination_float_buf_alloc) + babl_free (destination_float_buf_alloc); + if (rgba_float_buf_alloc) + babl_free (rgba_float_buf_alloc); + if (source_float_buf_alloc) + babl_free (source_float_buf_alloc); + if (source_image) + babl_free (source_image); + if (rgba_image) + babl_free (rgba_image); + if (destination_image) + babl_free (destination_image); +} + +void +babl_fish_reference_process (const Babl *babl, + const char *source, + char *destination, + long n, + void *data) +{ + static const void *type_float = NULL; + static int allow_float_reference = -1; + + if (!type_float) type_float = babl_type_from_id (BABL_FLOAT); + + /* same format in source/destination */ + if (BABL (babl->fish.source) == BABL (babl->fish.destination)) + { + if (source == destination) + { + memcpy (destination, source, n * babl->fish.source->format.bytes_per_pixel); + } + return; + } + + /* same model and space, only convert type */ + if ((BABL (babl->fish.source)->format.model == + BABL (babl->fish.destination)->format.model) && + (BABL (babl->fish.source)->format.space == + BABL (babl->fish.destination)->format.space) + ) + { + process_same_model (babl, source, destination, n); + return; + } + + /* we're converting to a n_component format - special case */ + if (babl_format_is_format_n (BABL (babl->fish.destination))) + { + process_to_n_component (babl, source, destination, n); + return; + } + + if (format_has_cmyk_model (babl->fish.source) || + format_has_cmyk_model (babl->fish.destination)) + { + babl_fish_reference_process_double (babl, source, destination, n, data); + return; + } + + if (allow_float_reference == -1) + allow_float_reference = getenv ("BABL_REFERENCE_NOFLOAT") ? 0 : 1; + + /* both source and destination are either single precision float or <32bit component, + we then do a similar to the double reference - using the first registered + float conversions - note that this makes the first registered float conversion of + a given type a reference, and we thus rely on the *first* float conversion regsitered + to be correct, this will be the case if the code paths are duplicated and we register + either a planar or linear conversion to and from "RGBA float" at the same time as + registering conversions for double. When needed conversions do not exist, we defer + to the double code paths + */ + if (allow_float_reference && + (babl->fish.source->format.type[0]->bits < 32 || + babl->fish.source->format.type[0] == type_float) && + (babl->fish.destination->format.type[0]->bits < 32 || + babl->fish.destination->format.type[0] == type_float) && + !babl_format_is_palette (babl->fish.source) && + !babl_format_is_palette (babl->fish.destination)) + { + babl_fish_reference_process_float (babl, source, destination, n, data); + } + else /* double */ + { + babl_fish_reference_process_double (babl, source, destination, n, data); + } + +} diff --git a/babl/babl-fish-simple.c b/babl/babl-fish-simple.c new file mode 100644 index 0000000..7c2777a --- /dev/null +++ b/babl/babl-fish-simple.c @@ -0,0 +1,66 @@ +/* babl - dynamically extendable universal pixel fish library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include "babl-internal.h" + +static char * +create_name (BablConversion *conversion) +{ + return conversion->instance.name; +} + +Babl * +babl_fish_simple (BablConversion *conversion) +{ + Babl *babl = NULL; + char *name; + + babl_assert (BABL_IS_BABL (conversion)); + name = create_name (conversion); + babl = babl_db_exist_by_name (babl_fish_db (), name); + if (babl) + { + /* There is an instance already registered by the required name, + * returning the preexistent one instead. + */ + return babl; + } + + babl = babl_calloc (1, sizeof (BablFishSimple) + + strlen (name) + 1); + babl->class_type = BABL_FISH_SIMPLE; + babl->instance.id = babl_fish_get_id (conversion->source, conversion->destination); + babl->instance.name = ((char *) babl) + sizeof (BablFishSimple); + strcpy (babl->instance.name, name); + babl->fish.source = conversion->source; + babl->fish.destination = conversion->destination; + + babl->fish.pixels = 0; + babl->fish_simple.conversion = conversion; + babl->fish.error = 0.0;/* babl fish simple should only be used by bablfish + reference, and babl fish reference only requests clean + conversions */ + + _babl_fish_rig_dispatch (babl); + /* Since there is not an already registered instance by the required + * name, inserting newly created class into database. + */ + babl_db_insert (babl_fish_db (), babl); + return babl; +} diff --git a/babl/babl-fish.c b/babl/babl-fish.c new file mode 100644 index 0000000..ce22b6b --- /dev/null +++ b/babl/babl-fish.c @@ -0,0 +1,362 @@ +/* babl - dynamically extendable universal pixel fish library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#define NEEDS_BABL_DB +#include "babl-internal.h" +#include "babl-db.h" +#include +#include +#include + +typedef struct _BablFindFish BablFindFish; + +typedef struct _BablFindFish +{ + Babl *fish_path; + Babl *fish_ref; + Babl *fish_fish; + int fishes; + const Babl *source; + const Babl *destination; +} _BablFishFish; + + +static int +match_conversion (Babl *conversion, + void *inout); + +static int +find_fish_path (Babl *item, + void *data); + +static int +find_memcpy_fish (Babl *item, + void *data); + +static int +find_fish_path (Babl *item, + void *data) +{ + BablFindFish *ffish = (BablFindFish *) data; + if ((item->fish.source == ffish->source) && + (item->fish.destination == ffish->destination)) + { + if (item->instance.class_type == BABL_FISH_REFERENCE) + { + ffish->fish_ref = item; + ffish->fishes++; + } + else if (item->instance.class_type == BABL_FISH_PATH) + { + ffish->fish_path = item; + ffish->fishes++; + } + else if (item->instance.class_type == BABL_FISH) + { + ffish->fish_fish = item; + ffish->fishes++; + } + if (ffish->fishes == 3) + return 1; + } + + return 0; +} + +static int +find_memcpy_fish (Babl *item, + void *data) +{ + BablFindFish *ffish = (BablFindFish *) data; + if ((item->fish.source == ffish->source) && + (item->fish.destination == ffish->destination)) + { + if ((item->fish.source == item->fish.destination) && + (item->instance.class_type == BABL_FISH_REFERENCE)) + { + ffish->fish_ref = item; + return 1; + } + } + + return 0; +} + +static int +match_conversion (Babl *conversion, + void *inout) +{ + void **data = inout; + + + if ((Babl *) conversion->conversion.destination == (Babl *) *data) + { + *data = (void *) conversion; + return 1; + } + + return 0; +} + + + +Babl * +babl_conversion_find (const void *source, + const void *destination) +{ + void *data = (void*)destination; + + if (BABL (source)->type.from_list) + babl_list_each (BABL (source)->type.from_list, match_conversion, &data); + if (data != (void*)destination) /* didn't change */ + { + return data; /* found conversion */ + } + data = NULL; + + if (BABL (source)->class_type == BABL_MODEL) + { + const Babl *srgb_source = BABL (source)->model.model ? BABL (source)->model.model:source; + const Babl *srgb_destination = BABL (destination)->model.model ? BABL (destination)->model.model:destination; + + + Babl *reference; + + if (srgb_source == source && srgb_destination == destination) + { + fprintf (stderr, "expected finding model conversion %s to %s", babl_get_name (source), babl_get_name (destination)); + return NULL; + } + + reference = babl_conversion_find (srgb_source, srgb_destination); + + /* when conversions are sought between models, with non-sRGB chromaticities, + we create the needed conversions from existing ones on the fly, and + register them. The conversions registered by the models should pick up the + RGB chromaticities, and TRC to use from the space on the model instead of + hard-coding it. + */ + + switch (reference->instance.class_type) + { + case BABL_CONVERSION_LINEAR: + return _conversion_new ("", 0, (void*)source, (void*)destination, + reference->conversion.function.linear, + NULL, + NULL, + reference->conversion.data, 1); + case BABL_CONVERSION_PLANE: + return _conversion_new ("", 0, source, destination, + NULL, + reference->conversion.function.plane, + NULL, + reference->conversion.data, 1); + case BABL_CONVERSION_PLANAR: + return _conversion_new ("", 0, source, destination, + NULL, + NULL, + reference->conversion.function.planar, + reference->conversion.data, 1); + } + } + return NULL; +} + +int +babl_fish_get_id (const Babl *source, + const Babl *destination) +{ + /* value of 'id' will be used as argument for hash function, + * substraction serves as simple combination of + * source/destination values. */ + int id = (((size_t)source * 93)) ^ ((size_t)destination); + /* instances with id 0 won't be inserted into database */ + id *= ((((size_t) (destination))) % 37); + + if (id == 0) + id = 1; + return id; +} + +const Babl * +babl_fish (const void *source, + const void *destination) +{ + const Babl *source_format = NULL; + const Babl *destination_format = NULL; + + babl_assert (source); + babl_assert (destination); + + if (BABL_IS_BABL (source)) + source_format = source; + + if (!source_format) + source_format = babl_format ((char *) source); + + if (!source_format) + { + babl_log ("args=(%p, %p) source format invalid", source, destination); + return NULL; + } + + if (BABL_IS_BABL (destination)) + destination_format = destination; + + if (!destination_format) + destination_format = babl_format ((char *) destination); + + if (!destination_format) + { + babl_log ("args=(%p, %p) destination format invalid", source, destination); + return NULL; + } + + { + int hashval; + BablHashTable *id_htable; + BablFindFish ffish = {(Babl *) NULL, + (Babl *) NULL, + (Babl *) NULL, + 0, + (Babl *) NULL, + (Babl *) NULL}; + + /* some vendor compilers can't compile non-constant elements of + * compound struct initializers + */ + ffish.source = source_format; + ffish.destination = destination_format; + + id_htable = (babl_fish_db ())->id_hash; + hashval = babl_hash_by_int (id_htable, babl_fish_get_id (source_format, destination_format)); + + if (source_format == destination_format) + { + /* In the case of equal source and destination formats + * we will search through the fish database for reference fish + * to handle the memcpy */ + babl_hash_table_find (id_htable, hashval, find_memcpy_fish, (void *) &ffish); + } + else + { + /* In the case of different source and destination formats + * we will search through the fish database for appropriate fish path + * to handle the conversion. In the case that preexistent + * fish path is found, we'll return it. In the case BABL_FISH + * instance with the same source/destination is found, we'll + * return reference fish. + * In the case neither fish path nor BABL_FISH path are found, + * we'll try to construct new fish path for requested + * source/destination. In the case new fish path is found, we'll + * return it, otherwise we'll create dummy BABL_FISH instance and + * insert it into the fish database to indicate non-existent fish + * path. + */ + babl_hash_table_find (id_htable, hashval, find_fish_path, (void *) &ffish); + if (ffish.fish_path) + { + /* we have found suitable fish path in the database */ + return ffish.fish_path; + } + + babl_mutex_lock (babl_fish_mutex); + /* do a second look in the database, in case another thread held the + mutex and made the fish + */ + if (!ffish.fish_fish) + { + babl_hash_table_find (id_htable, hashval, find_fish_path, (void *) &ffish); + if (ffish.fish_path) + { + /* we have found suitable fish path in the database */ + babl_mutex_unlock (babl_fish_mutex); + return ffish.fish_path; + } + } + + if (!ffish.fish_fish) + { + const Babl *src_space = (void*)source_format->format.space; + const Babl *dst_space = (void*)destination_format->format.space; + /* we haven't tried to search for suitable path yet */ + + if (!babl_space_is_cmyk (src_space) && + !babl_space_is_cmyk (dst_space)) + { + Babl *fish_path = babl_fish_path (source_format, destination_format); + + if (fish_path) + { + babl_mutex_unlock (babl_fish_mutex); + return fish_path; + } +#if 1 + else + { + /* there isn't a suitable path for requested formats, + * let's create a dummy BABL_FISH instance and insert + * it into the fish database to indicate that such path + * does not exist. + */ + char *name = "X"; /* name does not matter */ + Babl *fish = babl_calloc (1, sizeof (BablFish) + strlen (name) + 1); + + fish->class_type = BABL_FISH; + fish->instance.id = babl_fish_get_id (source_format, destination_format); + fish->instance.name = ((char *) fish) + sizeof (BablFish); + strcpy (fish->instance.name, name); + fish->fish.source = source_format; + fish->fish.destination = destination_format; + babl_db_insert (babl_fish_db (), fish); + } +#endif + } + } + else if (ffish.fish_fish->fish.data) + { + /* the dummy fish was created by the cache, and we need to manually + * show a "missing fast path" warning for it on the first lookup. + */ +#if 0 + _babl_fish_missing_fast_path_warning (ffish.fish_fish->fish.source, + ffish.fish_fish->fish.destination); +#endif + + ffish.fish_fish->fish.data = NULL; + } + } + + if (ffish.fish_ref) + { + /* we have already found suitable reference fish */ + babl_mutex_unlock (babl_fish_mutex); + return ffish.fish_ref; + } + else + { + /* we have to create new reference fish */ + Babl *ret = babl_fish_reference (source_format, destination_format); + babl_mutex_unlock (babl_fish_mutex); + return ret; + } + } +} + +BABL_CLASS_MINIMAL_IMPLEMENT (fish); diff --git a/babl/babl-fish.h b/babl/babl-fish.h new file mode 100644 index 0000000..35382f0 --- /dev/null +++ b/babl/babl-fish.h @@ -0,0 +1,93 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005-2008, Øyvind Kolås and others. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#ifndef _BABL_FISH_H +#define _BABL_FISH_H + + +/****************************************************************/ +/* BablFish */ +BABL_CLASS_DECLARE (fish); + +/* BablFish, common base class for various fishes. + */ +typedef struct +{ + BablInstance instance; + const Babl *source; + const Babl *destination; + void (*dispatch) (const Babl *babl, const char *src, char *dst, long n, void *data); + void **data; /* user data - only used for conversion redirect */ + long pixels; /* number of pixels translates */ + double error; /* the amount of noise introduced by the fish */ + /* instrumentation */ +} BablFish; + +/* BablFishSimple is the simplest type of fish, wrapping a single + * conversion function, (note this might not be the optimal chosen + * conversion even if it exists), these fishes are used internally for + * instance in reference fishes. + */ +typedef struct +{ + BablFish fish; + BablConversion *conversion; + double cost; /* number of ticks *10 + chain_length */ + int source_bpp; + int dest_bpp; + void *foo; +} BablFishSimple; + + +/* BablFishPath is a combination of registered conversions, both + * from the reference types / model conversions, and optimized format to + * format conversion. + * + * This is the most advanced scheduled species of fish, some future + * version of babl might even be evovling path fishes in a background + * thread, based on the fish instrumentation. For this to work in a future + * version transmogrification between the fish classes would be used. + */ +typedef struct +{ + BablFish fish; + double cost; /* number of ticks *10 + chain_length */ + int source_bpp; + int dest_bpp; + BablList *conversion_list; +} BablFishPath; + +/* BablFishReference + * + * A BablFishReference is not intended to be fast, thus the algorithm + * encoded can use a multi stage approach, based on the knowledge babl + * has encoded in the pixel formats. + * + * One of the contributions that would be welcome are new fish factories. + * + * TODO: + * * make optimal use of a single allocation containing enough space + * for the maximum amount of memory needed in two adjecant buffers + * at any time. + */ +typedef struct +{ + BablFish fish; +} BablFishReference; + +#endif diff --git a/babl/babl-format.c b/babl/babl-format.c new file mode 100644 index 0000000..2e4e3d7 --- /dev/null +++ b/babl/babl-format.c @@ -0,0 +1,789 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include +#include +#include + +#define NEEDS_BABL_DB +#include "babl-internal.h" +#include "babl-db.h" +#include "babl-ref-pixels.h" + + +static int +babl_format_destruct (void *babl) +{ + BablFormat *format = babl; + if (format->image_template != NULL) + { + babl_set_destructor (format->image_template, NULL); + /* with no destructor set, the circular reference is no problem */ + babl_free (format->image_template); + format->image_template = NULL; + } + if (format->from_list) + babl_free (format->from_list); + return 0; +} + +static Babl * +format_new (const char *name, + int id, + int planar, + int components, + BablModel *model, + const Babl *space, + BablComponent **component, + BablSampling **sampling, + const BablType **type, + const char *doc) +{ + Babl *babl; + + /* i is destination position */ + int i, j, component_found = 0; + for (i = 0; i < model->components; i++) + { + for (j = 0; j < components; j++) + { + if (component[j] == model->component[i]) + { + component_found = 1; + break; + } + } + if (!component_found) + { + component_found = 0; +#if 0 /* since babl does the right thing, let it happen */ + babl_fatal("matching source component for %s in model %s not found", + model->component[i]->instance.name, model->instance.name); +#endif + } + } + + /* allocate all memory in one chunk */ + babl = babl_malloc (sizeof (BablFormat) + + strlen (name) + 1 + + sizeof (BablComponent *) * (components) + + sizeof (BablSampling *) * (components) + + sizeof (BablType *) * (components) + + sizeof (int) * (components) + + sizeof (int) * (components)); + + babl_set_destructor (babl, babl_format_destruct); + + babl->format.from_list = NULL; + babl->format.component = (void *) (((char *) babl) + sizeof (BablFormat)); + babl->format.type = (void *) (((char *) babl->format.component) + sizeof (BablComponent *) * (components)); + babl->format.sampling = (void *) (((char *) babl->format.type) + sizeof (BablType *) * (components)); + babl->instance.name = ((char *) babl->format.sampling) + sizeof (BablSampling *) * (components); + + babl->class_type = BABL_FORMAT; + babl->instance.id = id; + + strcpy (babl->instance.name, name); + + babl->format.components = components; + + if (space == babl_space ("sRGB")) + babl->format.model = model; + else + babl->format.model = (void*)babl_remodel_with_space ((void*)model, space); + + memcpy (babl->format.component, component, sizeof (BablComponent *) * components); + memcpy (babl->format.type, type, sizeof (BablType *) * components); + memcpy (babl->format.sampling, sampling, sizeof (BablSampling *) * components); + + babl->format.planar = planar; + + babl->format.bytes_per_pixel = 0; + { + int i; + for (i = 0; i < components; i++) + babl->format.bytes_per_pixel += type[i]->bits / 8; + } + + babl->format.loss = -1.0; + babl->format.visited = 0; + babl->format.image_template = NULL; + babl->format.format_n = 0; + babl->format.palette = 0; + + babl->format.space = (void*)space; + babl->format.encoding = NULL; + babl->instance.doc = doc; + + return babl; +} + +Babl * +format_new_from_format_with_space (const Babl *format, + const Babl *space) +{ + Babl *ret; + char new_name[256]; + snprintf (new_name, sizeof (new_name), "%s-%s", babl_get_name ((void*)format), + babl_get_name ((void*)space)); + ret = babl_db_find (babl_format_db(), new_name); + if (ret) + return ret; + + ret = format_new (new_name, + 0, + format->format.planar, format->format.components, + (void*)babl_remodel_with_space (BABL(format->format.model), space), + space, + format->format.component, format->format.sampling, (void*)format->format.type, NULL); + + ret->format.encoding = babl_get_name(format); + babl_db_insert (db, (void*)ret); + return ret; +} + + +static char * +create_name (const BablModel *model, + int components, + BablComponent **component, + const BablType **type) +{ + char buf[512] = ""; + char *p = &buf[0]; + ssize_t left; + int i; + int same_types = 1; + const BablType**t = type; + const BablType *first_type = *type; + BablComponent **c1 = component; + BablComponent **c2 = model->component; + + left = 512; + snprintf (p, left, "%s ", model->instance.name); + p += strlen (model->instance.name) + 1; + left -= strlen (model->instance.name) + 1; + babl_assert (left >= 0); + + i = components; + while (i--) + { + if (first_type != *t) + { + same_types = 0; + break; + } + t++; + } + + if (same_types && + components != model->components) + same_types = 0; + + i = components; + while (same_types && i--) + { + if (*c1 != *c2) + { + same_types = 0; + break; + } + c1++; + c2++; + } + + + if (same_types) + { + snprintf (p, left, "%s", first_type->instance.name); + return babl_strdup (buf); + } + + i = components; + + while (i--) + { + snprintf (p, left, "(%s as %s) ", + (*component)->instance.name, + (*type)->instance.name); + p += strlen ((*component)->instance.name) + + strlen ((*type)->instance.name) + strlen ("( as ) "); + left -= strlen ((*component)->instance.name) + + strlen ((*type)->instance.name) + strlen ("( as ) "); + babl_assert (left >= 0); + component++; + type++; + } + return babl_strdup (buf); +} + +static char * +ncomponents_create_name (const Babl *type, + int components) +{ + char buf[512]; + snprintf (buf, sizeof (buf), "%s[%i] ", type->instance.name, components); + return babl_strdup (buf); +} + +static void +babl_format_set_is_format_n (Babl *format) +{ + if (format->class_type == BABL_FORMAT) + { + format->format.format_n = 1; + } +} + +const Babl * +babl_format_n (const Babl *btype, + int components) +{ + int i; + Babl *babl; + int id = 0; + int planar = 0; + BablModel *model = (BablModel *)babl_model ("Y"); + BablComponent *component [components]; + BablSampling *sampling [components]; + const BablType *type [components]; + char *name = NULL; + + for (i = 0; icomponent[0]; + type[i] = &btype->type; + sampling[i] = (BablSampling *) babl_sampling (1, 1); + } + + name = ncomponents_create_name (btype, components); + babl = babl_db_exist (db, id, name); + if (babl) + { + /* There is an instance already registered by the required id/name, + * returning the preexistent one instead. + */ + babl_free (name); + return babl; + } + + babl = format_new (name, + id, + planar, components, model, + babl_space("sRGB"), + component, sampling, type, NULL); + + babl_format_set_is_format_n (babl); + + babl_db_insert (db, babl); + babl_free (name); + return babl; +} + +int +babl_format_is_format_n (const Babl *format) +{ + if (format->class_type == BABL_FORMAT) + { + return format->format.format_n; + } + + return 0; +} + +static int +is_format_duplicate (Babl *babl, + int planar, + int components, + BablModel *model, + const Babl *space, + BablComponent **component, + BablSampling **sampling, + const BablType **type) +{ + int i; + + if (babl->format.planar != planar || + babl->format.components != components || + babl->format.model != model || + babl->format.space != (void*)space) + return 0; + + for (i = 0; i < components; i++) + { + if (babl->format.component[i] != component[i] || + babl->format.sampling[i] != sampling[i] || + babl->format.type[i] != type[i]) + return 0; + } + return 1; +} + +const Babl * +babl_format_new (const void *first_arg, + ...) +{ + va_list varg; + Babl *babl; + int id = 0; + int planar = 0; + int components = 0; + BablModel *model = NULL; + const Babl *space = babl_space ("sRGB"); + const char *doc = NULL; + BablComponent *component [BABL_MAX_COMPONENTS]; + BablSampling *sampling [BABL_MAX_COMPONENTS]; + const BablType*type [BABL_MAX_COMPONENTS]; + + BablSampling *current_sampling = (BablSampling *) babl_sampling (1, 1); + BablType *current_type = (BablType *) babl_type_from_id (BABL_DOUBLE); + char *name = NULL; + const void *arg = first_arg; + + va_start (varg, first_arg); + + while (1) + { + /* first, we assume arguments to be strings */ + if (!strcmp (arg, "id")) + { + id = va_arg (varg, int); + } + + else if (!strcmp (arg, "name")) + { + name = babl_strdup (va_arg (varg, char *)); + } + + else if (!strcmp (arg, "doc")) + { + doc = babl_strdup (va_arg (varg, const char *)); + } + + else if (!strcmp (arg, "packed")) + { + planar = 0; + } + + else if (!strcmp (arg, "planar")) + { + planar = 1; + } + + /* if we didn't point to a known string, we assume argument to be babl */ + else if (BABL_IS_BABL (arg)) + { + Babl *babl = (Babl *) arg; + + switch (babl->class_type) + { + case BABL_TYPE: + case BABL_TYPE_FLOAT: + case BABL_TYPE_INTEGER: + current_type = (BablType *) babl; + break; + + case BABL_COMPONENT: + if (!model) + { + babl_fatal ("no model specified before component %s", + babl->instance.name); + } + component [components] = (BablComponent *) babl; + type [components] = current_type; + sampling [components] = current_sampling; + components++; + + if (components >= BABL_MAX_COMPONENTS) + { + babl_fatal ("maximum number of components (%i) exceeded for %s", + BABL_MAX_COMPONENTS, name); + } + break; + + case BABL_SAMPLING: + current_sampling = (BablSampling *) arg; + break; + + case BABL_SPACE: + space = (Babl*) arg; + break; + + case BABL_MODEL: + if (model) + { + babl_log ("args=(%s): model %s already requested", + babl->instance.name, model->instance.name); + } + model = (BablModel *) arg; + break; + + case BABL_INSTANCE: + case BABL_FORMAT: + case BABL_CONVERSION: + case BABL_CONVERSION_LINEAR: + case BABL_CONVERSION_PLANE: + case BABL_CONVERSION_PLANAR: + case BABL_FISH: + case BABL_FISH_REFERENCE: + case BABL_FISH_SIMPLE: + case BABL_FISH_PATH: + case BABL_IMAGE: + case BABL_EXTENSION: + babl_log ("%s unexpected", + babl_class_name (babl->class_type)); + break; + + case BABL_SKY: /* shut up compiler */ + break; + } + } + + else + { + babl_fatal ("unhandled argument '%s' for format '%s'", arg, name); + } + + arg = va_arg (varg, char *); + if (!arg) + break; + } + + va_end (varg); + + if (!name) + name = create_name (model, components, component, type); + + if (space != babl_space ("sRGB")) + { + char *new_name = babl_malloc (strlen (name) + + strlen (babl_get_name ((Babl*)space)) + 1); + sprintf (new_name, "%s-%s", name, babl_get_name ((Babl*)space)); + babl_free (name); + name = new_name; + } + + if (!model) + { + babl_log ("no model specified for format '%s'", name); + babl_free(name); + return NULL; + } + + if (!components) + { + babl_log ("no components specified for format '%s'", name); + babl_free(name); + return NULL; + } + + babl = babl_db_exist (db, id, name); + if (id && !babl && babl_db_exist (db, 0, name)) + babl_fatal ("Trying to reregister BablFormat '%s' with different id!", name); + + if (babl) + { + /* There is an instance already registered by the required id/name, + * returning the preexistent one instead if it doesn't differ. + */ + if(0)if (!is_format_duplicate (babl, planar, components, model, space, + component, sampling, type)) + babl_fatal ("BablFormat '%s' already registered " + "with different content!", name); + + babl_free (name); + return babl; + } + + babl = format_new ((void*)name, + id, + planar, components, model, space, + component, sampling, type, doc); + + babl_db_insert (db, babl); + babl_free (name); + return babl; +} + +int +babl_formats_count (void) +{ + return babl_db_count (db); +} + +int +babl_format_has_alpha (const Babl *format) +{ + int n = babl_format_get_n_components (format); + int i; + + for (i = 0; i < n; i++) + { + if (format->format.component[i]->alpha) + { + return 1; + } + } + + return 0; +} + +int +babl_format_get_bytes_per_pixel (const Babl *format) +{ + if (format->class_type == BABL_FORMAT) + { + return format->format.bytes_per_pixel; + } + + return 0; +} + +int +babl_format_get_n_components (const Babl *format) +{ + if (format->class_type == BABL_FORMAT) + { + return format->format.components; + } + + return 0; +} + +const Babl * +babl_format_get_type (const Babl *format, + int component_index) +{ + if (format->class_type == BABL_FORMAT && + component_index >= 0 && + component_index < format->format.components) + { + return (Babl *)format->format.type[component_index]; + } + + return NULL; +} + +const Babl * +babl_format_with_model_as_type (const Babl *model, + const Babl *type) +{ + BablComponent *component[10]; + int i; + + for (i = 0; i < model->model.components; i++) + { + component[i] = model->model.component[i]; + } + component[i] = NULL; + + return babl_format_new ( + model, + type, + component[0], + component[1], + component[2], + component[3], + component[4], + component[5], + component[6], + component[7], + component[8], + component[9], + NULL + ); +} + +double +babl_format_loss (const Babl *babl) +{ + double loss = 0.0; + void *original; + double *clipped; + void *destination; + double *transformed; + + const Babl *ref_fmt; + const Babl *fmt; + Babl *fish_to; + Babl *fish_from; + + const double *test = babl_get_format_test_pixels (); + const int test_pixels = babl_get_num_format_test_pixels (); + + ref_fmt = babl_format_new ( + babl_model ("RGBA"), + babl_type ("double"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + babl_component ("A"), + NULL); + + if (babl->format.loss != -1.0) + return babl->format.loss; + + fmt = babl; + fish_to = babl_fish_reference (ref_fmt, fmt); + fish_from = babl_fish_reference (fmt, ref_fmt); + + original = babl_calloc (test_pixels, fmt->format.bytes_per_pixel); + clipped = babl_calloc (test_pixels, ref_fmt->format.bytes_per_pixel); + destination = babl_calloc (test_pixels, fmt->format.bytes_per_pixel); + transformed = babl_calloc (test_pixels, ref_fmt->format.bytes_per_pixel); + + babl_process (fish_to, test, original, test_pixels); + babl_process (fish_from, original, clipped, test_pixels); + babl_process (fish_to, clipped, destination, test_pixels); + babl_process (fish_from, destination, transformed, test_pixels); + + loss = babl_rel_avg_error (clipped, test, test_pixels * 4); + + fish_to->fish.pixels -= test_pixels * 2; + fish_from->fish.pixels -= test_pixels * 2; + + babl_free (original); + babl_free (clipped); + babl_free (destination); + babl_free (transformed); + + ((Babl*)babl)->format.loss = loss; + return loss; +} + + +void * +babl_get_user_data (const Babl *babl) +{ + switch (babl->instance.class_type) + { + case BABL_MODEL: + return babl->model.data; + case BABL_FORMAT: + return babl->format.model->data; + default: + babl_fatal ("babl_get_user_data called on non-model/format"); + } + babl_fatal ("eeeek"); + return NULL; +} + +void +babl_set_user_data (const Babl *cbabl, + void *data) +{ + Babl *babl = (Babl*) cbabl; + switch (cbabl->instance.class_type) + { + case BABL_MODEL: + babl->model.data = data; + break; + case BABL_FORMAT: + babl->format.model->data = data; + break; + default: + babl_fatal ("babl_set_user_data called on non-model/format"); + } +} + +const Babl * +babl_format_get_model (const Babl *format) +{ + if (format->class_type == BABL_FORMAT) + { + return (Babl*)format->format.model; + } + return NULL; +} + +const Babl * babl_format_get_space (const Babl *format) +{ + if (format->class_type == BABL_FORMAT) + { + return (Babl*)format->format.space; + } + return NULL; +} + +BABL_CLASS_IMPLEMENT (format) + +const char * +babl_format_get_encoding (const Babl *babl) +{ + if (!babl) return NULL; + if (babl->format.encoding) return babl->format.encoding; + return babl_get_name (babl); +} + +const Babl * +babl_format_with_space (const char *encoding, const Babl *space) +{ + const Babl *example_format = (void*) encoding; + if (!encoding) return NULL; + + if (BABL_IS_BABL (example_format)) + { + encoding = babl_get_name (example_format); + if (babl_format_get_space (example_format) != babl_space ("sRGB")) + { + encoding = babl_format_get_encoding (example_format); + } + } + + if (!space) + space = babl_space ("sRGB"); + + if (space->class_type == BABL_FORMAT) + { + space = space->format.space; + } + else if (space->class_type == BABL_MODEL) + { + space = space->model.space; + } + else if (space->class_type != BABL_SPACE) + { + return NULL; + } + example_format = babl_format (encoding); + + if (space == babl_space("sRGB")) + return example_format; + + if (babl_format_is_palette (example_format)) + { + /* XXX we should allocate a new palette name, and + duplicate the path data, converted for new space + */ + return example_format; + } + + return format_new_from_format_with_space (example_format, space); +} + +int +babl_format_exists (const char *name) +{ + if (babl_db_exist_by_name (db, name)) + return 1; + return 0; +} + + + diff --git a/babl/babl-format.h b/babl/babl-format.h new file mode 100644 index 0000000..9ebdcec --- /dev/null +++ b/babl/babl-format.h @@ -0,0 +1,49 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005-2008, Øyvind Kolås and others. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#ifndef _BABL_FORMAT_H +#define _BABL_FORMAT_H + +BABL_CLASS_DECLARE (format); + +typedef struct +{ + BablInstance instance; + BablList *from_list; + int components; + BablComponent **component; + BablType **type; + BablModel *model; + const Babl *space; + void *model_data; + void *image_template; /* image template for use with + linear (non-planer) images */ + + BablSampling **sampling; + int bytes_per_pixel; + int planar; + double loss; /*< average relative error when converting + from and to RGBA double */ + int visited; /* for convenience in code while searching + for conversion paths */ + int format_n; /* whether the format is a format_n type or not */ + int palette; + const char *encoding; +} BablFormat; + +#endif diff --git a/babl/babl-hash-table.c b/babl/babl-hash-table.c new file mode 100644 index 0000000..97e7012 --- /dev/null +++ b/babl/babl-hash-table.c @@ -0,0 +1,190 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +/* Implementation of hash table data structure based on coalesced hashing. + * Copyright (C) 2008, Jan Heller + */ + +#include "config.h" +#include "babl-internal.h" + +#define BABL_HASH_TABLE_INITIAL_MASK 0x1FF /* 511 */ + +/* static functions declarations */ +static inline int +hash_insert (BablHashTable *htab, + Babl *item); + +static void +hash_rehash (BablHashTable *htab); + +static inline int +hash_insert (BablHashTable *htab, + Babl *item) +{ + int hash = htab->hash_func(htab, item); + + if (htab->data_table[hash] == NULL) + { + /* create new chain */ + htab->data_table[hash] = item; + } + else + { + int it, oit, cursor = 0; + + while ((cursor < (htab->mask + 1)) && (htab->data_table[cursor] != NULL)) + ++cursor; + + htab->data_table[cursor] = item; + + for (oit = hash, it = htab->chain_table[oit]; it != -1; oit = it, it = htab->chain_table[oit]) + ; + htab->chain_table[oit] = cursor; + } + + htab->count++; + return 0; +} + +static void +hash_rehash (BablHashTable *htab) +{ + Babl *item; + int i; + BablHashTable *nhtab = babl_calloc (sizeof (BablHashTable), 1); + + nhtab->data_table = NULL; + nhtab->chain_table = NULL; + nhtab->mask = (htab->mask << 1) + 1; + nhtab->count = 0; + nhtab->hash_func = htab->hash_func; + nhtab->find_func = htab->find_func; + if (nhtab->mask) + { + nhtab->data_table = babl_calloc (sizeof (BablInstance *), babl_hash_table_size(nhtab)); + nhtab->chain_table = babl_malloc (sizeof (int) * babl_hash_table_size(nhtab)); + memset (nhtab->chain_table, -1, sizeof (int) * babl_hash_table_size(nhtab)); + } + + for (i = 0; i < babl_hash_table_size (htab); i++) + { + item = htab->data_table[i]; + babl_hash_table_insert (nhtab, item); + } + + htab->mask = nhtab->mask; + babl_free (htab->data_table); + babl_free (htab->chain_table); + htab->data_table = nhtab->data_table; + htab->chain_table = nhtab->chain_table; + babl_free (nhtab); +} + +int +babl_hash_table_size (BablHashTable *htab) +{ + return htab->mask + 1; +} + + +static int +babl_hash_table_destroy (void *data) +{ + BablHashTable *htab = data; + babl_free (htab->data_table); + babl_free (htab->chain_table); + return 0; +} + + +BablHashTable * +babl_hash_table_init (BablHashValFunction hfunc, + BablHashFindFunction ffunc) +{ + BablHashTable *htab; + + babl_assert(hfunc); + babl_assert(ffunc); + + htab = babl_calloc (sizeof (BablHashTable), 1); + babl_set_destructor (htab, babl_hash_table_destroy); + + htab->data_table = NULL; + htab->chain_table = NULL; + htab->mask = BABL_HASH_TABLE_INITIAL_MASK; + htab->count = 0; + htab->hash_func = hfunc; + htab->find_func = ffunc; + if (htab->mask) + { + htab->data_table = babl_calloc (sizeof (BablInstance *), babl_hash_table_size(htab)); + htab->chain_table = babl_malloc (sizeof (int) * babl_hash_table_size(htab)); + memset (htab->chain_table, -1, sizeof (int) * babl_hash_table_size(htab)); + } + + return htab; +} + +int +babl_hash_table_insert (BablHashTable *htab, + Babl *item) +{ + babl_assert (htab); + babl_assert (BABL_IS_BABL(item)); + + if (babl_hash_table_size (htab) < htab->count + 1) + hash_rehash (htab); + return hash_insert (htab, item); +} + +Babl * +babl_hash_table_find (BablHashTable *htab, + int hash, + BablHashFindFunction find_func, + void *data) +{ + int it; + Babl *item; + + babl_assert (htab); + + it = hash; + item = htab->data_table[it]; + + if (!item) + return NULL; + + for (;;) + { + if (find_func) + { + if (find_func (item, data)) + return item; + } + else if (htab->find_func (item, data)) + return item; + it = htab->chain_table[it]; + if (it == -1) + break; + item = htab->data_table[it]; + } + + return NULL; +} + diff --git a/babl/babl-hash-table.h b/babl/babl-hash-table.h new file mode 100644 index 0000000..04a4698 --- /dev/null +++ b/babl/babl-hash-table.h @@ -0,0 +1,68 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#ifndef _BABL_HASH_TABLE_H +#define _BABL_HASH_TABLE_H + +#ifndef _BABL_H +#error babl-hash-table.h is only to be included after babl.h +#endif + + +typedef struct _BablHashTable BablHashTable; + +typedef int (*BablHashValFunction) (BablHashTable *htab, Babl *item); +typedef int (*BablHashFindFunction) (Babl *item, void *data); + +typedef struct _BablHashTable +{ + Babl **data_table; + int *chain_table; + int mask; + int count; + BablHashValFunction hash_func; + BablHashFindFunction find_func; +} _BablHashTable; + + +BablHashTable * +babl_hash_table_init (BablHashValFunction hfunc, + BablHashFindFunction ffunc); + +int +babl_hash_by_str (BablHashTable *htab, + const char *str); + +int +babl_hash_by_int (BablHashTable *htab, + int id); + +int +babl_hash_table_size (BablHashTable *htab); + +int +babl_hash_table_insert (BablHashTable *htab, + Babl *item); + +Babl * +babl_hash_table_find (BablHashTable *htab, + int hash, + BablHashFindFunction find_func, + void *data); + +#endif diff --git a/babl/babl-icc.c b/babl/babl-icc.c new file mode 100644 index 0000000..7d1fd67 --- /dev/null +++ b/babl/babl-icc.c @@ -0,0 +1,1496 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2017, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "../config.h" +#include "babl-internal.h" +#include +#include + +typedef struct ICC { + char *data; + int length; + + int tags; + int headpos; + int o, no; + int p; + int psize; +} ICC; + +ICC * +icc_state_new (char *data, + int length, + int tags); + +ICC * +icc_state_new (char *data, + int length, + int tags) +{ + ICC *ret = babl_calloc (sizeof (ICC), 1); + ret->data = data; + ret->length = length; + ret->tags = tags; + + return ret; +} + +#define ICC_HEADER_LEN 128 +#define TAG_COUNT_OFF ICC_HEADER_LEN + +typedef struct { + int16_t integer; + uint16_t fraction; +} s15f16_t; + +typedef struct { + int16_t integer; + uint16_t fraction; +} u8f8_t; + +typedef struct { + char str[5]; +} sign_t; + +#define icc_write(type, offset, value) write_##type(state,offset,value) +#define icc_read(type, offset) read_##type(state,offset) + +static void +write_u8 (ICC *state, + int offset, + uint8_t value) +{ + if (offset < 0 || offset >= state->length) + return; + *(uint8_t*) (&state->data[offset]) = value; +} + +static void +write_s8 (ICC *state, + int offset, + int8_t value) +{ + if (offset < 0 || offset >= state->length) + return; + *(int8_t*) (&state->data[offset]) = value; +} + +static int +read_u8 (ICC *state, + int offset) +{ +/* all reading functions take both the char *pointer and the length of the + * buffer, and all reads thus gets protected by this condition. + */ + if (offset < 0 || offset > state->length) + return 0; + + return *(uint8_t*) (&state->data[offset]); +} + +static int +read_s8 (ICC *state, + int offset) +{ + if (offset < 0 || offset > state->length) + return 0; + + return *(int8_t*) (&state->data[offset]); +} + +static void +write_s16 (ICC *state, + int offset, + int16_t value) +{ + write_s8 (state, offset + 0, value >> 8); + write_u8 (state, offset + 1, value & 0xff); +} + +static int16_t +read_s16 (ICC *state, + int offset) +{ + return icc_read (u8, offset + 1) + + (read_s8 (state, offset + 0) << 8); //XXX: transform to icc_read macro +} + +static +uint16_t read_u16 (ICC *state, + int offset) +{ + return icc_read (u8, offset + 1) + + (icc_read (u8, offset + 0) << 8); +} + +static void +write_u16 (ICC *state, + int offset, + uint16_t value) +{ + write_u8 (state, offset + 0, value >> 8); + write_u8 (state, offset + 1, value & 0xff); +} + +static u8f8_t +read_u8f8_ (ICC *state, + int offset) +{ + u8f8_t ret ={icc_read (u8, offset), + icc_read (u8, offset + 1)}; + return ret; +} + +static s15f16_t +read_s15f16_ (ICC *state, + int offset) +{ + s15f16_t ret ={icc_read (s16, offset), + icc_read (u16, offset + 2)}; + return ret; +} + +static void +write_u8f8_ (ICC *state, + int offset, + u8f8_t val) +{ + icc_write (u8, offset, val.integer), + icc_write (u8, offset + 1, val.fraction); +} + +static void +write_s15f16_ (ICC *state, + int offset, + s15f16_t val) +{ + icc_write (s16, offset, val.integer), + icc_write (u16, offset + 2, val.fraction); +} + +static s15f16_t +d_to_s15f16 (double value) +{ + s15f16_t ret; + ret.integer = floor (value); + ret.fraction = fmod(value, 1.0) * 65536.0; + return ret; +} + +static u8f8_t +d_to_u8f8 (double value) +{ + u8f8_t ret; + ret.integer = floor (value); + ret.fraction = fmod(value, 1.0) * 256.0; + return ret; +} + +static double +s15f16_to_d (s15f16_t fix) +{ + return fix.integer + fix.fraction / 65536.0; +} + +static double +u8f8_to_d (u8f8_t fix) +{ + return fix.integer + fix.fraction / 256.0; +} + +static void +write_s15f16 (ICC *state, + int offset, + double value) +{ + write_s15f16_ (state, offset, d_to_s15f16 (value)); +} + +static void +write_u8f8 (ICC *state, + int offset, + double value) +{ + write_u8f8_ (state, offset, d_to_u8f8 (value)); +} + + +static double +read_s15f16 (ICC *state, + int offset) +{ + return s15f16_to_d (read_s15f16_ (state, offset)); +} + +static double +read_u8f8 (ICC *state, + int offset) +{ + return u8f8_to_d (read_u8f8_ (state, offset)); +} + +#if 0 +static inline void +print_u8f8 (u8f8_t fix) +{ + int i; + uint32_t foo; + foo = fix.fraction; + fprintf (stdout, "%i.", fix.integer); + for (i = 0; i < 18; i++) + { + foo *= 10; + fprintf (stdout, "%i", (foo / 256) % 10); + foo = foo & 0xff; + } +} + +static inline void +print_s15f16 (s15f16_t fix) +{ + int i; + uint32_t foo; + foo = fix.fraction; + if (fix.integer < 0) + { + if (fix.integer == -1) + fprintf (stdout, "-"); + fprintf (stdout, "%i.", fix.integer + 1); + foo = 65535-fix.fraction; + for (i = 0; i < 18; i++) + { + foo *= 10; + fprintf (stdout, "%i", (foo / 65536) % 10); + foo = foo & 0xffff; + } + } + else + { + fprintf (stdout, "%i.", fix.integer); + for (i = 0; i < 18; i++) + { + foo *= 10; + fprintf (stdout, "%i", (foo / 65536) % 10); + foo = foo & 0xffff; + } + } +} +#endif + +static void +write_u32 (ICC *state, + int offset, + uint32_t value) +{ + int i; + for (i = 0; i < 4; i ++) + { + write_u8 (state, offset + i, + (value & 0xff000000) >> 24 + ); + value <<= 8; + } +} + +static uint32_t +read_u32 (ICC *state, + int offset) +{ + return icc_read (u8, offset + 3) + + (icc_read (u8, offset + 2) << 8) + + (icc_read (u8, offset + 1) << 16) + + (icc_read (u8, offset + 0) << 24); +} + +static sign_t +read_sign (ICC *state, + int offset) +{ + sign_t ret; + ret.str[0]=icc_read (u8, offset); + ret.str[1]=icc_read (u8, offset + 1); + ret.str[2]=icc_read (u8, offset + 2); + ret.str[3]=icc_read (u8, offset + 3); + ret.str[4]=0; + return ret; +} + +static void +write_sign (ICC *state, + int offset, + const char *sign) +{ + int i; + for (i = 0; i < 4; i ++) + icc_write (u8, offset + i, sign[i]); +} + +/* looks up offset and length for a specific icc tag + */ +static int +icc_tag (ICC *state, + const char *tag, + int *offset, + int *el_length) +{ + int tag_count = icc_read (u32, TAG_COUNT_OFF); + int t; + + for (t = 0; t < tag_count; t++) + { + sign_t sign = icc_read (sign, TAG_COUNT_OFF + 4 + 12 * t); + if (!strcmp (sign.str, tag)) + { + if (offset) + *offset = icc_read (u32, TAG_COUNT_OFF + 4 + 12* t + 4); + if (el_length) + *el_length = icc_read (u32, TAG_COUNT_OFF + 4 + 12* t + 4*2); + return 1; + } + } + return 0; +} + +static const Babl * +babl_trc_from_icc (ICC *state, + int offset, + const char **error) +{ + { + int count = icc_read (u32, offset + 8); + int i; + if (!strcmp (state->data + offset, "para")) + { + int function_type = icc_read (u16, offset + 8); + float g; + switch (function_type) + { + case 0: + g = icc_read (s15f16, offset + 12 + 4 * 0); + return babl_trc_gamma (g); + break; + case 1: + { + float a,b,c; + g = icc_read (s15f16, offset + 12 + 4 * 0); + a = icc_read (s15f16, offset + 12 + 4 * 1); + b = icc_read (s15f16, offset + 12 + 4 * 2); + c = 0; + return babl_trc_formula_cie (g, a, b, c); + } + case 2: + { + float a,b,c; + g = icc_read (s15f16, offset + 12 + 4 * 0); + a = icc_read (s15f16, offset + 12 + 4 * 1); + b = icc_read (s15f16, offset + 12 + 4 * 2); + c = icc_read (s15f16, offset + 12 + 4 * 3); + return babl_trc_formula_cie (g, a, b, c); + } + case 3: + { + float a,b,c,d,e,f; + g = icc_read (s15f16, offset + 12 + 4 * 0); + a = icc_read (s15f16, offset + 12 + 4 * 1); + b = icc_read (s15f16, offset + 12 + 4 * 2); + c = icc_read (s15f16, offset + 12 + 4 * 3); + d = icc_read (s15f16, offset + 12 + 4 * 4); + e = 0.0f; + f = 0.0f; + return babl_trc_formula_srgb (g, a, b, c, d, e, f); + } + case 4: + { + float a,b,c,d,e,f; + g = icc_read (s15f16, offset + 12 + 4 * 0); + a = icc_read (s15f16, offset + 12 + 4 * 1); + b = icc_read (s15f16, offset + 12 + 4 * 2); + c = icc_read (s15f16, offset + 12 + 4 * 3); + d = icc_read (s15f16, offset + 12 + 4 * 4); + e = icc_read (s15f16, offset + 12 + 4 * 5); + f = icc_read (s15f16, offset + 12 + 4 * 6); + return babl_trc_formula_srgb (g, a, b, c, d, e, f); + } + default: + *error = "unhandled parametric TRC"; + fprintf (stderr, "unhandled parametric TRC type %i\n", function_type); + return babl_trc_gamma (2.2); + break; + } + } + else + { + if (count == 0) + { + return babl_trc_gamma (1.0); + } + else if (count == 1) + { + return babl_trc_gamma (icc_read (u8f8, offset + 12)); + } + else + { + const Babl *ret; + float *lut; + + lut = babl_malloc (sizeof (float) * count); + + for (i = 0; i < count; i ++) + { + lut[i] = icc_read (u16, offset + 12 + i * 2) / 65535.0; + } + + ret = babl_trc_lut_find (lut, count); + if (ret) + return ret; + + ret = babl_trc_lut (NULL, count, lut); + babl_free (lut); + return ret; + } + } + } + return NULL; +} + +static void +icc_allocate_tag (ICC *state, + const char *tag, + int size) +{ + while (state->no % 4 != 0) + state->no++; + + state->o = state->no;state->psize = size; + icc_write (sign, 128 + 4 + 4 * state->headpos++, tag); + icc_write (u32, 128 + 4 + 4 * state->headpos++, state->o); + icc_write (u32, 128 + 4 + 4 * state->headpos++, size); + state->p = state->no;\ + state->no+=size; +} + +static void +icc_duplicate_tag(ICC *state, + const char *tag) +{ + icc_write (sign, 128 + 4 + 4 * state->headpos++, tag); + icc_write (u32, 128 + 4 + 4 * state->headpos++, state->p); + icc_write (u32, 128 + 4 + 4 * state->headpos++, state->psize); +} + +/* brute force optimized 26 entry sRGB LUT */ +static const uint16_t lut_srgb_26[]={0,202,455,864,1423,2154,3060,4156,5454,6960,8689,10637,12821,15247,17920,20855,24042,27501,31233,35247,39549,44132,49018,54208,59695,65535}; + + +void write_trc (ICC *state, + const char *name, + const BablTRC *trc, + BablICCFlags flags); + +void write_trc (ICC *state, + const char *name, + const BablTRC *trc, + BablICCFlags flags) +{ +switch (trc->type) +{ + case BABL_TRC_LINEAR: + icc_allocate_tag (state, name, 13); + icc_write (sign, state->o, "curv"); + icc_write (u32, state->o + 4, 0); + icc_write (u32, state->o + 8, 0); + break; + case BABL_TRC_FORMULA_GAMMA: + icc_allocate_tag (state, name, 14); + icc_write (sign, state->o, "curv"); + icc_write (u32, state->o + 4, 0); + icc_write (u32, state->o + 8, 1); + icc_write (u8f8, state->o + 12, trc->gamma); + break; + case BABL_TRC_LUT: + icc_allocate_tag (state, name, 12 + trc->lut_size * 2); + icc_write (sign, state->o, "curv"); + icc_write (u32, state->o + 4, 0); + icc_write (u32, state->o + 8, trc->lut_size); + { + int j; + for (j = 0; j < trc->lut_size; j ++) + icc_write (u16, state->o + 12 + j * 2, (int)(trc->lut[j]*65535.5f)); + } + break; + // this is the case catching things not directly representable in v2 + case BABL_TRC_SRGB: + if (flags == BABL_ICC_COMPACT_TRC_LUT) + { + int lut_size = 26; + icc_allocate_tag (state, name, 12 + lut_size * 2); + icc_write (sign, state->o, "curv"); + icc_write (u32, state->o + 4, 0); + icc_write (u32, state->o + 8, lut_size); + { + int j; + for (j = 0; j < lut_size; j ++) + icc_write (u16, state->o + 12 + j * 2, lut_srgb_26[j]); + } + break; + } + case BABL_TRC_FORMULA_SRGB: + case BABL_TRC_FORMULA_CIE: + { + int lut_size = 512; + if (flags == BABL_ICC_COMPACT_TRC_LUT) + lut_size = 128; + + icc_allocate_tag (state, name, 12 + lut_size * 2); + icc_write (sign, state->o, "curv"); + icc_write (u32, state->o + 4, 0); + icc_write (u32, state->o + 8, lut_size); + { + int j; + for (j = 0; j < lut_size; j ++) + icc_write (u16, state->o + 12 + j * 2, + babl_trc_to_linear ((void*)trc, j / (lut_size-1.0)) * 65535.5); + } + } +} +} + +static void +symmetry_test (ICC *state); + + +static char * +babl_space_to_icc_rgb (const Babl *babl, + const char *description, + const char *copyright, + BablICCFlags flags, + int *ret_length) +{ + const BablSpace *space = &babl->space; + char icc[65536]; + int length=65535; + ICC *state = icc_state_new (icc, length, 10); + + icc[length]=0; + + symmetry_test (state); + + icc_write (sign, 4, "babl"); // ICC verison + icc_write (u8, 8, 2); // ICC verison + icc_write (u8, 9, 0x20); // 2.2 for now.. + icc_write (u32,64, 0); // rendering intent + + icc_write (s15f16,68, 0.96421); // Illuminant + icc_write (s15f16,72, 1.0); + icc_write (s15f16,76, 0.82491); + + icc_write (sign, 80, "babl"); // creator + + icc_write (sign, 12, "mntr"); + icc_write (sign, 16, "RGB "); + icc_write (sign, 20, "XYZ "); + + icc_write (u16, 24, 2222); // babl profiles + icc_write (u16, 26, 11); // should + icc_write (u16, 28, 11); // use a fixed + icc_write (u16, 30, 3); // date + icc_write (u16, 32, 44); // that gets updated + icc_write (u16, 34, 55); // when the generator changes + + icc_write (sign, 36, "acsp"); // changes + + { + state->tags = 9; /* note: we could reserve a couple of spots and + still use a very simple allocator and + still be valid - albeit with tiny waste of + space. + */ + state->no = state->o = 128 + 4 + 12 * state->tags; + + icc_write (u32, 128, state->tags); + + icc_allocate_tag (state, "wtpt", 20); + icc_write (sign, state->o, "XYZ "); + icc_write (u32, state->o + 4, 0); + icc_write (s15f16, state->o + 8, space->whitepoint[0]); + icc_write (s15f16, state->o + 12, space->whitepoint[1]); + icc_write (s15f16, state->o + 16, space->whitepoint[2]); + + icc_allocate_tag (state, "rXYZ", 20); + icc_write (sign, state->o, "XYZ "); + icc_write (u32, state->o + 4, 0); + icc_write (s15f16, state->o + 8, space->RGBtoXYZ[0]); + icc_write (s15f16, state->o + 12, space->RGBtoXYZ[3]); + icc_write (s15f16, state->o + 16, space->RGBtoXYZ[6]); + + icc_allocate_tag (state, "gXYZ", 20); + icc_write (sign, state->o, "XYZ "); + icc_write (u32, state->o + 4, 0); + icc_write (s15f16, state->o + 8, space->RGBtoXYZ[1]); + icc_write (s15f16, state->o + 12, space->RGBtoXYZ[4]); + icc_write (s15f16, state->o + 16, space->RGBtoXYZ[7]); + + icc_allocate_tag (state, "bXYZ", 20); + icc_write (sign, state->o, "XYZ "); + icc_write (u32, state->o + 4, 0); + icc_write (s15f16, state->o + 8, space->RGBtoXYZ[2]); + icc_write (s15f16, state->o + 12, space->RGBtoXYZ[5]); + icc_write (s15f16, state->o + 16, space->RGBtoXYZ[8]); + + write_trc (state, "rTRC", &space->trc[0]->trc, flags); + + if (space->trc[0] == space->trc[1] && + space->trc[0] == space->trc[2]) + { + icc_duplicate_tag (state, "gTRC"); + icc_duplicate_tag (state, "bTRC"); + } + else + { + write_trc (state, "gTRC", &space->trc[1]->trc, flags); + write_trc (state, "bTRC", &space->trc[2]->trc, flags); + } + + { + char str[128]="CC0/public domain"; + int i; + if (!copyright) copyright = str; + icc_allocate_tag(state, "cprt", 8 + strlen (copyright) + 1); + icc_write (sign, state->o, "text"); + icc_write (u32, state->o + 4, 0); + for (i = 0; copyright[i]; i++) + icc_write (u8, state->o + 8 + i, copyright[i]); + } + { + char str[128]="babl"; + int i; + if (!description) description = str; + icc_allocate_tag(state, "desc", 90 + strlen (description) + 0); + icc_write (sign, state->o,"desc"); + icc_write (u32, state->o + 4, 0); + icc_write (u32, state->o + 8, strlen(description) + 1); + for (i = 0; description[i]; i++) + icc_write (u8, state->o + 12 + i, description[i]); + } + + icc_write (u32, 0, state->no + 0); + length = state->no + 0; + } + + if (ret_length) + *ret_length = length; + + babl_free (state); + { + char *ret = malloc (length); + memcpy (ret, icc, length); + return ret; + } +} + + +static char * +babl_space_to_icc_gray (const Babl *babl, + const char *description, + const char *copyright, + BablICCFlags flags, + int *ret_length) +{ + const BablSpace *space = &babl->space; + char icc[65536]; + int length=65535; + ICC *state = icc_state_new (icc, length, 10); + + icc[length]=0; + + symmetry_test (state); + + icc_write (sign, 4, "babl"); // ICC verison + icc_write (u8, 8, 2); // ICC verison + icc_write (u8, 9, 0x20); // 2.2 for now.. + icc_write (u32,64, 0); // rendering intent + + icc_write (s15f16,68, 0.96421); // Illuminant + icc_write (s15f16,72, 1.0); + icc_write (s15f16,76, 0.82491); + + icc_write (sign, 80, "babl"); // creator + + icc_write (sign, 12, "mntr"); + icc_write (sign, 16, "GRAY"); + icc_write (sign, 20, "XYZ "); + + icc_write (u16, 24, 2222); // babl profiles + icc_write (u16, 26, 11); // should + icc_write (u16, 28, 11); // use a fixed + icc_write (u16, 30, 3); // date + icc_write (u16, 32, 44); // that gets updated + icc_write (u16, 34, 55); // when the generator changes + + icc_write (sign, 36, "acsp"); // changes + + { + state->tags = 6; /* note: we could reserve a couple of spots and + still use a very simple allocator and + still be valid - albeit with tiny waste of + space. + */ + state->no = state->o = 128 + 4 + 12 * state->tags; + + icc_write (u32, 128, state->tags); + + icc_allocate_tag (state, "wtpt", 20); + icc_write (sign, state->o, "XYZ "); + icc_write (u32, state->o + 4, 0); + icc_write (s15f16, state->o + 8, space->whitepoint[0]); + icc_write (s15f16, state->o + 12, space->whitepoint[1]); + icc_write (s15f16, state->o + 16, space->whitepoint[2]); + + write_trc (state, "kTRC", &space->trc[0]->trc, flags); + + { + char str[128]="CC0/public domain"; + int i; + if (!copyright) copyright = str; + icc_allocate_tag(state, "cprt", 8 + strlen (copyright) + 1); + icc_write (sign, state->o, "text"); + icc_write (u32, state->o + 4, 0); + for (i = 0; copyright[i]; i++) + icc_write (u8, state->o + 8 + i, copyright[i]); + } + { + char str[128]="babl"; + int i; + if (!description) description = str; + icc_allocate_tag(state, "desc", 90 + strlen (description) + 0); + icc_write (sign, state->o,"desc"); + icc_write (u32, state->o + 4, 0); + icc_write (u32, state->o + 8, strlen(description) + 1); + for (i = 0; description[i]; i++) + icc_write (u8, state->o + 12 + i, description[i]); + } + icc_write (u32, 0, state->no + 0); + length = state->no + 0; + } + + if (ret_length) + *ret_length = length; + + babl_free (state); + { + char *ret = malloc (length); + memcpy (ret, icc, length); + return ret; + } +} + +char * +babl_space_to_icc (const Babl *babl, + const char *description, + const char *copyright, + BablICCFlags flags, + int *ret_length) +{ + if (babl->space.icc_type == BablICCTypeRGB) + return babl_space_to_icc_rgb (babl, description, copyright, flags, + ret_length); + else if (babl->space.icc_type == BablICCTypeGray) + return babl_space_to_icc_gray (babl, description, copyright, flags, + ret_length); + fprintf (stderr, "unexpected icc type in %s\n", __FUNCTION__); + return NULL; +} + +const char * +babl_space_get_icc (const Babl *babl, + int *length) +{ + if (!babl->space.icc_profile) + { + /* overriding constness of babl */ + Babl *babl_noconst = (void*) babl; + babl_noconst->space.icc_profile = babl_space_to_icc (babl, + "babl profile", NULL, 0, + &babl_noconst->space.icc_length); + } + if (length) *length = babl->space.icc_length; + return babl->space.icc_profile; +} + + +typedef uint32_t UTF32; +typedef uint16_t UTF16; +typedef uint8_t UTF8; + +typedef enum { + strictConversion = 0, + lenientConversion +} ConversionFlags; + +static int +ConvertUTF16toUTF8 (const UTF16 **sourceStart, + const UTF16 *sourceEnd, + UTF8 **targetStart, + UTF8 *targetEnd, + ConversionFlags flags); + +static char * +icc_decode_mluc (ICC *state, + int offset, + int element_length, + const char *lang, + const char *country) +{ + int n_records = icc_read (u32, offset + 8); + int record_size = icc_read (u32, offset + 12); + int i; + int o = 16; + for (i = 0; i < n_records; i++) + { + char icountry[3]=" "; + char ilang[3]=" "; + + ilang[0] = icc_read(u8, offset + o + 0); + ilang[1] = icc_read(u8, offset + o + 1); + icountry[0] = icc_read(u8, offset + o + 2); + icountry[1] = icc_read(u8, offset + o + 3); + + if (((!lang || !strcmp (lang, ilang)) && + (!country || !strcmp (country, icountry))) || + (i == n_records - 1)) + { + int slength = (icc_read(u32, offset + o + 4))/2; + int soffset = icc_read(u32, offset + o + 8); + UTF16 *tmp_ret = babl_calloc (sizeof (uint16_t), slength + 1); + UTF16 *tmp_ret2 = tmp_ret; + unsigned char *ret = babl_calloc (1, slength * 4 + 1); // worst case scenario + unsigned char *ret2 = ret; + int j; + + for (j = 0; j < slength; j++) + { + tmp_ret[j] = icc_read(u16, offset + soffset + j * 2); + } + tmp_ret[j] = 0; + memset (ret, 0, slength * 4 + 1); + ConvertUTF16toUTF8 ((void*)&tmp_ret2, tmp_ret + slength, &ret2, ret + slength, lenientConversion); + babl_free(tmp_ret); + { // trim down to actually used utf8 + unsigned char *tmp = (void*)strdup ((void*)ret); + babl_free (ret); + ret = tmp; + } + return (void*)ret; + } + o+=record_size; + } + return NULL; +} + +static char * +decode_string (ICC *state, + const char *tag, + const char *lang, + const char *country) +{ + int offset, element_size; + + if (!icc_tag (state, tag, &offset, &element_size)) + return NULL; + + if (!strcmp (state->data + offset, "mluc")) + { + return icc_decode_mluc (state, offset, element_size, lang, country); + } + else if (!strcmp (state->data + offset, "text")) + { + return strdup (state->data + offset + 8); + } + else if (!strcmp (state->data + offset, "desc")) + { + return strdup (state->data + offset + 12); + } + return NULL; +} + +#ifdef HAVE_LCMS +static cmsHPROFILE sRGBProfile = 0; +#endif + +const Babl * +babl_space_from_icc (const char *icc_data, + int icc_length, + BablIccIntent intent, + const char **error) +{ + ICC *state = icc_state_new ((char*)icc_data, icc_length, 0); + int profile_size = icc_read (u32, 0); + //int icc_ver_major = icc_read (u8, 8); + const Babl *trc_red = NULL; + const Babl *trc_green = NULL; + const Babl *trc_blue = NULL; + const Babl *trc_gray = NULL; + const char *int_err; + Babl *ret = NULL; + int speed_over_accuracy = intent & BABL_ICC_INTENT_PERFORMANCE; + int is_gray = 0; + + sign_t profile_class, color_space, pcs; + + if (!error) error = &int_err; + *error = NULL; + + if (profile_size != icc_length) + { + *error = "icc profile length inconsistency"; + } + else + { + profile_class = icc_read (sign, 12); + color_space = icc_read (sign, 16); + + if (!strcmp (color_space.str, "CMYK")) + { + ret = _babl_space_for_lcms (icc_data, icc_length); + if (ret->space.icc_type == BablICCTypeCMYK) + return ret; + ret->space.icc_length = icc_length; + ret->space.icc_profile = malloc (icc_length); + if (!ret->space.icc_profile) + return NULL; + memcpy (ret->space.icc_profile, icc_data, icc_length); + +#ifdef HAVE_LCMS + if (sRGBProfile == 0) + { + const Babl *rgb = babl_space("scRGB"); /* should use a forced linear profile */ + sRGBProfile = cmsOpenProfileFromMem(rgb->space.icc_profile, rgb->space.icc_length); + } + + ret->space.cmyk.lcms_profile = cmsOpenProfileFromMem(ret->space.icc_profile, ret->space.icc_length); + +/* these are not defined by lcms2.h we hope that following the existing pattern of pixel-format definitions work */ +#ifndef TYPE_CMYKA_DBL +#define TYPE_CMYKA_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_CMYK)|EXTRA_SH(1)|CHANNELS_SH(4)|BYTES_SH(0)) +#endif +#ifndef TYPE_RGBA_DBL +#define TYPE_RGBA_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(0)) +#endif + + ret->space.cmyk.lcms_to_rgba = cmsCreateTransform(ret->space.cmyk.lcms_profile, TYPE_CMYKA_DBL, + sRGBProfile, TYPE_RGBA_DBL, + INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_BLACKPOINTCOMPENSATION); +// INTENT_PERCEPTUAL,0);//intent & 7, 0); + ret->space.cmyk.lcms_from_rgba = cmsCreateTransform(sRGBProfile, TYPE_RGBA_DBL, + ret->space.cmyk.lcms_profile, TYPE_CMYKA_DBL, + INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_BLACKPOINTCOMPENSATION); + // INTENT_PERCEPTUAL,0);//intent & 7, 0); + cmsCloseProfile (ret->space.cmyk.lcms_profile); // XXX keep it open in case of CMYK to CMYK transforms needed? +#endif + return ret; + } + + + + + if (strcmp (color_space.str, "RGB ") + && strcmp (color_space.str, "GRAY") + ) + { + *error = "not defining RGB, CMYK or GRAY space.."; + } + else + { + if (strcmp (profile_class.str, "mntr")) + *error = "not a monitor-class profile"; + if (!strcmp (color_space.str, "GRAY")) + is_gray = 1; + } + } + + if (!*error) + { + pcs = icc_read (sign, 20); + if (strcmp (pcs.str, "XYZ ")) + *error = "PCS is not XYZ"; + } + + if (!*error) + switch (intent & 7) /* enum of intent is in lowest bits */ + { + case BABL_ICC_INTENT_RELATIVE_COLORIMETRIC: + /* that is what we do well */ + + if (!speed_over_accuracy) + { + if (icc_tag (state, "A2B0", NULL, NULL) && + icc_tag (state, "B2A0", NULL, NULL)) + { + *error = "use lcms, accuracy desired and cluts are present"; + } + } + + break; + case BABL_ICC_INTENT_PERCEPTUAL: + /* if there is an A2B0 and B2A0 tags, we do not do what that + * profile is capable of - since the CLUT code is work in progress + * not in git master yet. + */ + if (icc_tag (state, "A2B0", NULL, NULL) && + icc_tag (state, "B2A0", NULL, NULL)) + { + *error = "profile contains perceptual luts and perceptual was explicitly asked for, babl does not yet support CLUTs"; + } + else + { + intent = BABL_ICC_INTENT_RELATIVE_COLORIMETRIC; + } + break; + case BABL_ICC_INTENT_ABSOLUTE_COLORIMETRIC: + *error = "absolute colormetric not implemented"; + break; + case BABL_ICC_INTENT_SATURATION: + *error = "absolute stauration not supported"; + break; + } + + { + int offset, element_size; + if (!*error && icc_tag (state, "rTRC", &offset, &element_size)) + { + trc_red = babl_trc_from_icc (state, offset, error); + } + if (!*error && icc_tag (state, "gTRC", &offset, &element_size)) + { + trc_green = babl_trc_from_icc (state, offset, error); + } + if (!*error && icc_tag (state, "bTRC", &offset, &element_size)) + { + trc_blue = babl_trc_from_icc (state, offset, error); + } + if (!*error && icc_tag (state, "kTRC", &offset, &element_size)) + { + trc_gray = babl_trc_from_icc (state, offset, error); + } + } + + if (is_gray) + { + if (!*error && (!trc_gray)) + { + *error = "missing TRC"; + } + } + else + { + if (!*error && (!trc_red || !trc_green || !trc_blue)) + { + *error = "missing TRCs"; + } + } + + if (*error) + { + + babl_free (state); + return NULL; + } + + if (is_gray) + { + int offset, element_size; + if (icc_tag (state, "wtpt", &offset, &element_size)) + { + // wX = icc_read (s15f16, offset + 8); + // wY = icc_read (s15f16, offset + 8 + 4); + // wZ = icc_read (s15f16, offset + 8 + 4 * 2); + } + ret = (void*)babl_space_from_gray_trc (NULL, trc_gray, 1); + ret->space.icc_length = icc_length; + ret->space.icc_profile = malloc (icc_length); + memcpy (ret->space.icc_profile, icc_data, icc_length); + babl_free (state); + return ret; + + + *error = "gray parsing NYI"; + } + else + { + if (icc_tag (state, "rXYZ", NULL, NULL) && + icc_tag (state, "gXYZ", NULL, NULL) && + icc_tag (state, "bXYZ", NULL, NULL) && + icc_tag (state, "wtpt", NULL, NULL)) + { + int offset, element_size; + double rx, gx, bx; + double ry, gy, by; + double rz, gz, bz; + + double wX, wY, wZ; + + icc_tag (state, "rXYZ", &offset, &element_size); + rx = icc_read (s15f16, offset + 8 + 4 * 0); + ry = icc_read (s15f16, offset + 8 + 4 * 1); + rz = icc_read (s15f16, offset + 8 + 4 * 2); + icc_tag (state, "gXYZ", &offset, &element_size); + gx = icc_read (s15f16, offset + 8 + 4 * 0); + gy = icc_read (s15f16, offset + 8 + 4 * 1); + gz = icc_read (s15f16, offset + 8 + 4 * 2); + icc_tag (state, "bXYZ", &offset, &element_size); + bx = icc_read (s15f16, offset + 8 + 4 * 0); + by = icc_read (s15f16, offset + 8 + 4 * 1); + bz = icc_read (s15f16, offset + 8 + 4 * 2); + icc_tag (state, "wtpt", &offset, &element_size); + wX = icc_read (s15f16, offset + 8); + wY = icc_read (s15f16, offset + 8 + 4); + wZ = icc_read (s15f16, offset + 8 + 4 * 2); + + /* detect inconsistent Argyll cLUT + matrix profiles */ + if (icc_tag (state, "A2B0", NULL, NULL) || + icc_tag (state, "B2A0", NULL, NULL)) + { + if (rz > rx) + { + *error = "Inconsistent ICC profile detected, profile contains both cLUTs and a matrix with swapped primaries, this likely means it is an intentionally inconsistent Argyll profile is in use; this profile is only capable of high accuracy rendering and does not permit acceleration for interactive previews."; + fprintf (stderr, "babl ICC warning: %s\n", *error); + babl_free (state); + return NULL; + } + } + + ret = (void*)babl_space_match_trc_matrix (trc_red, trc_green, trc_blue, + rx, ry, rz, gx, gy, gz, bx, by, bz); + if (ret) + { + babl_free (state); + return ret; + } + + { + ret = (void*)babl_space_from_rgbxyz_matrix (NULL, + wX, wY, wZ, + rx, gx, bx, + ry, gy, by, + rz, gz, bz, + trc_red, trc_green, trc_blue); + + babl_free (state); + ret->space.icc_length = icc_length; + ret->space.icc_profile = malloc (icc_length); + memcpy (ret->space.icc_profile, icc_data, icc_length); + return ret; + } + } + else if (icc_tag (state, "chrm", NULL, NULL) && + icc_tag (state, "wtpt", NULL, NULL)) + { + int offset, element_size; + double red_x, red_y, green_x, green_y, blue_x, blue_y; + int channels, phosporant; + + icc_tag (state, "chrm", &offset, &element_size); + channels = icc_read (u16, offset + 8); + phosporant = icc_read (u16, offset + 10); + + if (phosporant != 0) + { + *error = "unhandled phosporants, please report bug against babl with profile"; + return NULL; + } + if (channels != 3) + { + *error = "unexpected non 3 count of channels"; + return NULL; + } + + red_x = icc_read (s15f16, offset + 12); + red_y = icc_read (s15f16, offset + 12 + 4); + green_x = icc_read (s15f16, offset + 20); + green_y = icc_read (s15f16, offset + 20 + 4); + blue_x = icc_read (s15f16, offset + 28); + blue_y = icc_read (s15f16, offset + 28 + 4); + + icc_tag (state, "wtpt", &offset, &element_size); + { + double wX = icc_read (s15f16, offset + 8); + double wY = icc_read (s15f16, offset + 8 + 4); + double wZ = icc_read (s15f16, offset + 8 + 4 * 2); + babl_free (state); + + ret = (void*) babl_space_from_chromaticities (NULL, + wX / (wX + wY + wZ), + wY / (wX + wY + wZ), + red_x, red_y, + green_x, green_y, + blue_x, blue_y, + trc_red, trc_green, trc_blue, 1); + + ret->space.icc_length = icc_length; + ret->space.icc_profile = malloc (icc_length); + memcpy (ret->space.icc_profile, icc_data, icc_length); + + return ret; + } + } + *error = "didnt find RGB primaries"; + } + + babl_free (state); + return NULL; +} + +/* NOTE: GIMP-2.10.0-4 releases depends on this symbol */ +const Babl * +babl_icc_make_space (const char *icc_data, + int icc_length, + BablIccIntent intent, + const char **error) +{ + return babl_space_from_icc (icc_data, icc_length, intent, error); +} + +static void symmetry_test (ICC *state) +{ + icc_write (s8, 8,-2); + assert (icc_read (s8, 8) == -2); + icc_write (s8, 8, 3); + assert (icc_read (s8, 8) == 3); + + icc_write (u8, 8, 2); + assert (icc_read (u8, 8) == 2); + + icc_write (u16, 8, 3); + assert (icc_read (u16, 8) == 3); + + icc_write (s16, 8, -3); + assert (icc_read (s16, 8) == -3); + + icc_write (s16, 8, 9); + assert (icc_read (s16, 8) == 9); + + icc_write (u32, 8, 4); + assert (icc_read (u32, 8) == 4); +} + +char * +babl_icc_get_key (const char *icc_data, + int icc_length, + const char *key, + const char *language, + const char *country) +{ + char *ret = NULL; + ICC *state = icc_state_new ((void*)icc_data, icc_length, 0); + + if (!state) + return ret; + + if (!strcmp (key, "copyright") || + !strcmp (key, "cprt")) + { + ret = decode_string (state, "cprt", language, country); + + } else if (!strcmp (key, "description") || + !strcmp (key, "profileDescriptionTag") || + !strcmp (key, "desc")) + { + ret = decode_string (state, "desc", language, country); + + } else if (!strcmp (key, "manufacturer") || + !strcmp (key, "deviceMfgDescTag") || + !strcmp (key, "dmnd")) + { + ret = decode_string (state, "dmnd", language, country); + + } else if (!strcmp (key, "device") || + !strcmp (key, "deviceModelDescTag") || + !strcmp (key, "dmdd")) + { + ret = decode_string (state, "dmdd", language, country); + } else if (!strcmp (key, "class") || + !strcmp (key, "profile-class")) + { + sign_t tag = icc_read (sign, 12); + return strdup (tag.str); + } else if (!strcmp (key, "color-space")) + { + sign_t tag = icc_read (sign, 16); + return strdup (tag.str); + } else if (!strcmp (key, "pcs")) + { + sign_t tag = icc_read (sign, 20); + return strdup (tag.str); + } else if (!strcmp (key, "intent")) + { + char tag[5]; + int val = icc_read (u32, 64); + snprintf (tag, sizeof (tag), "%i", val); + return strdup (tag); + } else if (!strcmp (key, "tags")) + { + char tag[4096]="NYI"; + return strdup (tag); + } + babl_free (state); + return ret; +} + + +/* + * Copyright 2001-2004 Unicode, Inc. + * + * Disclaimer + * + * This source code is provided as is by Unicode, Inc. No claims are + * made as to fitness for any particular purpose. No warranties of any + * kind are expressed or implied. The recipient agrees to determine + * applicability of information provided. If this file has been + * purchased on magnetic or optical media from Unicode, Inc., the + * sole remedy for any claim will be exchange of defective media + * within 90 days of receipt. + * + * Limitations on Rights to Redistribute This Code + * + * Unicode, Inc. hereby grants the right to freely use the information + * supplied in this file in the creation of products supporting the + * Unicode Standard, and to make copies of this file in any form + * for internal or external distribution as long as this notice + * remains attached. + */ +/* --------------------------------------------------------------------- + + Conversions between UTF32, UTF-16, and UTF-8. Source code file. + Author: Mark E. Davis, 1994. + Rev History: Rick McGowan, fixes & updates May 2001. + Sept 2001: fixed const & error conditions per + mods suggested by S. Parent & A. Lillich. + June 2002: Tim Dodd added detection and handling of incomplete + source sequences, enhanced error detection, added casts + to eliminate compiler warnings. + July 2003: slight mods to back out aggressive FFFE detection. + Jan 2004: updated switches in from-UTF8 conversions. + Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions. + Sep 2017: copied only the bits neccesary for utf16toutf8 into babl, + otherwise unchanged from upstream. + + See the header file "ConvertUTF.h" for complete documentation. + +------------------------------------------------------------------------ */ + +typedef uint32_t UTF32; /* at least 32 bits */ +typedef unsigned short UTF16; /* at least 16 bits */ +typedef unsigned char UTF8; /* typically 8 bits */ +typedef unsigned char Boolean; /* 0 or 1 */ + +typedef enum { + conversionOK, /* conversion successful */ + sourceExhausted, /* partial character in source, but hit end */ + targetExhausted, /* insuff. room in target for conversion */ + sourceIllegal /* source sequence is illegal/malformed */ +} ConversionResult; + +#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD + + +#define UNI_SUR_HIGH_START (UTF32)0xD800 +#define UNI_SUR_HIGH_END (UTF32)0xDBFF +#define UNI_SUR_LOW_START (UTF32)0xDC00 +#define UNI_SUR_LOW_END (UTF32)0xDFFF +static const int halfShift = 10; /* used for shifting by 10 bits */ + +static const UTF32 halfBase = 0x0010000UL; +static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + +static int +ConvertUTF16toUTF8 (const UTF16 **sourceStart, + const UTF16 *sourceEnd, + UTF8 **targetStart, + UTF8 *targetEnd, + ConversionFlags flags) +{ + ConversionResult result = conversionOK; + const UTF16* source = *sourceStart; + UTF8* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + unsigned short bytesToWrite = 0; + const UTF32 byteMask = 0xBF; + const UTF32 byteMark = 0x80; + const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ + ch = *source++; + /* If we have a surrogate pair, convert to UTF32 first. */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { + /* If the 16 bits following the high surrogate are in the source buffer... */ + if (source < sourceEnd) { + UTF32 ch2 = *source; + /* If it's a low surrogate, convert to UTF32. */ + if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { + ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + + (ch2 - UNI_SUR_LOW_START) + halfBase; + ++source; + } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --source; /* return to the high surrogate */ + result = sourceExhausted; + break; + } + } else if (flags == strictConversion) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + /* Figure out how many bytes the result will require */ + if (ch < (UTF32)0x80) { bytesToWrite = 1; + } else if (ch < (UTF32)0x800) { bytesToWrite = 2; + } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; + } else if (ch < (UTF32)0x110000) { bytesToWrite = 4; + } else { bytesToWrite = 3; + ch = UNI_REPLACEMENT_CHAR; + } + + target += bytesToWrite; + if (target > targetEnd) { + source = oldSource; /* Back up source pointer! */ + target -= bytesToWrite; result = targetExhausted; break; + } + switch (bytesToWrite) { /* note: everything falls through. */ + case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]); + } + target += bytesToWrite; + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* Trademarks: + * + * International Color Consortium is a registered trademarks of the. + * International Color Consortium. + */ diff --git a/babl/babl-ids.h b/babl/babl-ids.h new file mode 100644 index 0000000..727d828 --- /dev/null +++ b/babl/babl-ids.h @@ -0,0 +1,135 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#ifndef _BABL_IDS_H +#define _BABL_IDS_H + +enum { + BABL_UNDEFINED = 0, + BABL_TYPE_BASE = 100, + BABL_U8, + BABL_U16, + BABL_U32, + BABL_HALF, + BABL_FLOAT, + BABL_DOUBLE, + BABL_HALF_FLOAT, + + BABL_U8_LUMA, + BABL_U8_CHROMA, + BABL_U16_CIE_L, + BABL_U16_CIE_AB, + BABL_U8_CIE_L, + BABL_U8_CIE_AB, + BABL_TYPE_LAST_INTERNAL, + + BABL_MODEL_BASE = 1000, + BABL_GRAY, + BABL_GRAY_ALPHA, + BABL_GRAY_ALPHA_PREMULTIPLIED, + BABL_RGB, + BABL_RGBA, + BABL_RGBA_PREMULTIPLIED, + BABL_MODEL_GRAY_NONLINEAR, + BABL_MODEL_GRAY_NONLINEAR_ALPHA, + BABL_MODEL_GRAY_NONLINEAR_ALPHA_PREMULTIPLIED, + BABL_MODEL_GRAY_PERCEPTUAL, + BABL_MODEL_GRAY_PERCEPTUAL_ALPHA, + BABL_MODEL_GRAY_PERCEPTUAL_ALPHA_PREMULTIPLIED, + BABL_RGB_NONLINEAR, + BABL_RGBA_NONLINEAR, + BABL_RGBA_NONLINEAR_PREMULTIPLIED, + BABL_RGB_PERCEPTUAL, + BABL_RGBA_PERCEPTUAL, + BABL_RGBA_PERCEPTUAL_PREMULTIPLIED, + BABL_YCBCR, + BABL_YCBCR_ALPHA, + BABL_CIE_LAB, + BABL_CIE_LAB_ALPHA, + BABL_MODEL_LAST_INTERNAL, + + BABL_COMPONENT_BASE = 10000, + BABL_GRAY_LINEAR, + BABL_GRAY_LINEAR_MUL_ALPHA, + BABL_RED, + BABL_GREEN, + BABL_BLUE, + BABL_ALPHA, + BABL_RED_MUL_ALPHA, + BABL_GREEN_MUL_ALPHA, + BABL_BLUE_MUL_ALPHA, + BABL_GRAY_PERCEPTUAL, + BABL_GRAY_PERCEPTUAL_MUL_ALPHA, + BABL_GRAY_NONLINEAR, + BABL_GRAY_NONLINEAR_MUL_ALPHA, + BABL_RED_NONLINEAR, + BABL_GREEN_NONLINEAR, + BABL_BLUE_NONLINEAR, + BABL_RED_NONLINEAR_MUL_ALPHA, + BABL_GREEN_NONLINEAR_MUL_ALPHA, + BABL_BLUE_NONLINEAR_MUL_ALPHA, + BABL_RED_PERCEPTUAL, + BABL_GREEN_PERCEPTUAL, + BABL_BLUE_PERCEPTUAL, + BABL_RED_PERCEPTUAL_MUL_ALPHA, + BABL_GREEN_PERCEPTUAL_MUL_ALPHA, + BABL_BLUE_PERCEPTUAL_MUL_ALPHA, + + + BABL_X, + BABL_Y, + BABL_Z, + BABL_CIE_L, + BABL_CIE_A, + BABL_CIE_B, + BABL_CB, + BABL_CR, + BABL_PADDING, + BABL_COMPONENT_LAST_INTERNAL, + + BABL_FORMAT_BASE = 100000, + BABL_SRGB, + BABL_SRGBA, + BABL_RGB_HALF, + BABL_RGBA_HALF, + BABL_RGB_FLOAT, + BABL_RGBA_FLOAT, + BABL_RGBA_DOUBLE, + BABL_LAB_FLOAT, + BABL_LAB_U16, + BABL_LAB_U8, + BABL_RGB_U8, + BABL_RGBA_U8, + BABL_RGBA_U16, + BABL_CMYK_HALF, + BABL_CMYK_FLOAT, + BABL_CMYK_ALPHA_FLOAT, + BABL_CMYK_ALPHA_HALF, + BABL_YCBCR411, + BABL_YCBCR422, + BABL_YCBCR420, + BABL_FORMAT_LAST_INTERNAL, + + BABL_PIXEL_USER_BASE +}; + + +#endif + + + diff --git a/babl/babl-image.c b/babl/babl-image.c new file mode 100644 index 0000000..44c0cac --- /dev/null +++ b/babl/babl-image.c @@ -0,0 +1,254 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include +#include + +#include "babl-internal.h" + +static int +babl_image_destruct (void *babl) +{ + BablFormat *format = BABL (babl)->image.format; + if (format && format->image_template == NULL) + { + format->image_template = babl; + return -1; /* this should avoid freeing images created for formats,. */ + } + return 0; +} + +static Babl * +image_new (BablFormat *format, + BablModel *model, + int components, + BablComponent **component, + BablSampling **sampling, + BablType **type, + char **data, + int *pitch, + int *stride) +{ + Babl *babl; + + /* allocate all memory in one chunk */ + babl = babl_malloc (sizeof (BablImage) + + sizeof (BablComponent*) * (components) + + sizeof (BablSampling*) * (components) + + sizeof (BablType*) * (components) + + sizeof (void*) * (components) + + sizeof (int) * (components) + + sizeof (int) * (components)); + babl_set_destructor (babl, babl_image_destruct); + babl->image.component = (void*)(((char *)babl) + sizeof (BablImage)); + babl->image.sampling = (void*)(((char *)babl->image.component) + sizeof (BablComponent*) * (components)); + babl->image.type = (void*)(((char *)babl->image.sampling) + sizeof (BablSampling*) * (components)); + babl->image.data = (void*)(((char *)babl->image.type) + sizeof (BablType*) * (components)); + babl->image.pitch = (void*)(((char *)babl->image.data) + sizeof (void*) * (components)); + babl->image.stride = (void*)(((char *)babl->image.pitch) + sizeof (int) * (components)); + + babl->class_type = BABL_IMAGE; + babl->instance.id = 0; + babl->instance.name = "slartibartfast"; + babl->image.format = format; + babl->image.model = model; + babl->image.components = components; + + memcpy (babl->image.component, component, components * sizeof (void *)); + memcpy (babl->image.type, type, components * sizeof (void *)); + memcpy (babl->image.data, data, components * sizeof (void *)); + memcpy (babl->image.pitch, pitch, components * sizeof (int)); + memcpy (babl->image.stride, stride, components * sizeof (int)); + + return babl; +} + +Babl * +babl_image_from_linear (char *buffer, + const Babl *cformat) +{ + Babl *format = (Babl*) cformat; + Babl *babl; + BablModel *model = NULL; + int components = 0; + int i; + BablComponent *component [BABL_MAX_COMPONENTS]; + BablSampling *sampling [BABL_MAX_COMPONENTS]; + BablType *type [BABL_MAX_COMPONENTS]; + char *data [BABL_MAX_COMPONENTS]; + int pitch [BABL_MAX_COMPONENTS]; + int stride [BABL_MAX_COMPONENTS]; + + int offset = 0; + int calc_pitch = 0; + + babl_assert (format); + babl_assert (format->class_type == BABL_FORMAT || + format->class_type == BABL_MODEL); + + switch (format->class_type) + { + case BABL_FORMAT: + components = format->format.components; + +#if 1 + babl = __atomic_exchange_n (&format->format.image_template, NULL, + __ATOMIC_ACQ_REL); +#else + /* todo: add a configure check for the above gcc extension and use + a mutex if we do not have it? + */ + babl = NULL; + if (format->format.image_template != NULL) /* single item cache for speeding + up subsequent use of linear buffers + for subsequent accesses + */ + { + babl = format->format.image_template; + format->format.image_template = NULL; + } +#endif + if (babl) + { + for (i = 0; i < components; i++) + { + babl->image.data[i] = buffer + offset; + offset += (format->format.type[i]->bits / 8); + } + return babl; + } + model = (BablModel *) format->format.model; + + memcpy (component, format->format.component, sizeof (Babl *) * components); + memcpy (sampling, format->format.sampling, sizeof (Babl *) * components); + memcpy (type, format->format.type, sizeof (Babl *) * components); + + for (i = 0; i < components; i++) + { + calc_pitch += (type[i]->bits / 8); + } + for (i = 0; i < components; i++) + { + pitch[i] = calc_pitch; + stride[i] = 0; + data[i] = buffer + offset; + offset += (type[i]->bits / 8); + } + break; + + case BABL_MODEL: + model = (BablModel *) format; + components = format->format.components; + for (i = 0; i < components; i++) + { + calc_pitch += (64 / 8); /*< known to be double when we create from model */ + } + memcpy (component, model->component, sizeof (Babl *) * components); + for (i = 0; i < components; i++) + { + sampling[i] = (BablSampling *) babl_sampling (1, 1); + type[i] = (BablType *) babl_type_from_id (BABL_DOUBLE); + pitch[i] = calc_pitch; + stride[i] = 0; + data[i] = buffer + offset; + offset += (type[i]->bits / 8); + } + break; + + default: + babl_log ("Eeeek!"); + break; + } + + babl = image_new ( + ((void*)format!=(void*)model)?(BablFormat*)format:NULL, + model, components, + component, sampling, type, data, pitch, stride); + return babl; +} + +Babl * +babl_image_new (const void *first, + ...) +{ + va_list varg; + Babl *babl; + int components = 0; + BablFormat *format = NULL; + BablModel *model = NULL; + BablComponent *component [BABL_MAX_COMPONENTS]; + BablSampling *sampling [BABL_MAX_COMPONENTS]; + BablType *type [BABL_MAX_COMPONENTS]; + char *data [BABL_MAX_COMPONENTS]; + int pitch [BABL_MAX_COMPONENTS]; + int stride [BABL_MAX_COMPONENTS]; + + const char *arg = first; + + va_start (varg, first); + + while (1) + { + BablComponent *new_component = NULL; + if (!arg) + break; + + if (BABL_IS_BABL (arg)) + { + Babl *babl = (Babl *) arg; + + if (babl->class_type == BABL_COMPONENT) + { + new_component = (BablComponent *) babl; + } + else + { + babl_log ("%s unexpected", babl_class_name (babl->class_type)); + va_end (varg); + return NULL; + } + } + else + { + new_component = (BablComponent *) babl_component (arg); + } + + /* FIXME: add error checking */ + component [components] = new_component; + sampling [components] = NULL; + type [components] = NULL; + data [components] = va_arg (varg, void *); + pitch [components] = va_arg (varg, int); + stride [components] = va_arg (varg, int); + components++; + + if (components >= BABL_MAX_COMPONENTS) + { + babl_log ("maximum number of components (%i) exceeded", BABL_MAX_COMPONENTS); + } + + arg = va_arg (varg, char *); + } + + va_end (varg); + + + babl = image_new (format, model, components, component, sampling, type, data, pitch, stride); + return babl; +} diff --git a/babl/babl-image.h b/babl/babl-image.h new file mode 100644 index 0000000..c20c06e --- /dev/null +++ b/babl/babl-image.h @@ -0,0 +1,61 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005-2008, Øyvind Kolås and others. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#ifndef _BABL_IMAGE_H +#define _BABL_IMAGE_H + + +/****************************************************************/ +/* BablImage */ +BABL_CLASS_DECLARE (image); +/* + * Babl images can be used for planar buffers instead of linear buffers for + * babl_process(), BablImages are still experimental, for now BablImages can be + * passed to babl_process, two different babl_process() functions will be + * needed for this since the polymorphism cannot be trusted to work on linear + * buffers that originate outside babl's control. + * + * Babl * babl_image_new (BablComponent *component1, + * void *data, + * int pitch, + * int stride, + * [BablComponent *component1, + * void *data, + * int pitch, + * int stride, + * ...] + * NULL); + */ +Babl * babl_image_new (const void *first_component, + ...) BABL_ARG_NULL_TERMINATED; + +typedef struct +{ + BablInstance instance; + BablFormat *format; /*< (if known) */ + int components; + BablComponent **component; + BablType **type; + BablModel *model; /*< (always known) */ + BablSampling **sampling; + char **data; + int *pitch; + int *stride; +} BablImage; + +#endif diff --git a/babl/babl-internal.c b/babl/babl-internal.c new file mode 100644 index 0000000..f7939a1 --- /dev/null +++ b/babl/babl-internal.c @@ -0,0 +1,132 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include +#include "babl-internal.h" + +static const char *class_names[] = +{ + "BablInstance", + "BablType", + "BablTypeInteger", + "BablTypeFloat", + "BablSampling", + "BablTRC", + "BablComponent", + "BablModel", + "BablFormat", + "BablSpace", + "BablConversion", + "BablConversionLinear", + "BablConversionPlane", + "BablConversionPlanar", + "BablFish", + "BablFishReference", + "BablFishSimple", + "BablFishPath", + "BablImage", + "BablExtenstion", + "BablSky" +}; + +const char * +babl_class_name (BablClassType klass) +{ + return class_names[klass - BABL_INSTANCE]; +} + +/* global variable, indicating whether name lookups + * are frowned upon or not (they are frowned upon within BablBase, + * since that leads to more strings than neccesary in the library.) + */ +int babl_hmpf_on_name_lookups = 0; + +#include +#include + +int +babl_backtrack (void) +{ + char buf[512]; + + snprintf (buf, sizeof (buf), "echo bt>/tmp/babl.gdb;" + "gdb -q --batch -x /tmp/babl.gdb --pid=%i | grep 'in ''babl_die' -A40", getpid ()); + return system (buf); +} + +void +babl_die (void) +{ + babl_backtrack (); + exit (-1); +} + +BablMutex *babl_fish_mutex; + +BablMutex *babl_format_mutex; +#if BABL_DEBUG_MEM +BablMutex *babl_debug_mutex; +#endif +BablMutex *babl_reference_mutex; + +void +babl_internal_init (void) +{ + babl_set_malloc (malloc); + babl_set_free (free); + babl_fish_mutex = babl_mutex_new (); + babl_format_mutex = babl_mutex_new (); + babl_reference_mutex = babl_mutex_new (); +#if BABL_DEBUG_MEM + babl_debug_mutex = babl_mutex_new (); +#endif +} + +void +babl_internal_destroy (void) +{ + babl_mutex_destroy (babl_fish_mutex); + babl_mutex_destroy (babl_format_mutex); + babl_mutex_destroy (babl_reference_mutex); +#if BABL_DEBUG_MEM + babl_mutex_destroy (babl_debug_mutex); +#endif +} + + +const char * +babl_get_name (const Babl *babl) +{ + babl_assert (BABL_IS_BABL (babl)); + return babl->instance.name; +} + +const char * +babl_get_doc (const Babl *babl) +{ + babl_assert (BABL_IS_BABL (babl)); + return babl->instance.doc; +} + +void babl_doc (const Babl *babl, + const char *doc) +{ + babl_assert (BABL_IS_BABL (babl)); + ((Babl*)babl)->instance.doc = doc; +} diff --git a/babl/babl-internal.h b/babl/babl-internal.h new file mode 100644 index 0000000..56e95e4 --- /dev/null +++ b/babl/babl-internal.h @@ -0,0 +1,470 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#ifndef _BABL_INTERNAL_H +#define _BABL_INTERNAL_H + +#ifndef BABL_LIBRARY +#error "config.h must be included prior to babl-internal.h" +#endif + +#ifdef _BABL_H +#error babl-internal.h included after babl.h +#endif + +#define BABL_MAX_COMPONENTS 32 +#define BABL_CONVERSIONS 5 + + +#include +#include +#include +#include +#include "assert.h" + +#undef _BABL_INTERNAL_H +#include "babl.h" +#define _BABL_INTERNAL_H + +#include "babl-classes.h" +#include "babl-introspect.h" +#include "babl-class.h" +#include "babl-list.h" +#include "babl-hash-table.h" +#include "babl-db.h" +#include "babl-ids.h" +#include "babl-util.h" +#include "babl-memory.h" +#include "babl-mutex.h" +#include "babl-cpuaccel.h" +#include "babl-polynomial.h" + +/* fallback to floor function when rint is not around */ +#ifndef HAVE_RINT +# define rint(f) (floor (((double) (f)) + 0.5)) +#endif + +#ifdef __ANDROID_API__ +#include +#endif + +Babl * babl_conversion_find (const void *source, + const void *destination); +double babl_conversion_error (BablConversion *conversion); +long babl_conversion_cost (BablConversion *conversion); + +Babl * babl_extension_base (void); + +Babl * babl_extender (void); +void babl_set_extender (Babl *new_extender); + +Babl * babl_extension_quiet_log (void); +void babl_extension_deinit (void); + +void babl_fish_reference_process (const Babl *babl, + const char *source, + char *destination, + long n, + void *data); // data is ignored + +Babl * babl_fish_reference (const Babl *source, + const Babl *destination); +Babl * babl_fish_simple (BablConversion *conversion); +Babl * babl_fish_path (const Babl *source, + const Babl *destination); + +int babl_fish_get_id (const Babl *source, + const Babl *destination); + +double babl_format_loss (const Babl *babl); +Babl * babl_image_from_linear (char *buffer, + const Babl *format); +Babl * babl_image_double_from_image (const Babl *source); + +double babl_model_is_symmetric (const Babl *babl); +void babl_die (void); +int babl_sanity (void); + +void babl_doc (const Babl *babl, + const char *doc); + +const char * babl_get_doc (const Babl *babl); + +void babl_core_init (void); +const Babl *babl_format_with_model_as_type (const Babl *model, + const Babl *type); +int babl_formats_count (void); /* should maybe be templated? */ +int babl_type_is_symmetric (const Babl *babl); + +/**** LOGGER ****/ +#include + +int babl_backtrack (void); + +static inline void +real_babl_log_va(const char *file, + int line, + const char *function, + const char *fmt, + va_list varg) +{ + Babl *extender = babl_extender(); + + if (extender != babl_extension_quiet_log()) + { + if (babl_extender()) + { +#ifdef __ANDROID_API__ + __android_log_print (ANDROID_LOG_DEBUG, "BABL", + "When loading %s:\n\t", babl_extender()->instance.name); +#else + fprintf (stderr, "When loading %s:\n\t", babl_extender()->instance.name); +#endif + } + +#ifdef __ANDROID_API__ + __android_log_print (ANDROID_LOG_DEBUG, "BABL", + "%s:%i %s()", file, line, function); +#else + fprintf (stderr, "%s:%i %s()\n\t", file, line, function); +#endif + } + +#ifdef __ANDROID_API__ + __android_log_vprint (ANDROID_LOG_DEBUG, "BABL", + fmt, varg); +#else + vfprintf (stderr, fmt, varg); + fprintf (stderr, "\n"); + fflush (NULL); +#endif + return; +} + +static inline void +real_babl_log (const char *file, + int line, + const char *function, + const char *fmt, ...) +{ + va_list varg; + + va_start (varg, fmt); + real_babl_log_va (file, line, function, fmt, varg); + va_end (varg); +} + +/* Provide a string identifying the current function, non-concatenatable */ +#ifndef G_STRFUNC +#if defined (__GNUC__) +# define G_STRFUNC ((const char*) (__PRETTY_FUNCTION__)) +#elif defined (G_HAVE_ISO_VARARGS) +# define G_STRFUNC ((const char*) (__func__)) +#else +# define G_STRFUNC ((const char*) ("???")) +#endif +#endif + +#if defined(__cplusplus) && defined(BABL_ISO_CXX_VARIADIC_MACROS) +# define BABL_ISO_VARIADIC_MACROS 1 +#endif + +#if defined(BABL_ISO_VARIADIC_MACROS) + +#define babl_log(...) \ + real_babl_log(__FILE__, __LINE__, G_STRFUNC, __VA_ARGS__) + +#define babl_fatal(...) do{ \ + real_babl_log(__FILE__, __LINE__, G_STRFUNC, __VA_ARGS__); \ + babl_die();} \ +while(0) + +#elif defined(BABL_GNUC_VARIADIC_MACROS) + +#define babl_log(args...) \ + real_babl_log(__FILE__, __LINE__, G_STRFUNC, args) + +#define babl_fatal(args...) do{ \ + real_babl_log(__FILE__, __LINE__, G_STRFUNC, args); \ + babl_die();} \ +while(0) + +#else + +static inline void +babl_log (const char *format, ...) +{ + va_list args; + va_start (args, format); + real_babl_log_va (__FILE__, __LINE__, G_STRFUNC, format, args); + va_end (args); +} +static inline void +babl_fatal (const char *format, ...) +{ + va_list args; + va_start (args, format); + real_babl_log_va (__FILE__, __LINE__, G_STRFUNC, format, args); + va_end (args); + babl_die(); +} + +#endif + + +#define babl_assert(expr) do{ \ + if(!(expr)) \ + { \ + real_babl_log(__FILE__, __LINE__, G_STRFUNC, "Eeeeek! Assertion failed: `" #expr "`"); \ + assert(expr); \ + } \ +}while(0) +/***** LOGGER (end)**/ + +#define BABL_CLASS_TYPE_IS_VALID(klass_type) \ + ( ((klass_type)>=BABL_INSTANCE ) && ((klass_type)<=BABL_SKY) ?1:0 ) + +#define BABL_IS_BABL(obj) \ +(NULL==(obj)?0 \ + :BABL_CLASS_TYPE_IS_VALID(((Babl*)(obj))->class_type) \ +) + +extern int babl_hmpf_on_name_lookups; +extern int babl_in_fish_path; +extern BablMutex *babl_format_mutex; +extern BablMutex *babl_fish_mutex; +extern BablMutex *babl_reference_mutex; + +#define BABL_DEBUG_MEM 0 +#if BABL_DEBUG_MEM +extern BablMutex *babl_debug_mutex; +#endif + +const char *babl_class_name (BablClassType klass); +void babl_internal_init (void); +void babl_internal_destroy (void); + + +/* this template is expanded in the files including babl-internal.h, + * generating code, the declarations for these functions are found in + * the BABL_CLASS expansions done in babl.h as well, thus babl.h needs + * to be kept in sync with the C files. + */ + +#define BABL_CLASS_MINIMAL_IMPLEMENT(klass) \ + \ +BablDb * \ +babl_##klass##_db (void) \ +{ \ + if (!db) \ + db=babl_db_init (); \ + return db; \ +} \ + \ +void \ +babl_##klass##_class_for_each (BablEachFunction each_fun, \ + void *user_data) \ +{ \ + babl_db_each (db, each_fun, user_data); \ +} \ + +#define BABL_CLASS_IMPLEMENT(klass) \ +BABL_CLASS_MINIMAL_IMPLEMENT(klass) \ + \ +const Babl * \ +babl_##klass (const char *name) \ +{ \ + Babl *babl; \ + \ + if (babl_hmpf_on_name_lookups) \ + { \ + babl_log ("%s(\"%s\"): looking up", G_STRFUNC, name); \ + } \ + if (!db) \ + { \ + babl_fatal ("%s(\"%s\"): you must call babl_init first", G_STRFUNC, name); \ + } \ + babl = babl_db_exist_by_name (db, name); \ + \ + if (!babl) \ + { \ + babl_fatal ("%s(\"%s\"): not found", G_STRFUNC, name); \ + } \ + return babl; \ +} \ + \ +const Babl * \ +babl_##klass##_from_id (int id) \ +{ \ + Babl *babl; \ + babl = babl_db_exist_by_id (db, id); \ + if (!babl) \ + { \ + babl_fatal ("%s(%i): not found", G_STRFUNC, id); \ + } \ + return babl; \ +} \ + +#define BABL(obj) ((Babl*)(obj)) + +static inline double babl_parse_double (const char *str) +{ + double result = 0; + if (!str) + return 0.0; + result = atoi (str); + if (strchr (str, '.')) + { + char *p = strchr (str, '.') + 1; + double d = 10; + for (;*p && *p >= '0' && *p <= '9';p++, d *= 10) + { + if (result >= 0) + result += (*p - '0') / d; + else + result -= (*p - '0') / d; + } + } + return result; +} + +const Babl * +babl_remodel_with_space (const Babl *model, const Babl *space); +Babl * +_conversion_new (const char *name, + int id, + const Babl *source, + const Babl *destination, + BablFuncLinear linear, + BablFuncPlane plane, + BablFuncPlanar planar, + void *user_data, + int allow_collision); + +double _babl_legal_error (void); +void babl_init_db (void); +void babl_store_db (void); +int _babl_max_path_len (void); + + +const Babl * +babl_trc_new (const char *name, + BablTRCType type, + double gamma, + int n_lut, + float *lut); + +void babl_space_to_xyz (const Babl *space, const double *rgb, double *xyz); +void babl_space_from_xyz (const Babl *space, const double *xyz, double *rgb); + +const Babl *babl_trc_lut_find (float *lut, int lut_size); +const Babl *babl_trc_lut (const char *name, int n, float *entries); + +Babl * format_new_from_format_with_space (const Babl *format, const Babl *space); + +int babl_list_destroy (void *data); + +const char * +babl_conversion_create_name (Babl *source, Babl *destination, int type, + int allow_collision); + +void _babl_space_add_universal_rgb (const Babl *space); +const Babl * +babl_trc_formula_srgb (double gamma, double a, double b, double c, double d, double e, double f); +const Babl * +babl_trc_formula_cie (double gamma, double a, double b, double c); + + +const Babl *babl_space_match_trc_matrix (const Babl *trc_red, + const Babl *trc_green, + const Babl *trc_blue, + float rx, float ry, float rz, + float gx, float gy, float gz, + float bx, float by, float bz); + + + + +int _babl_file_get_contents (const char *path, + char **contents, + long *length, + void *error); + + + +/* babl_space_get_rgbtoxyz: + + Returns the double-precision 3x3 matrix used to convert linear + RGB data to CIE XYZ. + */ +const double * babl_space_get_rgbtoxyz (const Babl *space); + +/* babl_space_to_xyz: + * + * converts a double triplet from linear RGB to CIE XYZ. + */ +void babl_space_to_xyz (const Babl *space, const double *rgb, double *xyz); + +/* babl_space_from_xyz: + * + * converts double triplet from CIE XYZ to linear RGB + */ +void babl_space_from_xyz (const Babl *space, const double *xyz, double *rgb); + +extern int _babl_instrument; + +static inline void +babl_conversion_process (const Babl *babl, + const char *source, + char *destination, + long n) +{ + BablConversion *conversion = (BablConversion *) babl; + if (_babl_instrument) + conversion->pixels += n; + conversion->dispatch (babl, source, destination, n, conversion->data); +} + +void _babl_fish_missing_fast_path_warning (const Babl *source, + const Babl *destination); +void _babl_fish_rig_dispatch (Babl *babl); +void _babl_fish_prepare_bpp (Babl *babl); + + +/* babl_space_to_icc: + * + * Creates an ICCv2 RGB matrix profile for a babl space. The profiles strive to + * be as small and compact as possible, TRCs are stored as 1024 entry LUT(s). + * + * the result is allocated with malloc and you should free it when done. + */ + +typedef enum { + BABL_ICC_DEFAULTS = 0, + BABL_ICC_COMPACT_TRC_LUT = 1, +} BablICCFlags; + +char *babl_space_to_icc (const Babl *space, + const char *description, + const char *copyright, + BablICCFlags flags, + int *icc_length); +Babl * +_babl_space_for_lcms (const char *icc_data, int icc_length); // XXX pass profile for dedup? + +#endif diff --git a/babl/babl-introspect.c b/babl/babl-introspect.c new file mode 100644 index 0000000..6230f92 --- /dev/null +++ b/babl/babl-introspect.c @@ -0,0 +1,253 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include "babl-internal.h" /* for babl_log */ + +#define BABL_LOG + +#ifdef BABL_LOG + +static void sampling_introspect (Babl *babl); +static void model_introspect (Babl *babl); +static void type_introspect (Babl *babl); +static void format_introspect (Babl *babl); + +static int each_introspect (Babl *babl, + void *user_data); +#endif + +void +babl_introspect (Babl *babl) +{ +#ifdef BABL_LOG + Babl *extender_backup = babl_extender (); + + babl_set_extender (babl_extension_quiet_log ()); + + if (babl) + { + each_introspect (babl, NULL); + return; + } + babl_log ("Introspection report"); + babl_log ("===================================================="); + + babl_log (""); + babl_log ("Data Types:"); + babl_type_class_for_each (each_introspect, NULL); + babl_log (""); + babl_log ("Sampling (chroma subsampling) factors:"); + babl_sampling_class_for_each (each_introspect, NULL); + babl_log (""); + babl_log ("Components:"); + babl_component_class_for_each (each_introspect, NULL); + babl_log (""); + babl_log ("Models (of components):"); + babl_model_class_for_each (each_introspect, NULL); + babl_log (""); + babl_log ("Pixel formats:"); + babl_format_class_for_each (each_introspect, NULL); + babl_log (""); + babl_log ("conversions:"); + babl_conversion_class_for_each (each_introspect, NULL); + babl_log (""); + babl_log ("trcs:"); + babl_trc_class_for_each (each_introspect, NULL); + babl_log (""); + babl_log ("spaces:"); + babl_space_class_for_each (each_introspect, NULL); + babl_log (""); + babl_log ("extensions:"); + babl_extension_class_for_each (each_introspect, NULL); + babl_log (""); + babl_log ("fishes"); + babl_fish_class_for_each (each_introspect, NULL); + babl_log (""); + + babl_set_extender (extender_backup); +#endif +} + +#ifdef BABL_LOG + +static void +item_conversions_introspect (Babl *babl) +{ + int i; + BablList *list; + + list = babl->type.from_list; + if (list) + { + babl_log ("\t\tconversions from %s: %i", + babl->instance.name, babl_list_size (list)); + + for (i = 0; i < babl_list_size (list); i++) + babl_log ("\t\t\t'%s'", BABL (list->items[i])->instance.name); + } +} + +static void +model_introspect (Babl *babl) +{ + int i; + + babl_log ("\t\tcomponents=%i", babl->model.components); + + for (i = 0; i < babl->model.components; i++) + { + babl_log ("\t\tindex[%i] = \"%s\"", i, + BABL (babl->model.component[i])->instance.name); + } +} + +static void +type_introspect (Babl *babl) +{ + babl_log ("\t\tbits=%i", babl->type.bits); +} + + +static void +sampling_introspect (Babl *babl) +{ + babl_log ("\t\thorizontal = %i", + babl->sampling.horizontal); + babl_log ("\t\tvertical = %i", + babl->sampling.vertical); +} + +static void +space_introspect (Babl *babl) +{ + // XXX: print TRCs and matrix, possibly if we have an icc and intent +} + +static void +trc_introspect (Babl *babl) +{ + // XXX: print type, and parameters +} + +static void +format_introspect (Babl *babl) +{ + int i; + + babl_log ("\t\tmodel=\"%s\"", babl->format.model->instance.name); + babl_log ("\t\tplanar=%i", babl->format.planar); + babl_log ("\t\tcomponents=%i", babl->format.components); + + for (i = 0; i < babl->format.components; i++) + { + babl_log ("\t\tband[%i] type=\"%s\" sampling=\"%s\" component=\"%s\"", + i, babl->format.type[i]->instance.name, + babl->format.sampling[i]->instance.name, + babl->format.component[i]->instance.name); + } +} + +static void +conversion_introspect (Babl *babl) +{ + babl_log ("\t\tpixels:%li", babl->conversion.pixels); + if (BABL (babl->conversion.source)->class_type == BABL_FORMAT) + { + babl_log ("\t\terror: %f", babl_conversion_error (&babl->conversion)); + } +} + +static void +fish_introspect (Babl *babl) +{ + babl_log ("\t\tpixels:%li", babl->fish.pixels); +} + +static void +fish_path_introspect (Babl *babl) +{ + babl_log ("\t\tcost:%f error:%.12f", + babl->fish_path.cost, babl->fish.error); + + babl_list_each(babl->fish_path.conversion_list, each_introspect, NULL); +} + +static int +each_introspect (Babl *babl, + void *user_data) +{ + babl_log ("\t\"%s\"\t%i\t%s", + babl->instance.name, + babl->instance.id, + babl_class_name (babl->class_type)); + switch (babl->class_type) + { + case BABL_TYPE: + type_introspect (babl); + item_conversions_introspect (babl); + break; + + case BABL_COMPONENT: + break; + + case BABL_MODEL: + model_introspect (babl); + item_conversions_introspect (babl); + break; + + case BABL_FORMAT: + format_introspect (babl); + item_conversions_introspect (babl); + break; + + case BABL_SAMPLING: + sampling_introspect (babl); + break; + + case BABL_SPACE: + space_introspect (babl); + break; + + case BABL_TRC: + trc_introspect (babl); + break; + + case BABL_CONVERSION: + case BABL_CONVERSION_PLANE: + case BABL_CONVERSION_PLANAR: + case BABL_CONVERSION_LINEAR: + conversion_introspect (babl); + break; + + case BABL_FISH: + case BABL_FISH_REFERENCE: + case BABL_FISH_SIMPLE: + fish_introspect (babl); + break; + + case BABL_FISH_PATH: + fish_path_introspect (babl); + break; + + default: + break; + } + return 0; +} +#endif diff --git a/babl/babl-introspect.h b/babl/babl-introspect.h new file mode 100644 index 0000000..d164031 --- /dev/null +++ b/babl/babl-introspect.h @@ -0,0 +1,33 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005-2008, Øyvind Kolås and others. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#ifndef _BABL_INTROSPECT_H +#define _BABL_INTROSPECT_H + +#include + +/** + * babl_introspect: + * @babl: A #Babl + * + * introspect a given BablObject + */ +void babl_introspect (Babl *babl); + + +#endif diff --git a/babl/babl-list.c b/babl/babl-list.c new file mode 100644 index 0000000..6466a21 --- /dev/null +++ b/babl/babl-list.c @@ -0,0 +1,131 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +/* Implementation of list data structure. + * Copyright (C) 2008, Jan Heller + */ + +#include "config.h" +#include "babl-internal.h" + +#define BABL_LIST_INITIAL_SIZE 0x7F + +BablList * +babl_list_init (void) +{ + return babl_list_init_with_size (BABL_LIST_INITIAL_SIZE); +} + +int +babl_list_destroy (void *data) +{ + BablList *list = data; + babl_free (list->items); + return 0; +} + +BablList * +babl_list_init_with_size (int initial_size) +{ + BablList *list = babl_calloc (sizeof (BablList), 1); + + babl_set_destructor (list, babl_list_destroy); + + if (initial_size == 0) + initial_size = 1; + list->size = initial_size; + list->count = 0; + list->items = NULL; + if (list->size) + { + list->items = babl_calloc (sizeof (BablInstance *), list->size); + } + + return list; +} + +void +babl_list_insert_last (BablList *list, + Babl *item) +{ + babl_assert(list); + babl_assert(BABL_IS_BABL(item)); + + if (list->size < list->count + 1) + { + Babl **new_items; + + new_items = babl_realloc (list->items, (list->size * 2) * sizeof (BablInstance *)); + babl_assert (new_items); + list->items = new_items; + memset (list->items + list->size, 0, list->size * sizeof (BablInstance *)); + list->size *= 2; + } + list->items[list->count++] = item; +} + +void +babl_list_remove_last (BablList *list) +{ + babl_assert (list); + babl_assert (list->count > 0); + + list->count--; +} + +void +babl_list_copy (BablList *from, + BablList *to) +{ + babl_assert (from); + babl_assert (to); + + if (to->size < from->count) + { + Babl **new_items; + + new_items = babl_realloc (to->items, from->count * sizeof (BablInstance *)); + babl_assert (new_items); + to->items = new_items; + to->size = from->count; + } + + memcpy (to->items, from->items, from->count * sizeof (BablInstance *)); + to->count = from->count; +} + +void +babl_list_each (BablList *list, + BablEachFunction each_fun, + void *user_data) +{ + int i; + + babl_assert(list); + babl_assert(each_fun); + + for (i = 0; i < list->count; i++) + { + if (list->items[i]) + { + if (each_fun ((Babl *) list->items[i], user_data)) + break; + } + } +} + diff --git a/babl/babl-list.h b/babl/babl-list.h new file mode 100644 index 0000000..aad8862 --- /dev/null +++ b/babl/babl-list.h @@ -0,0 +1,64 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#ifndef _BABL_LIST_H +#define _BABL_LIST_H + +#ifndef _BABL_H +#error babl-list.h is only to be included after babl.h +#endif + +struct _BablList +{ + int count; + int size; + Babl **items; +}; + +BablList * +babl_list_init (void); + +BablList * +babl_list_init_with_size (int initial_size); + +int +babl_list_size (BablList *list); + +void +babl_list_insert_last (BablList *list, + Babl *item); + +void +babl_list_remove_last (BablList *list); + +#define babl_list_get_n(list,n) (list->items[(n)]) +#define babl_list_get_first(list) (babl_list_get_n(list,0)) +#define babl_list_size(list) (list->count) +#define babl_list_get_last(list) (babl_list_get_n(list, babl_list_size(list)-1)) + +void +babl_list_copy (BablList *from, + BablList *to); + +void +babl_list_each (BablList *list, + BablEachFunction each_fun, + void *user_data); + + +#endif diff --git a/babl/babl-macros.h b/babl/babl-macros.h new file mode 100644 index 0000000..010d97f --- /dev/null +++ b/babl/babl-macros.h @@ -0,0 +1,33 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005-2008, Øyvind Kolås and others. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#ifndef _BABL_MACROS_H +#define _BABL_MACROS_H + +#if !defined(BABL_INSIDE_BABL_H) && !defined(BABL_IS_BEING_COMPILED) +#error "babl-macros.h must not be included directly, include babl.h instead." +#endif + + +#if __GNUC__ >= 4 +#define BABL_ARG_NULL_TERMINATED __attribute__((__sentinel__)) +#else +#define BABL_ARG_NULL_TERMINATED +#endif + +#endif diff --git a/babl/babl-main.h b/babl/babl-main.h new file mode 100644 index 0000000..e69de29 diff --git a/babl/babl-matrix.h b/babl/babl-matrix.h new file mode 100644 index 0000000..2107b31 --- /dev/null +++ b/babl/babl-matrix.h @@ -0,0 +1,222 @@ +#ifndef _BABL_MATRIX_H_ +#define _BABL_MATRIX_H_ + +#include + +#define m(matr, j, i) matr[j*3+i] + +static inline void babl_matrix_mul_matrix (const double *matA_, + const double *matB_, + double *out) +{ + int i, j; + double matA[9]; + double matB[9]; + double t1, t2, t3; + memcpy (matA, matA_, sizeof (matA)); + memcpy (matB, matB_, sizeof (matB)); + + for (i = 0; i < 3; i++) + { + t1 = m(matA, i, 0); + t2 = m(matA, i, 1); + t3 = m(matA, i, 2); + + for (j = 0; j < 3; j ++) + { + m(out,i,j) = t1 * m(matB, 0, j); + m(out,i,j) += t2 * m(matB, 1, j); + m(out,i,j) += t3 * m(matB, 2, j); + } + } +} + + +static inline void babl_matrix_mul_matrixf (const float *matA_, + const float *matB_, + float *out) +{ + int i, j; + float matA[9]; + float matB[9]; + float t1, t2, t3; + memcpy (matA, matA_, sizeof (matA)); + memcpy (matB, matB_, sizeof (matB)); + + for (i = 0; i < 3; i++) + { + t1 = m(matA, i, 0); + t2 = m(matA, i, 1); + t3 = m(matA, i, 2); + + for (j = 0; j < 3; j ++) + { + m(out,i,j) = t1 * m(matB, 0, j); + m(out,i,j) += t2 * m(matB, 1, j); + m(out,i,j) += t3 * m(matB, 2, j); + } + } +} + +static inline void babl_matrix_to_float (const double *in, float *out) +{ + int i; + for (i = 0; i < 9; i ++) + out[i] = in[i]; +} + +static inline void babl_matrix_invert (const double *in, double *out) +{ + double mat[9]; + double det, invdet; + memcpy (mat, in, sizeof (mat)); + det = m(mat, 0, 0) * (m(mat, 1, 1) *m(mat, 2, 2) - m(mat, 2, 1)*m(mat, 1, 2)) - + m(mat, 0, 1) * (m(mat, 1, 0) *m(mat, 2, 2) - m(mat, 1, 2)*m(mat, 2, 0)) + + m(mat, 0, 2) * (m(mat, 1, 0) *m(mat, 2, 1) - m(mat, 1, 1)*m(mat, 2, 0)); + invdet = 1.0 / det; + m(out, 0, 0) = (m(mat, 1, 1) * m(mat, 2, 2) - m(mat, 2, 1) * m(mat, 1, 2)) * invdet; + m(out, 0, 1) = (m(mat, 0, 2) * m(mat, 2, 1) - m(mat, 0, 1) * m(mat, 2, 2)) * invdet; + m(out, 0, 2) = (m(mat, 0, 1) * m(mat, 1, 2) - m(mat, 0, 2) * m(mat, 1, 1)) * invdet; + m(out, 1, 0) = (m(mat, 1, 2) * m(mat, 2, 0) - m(mat, 1, 0) * m(mat, 2, 2)) * invdet; + m(out, 1, 1) = (m(mat, 0, 0) * m(mat, 2, 2) - m(mat, 0, 2) * m(mat, 2, 0)) * invdet; + m(out, 1, 2) = (m(mat, 1, 0) * m(mat, 0, 2) - m(mat, 0, 0) * m(mat, 1, 2)) * invdet; + m(out, 2, 0) = (m(mat, 1, 0) * m(mat, 2, 1) - m(mat, 2, 0) * m(mat, 1, 1)) * invdet; + m(out, 2, 1) = (m(mat, 2, 0) * m(mat, 0, 1) - m(mat, 0, 0) * m(mat, 2, 1)) * invdet; + m(out, 2, 2) = (m(mat, 0, 0) * m(mat, 1, 1) - m(mat, 1, 0) * m(mat, 0, 1)) * invdet; +} + + +static inline void babl_matrix_mul_vector (const double *mat, const double *v_in, double *v_out) +{ + double a = v_in[0], b = v_in[1], c = v_in[2]; + double m_0_0 = m(mat, 0, 0); + double m_0_1 = m(mat, 0, 1); + double m_0_2 = m(mat, 0, 2); + double m_1_0 = m(mat, 1, 0); + double m_1_1 = m(mat, 1, 1); + double m_1_2 = m(mat, 1, 2); + double m_2_0 = m(mat, 2, 0); + double m_2_1 = m(mat, 2, 1); + double m_2_2 = m(mat, 2, 2); + + v_out[0] = m_0_0 * a + m_0_1 * b + m_0_2 * c; + v_out[1] = m_1_0 * a + m_1_1 * b + m_1_2 * c; + v_out[2] = m_2_0 * a + m_2_1 * b + m_2_2 * c; +} + +static inline void babl_matrix_mul_vectorf (const double *mat, const float *v_in, float *v_out) +{ + float a = v_in[0], b = v_in[1], c = v_in[2]; + float m_0_0 = m(mat, 0, 0); + float m_0_1 = m(mat, 0, 1); + float m_0_2 = m(mat, 0, 2); + float m_1_0 = m(mat, 1, 0); + float m_1_1 = m(mat, 1, 1); + float m_1_2 = m(mat, 1, 2); + float m_2_0 = m(mat, 2, 0); + float m_2_1 = m(mat, 2, 1); + float m_2_2 = m(mat, 2, 2); + + v_out[0] = m_0_0 * a + m_0_1 * b + m_0_2 * c; + v_out[1] = m_1_0 * a + m_1_1 * b + m_1_2 * c; + v_out[2] = m_2_0 * a + m_2_1 * b + m_2_2 * c; +} + +static inline void babl_matrix_mul_vectorff (const float *mat, const float *v_in, float *v_out) +{ + const float a = v_in[0], b = v_in[1], c = v_in[2]; + const float m_0_0 = m(mat, 0, 0); + const float m_0_1 = m(mat, 0, 1); + const float m_0_2 = m(mat, 0, 2); + const float m_1_0 = m(mat, 1, 0); + const float m_1_1 = m(mat, 1, 1); + const float m_1_2 = m(mat, 1, 2); + const float m_2_0 = m(mat, 2, 0); + const float m_2_1 = m(mat, 2, 1); + const float m_2_2 = m(mat, 2, 2); + + v_out[0] = m_0_0 * a + m_0_1 * b + m_0_2 * c; + v_out[1] = m_1_0 * a + m_1_1 * b + m_1_2 * c; + v_out[2] = m_2_0 * a + m_2_1 * b + m_2_2 * c; +} + +static inline void babl_matrix_mul_vectorff_buf3 (const float *mat, const float *v_in, float *v_out, + int samples) +{ + int i; + const float m_0_0 = m(mat, 0, 0); + const float m_0_1 = m(mat, 0, 1); + const float m_0_2 = m(mat, 0, 2); + const float m_1_0 = m(mat, 1, 0); + const float m_1_1 = m(mat, 1, 1); + const float m_1_2 = m(mat, 1, 2); + const float m_2_0 = m(mat, 2, 0); + const float m_2_1 = m(mat, 2, 1); + const float m_2_2 = m(mat, 2, 2); + for (i = 0; i < samples; i ++) + { + const float a = v_in[0], b = v_in[1], c = v_in[2]; + + v_out[0] = m_0_0 * a + m_0_1 * b + m_0_2 * c; + v_out[1] = m_1_0 * a + m_1_1 * b + m_1_2 * c; + v_out[2] = m_2_0 * a + m_2_1 * b + m_2_2 * c; + v_in += 3; + v_out += 3; + } +} + +static inline void babl_matrix_mul_vectorff_buf4 (const float *mat, const float *v_in, float *v_out, + int samples) +{ + const float m_0_0 = m(mat, 0, 0); + const float m_0_1 = m(mat, 0, 1); + const float m_0_2 = m(mat, 0, 2); + const float m_1_0 = m(mat, 1, 0); + const float m_1_1 = m(mat, 1, 1); + const float m_1_2 = m(mat, 1, 2); + const float m_2_0 = m(mat, 2, 0); + const float m_2_1 = m(mat, 2, 1); + const float m_2_2 = m(mat, 2, 2); + int i; + for (i = 0; i < samples; i ++) + { + float a = v_in[0], b = v_in[1], c = v_in[2]; + + v_out[0] = m_0_0 * a + m_0_1 * b + m_0_2 * c; + v_out[1] = m_1_0 * a + m_1_1 * b + m_1_2 * c; + v_out[2] = m_2_0 * a + m_2_1 * b + m_2_2 * c; + v_out[3] = v_in[3]; + v_in += 4; + v_out += 4; + } +} + +static inline void babl_matrix_mul_vector_buf4 (const double *mat, const double *v_in, double *v_out, + int samples) +{ + int i; + const double m_0_0 = m(mat, 0, 0); + const double m_0_1 = m(mat, 0, 1); + const double m_0_2 = m(mat, 0, 2); + const double m_1_0 = m(mat, 1, 0); + const double m_1_1 = m(mat, 1, 1); + const double m_1_2 = m(mat, 1, 2); + const double m_2_0 = m(mat, 2, 0); + const double m_2_1 = m(mat, 2, 1); + const double m_2_2 = m(mat, 2, 2); + for (i = 0; i < samples; i ++) + { + const double a = v_in[0], b = v_in[1], c = v_in[2]; + + v_out[0] = m_0_0 * a + m_0_1 * b + m_0_2 * c; + v_out[1] = m_1_0 * a + m_1_1 * b + m_1_2 * c; + v_out[2] = m_2_0 * a + m_2_1 * b + m_2_2 * c; + v_out[3] = v_in[3]; + v_in += 4; + v_out += 4; + } +} + + +#undef m +#endif diff --git a/babl/babl-memory.c b/babl/babl-memory.c new file mode 100644 index 0000000..5c9214e --- /dev/null +++ b/babl/babl-memory.c @@ -0,0 +1,368 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include +#include +#include +#include +#include "babl-internal.h" + +static BablMallocFunc malloc_f = malloc; +static BablFreeFunc free_f = free; + +static void *first_malloc_used = NULL; +static void *first_free_used = NULL; + +void +babl_set_malloc (BablMallocFunc malloc_function) +{ + malloc_f = malloc_function; +} + +void +babl_set_free (BablFreeFunc free_function) +{ + free_f = free_function; +} + +static char *signature = "babl-memory"; +static char *freed = "So long and thanks for all the fish."; + +typedef struct +{ + char *signature; + size_t size; + int (*destructor)(void *ptr); +} BablAllocInfo; + +#define BABL_ALIGN 16 +#define BABL_ALLOC (sizeof (BablAllocInfo) + sizeof (void *)) +#define BAI(ptr) ((BablAllocInfo *) *((void **) ptr - 1)) +#define IS_BAI(ptr) (BAI (ptr)->signature == signature) + +#if BABL_DEBUG_MEM + +/* runtime statistics: */ +static int mallocs = 0; +static int frees = 0; +static int strdups = 0; +static int reallocs = 0; +static int callocs = 0; +static int dups = 0; + +static const char * +mem_stats (void) +{ + static char buf[128]; + + snprintf (buf, sizeof (buf), "mallocs:%i callocs:%i strdups:%i dups:%i allocs:%i frees:%i reallocs:%i\t|", + mallocs, callocs, strdups, dups, mallocs + callocs + strdups + dups, frees, reallocs); + return buf; +} + +#endif + +static void +functions_sanity (void) +{ + if (first_malloc_used != malloc_f || + first_free_used != free_f) + { + static int displayed = 0; + + if (first_malloc_used == NULL) + { + first_malloc_used = malloc_f; + first_free_used = free_f; + } + else if (!displayed) + { + fprintf (stderr, "HMM....\nSomething strange is happening,\n%s function pointer changing between invocations in babl.\n", + first_malloc_used == malloc_f ? "free" : + (first_free_used == free_f ? "malloc" : "malloc and free")); + displayed = 1; + } + } +} + +/* Allocate /size/ bytes of memory + * + * contents of memory undefined. + */ +void * +babl_malloc (size_t size) +{ + char *ret; + int offset; + + functions_sanity (); + ret = malloc_f (BABL_ALLOC + BABL_ALIGN + size); + if (!ret) + babl_fatal ("args=(%i): failed", size); + + offset = BABL_ALIGN - ((uintptr_t) ret + BABL_ALLOC) % BABL_ALIGN; + ret = ret + BABL_ALLOC + offset; + + *((void **) ret - 1) = ret - BABL_ALLOC - offset; + BAI (ret)->signature = signature; + BAI (ret)->size = size; + BAI (ret)->destructor = NULL; +#if BABL_DEBUG_MEM + babl_mutex_lock (babl_debug_mutex); + mallocs++; + babl_mutex_unlock (babl_debug_mutex); +#endif + return (void *) (ret); +} + +/* set a callback to be called when the segment is freed. + */ +void +babl_set_destructor (void *ptr, + int (*destructor)(void *ptr)) +{ + babl_assert (IS_BAI (ptr)); + BAI(ptr)->destructor = destructor; +} + +/* Create a duplicate allocation of the same size, note + * that the exact location of the allocation needs to be + * passed. + */ +void * +babl_dup (void *ptr) +{ + void *ret; + + babl_assert (IS_BAI (ptr)); + + ret = babl_malloc (BAI (ptr)->size); + memcpy (ret, ptr, BAI (ptr)->size); + +#if BABL_DEBUG_MEM + babl_mutex_lock (babl_debug_mutex); + dups++; + mallocs--; + babl_mutex_unlock (babl_debug_mutex); +#endif + return NULL; +} + +/* Free memory allocated by a babl function (note: babl_free + * will complain if memory not allocated by babl is passed.) + * + * Note: the function is made variadic to be a legal callback + * function in some circumstances. + */ +void +babl_free (void *ptr, + ...) +{ + functions_sanity (); + if (!ptr) + return; + if (!IS_BAI (ptr)) + { + #define IS_BAI(ptr) (BAI (ptr)->signature == signature) + if (freed == BAI (ptr)->signature) + fprintf (stderr, "\nbabl:double free detected\n"); + else + fprintf (stderr, "\nbabl_free passed unknown pointer, bailing and leaking it\n"); + return; + //assert(0); + } + + if (BAI (ptr)->destructor) + if (BAI (ptr)->destructor (ptr)) + return; /* bail out on non 0 return from destructor */ + + BAI (ptr)->signature = freed; + free_f (BAI (ptr)); +#if BABL_DEBUG_MEM + babl_mutex_lock (babl_debug_mutex); + frees++; + babl_mutex_unlock (babl_debug_mutex); +#endif +} + +/* reallocate allocation to be in size instead, contents of + * common allocated memory between old and new size is preserved. + */ +void * +babl_realloc (void *ptr, + size_t size) +{ + void *ret = NULL; + + if (!ptr) + { + return babl_malloc (size); + } + + babl_assert (IS_BAI (ptr)); + + if (size == 0) + { + babl_free (ptr); + return NULL; + } + if (babl_sizeof (ptr) >= size) + { + return ptr; + } + else if (babl_sizeof (ptr) < size) + { +#ifdef USE_REALLOC_CLEAR + /* not needed yet by babl, if aviodable, preferred, since + * it has performance hits where it isn't wanted, a special + * function might be better when needd. + */ + ret = babl_calloc (size, 1); +#else + ret = babl_malloc (size); +#endif + memcpy (ret, ptr, babl_sizeof (ptr)); + BAI (ret)->destructor = BAI (ptr)->destructor; + BAI (ptr)->destructor = NULL; + babl_free (ptr); +#if BABL_DEBUG_MEM + babl_mutex_lock (babl_debug_mutex); + reallocs++; + babl_mutex_unlock (babl_debug_mutex); +#endif + return ret; + } + + if (!ret) + babl_fatal ("args=(%p, %i): failed", ptr, size); + + return NULL; +} + +/* allocate nmemb*size bytes and set it to all zeros. */ +void * +babl_calloc (size_t nmemb, + size_t size) +{ + void *ret = babl_malloc (nmemb * size); + + if (!ret) + babl_fatal ("args=(%i, %i): failed", nmemb, size); + + memset (ret, 0, nmemb * size); + +#if BABL_DEBUG_MEM + babl_mutex_lock (babl_debug_mutex); + callocs++; + mallocs--; + babl_mutex_unlock (babl_debug_mutex); +#endif + return ret; +} + +/* Returns the size of an allocation. + */ +size_t +babl_sizeof (void *ptr) +{ + babl_assert (IS_BAI (ptr)); + return BAI (ptr)->size; +} + +/* duplicate allocation needed for a string, and + * copy string contents, string is zero terminated. + */ +char * +babl_strdup (const char *s) +{ + char *ret; + + ret = babl_malloc (strlen (s) + 1); + if (!ret) + babl_log ("args=(%s): failed", s); + strcpy (ret, s); + +#if BABL_DEBUG_MEM + babl_mutex_lock (babl_debug_mutex); + strdups++; + mallocs--; + babl_mutex_unlock (babl_debug_mutex); +#endif + return ret; +} + +/* append string to babl allocated string dest, the returned + * string is the new canonical position with src added to dest + * if the dest allocation needed to be resized. Passing NULL + * causes a new allocation (thus babl-memory sees NULL as the empty + * string). + */ +char * +babl_strcat (char *dest, + const char *src) +{ + char *ret; + int src_len; + int dst_len; + + if (NULL == src) + return dest; + + src_len = strlen (src); + if (!dest) + { + ret = babl_malloc (src_len + 1); + strcpy (ret, src); + return ret; + } + babl_assert (IS_BAI (dest)); + dst_len = strlen (dest); + + ret = dest; + + if (babl_sizeof (dest) < src_len + dst_len + 1) + { + size_t new_size = babl_sizeof (dest); + while (new_size < src_len + dst_len + 1) + new_size *= 2; + ret = babl_realloc (dest, new_size); + } + + strcpy (&ret[dst_len], src); + return ret; +} + +#if BABL_DEBUG_MEM +/* performs a sanity check on memory, (checks if number of + * allocations and frees on babl memory evens out to zero). + */ +int +babl_memory_sanity (void) +{ + if (frees != mallocs + strdups + callocs) + { + babl_log ("memory usage does not add up!\n" + "%s\n" + "\tbalance: %i-%i=%i\n", + mem_stats (), (strdups + mallocs + callocs), frees, (strdups + mallocs + callocs) - frees); + return -1; + } + return 0; +} +#endif diff --git a/babl/babl-memory.h b/babl/babl-memory.h new file mode 100644 index 0000000..eb55c8d --- /dev/null +++ b/babl/babl-memory.h @@ -0,0 +1,49 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#ifndef _BABL_MEMORY_H +#define _BABL_MEMORY_H + + +typedef void * (* BablMallocFunc) (size_t size); +typedef void (* BablFreeFunc) (void *ptr); + + +void babl_set_malloc (BablMallocFunc malloc_function); +void babl_set_free (BablFreeFunc free_function); +int babl_memory_sanity (void); + +void * babl_malloc (size_t size); +void babl_set_destructor (void *ptr, + int (*destructor)(void *ptr)); + +void babl_free (void *ptr, + ...); +void * babl_calloc (size_t nmemb, + size_t size); +void * babl_realloc (void *ptr, + size_t size); + +size_t babl_sizeof (void *ptr); +void * babl_dup (void *ptr); + +char * babl_strdup (const char *s); +char * babl_strcat (char *dest, + const char *src); + +#endif diff --git a/babl/babl-model.c b/babl/babl-model.c new file mode 100644 index 0000000..44481ac --- /dev/null +++ b/babl/babl-model.c @@ -0,0 +1,497 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include +#include +#include +#define NEEDS_BABL_DB +#include "babl-internal.h" +#include "babl-db.h" +#include "babl-ref-pixels.h" + +static const Babl *construct_double_format (const Babl *model); + +static int +babl_model_destroy (void *data) +{ + Babl *babl = data; + if (babl->model.from_list) + babl_free (babl->model.from_list); + return 0; +} + +static char * +babl_model_create_name (int components, + BablComponent **component) +{ + char *p = NULL; + + while (components--) + { + p = babl_strcat(p, (*component)->instance.name); + component++; + } + + return p; +} + +static Babl * +model_new (const char *name, + const Babl *space, + int id, + int components, + BablComponent **component, + BablModelFlag flags, + const char *doc) +{ + Babl *babl; + + babl = babl_malloc (sizeof (BablModel) + + sizeof (BablComponent *) * (components) + + strlen (name) + 1); + babl_set_destructor (babl, babl_model_destroy); + babl->model.component = (void *) (((char *) babl) + sizeof (BablModel)); + babl->instance.name = (void *) (((char *) babl->model.component) + sizeof (BablComponent *) * (components)); + + babl->class_type = BABL_MODEL; + babl->instance.id = id; + babl->instance.doc = doc; + babl->model.components = components; + babl->model.space = space; + babl->model.data = NULL; + babl->model.model = NULL; + babl->model.flags = flags; + strcpy (babl->instance.name, name); + memcpy (babl->model.component, component, sizeof (BablComponent *) * components); + + babl->model.from_list = NULL; + return babl; +} + +static int +is_model_duplicate (Babl *babl, + const Babl *space, + int components, + BablComponent **component) +{ + int i; + + if (babl->model.space != space) + return 0; + + if (babl->model.components != components) + return 0; + + for (i = 0; i < components; i++) + { + if (babl->model.component[i] != component[i]) + return 0; + } + + return 1; +} + + +const Babl * +babl_model_new (void *first_argument, + ...) +{ + va_list varg; + Babl *babl = NULL; + int id = 0; + int components = 0; + const char *arg = first_argument; + const char *assigned_name = NULL; + char *name = NULL; + const char *doc = NULL; + const Babl *space = babl_space ("sRGB"); + BablComponent *component [BABL_MAX_COMPONENTS]; + BablModelFlag flags = 0; + + va_start (varg, first_argument); + + while (1) + { + /* first, we assume arguments to be strings */ + if (!strcmp (arg, "id")) + { + id = va_arg (varg, int); + } + else if (!strcmp (arg, "doc")) + { + doc = va_arg (varg, const char *); + } + else if (!strcmp (arg, "name")) + { + assigned_name = va_arg (varg, char *); + } + else if (!strcmp (arg, "gray")) + { + flags |= BABL_MODEL_FLAG_GRAY; + } + else if (!strcmp (arg, "CIE")) + { + flags |= BABL_MODEL_FLAG_CIE; + } + else if (!strcmp (arg, "rgb")) + { + flags |= BABL_MODEL_FLAG_RGB; + } + else if (!strcmp (arg, "cmyk")) + { + flags |= BABL_MODEL_FLAG_CMYK; + } + else if (!strcmp (arg, "inverted")) + { + flags |= BABL_MODEL_FLAG_INVERTED; + } + else if (!strcmp (arg, "associated")) + { + flags |= BABL_MODEL_FLAG_ASSOCIATED; + } + else if (!strcmp (arg, "alpha")) + { + flags |= BABL_MODEL_FLAG_ALPHA; + } + else if (!strcmp (arg, "linear")) + { + flags |= BABL_MODEL_FLAG_LINEAR; + } + else if (!strcmp (arg, "nonlinear")) + { + flags |= BABL_MODEL_FLAG_NONLINEAR; + } + else if (!strcmp (arg, "perceptual")) + { + flags |= BABL_MODEL_FLAG_PERCEPTUAL; + } + + /* if we didn't point to a known string, we assume argument to be babl */ + else if (BABL_IS_BABL (arg)) + { + Babl *bablc = (Babl *) arg; + + switch (bablc->class_type) + { + case BABL_COMPONENT: + if (components >= BABL_MAX_COMPONENTS) + { + babl_log ("maximum number of components (%i) exceeded for %s", + BABL_MAX_COMPONENTS, + assigned_name ? assigned_name : "(unnamed)"); + } + component [components++] = (BablComponent *) bablc; + break; + + case BABL_MODEL: + babl_log ("submodels not handled yet"); + break; + + case BABL_SPACE: + space = bablc; + break; + + case BABL_TYPE: + case BABL_TYPE_INTEGER: + case BABL_TYPE_FLOAT: + case BABL_SAMPLING: + case BABL_INSTANCE: + case BABL_FORMAT: + + + case BABL_CONVERSION: + case BABL_CONVERSION_LINEAR: + case BABL_CONVERSION_PLANE: + case BABL_CONVERSION_PLANAR: + case BABL_FISH: + case BABL_FISH_SIMPLE: + case BABL_FISH_REFERENCE: + case BABL_FISH_PATH: + case BABL_IMAGE: + case BABL_EXTENSION: + babl_log ("%s unexpected", babl_class_name (bablc->class_type)); + break; + + case BABL_SKY: /* shut up compiler */ + break; + } + } + + else + { + babl_fatal ("unhandled argument '%s' for babl_model '%s'", + arg, assigned_name ? assigned_name : "(unnamed)"); + } + + arg = va_arg (varg, char *); + if (!arg) + break; + } + + va_end (varg); + + if (assigned_name) + name = babl_strdup(assigned_name); + else + name = babl_model_create_name (components, component); + + if (!components) + { + babl_log("no components specified for model '%s'", name); + goto out; + } + + babl = babl_db_exist (db, id, name); + if (id && !babl && babl_db_exist (db, 0, name)) + babl_fatal ("Trying to reregister BablModel '%s' with different id!", name); + + if (! babl) + { + babl = model_new (name, space, id, components, component, flags, doc); + babl_db_insert (db, babl); + construct_double_format (babl); + } + else + { + if (!is_model_duplicate (babl, space, components, component)) + babl_fatal ("BablModel '%s' already registered " + "with different components!", name); + } + + out: + babl_free (name); + + return babl; +} + + +#define TOLERANCE 0.001 + +static const Babl * +reference_format (void) +{ + static const Babl *self = NULL; + + if (!self) + self = babl_format_new ( + babl_model ("RGBA"), + babl_type ("double"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + babl_component ("A"), + NULL); + return self; +} + +static const Babl * +construct_double_format (const Babl *model) +{ + const void *argument[44 + 1]; + int args = 0; + int i; + + if (model == babl_model_from_id (BABL_RGBA)) + { + argument[args++] = "id"; + argument[args++] = (void*) BABL_RGBA_DOUBLE; + } + argument[args++] = model; + argument[args++] = babl_type_from_id (BABL_DOUBLE); + + for (i = 0; i < model->model.components; i++) + { + argument[args++] = model->model.component[i]; + } + argument[args++] = NULL; + +#define o(argno) argument[argno], + return babl_format_new (o (0) o (1) o (2) o (3) + o (4) o (5) o (6) o (7) + o (8) o (9) o (10) o (11) + o (12) o (13) o (14) o (15) + o (16) o (17) o (18) o (19) + o (20) o (21) o (22) o (23) + o (24) o (25) o (26) o (27) + o (28) o (29) o (30) o (31) + o (32) o (33) o (34) o (35) + o (36) o (37) o (38) o (39) + o (40) o (41) o (42) NULL); +#undef o +} + +double +babl_model_is_symmetric (const Babl *cbabl) +{ + Babl *babl = (Babl*)cbabl; + void *original; + double *clipped; + void *destination; + double *transformed; + int symmetric = 1; + + const Babl *ref_fmt; + const Babl *fmt; + Babl *fish_to; + Babl *fish_from; + + const int test_pixels = babl_get_num_model_test_pixels (); + const double *test = babl_get_model_test_pixels (); + + ref_fmt = reference_format (); + fmt = construct_double_format (babl); + fish_to = babl_fish_reference (ref_fmt, fmt); + fish_from = babl_fish_reference (fmt, ref_fmt); + + original = babl_calloc (1, 64 / 8 * babl->model.components * test_pixels); + clipped = babl_calloc (1, 64 / 8 * 4 * test_pixels); + destination = babl_calloc (1, 64 / 8 * babl->model.components * test_pixels); + transformed = babl_calloc (1, 64 / 8 * 4 * test_pixels); + + babl_process (fish_to, test, original, test_pixels); + babl_process (fish_from, original, clipped, test_pixels); + babl_process (fish_to, clipped, destination, test_pixels); + babl_process (fish_from, destination, transformed, test_pixels); + + fish_to->fish.pixels -= test_pixels * 2; + fish_from->fish.pixels -= test_pixels * 2; + + { + int i; + int log = 0; + + for (i = 0; i < test_pixels; i++) + { + int j; + for (j = 0; j < 4; j++) + { + float tolerance = TOLERANCE; + if (fabs(clipped[i*4+j]) > 1.0) + tolerance = fabs(clipped[i*4+j]) * 0.01; + if (fabs (clipped[i *4 + j] - transformed[i * 4 + j]) > tolerance) + { + if (!log) + log = 1; + symmetric = 0; + } + } + if (log && log < 5) + { + babl_log ("%s", babl->instance.name); + babl_log ("\ttest: %2.3f %2.3f %2.3f %2.3f", test [i *4 + 0], + test [i * 4 + 1], + test [i * 4 + 2], + test [i * 4 + 3]); + babl_log ("\tclipped: %2.3f %2.3f %2.3f %2.3f", clipped [i *4 + 0], + clipped [i * 4 + 1], + clipped [i * 4 + 2], + clipped [i * 4 + 3]); + babl_log ("\ttrnsfrmd: %2.3f %2.3f %2.3f %2.3f", transformed [i *4 + 0], + transformed [i * 4 + 1], + transformed [i * 4 + 2], + transformed [i * 4 + 3]); + log++; + } + } + } + + babl_free (original); + babl_free (clipped); + babl_free (destination); + babl_free (transformed); + return symmetric; +} + +BABL_CLASS_IMPLEMENT (model) + +/* XXX: probably better to do like with babl_format, add a -suffix and + * insert in normal database than to have this static cache list + */ +static const Babl *babl_remodels[512]={NULL,}; +int babl_n_remodels = 0; + +const Babl * +babl_remodel_with_space (const Babl *model, + const Babl *space) +{ + Babl *ret; + int i; + assert (BABL_IS_BABL (model)); + + if (!space) space = babl_space ("sRGB"); + if (space->class_type == BABL_FORMAT) + { + space = space->format.space; + } + else if (space->class_type == BABL_MODEL) + { + space = space->model.space; + } + else if (space->class_type != BABL_SPACE) + { + return NULL; + } + + if (model->model.space == space) + return (void*)model; + + assert (BABL_IS_BABL (model)); + + /* get back to the sRGB model if we are in a COW clone of it */ + if (model->model.model) + model = (void*)model->model.model; + + assert (BABL_IS_BABL (model)); + + for (i = 0; i < babl_n_remodels; i++) + { + if (babl_remodels[i]->model.model == model && + babl_remodels[i]->model.space == space) + return babl_remodels[i]; + } + + ret = babl_calloc (sizeof (BablModel), 1); + memcpy (ret, model, sizeof (BablModel)); + ret->model.space = space; + ret->model.model = (void*)model; /* use the data as a backpointer to original model */ + return babl_remodels[babl_n_remodels++] = ret; + return (Babl*)ret; +} + +const Babl * +babl_model_with_space (const char *name, + const Babl *space) +{ + return babl_remodel_with_space (babl_model (name), space); +} + +BablModelFlag +babl_get_model_flags (const Babl *babl) +{ + if (!babl) return 0; + switch (babl->class_type) + { + case BABL_MODEL: + return babl->model.flags; + case BABL_FORMAT: + return babl->format.model->flags; + } + return 0; +} + diff --git a/babl/babl-model.h b/babl/babl-model.h new file mode 100644 index 0000000..62e3c94 --- /dev/null +++ b/babl/babl-model.h @@ -0,0 +1,38 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005-2008, Øyvind Kolås and others. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#ifndef _BABL_MODEL_H +#define _BABL_MODEL_H + +BABL_CLASS_DECLARE (model); + +typedef struct +{ + BablInstance instance; + BablList *from_list; + int components; + BablComponent **component; + BablType **type; /*< must be doubles, + used here for convenience in code */ + void *data; /* user-data, used for palette */ + const Babl *space; + void *model; /* back pointer to model with sRGB space */ + BablModelFlag flags; +} BablModel; + +#endif diff --git a/babl/babl-mutex.c b/babl/babl-mutex.c new file mode 100644 index 0000000..92191c4 --- /dev/null +++ b/babl/babl-mutex.c @@ -0,0 +1,87 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2009, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include "babl-mutex.h" + +#include + +#ifndef _WIN32 + +static const pthread_mutexattr_t * +get_mutex_attr (void) +{ + static pthread_mutexattr_t mutexattr; + static int initialized = 0; + + if (!initialized) + { + /* On some platforms, this will keep an allocation till process + termination, but it isn't a growing leak. */ + pthread_mutexattr_init (&mutexattr); + pthread_mutexattr_settype (&mutexattr, PTHREAD_MUTEX_RECURSIVE); + initialized = 1; + } + + return &mutexattr; +} + +#endif + +BablMutex * +babl_mutex_new (void) +{ + BablMutex *mutex = malloc (sizeof (BablMutex)); +#ifdef _WIN32 + InitializeCriticalSection (mutex); +#else + pthread_mutex_init (mutex, get_mutex_attr ()); +#endif + return mutex; +} + +void +babl_mutex_destroy (BablMutex *mutex) +{ +#ifdef _WIN32 + DeleteCriticalSection (mutex); +#else + pthread_mutex_destroy(mutex); +#endif + free (mutex); +} + +void +babl_mutex_lock (BablMutex *mutex) +{ +#ifdef _WIN32 + EnterCriticalSection (mutex); +#else + pthread_mutex_lock (mutex); +#endif +} + +void +babl_mutex_unlock (BablMutex *mutex) +{ +#ifdef _WIN32 + LeaveCriticalSection (mutex); +#else + pthread_mutex_unlock (mutex); +#endif +} diff --git a/babl/babl-mutex.h b/babl/babl-mutex.h new file mode 100644 index 0000000..f5dcefb --- /dev/null +++ b/babl/babl-mutex.h @@ -0,0 +1,40 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2009, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#ifndef _BABL_MUTEX_H +#define _BABL_MUTEX_H + +#ifndef _WIN32 +#define _GNU_SOURCE 1 +#include +#else +#include +#endif + +#ifdef _WIN32 + typedef CRITICAL_SECTION BablMutex; +#else + typedef pthread_mutex_t BablMutex; +#endif + +BablMutex* babl_mutex_new (void); +void babl_mutex_destroy (BablMutex *mutex); +void babl_mutex_lock (BablMutex *mutex); +void babl_mutex_unlock (BablMutex *mutex); + +#endif diff --git a/babl/babl-palette.c b/babl/babl-palette.c new file mode 100644 index 0000000..086da67 --- /dev/null +++ b/babl/babl-palette.c @@ -0,0 +1,989 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2012, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include +#include +#include +#include +#include +#include +#include "config.h" +#include "babl-internal.h" +#include "babl.h" +#include "babl-memory.h" + +#ifdef HAVE_STDATOMIC_H +#include +#define BABL_ATOMIC _Atomic +#else +#define BABL_ATOMIC +#endif + +#define HASH_TABLE_SIZE 1111 + + +typedef struct BablPaletteRadius +{ + unsigned char idx; + unsigned short diff; +} BablPaletteRadius; + +typedef struct BablPalette +{ + int count; /* number of palette entries */ + const Babl *format; /* the pixel format the palette is stored in */ + unsigned char *data; /* one linear segment of all the pixels + * representing the palette, in order + */ + double *data_double; + unsigned char *data_u8; + BablPaletteRadius *BABL_ATOMIC radii; + volatile unsigned int hash[HASH_TABLE_SIZE]; +} BablPalette; + + +static unsigned short ceil_sqrt_u8[3 * 255 * 255 + 1]; + +/* A default palette, containing standard ANSI / EGA colors + * + */ +static unsigned char defpal_data[4*16] = +{ +0 ,0 ,0 ,255, +127,0 ,0 ,255, +0 ,127,0 ,255, +127,127,0 ,255, +0 ,0 ,127,255, +127,0 ,127,255, +0 ,127,127,255, +127,127,127,255, +63 ,63 ,63 ,255, +255,0 ,0 ,255, +0 ,255,0 ,255, +255,255,0 ,255, +0 ,0 ,255,255, +255,0 ,255,255, +0 ,255,255,255, +255,255,255,255, +}; +static double defpal_double[4*16]; +static BablPaletteRadius defpal_radii[15 * 16]; + + +static void +init_ceil_sqrt_u8 (void) +{ + int i; + + if (! ceil_sqrt_u8[1]) + { + for (i = 0; i <= 3 * 255 * 255; i++) + ceil_sqrt_u8[i] = ceil (sqrt (i)); + } +} + +static inline int +diff2_u8 (const unsigned char *p1, + const unsigned char *p2) +{ + return ((int) p1[0] - (int) p2[0]) * ((int) p1[0] - (int) p2[0]) + + ((int) p1[1] - (int) p2[1]) * ((int) p1[1] - (int) p2[1]) + + ((int) p1[2] - (int) p2[2]) * ((int) p1[2] - (int) p2[2]); +} + +static int +babl_palette_radius_compare (const void *r1, + const void *r2) +{ + const BablPaletteRadius *radius1 = r1; + const BablPaletteRadius *radius2 = r2; + + return (int) radius1->diff - (int) radius2->diff; +} + +static void +babl_palette_init_radii (BablPalette *pal, + BablPaletteRadius *radii) +{ + int i, j; + + /* calculate the distance between each pair of colors in the palette, and, for + * each color, construct a list of all other colors and their distances from + * it, sorted by distance. we use these lists in babl_palette_lookup() to + * speed up the search, as described in the function. + */ + + for (i = 0; i < pal->count; i++) + { + BablPaletteRadius *radii1 = radii + (pal->count - 1) * i; + const unsigned char *p1 = pal->data_u8 + 4 * i; + + for (j = i + 1; j < pal->count; j++) + { + BablPaletteRadius *radii2 = radii + (pal->count - 1) * j; + const unsigned char *p2 = pal->data_u8 + 4 * j; + unsigned short diff; + + diff = floor (sqrt (diff2_u8 (p1, p2))); + + radii1[j - 1].idx = j; + radii1[j - 1].diff = diff; + + radii2[i].idx = i; + radii2[i].diff = diff; + } + + qsort (radii1, pal->count - 1, sizeof (BablPaletteRadius), + babl_palette_radius_compare); + } +} + +static BablPaletteRadius * +babl_palette_create_radii (BablPalette *pal) +{ + BablPaletteRadius *radii; + + radii = babl_malloc (sizeof (BablPaletteRadius) * + (pal->count - 1) * + pal->count); + + babl_palette_init_radii (pal, radii); + + return radii; +} + +static const BablPaletteRadius * +babl_palette_get_radii (BablPalette *pal, + int entry) +{ + BablPaletteRadius *radii; + +#ifdef HAVE_STDATOMIC_H + radii = atomic_load_explicit (&pal->radii, memory_order_consume); + + if (! radii) + { + BablPaletteRadius *existing_radii; + + existing_radii = NULL; + radii = babl_palette_create_radii (pal); + + if (! atomic_compare_exchange_strong_explicit (&pal->radii, + &existing_radii, radii, + memory_order_acq_rel, + memory_order_consume)) + { + babl_free (radii); + + radii = existing_radii; + } + } +#else + radii = pal->radii; +#endif + + return radii + (pal->count - 1) * entry; +} + +static void +babl_palette_reset_hash (BablPalette *pal) +{ + int i; + for (i = 0; i < HASH_TABLE_SIZE; i++) + { + pal->hash[i] = i + 1; /* always a miss */ + } +} + +#define BABL_IDX_FACTOR 255.5 + +static int +babl_palette_lookup (BablPalette *pal, + const unsigned char *p, + int best_idx) +{ + unsigned int pixel = p[0] | (p[1] << 8) | (p[2] << 16); + int hash_index = pixel % HASH_TABLE_SIZE; + unsigned int hash_value = pal->hash[hash_index]; + unsigned int hash_pixel = hash_value & 0x00ffffffu; + int idx = hash_value >> 24; + + /* note: we're assuming the palette has no more than 256 colors, otherwise + * the index doesn't fit in the top 8 bits of the hash-table value. since + * we're only using this functions with u8 palette formats, there's no need + * to actually verify this, but if we add wider formats in the future, it's + * something to be aware of. + */ + + if (pixel == hash_pixel) + { + return idx; + } + else + { + const BablPaletteRadius *radii = babl_palette_get_radii (pal, best_idx); + const unsigned char *q; + int best_diff2; + int best_diff; + int diff0; + int i; + + /* best_idx is the closest palette entry to the previous pixel (referred + * to as the source color). based on the assumption that nearby pixels + * have similar color, we start the search for the current closest entry + * at best_idx, and iterate over the entry's color list, as calculated in + * babl_palette_init_radii(), in search for a better match. + */ + + q = pal->data_u8 + 4 * best_idx; + best_diff2 = diff2_u8 (p, q); + best_diff = ceil_sqrt_u8[best_diff2]; + diff0 = best_diff; + + for (i = 0; i < pal->count - 1; i++) + { + const BablPaletteRadius *radius = &radii[i]; + int min_diff; + int diff2; + + /* radius->diff is the distance from the source color to the current + * color. diff0 is the distance from the source color to the input + * color. according to the triangle inequality, the distance from + * the current color to the input color is at least + * radius->diff - diff0. if the shortest distance found so far is + * less than that, then the best match found so far is necessarily + * better than the current color, and we can stop the search, since + * the color list is sorted in ascending radius->diff order. + */ + + idx = radius->idx; + min_diff = radius->diff - diff0; + + if (best_diff < min_diff || (best_diff == min_diff && best_idx < idx)) + break; + + q = pal->data_u8 + 4 * idx; + diff2 = diff2_u8 (p, q); + + if (diff2 < best_diff2 || (diff2 == best_diff2 && idx < best_idx)) + { + best_idx = idx; + best_diff2 = diff2; + best_diff = ceil_sqrt_u8[diff2]; + } + } + + pal->hash[hash_index] = ((unsigned int) best_idx << 24) | pixel; + + return best_idx; + } +} + +static BablPalette * +make_pal (const Babl *pal_space, + const Babl *format, + const void *data, + int count) +{ + BablPalette *pal = NULL; + int bpp = babl_format_get_bytes_per_pixel (format); + + babl_assert (count > 0); + + pal = babl_malloc (sizeof (BablPalette)); + pal->count = count; + pal->format = format; + pal->data = babl_malloc (bpp * count); + pal->data_double = babl_malloc (4 * sizeof(double) * count); + pal->data_u8 = babl_malloc (4 * sizeof(char) * count); + pal->radii = NULL; + + memcpy (pal->data, data, bpp * count); + + babl_process (babl_fish (format, babl_format_with_space ("RGBA double", pal_space)), + data, pal->data_double, count); + babl_process (babl_fish (format, babl_format_with_space ("R'G'B'A u8", pal_space)), + data, pal->data_u8, count); + +#ifndef HAVE_STDATOMIC_H + pal->radii = babl_palette_create_radii (pal); +#endif + + babl_palette_reset_hash (pal); + + return pal; +} + +static void +babl_palette_free (BablPalette *pal) +{ + babl_free (pal->data); + babl_free (pal->data_double); + babl_free (pal->data_u8); + babl_free (pal->radii); + babl_free (pal); +} + +static BablPalette * +default_palette (void) +{ + static BablPalette pal; + static int inited = 0; + + babl_mutex_lock (babl_format_mutex); + + if (inited) + { + babl_mutex_unlock (babl_format_mutex); + + return &pal; + } + + init_ceil_sqrt_u8 (); + + memset (&pal, 0, sizeof (pal)); + pal.count = 16; + pal.format = babl_format ("R'G'B'A u8"); /* dynamically generated, so + the default palette can + not be fully static. + */ + pal.data = defpal_data; + pal.data_double = defpal_double; + pal.data_u8 = defpal_data; + pal.radii = defpal_radii; + + babl_process (babl_fish (pal.format, babl_format ("RGBA double")), + pal.data, pal.data_double, pal.count); + + babl_palette_init_radii (&pal, pal.radii); + + babl_palette_reset_hash (&pal); + + inited = 1; + + babl_mutex_unlock (babl_format_mutex); + + return &pal; +} + +static void +rgba_to_pal (Babl *conversion, + char *src_b, + char *dst, + long n, + void *dst_model_data) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + BablPalette **palptr = dst_model_data; + BablPalette *pal; + int best_idx = 0; + assert (palptr); + pal = *palptr; + assert(pal); + + while (n--) + { + double *src_d = (void*) src_b; + unsigned char src[4]; + int c; + for (c = 0; c < 3; c++) + { + if (src_d[c] >= 1.0f) + src[c] = 255; + else if (src_d[c] <= 0.0f) + src[c] = 0; + else + src[c] = babl_trc_from_linear (space->space.trc[0], + src_d[c]) * 255 + 0.5f; + } + if (src_d[3] >= 1.0f) + src[3] = 255; + else if (src_d[3] <= 0.0f) + src[3] = 0; + else + src[3] = src_d[3] * 255 + 0.5f; + + best_idx = babl_palette_lookup (pal, src, best_idx); + + ((double *) dst)[0] = best_idx / BABL_IDX_FACTOR; + + src_b += sizeof (double) * 4; + dst += sizeof (double) * 1; + } + +} + +static void +rgba_to_pala (Babl *conversion, + char *src_i, + char *dst, + long n, + void *dst_model_data) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + BablPalette **palptr = dst_model_data; + BablPalette *pal; + int best_idx = 0; + assert (palptr); + pal = *palptr; + assert(pal); + + while (n--) + { + double *src_d = (void*) src_i; + unsigned char src[4]; + int c; + for (c = 0; c < 3; c++) + { + if (src_d[c] >= 1.0f) + src[c] = 255; + else if (src_d[c] <= 0.0f) + src[c] = 0; + else + src[c] = babl_trc_from_linear (space->space.trc[0], + src_d[c]) * 255 + 0.5f; + } + if (src_d[3] >= 1.0f) + src[3] = 255; + else if (src_d[3] <= 0.0f) + src[3] = 0; + else + src[3] = src_d[3] * 255 + 0.5f; + + best_idx = babl_palette_lookup (pal, src, best_idx); + + ((double *) dst)[0] = best_idx / BABL_IDX_FACTOR; + ((double *) dst)[1] = src_d[3]; + + src_i += sizeof (double) * 4; + dst += sizeof (double) * 2; + } +} + +static void +pal_to_rgba (Babl *conversion, + char *src, + char *dst, + long n, + void *src_model_data) +{ + BablPalette **palptr = src_model_data; + BablPalette *pal = *palptr; + assert(pal); + while (n--) + { + int idx = (((double *) src)[0]) * BABL_IDX_FACTOR; + double *palpx; + + if (idx < 0) idx = 0; + if (idx >= pal->count) idx = pal->count-1; + + palpx = ((double *)pal->data_double) + idx * 4; + memcpy (dst, palpx, sizeof(double)*4); + + src += sizeof (double) * 1; + dst += sizeof (double) * 4; + } +} + +static void +pala_to_rgba (Babl *conversion, + char *src, + char *dst, + long n, + void *src_model_data) +{ + BablPalette **palptr = src_model_data; + BablPalette *pal; + + assert(palptr); + pal = *palptr; + + assert(pal); + while (n--) + { + int idx = (((double *) src)[0]) * BABL_IDX_FACTOR; + double alpha = (((double *) src)[1]); + double *palpx; + + if (idx < 0) idx = 0; + if (idx >= pal->count) idx = pal->count-1; + + palpx = ((double *)pal->data_double) + idx * 4; + memcpy (dst, palpx, sizeof(double)*4); + + ((double *)dst)[3] *= alpha; + + src += sizeof (double) * 2; + dst += sizeof (double) * 4; + } +} + +static void +rgba_float_to_pal_a (Babl *conversion, + unsigned char *src_b, + unsigned char *dst, + long n, + void *src_model_data) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + BablPalette **palptr = src_model_data; + BablPalette *pal; + int best_idx = 0; + assert (palptr); + pal = *palptr; + assert(pal); + + while (n--) + { + float *src_f = (void*) src_b; + unsigned char src[4]; + int c; + for (c = 0; c < 3; c++) + { + if (src_f[c] >= 1.0f) + src[c] = 255; + else if (src_f[c] <= 0.0f) + src[c] = 0; + else + src[c] = babl_trc_from_linear (space->space.trc[0], + src_f[c]) * 255 + 0.5f; + } + if (src_f[3] >= 1.0f) + src[3] = 255; + else if (src_f[3] <= 0.0f) + src[3] = 0; + else + src[3] = src_f[3] * 255 + 0.5f; + + + dst[0] = best_idx = babl_palette_lookup (pal, src, best_idx); + dst[1] = src[3]; + + src_b += sizeof (float) * 4; + dst += sizeof (char) * 2; + } +} + + +static void +rgba_float_to_pal (Babl *conversion, + unsigned char *src_b, + unsigned char *dst, + long n, + void *src_model_data) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + BablPalette **palptr = src_model_data; + BablPalette *pal; + int best_idx = 0; + assert (palptr); + pal = *palptr; + assert(pal); + + while (n--) + { + float *src_f = (void*) src_b; + unsigned char src[4]; + int c; + for (c = 0; c < 3; c++) + { + if (src_f[c] >= 1.0f) + src[c] = 255; + else if (src_f[c] <= 0.0f) + src[c] = 0; + else + src[c] = babl_trc_from_linear (space->space.trc[0], + src_f[c]) * 255 + 0.5f; + } + if (src_f[3] >= 1.0f) + src[3] = 255; + else if (src_f[3] <= 0.0f) + src[3] = 0; + else + src[3] = src_f[3] * 255 + 0.5f; + + dst[0] = best_idx = babl_palette_lookup (pal, src, best_idx); + + src_b += sizeof (float) * 4; + dst += sizeof (char) * 1; + } +} + +static void +rgba_u8_to_pal (Babl *conversion, + unsigned char *src, + unsigned char *dst, + long n, + void *src_model_data) +{ + BablPalette **palptr = src_model_data; + BablPalette *pal; + int best_idx = 0; + assert (palptr); + pal = *palptr; + assert(pal); + + while (n--) + { + dst[0] = best_idx = babl_palette_lookup (pal, src, best_idx); + + src += sizeof (char) * 4; + dst += sizeof (char) * 1; + } +} + +static void +rgba_u8_to_pal_a (Babl *conversion, + unsigned char *src, + unsigned char *dst, + long n, + void *src_model_data) +{ + BablPalette **palptr = src_model_data; + BablPalette *pal; + int best_idx = 0; + assert (palptr); + pal = *palptr; + assert(pal); + while (n--) + { + dst[0] = best_idx = babl_palette_lookup (pal, src, best_idx); + dst[1] = src[3]; + + src += sizeof (char) * 4; + dst += sizeof (char) * 2; + } +} + +static long +pal_u8_to_rgba_u8 (Babl *conversion, + unsigned char *src, + unsigned char *dst, + long n, + void *src_model_data) +{ + BablPalette **palptr = src_model_data; + BablPalette *pal; + assert (palptr); + pal = *palptr; + assert(pal); + while (n--) + { + int idx = src[0]; + unsigned char *palpx; + + if (idx < 0) idx = 0; + if (idx >= pal->count) idx = pal->count-1; + + palpx = pal->data_u8 + idx * 4; + memcpy (dst, palpx, sizeof(char)*4); + + src += sizeof (char) * 1; + dst += sizeof (char) * 4; + } + return n; +} + +static long +pala_u8_to_rgba_u8 (Babl *conversion, + unsigned char *src, + unsigned char *dst, + long n, + void *src_model_data) +{ + BablPalette **palptr = src_model_data; + BablPalette *pal; + assert (palptr); + pal = *palptr; + assert(pal); + while (n--) + { + int idx = src[0]; + unsigned char *palpx; + + if (idx < 0) idx = 0; + if (idx >= pal->count) idx = pal->count-1; + + palpx = pal->data_u8 + idx * 4; + memcpy (dst, palpx, sizeof(char)*4); + dst[3] = (dst[3] * src[1] + 128) / 255; + + src += sizeof (char) * 2; + dst += sizeof (char) * 4; + } + return n; +} + + +#include "base/util.h" + +static inline long +conv_pal8_pala8 (Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + dst[0] = src[0]; + dst[1] = 255; + src += 1; + dst += 2; + } + return samples; +} + +static inline long +conv_pala8_pal8 (Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + dst[0] = src[0]; + src += 2; + dst += 1; + } + return samples; +} + +int +babl_format_is_palette (const Babl *format) +{ + if (format->class_type == BABL_FORMAT) + return format->format.palette; + return 0; +} + + +const Babl * +babl_new_palette_with_space (const char *name, + const Babl *space, + const Babl **format_u8, + const Babl **format_u8_with_alpha) +{ + const Babl *model; + const Babl *model_no_alpha; + Babl *f_pal_u8; + Babl *f_pal_a_u8; + const Babl *component; + const Babl *alpha; + BablPalette **palptr; + + char cname[64]; + + if (!space) + space = babl_space ("sRGB"); + + if (!name) + { + static int cnt = 0; + snprintf (cname, sizeof (cname), "_babl-int-%i", cnt++); + name = cname; + } + else + { + snprintf (cname, sizeof (cname), "%s-%p", name, space); + name = cname; + + if ((model = babl_db_exist_by_name (babl_model_db (), name))) + { + cname[0] = ')'; + if (format_u8) + *format_u8 = babl_db_exist_by_name (babl_format_db (), name); + cname[0] = '\\'; + if (format_u8_with_alpha) + *format_u8_with_alpha = babl_db_exist_by_name (babl_format_db (), name); + return model; + } + } + + /* re-registering is a no-op */ + component = babl_component_new ( + "I", + "luma", + "chroma", + NULL); + alpha = babl_component ("A"); + model = babl_model_new ("name", name, component, alpha, NULL); + palptr = malloc (sizeof (void*)); + *palptr = default_palette ();; + cname[0] = 'v'; + model_no_alpha = babl_model_new ("name", name, component, NULL); + cname[0] = '\\'; + f_pal_a_u8 = (void*) babl_format_new ("name", name, model, space, + babl_type ("u8"), + component, alpha, NULL); + cname[0] = ')'; + f_pal_u8 = (void*) babl_format_new ("name", name, model_no_alpha, space, + babl_type ("u8"), + component, NULL); + + f_pal_a_u8->format.palette = 1; + f_pal_u8->format.palette = 1; + + babl_conversion_new ( + model, + babl_model ("RGBA"), + "linear", pala_to_rgba, + "data", palptr, + NULL + ); + + babl_conversion_new ( + babl_model ("RGBA"), + model, + "linear", rgba_to_pala, + "data", palptr, + NULL + ); + + babl_conversion_new ( + model_no_alpha, + babl_model ("RGBA"), + "linear", pal_to_rgba, + "data", palptr, + NULL + ); + babl_conversion_new ( + babl_model ("RGBA"), + model_no_alpha, + "linear", rgba_to_pal, + "data", palptr, + NULL + ); + babl_conversion_new ( + f_pal_u8, + f_pal_a_u8, + "linear", conv_pal8_pala8, + NULL + ); + babl_conversion_new ( + f_pal_a_u8, + f_pal_u8, + "linear", conv_pala8_pal8, + NULL + ); + babl_conversion_new ( + f_pal_u8, + babl_format ("R'G'B'A u8"), + "linear", pal_u8_to_rgba_u8, + "data", palptr, + NULL); + babl_conversion_new ( + f_pal_a_u8, + babl_format ("R'G'B'A u8"), + "linear", pala_u8_to_rgba_u8, + "data", palptr, + NULL); + + babl_conversion_new ( + babl_format ("R'G'B'A u8"), + f_pal_a_u8, + "linear", rgba_u8_to_pal_a, + "data", palptr, + NULL); + babl_conversion_new ( + babl_format ("R'G'B'A u8"), + f_pal_u8, + "linear", rgba_u8_to_pal, + "data", palptr, + NULL); + + babl_conversion_new ( + babl_format ("RGBA float"), + f_pal_a_u8, + "linear", rgba_float_to_pal_a, + "data", palptr, + NULL); + babl_conversion_new ( + babl_format ("RGBA float"), + f_pal_u8, + "linear", rgba_float_to_pal, + "data", palptr, + NULL); + + babl_set_user_data (model, palptr); + babl_set_user_data (model_no_alpha, palptr); + + if (format_u8) + *format_u8 = f_pal_u8; + if (format_u8_with_alpha) + *format_u8_with_alpha = f_pal_a_u8; + babl_sanity (); + return model; +} + +/* should return the BablModel, permitting to fetch + * other formats out of it? + */ +const Babl * +babl_new_palette (const char *name, + const Babl **format_u8, + const Babl **format_u8_with_alpha) +{ + return babl_new_palette_with_space (name, NULL, + format_u8, format_u8_with_alpha); +} + +void +babl_palette_set_palette (const Babl *babl, + const Babl *format, + void *data, + int count) +{ + BablPalette **palptr = babl_get_user_data (babl); + babl_palette_reset (babl); + + if (count > 256) + { + babl_log ("attempt to create a palette with %d colors. " + "truncating to 256 colors.", + count); + + count = 256; + } + + if (count > 0) + { + *palptr = make_pal (babl_format_get_space (babl), format, data, count); + } + else + { + babl_log ("attempt to create a palette with %d colors. " + "using default palette instead.", + count); + } +} + +void +babl_palette_reset (const Babl *babl) +{ + BablPalette **palptr = babl_get_user_data (babl); + if (*palptr != default_palette ()) + { + babl_palette_free (*palptr); + } + *palptr = default_palette (); +} diff --git a/babl/babl-polynomial.c b/babl/babl-polynomial.c new file mode 100644 index 0000000..bf3b6a8 --- /dev/null +++ b/babl/babl-polynomial.c @@ -0,0 +1,539 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2017, Øyvind Kolås and others. + * + * babl-polynomial.c + * Copyright (C) 2017 Ell + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#ifdef BABL_POLYNOMIAL_DEGREE + +BABL_POLYNOMIAL_DEGREE ( 0, __) +BABL_POLYNOMIAL_DEGREE ( 1, 0) +BABL_POLYNOMIAL_DEGREE ( 2, 1) +BABL_POLYNOMIAL_DEGREE ( 3, 2) +BABL_POLYNOMIAL_DEGREE ( 4, 3) +BABL_POLYNOMIAL_DEGREE ( 5, 4) +BABL_POLYNOMIAL_DEGREE ( 6, 5) +BABL_POLYNOMIAL_DEGREE ( 7, 6) +BABL_POLYNOMIAL_DEGREE ( 8, 7) +BABL_POLYNOMIAL_DEGREE ( 9, 8) +BABL_POLYNOMIAL_DEGREE (10, 9) +BABL_POLYNOMIAL_DEGREE (11, 10) +BABL_POLYNOMIAL_DEGREE (12, 11) +BABL_POLYNOMIAL_DEGREE (13, 12) +BABL_POLYNOMIAL_DEGREE (14, 13) +BABL_POLYNOMIAL_DEGREE (15, 14) +BABL_POLYNOMIAL_DEGREE (16, 15) +BABL_POLYNOMIAL_DEGREE (17, 16) +BABL_POLYNOMIAL_DEGREE (18, 17) +BABL_POLYNOMIAL_DEGREE (19, 18) +BABL_POLYNOMIAL_DEGREE (20, 19) +BABL_POLYNOMIAL_DEGREE (21, 20) +BABL_POLYNOMIAL_DEGREE (22, 21) + +#undef BABL_POLYNOMIAL_DEGREE + +#else + +#include "config.h" +#include +#include +#include "babl-internal.h" + + +#define BABL_BIG_POLYNOMIAL_MAX_DEGREE (2 * BABL_POLYNOMIAL_MAX_DEGREE + BABL_POLYNOMIAL_MAX_SCALE) +#define EPSILON 1e-10 + + +typedef struct +{ + BablPolynomialEvalFunc eval; + int degree; + int scale; + double coeff[BABL_BIG_POLYNOMIAL_MAX_DEGREE + 1]; +} BablBigPolynomial; + + +#define BABL_POLYNOMIAL_EVAL___(poly, x) 0.0 +#define BABL_POLYNOMIAL_EVAL_0(poly, x) ( (poly)->coeff[0]) +#define BABL_POLYNOMIAL_EVAL_1(poly, x) ( (poly)->coeff[1]) +#define BABL_POLYNOMIAL_EVAL_2(poly, x) (BABL_POLYNOMIAL_EVAL_0 (poly, x) * (x) + (poly)->coeff[2]) +#define BABL_POLYNOMIAL_EVAL_3(poly, x) (BABL_POLYNOMIAL_EVAL_1 (poly, x) * (x) + (poly)->coeff[3]) +#define BABL_POLYNOMIAL_EVAL_4(poly, x) (BABL_POLYNOMIAL_EVAL_2 (poly, x) * (x) + (poly)->coeff[4]) +#define BABL_POLYNOMIAL_EVAL_5(poly, x) (BABL_POLYNOMIAL_EVAL_3 (poly, x) * (x) + (poly)->coeff[5]) +#define BABL_POLYNOMIAL_EVAL_6(poly, x) (BABL_POLYNOMIAL_EVAL_4 (poly, x) * (x) + (poly)->coeff[6]) +#define BABL_POLYNOMIAL_EVAL_7(poly, x) (BABL_POLYNOMIAL_EVAL_5 (poly, x) * (x) + (poly)->coeff[7]) +#define BABL_POLYNOMIAL_EVAL_8(poly, x) (BABL_POLYNOMIAL_EVAL_6 (poly, x) * (x) + (poly)->coeff[8]) +#define BABL_POLYNOMIAL_EVAL_9(poly, x) (BABL_POLYNOMIAL_EVAL_7 (poly, x) * (x) + (poly)->coeff[9]) +#define BABL_POLYNOMIAL_EVAL_10(poly, x) (BABL_POLYNOMIAL_EVAL_8 (poly, x) * (x) + (poly)->coeff[10]) +#define BABL_POLYNOMIAL_EVAL_11(poly, x) (BABL_POLYNOMIAL_EVAL_9 (poly, x) * (x) + (poly)->coeff[11]) +#define BABL_POLYNOMIAL_EVAL_12(poly, x) (BABL_POLYNOMIAL_EVAL_10 (poly, x) * (x) + (poly)->coeff[12]) +#define BABL_POLYNOMIAL_EVAL_13(poly, x) (BABL_POLYNOMIAL_EVAL_11 (poly, x) * (x) + (poly)->coeff[13]) +#define BABL_POLYNOMIAL_EVAL_14(poly, x) (BABL_POLYNOMIAL_EVAL_12 (poly, x) * (x) + (poly)->coeff[14]) +#define BABL_POLYNOMIAL_EVAL_15(poly, x) (BABL_POLYNOMIAL_EVAL_13 (poly, x) * (x) + (poly)->coeff[15]) +#define BABL_POLYNOMIAL_EVAL_16(poly, x) (BABL_POLYNOMIAL_EVAL_14 (poly, x) * (x) + (poly)->coeff[16]) +#define BABL_POLYNOMIAL_EVAL_17(poly, x) (BABL_POLYNOMIAL_EVAL_15 (poly, x) * (x) + (poly)->coeff[17]) +#define BABL_POLYNOMIAL_EVAL_18(poly, x) (BABL_POLYNOMIAL_EVAL_16 (poly, x) * (x) + (poly)->coeff[18]) +#define BABL_POLYNOMIAL_EVAL_19(poly, x) (BABL_POLYNOMIAL_EVAL_17 (poly, x) * (x) + (poly)->coeff[19]) +#define BABL_POLYNOMIAL_EVAL_20(poly, x) (BABL_POLYNOMIAL_EVAL_18 (poly, x) * (x) + (poly)->coeff[20]) +#define BABL_POLYNOMIAL_EVAL_21(poly, x) (BABL_POLYNOMIAL_EVAL_19 (poly, x) * (x) + (poly)->coeff[21]) +#define BABL_POLYNOMIAL_EVAL_22(poly, x) (BABL_POLYNOMIAL_EVAL_20 (poly, x) * (x) + (poly)->coeff[22]) + +#define BABL_POLYNOMIAL_DEGREE(i, i_1) \ + static double \ + babl_polynomial_eval_1_##i (const BablPolynomial *poly, \ + double x) \ + { \ + /* quiet clang warnings */ \ + const BablBigPolynomial *const big_poly = (const BablBigPolynomial *) poly;\ + \ + const double x2 = x * x; \ + (void) x2; \ + \ + return BABL_POLYNOMIAL_EVAL_##i (big_poly, x2) + \ + BABL_POLYNOMIAL_EVAL_##i_1 (big_poly, x2) * x; \ + } +#include "babl-polynomial.c" + +#define BABL_POLYNOMIAL_DEGREE(i, i_1) \ + static double \ + babl_polynomial_eval_2_##i (const BablPolynomial *poly, \ + double x) \ + { \ + /* quiet clang warnings */ \ + const BablBigPolynomial *const big_poly = (const BablBigPolynomial *) poly;\ + \ + return BABL_POLYNOMIAL_EVAL_##i (big_poly, x) + \ + BABL_POLYNOMIAL_EVAL_##i_1 (big_poly, x) * sqrt (x); \ + } +#include "babl-polynomial.c" + +static const BablPolynomialEvalFunc babl_polynomial_eval_funcs[BABL_POLYNOMIAL_MAX_SCALE] + [BABL_BIG_POLYNOMIAL_MAX_DEGREE + 1] = +{ + { + #define BABL_POLYNOMIAL_DEGREE(i, i_1) babl_polynomial_eval_1_##i, + #include "babl-polynomial.c" + }, + { + #define BABL_POLYNOMIAL_DEGREE(i, i_1) babl_polynomial_eval_2_##i, + #include "babl-polynomial.c" + } +}; + + +static void +babl_polynomial_set_degree (BablPolynomial *poly, + int degree, + int scale) +{ + babl_assert (degree >= BABL_POLYNOMIAL_MIN_DEGREE && + degree <= BABL_BIG_POLYNOMIAL_MAX_DEGREE); + babl_assert (scale >= BABL_POLYNOMIAL_MIN_SCALE && + scale <= BABL_POLYNOMIAL_MAX_SCALE); + + poly->eval = babl_polynomial_eval_funcs[scale - 1][degree]; + poly->degree = degree; + poly->scale = scale; +} + +static double +babl_polynomial_get (const BablPolynomial *poly, + int i) +{ + return poly->coeff[poly->degree - i]; +} + +static void +babl_polynomial_set (BablPolynomial *poly, + int i, + double c) +{ + poly->coeff[poly->degree - i] = c; +} + +static void +babl_polynomial_copy (BablPolynomial *poly, + const BablPolynomial *rpoly) +{ + poly->eval = rpoly->eval; + poly->degree = rpoly->degree; + poly->scale = rpoly->scale; + memcpy (poly->coeff, rpoly->coeff, (rpoly->degree + 1) * sizeof (double)); +} + +static void +babl_polynomial_reset (BablPolynomial *poly, + int scale) +{ + babl_polynomial_set_degree (poly, 0, scale); + babl_polynomial_set (poly, 0, 0.0); +} + +static void +babl_polynomial_shrink (BablPolynomial *poly) +{ + int i; + + for (i = 0; i <= poly->degree; i++) + { + if (fabs (poly->coeff[i]) > EPSILON) + break; + } + + if (i == poly->degree + 1) + { + babl_polynomial_reset (poly, poly->scale); + } + else if (i > 0) + { + memmove (poly->coeff, &poly->coeff[i], + (poly->degree - i + 1) * sizeof (double)); + + babl_polynomial_set_degree (poly, poly->degree - i, poly->scale); + } +} + +static void +babl_polynomial_add (BablPolynomial *poly, + const BablPolynomial *rpoly) +{ + int i; + + babl_assert (poly->scale == rpoly->scale); + + if (poly->degree >= rpoly->degree) + { + for (i = 0; i <= rpoly->degree; i++) + { + babl_polynomial_set (poly, i, babl_polynomial_get (poly, i) + + babl_polynomial_get (rpoly, i)); + } + } + else + { + int orig_degree = poly->degree; + + babl_polynomial_set_degree (poly, rpoly->degree, poly->scale); + + for (i = 0; i <= orig_degree; i++) + { + babl_polynomial_set (poly, i, poly->coeff[orig_degree - i] + + babl_polynomial_get (rpoly, i)); + } + + for (; i <= rpoly->degree; i++) + babl_polynomial_set (poly, i, babl_polynomial_get (rpoly, i)); + } +} + +static void +babl_polynomial_sub (BablPolynomial *poly, + const BablPolynomial *rpoly) +{ + int i; + + babl_assert (poly->scale == rpoly->scale); + + if (poly->degree >= rpoly->degree) + { + for (i = 0; i <= rpoly->degree; i++) + { + babl_polynomial_set (poly, i, babl_polynomial_get (poly, i) - + babl_polynomial_get (rpoly, i)); + } + } + else + { + int orig_degree = poly->degree; + + babl_polynomial_set_degree (poly, rpoly->degree, poly->scale); + + for (i = 0; i <= orig_degree; i++) + { + babl_polynomial_set (poly, i, poly->coeff[orig_degree - i] - + babl_polynomial_get (rpoly, i)); + } + + for (; i <= rpoly->degree; i++) + babl_polynomial_set (poly, i, -babl_polynomial_get (rpoly, i)); + } +} + +static void +babl_polynomial_scalar_mul (BablPolynomial *poly, + double a) +{ + int i; + + for (i = 0; i <= poly->degree; i++) + poly->coeff[i] *= a; +} + +static void +babl_polynomial_scalar_div (BablPolynomial *poly, + double a) +{ + int i; + + for (i = 0; i <= poly->degree; i++) + poly->coeff[i] /= a; +} + +static void +babl_polynomial_mul_copy (BablPolynomial *poly, + const BablPolynomial *poly1, + const BablPolynomial *poly2) +{ + int i; + int j; + + babl_assert (poly1->scale == poly2->scale); + + babl_polynomial_set_degree (poly, poly1->degree + poly2->degree, poly1->scale); + + memset (poly->coeff, 0, (poly->degree + 1) * sizeof (double)); + + for (i = poly1->degree; i >= 0; i--) + { + for (j = poly2->degree; j >= 0; j--) + { + babl_polynomial_set (poly, i + j, babl_polynomial_get (poly, i + j) + + babl_polynomial_get (poly1, i) * + babl_polynomial_get (poly2, j)); + } + } +} + +static void +babl_polynomial_integrate (BablPolynomial *poly) +{ + int i; + + babl_polynomial_set_degree (poly, poly->degree + poly->scale, poly->scale); + + for (i = 0; i <= poly->degree - poly->scale; i++) + { + poly->coeff[i] *= poly->scale; + poly->coeff[i] /= poly->degree - i; + } + + for (; i <= poly->degree; i++) + poly->coeff[i] = 0.0; +} + +static void +babl_polynomial_gamma_integrate (BablPolynomial *poly, + double gamma) +{ + int i; + + babl_polynomial_set_degree (poly, poly->degree + poly->scale, poly->scale); + + gamma *= poly->scale; + + for (i = 0; i <= poly->degree - poly->scale; i++) + { + poly->coeff[i] *= poly->scale; + poly->coeff[i] /= poly->degree - i + gamma; + } + + for (; i <= poly->degree; i++) + poly->coeff[i] = 0.0; +} + +static double +babl_polynomial_inner_product (const BablPolynomial *poly1, + const BablPolynomial *poly2, + double x0, + double x1) +{ + BablBigPolynomial temp; + + babl_polynomial_mul_copy ((BablPolynomial *) &temp, poly1, poly2); + babl_polynomial_integrate ((BablPolynomial *) &temp); + + return babl_polynomial_eval ((BablPolynomial *) &temp, x1) - + babl_polynomial_eval ((BablPolynomial *) &temp, x0); +} + +static double +babl_polynomial_gamma_inner_product (const BablPolynomial *poly, + double gamma, + double x0, + double x1) +{ + BablBigPolynomial temp; + + babl_polynomial_copy ((BablPolynomial *) &temp, poly); + babl_polynomial_gamma_integrate ((BablPolynomial *) &temp, gamma); + + return babl_polynomial_eval ((BablPolynomial *) &temp, x1) * pow (x1, gamma) - + babl_polynomial_eval ((BablPolynomial *) &temp, x0) * pow (x0, gamma); +} + +static double +babl_polynomial_norm (const BablPolynomial *poly, + double x0, + double x1) +{ + return sqrt (babl_polynomial_inner_product (poly, poly, x0, x1)); +} + +static void +babl_polynomial_normalize (BablPolynomial *poly, + double x0, + double x1) +{ + double norm; + + norm = babl_polynomial_norm (poly, x0, x1); + + if (norm > EPSILON) + babl_polynomial_scalar_div (poly, norm); +} + +static void +babl_polynomial_project_copy (BablPolynomial *poly, + const BablPolynomial *rpoly, + const BablPolynomial *basis, + int basis_n, + double x0, + double x1) +{ + int i; + + babl_assert (basis_n > 0); + + babl_polynomial_reset (poly, basis[0].scale); + + for (i = 0; i < basis_n; i++) + { + BablPolynomial temp; + + babl_polynomial_copy (&temp, &basis[i]); + babl_polynomial_scalar_mul (&temp, + babl_polynomial_inner_product (&temp, rpoly, + x0, x1)); + babl_polynomial_add (poly, &temp); + } +} + +static void +babl_polynomial_gamma_project_copy (BablPolynomial *poly, + double gamma, + const BablPolynomial *basis, + int basis_n, + double x0, + double x1) +{ + int i; + + babl_assert (basis_n > 0); + + babl_polynomial_reset (poly, basis[0].scale); + + for (i = 0; i < basis_n; i++) + { + BablPolynomial temp; + + babl_polynomial_copy (&temp, &basis[i]); + babl_polynomial_scalar_mul (&temp, + babl_polynomial_gamma_inner_product (&temp, + gamma, + x0, x1)); + babl_polynomial_add (poly, &temp); + } +} + +static void +babl_polynomial_gram_schmidt (BablPolynomial *basis, + int basis_n, + double x0, + double x1) +{ + int i; + + for (i = 0; i < basis_n; i++) + { + if (i > 0) + { + BablPolynomial temp; + + babl_polynomial_project_copy (&temp, &basis[i], basis, i, x0, x1); + babl_polynomial_sub (&basis[i], &temp); + } + + babl_polynomial_normalize (&basis[i], x0, x1); + } +} + +static void +babl_polynomial_basis (BablPolynomial *basis, + int basis_n, + int scale) +{ + int i; + + for (i = 0; i < basis_n; i++) + { + babl_polynomial_set_degree (&basis[i], i, scale); + + basis[i].coeff[0] = 1.0; + memset (&basis[i].coeff[1], 0, i * sizeof (double)); + } +} + +static void +babl_polynomial_orthonormal_basis (BablPolynomial *basis, + int basis_n, + double x0, + double x1, + int scale) +{ + babl_polynomial_basis (basis, basis_n, scale); + babl_polynomial_gram_schmidt (basis, basis_n, x0, x1); +} + +void +babl_polynomial_approximate_gamma (BablPolynomial *poly, + double gamma, + double x0, + double x1, + int degree, + int scale) +{ + BablPolynomial *basis; + + babl_assert (poly != NULL); + babl_assert (gamma >= 0.0); + babl_assert (x0 >= 0.0); + babl_assert (x0 < x1); + babl_assert (degree >= BABL_POLYNOMIAL_MIN_DEGREE && + degree <= BABL_POLYNOMIAL_MAX_DEGREE); + babl_assert (scale >= BABL_POLYNOMIAL_MIN_SCALE && + scale <= BABL_POLYNOMIAL_MAX_SCALE); + + basis = alloca ((degree + 1) * sizeof (BablPolynomial)); + + babl_polynomial_orthonormal_basis (basis, degree + 1, x0, x1, scale); + + babl_polynomial_gamma_project_copy (poly, gamma, basis, degree + 1, x0, x1); + babl_polynomial_shrink (poly); +} + +#endif diff --git a/babl/babl-polynomial.h b/babl/babl-polynomial.h new file mode 100644 index 0000000..233c743 --- /dev/null +++ b/babl/babl-polynomial.h @@ -0,0 +1,79 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2017, Øyvind Kolås and others. + * + * babl-polynomial.h + * Copyright (C) 2017 Ell + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#ifndef _BABL_POLYNOMIAL_H +#define _BABL_POLYNOMIAL_H + + +/* BablPolynomial is an opaque type representing a real polynomial of a real + * variable. In addition to a degree, polynomials have an associated *scale*, + * which divides the exponents of the polynomial's terms. For example, a + * polynomial of degree 3 and of scale 1 has the form + * `c0*x^0 + c1*x^1 + c2*x^2 + c3*x^3`, while a polynomial of degree 3 and of + * scale 2 has the form `c0*x^0 + c1*x^0.5 + c2*x^1 + c3*x^1.5`. + */ + + +#define BABL_POLYNOMIAL_MIN_DEGREE 0 +#define BABL_POLYNOMIAL_MAX_DEGREE 10 + +#define BABL_POLYNOMIAL_MIN_SCALE 1 +#define BABL_POLYNOMIAL_MAX_SCALE 2 + + +typedef struct BablPolynomial BablPolynomial; + +typedef double (* BablPolynomialEvalFunc) (const BablPolynomial *poly, + double x); + + +struct BablPolynomial +{ + BablPolynomialEvalFunc eval; + int degree; + int scale; + double coeff[BABL_POLYNOMIAL_MAX_DEGREE + 1]; +}; + + +/* evaluates `poly` at `x`. */ +static inline double +babl_polynomial_eval (const BablPolynomial *poly, + double x) +{ + return poly->eval (poly, x); +} + + +/* calculates the polynomial of maximal degree `degree` and of scale `scale`, + * that minimizes the total error w.r.t. the gamma function `gamma`, over the + * range `[x0, x1]`. + */ +void +babl_polynomial_approximate_gamma (BablPolynomial *poly, + double gamma, + double x0, + double x1, + int degree, + int scale); + + +#endif diff --git a/babl/babl-ref-pixels.c b/babl/babl-ref-pixels.c new file mode 100644 index 0000000..265c1c8 --- /dev/null +++ b/babl/babl-ref-pixels.c @@ -0,0 +1,81 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005 Øyvind Kolås + * 2013 Daniel Sabo + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "babl-ref-pixels.h" +#include "babl-ref-pixels.inc" + +int +babl_get_num_path_test_pixels (void) +{ + return babl_num_path_test_pixels; +} + +int +babl_get_num_conversion_test_pixels (void) +{ + return babl_num_conversion_test_pixels; +} + +int +babl_get_num_format_test_pixels (void) +{ + return babl_num_format_test_pixels; +} + +int +babl_get_num_model_test_pixels (void) +{ + return babl_num_model_test_pixels; +} + +int +babl_get_num_type_test_pixels (void) +{ + return babl_num_type_test_pixels; +} + +const double * +babl_get_path_test_pixels (void) +{ + return babl_path_test_pixels; +} + +const double * +babl_get_conversion_test_pixels (void) +{ + return babl_conversion_test_pixels; +} + +const double * +babl_get_format_test_pixels (void) +{ + return babl_format_test_pixels; +} + +const double * +babl_get_model_test_pixels (void) +{ + return babl_model_test_pixels; +} + +const double * +babl_get_type_test_pixels (void) +{ + return babl_type_test_pixels; +} diff --git a/babl/babl-ref-pixels.h b/babl/babl-ref-pixels.h new file mode 100644 index 0000000..cab49ed --- /dev/null +++ b/babl/babl-ref-pixels.h @@ -0,0 +1,34 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005-2008, Øyvind Kolås and others. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#ifndef _BABL_REF_PIXELS_H +#define _BABL_REF_PIXELS_H + +int babl_get_num_path_test_pixels (void); +int babl_get_num_conversion_test_pixels (void); +int babl_get_num_format_test_pixels (void); +int babl_get_num_model_test_pixels (void); +int babl_get_num_type_test_pixels (void); + +const double *babl_get_path_test_pixels (void); +const double *babl_get_conversion_test_pixels (void); +const double *babl_get_format_test_pixels (void); +const double *babl_get_model_test_pixels (void); +const double *babl_get_type_test_pixels (void); + +#endif /* _BABL_REF_PIXELS_H */ \ No newline at end of file diff --git a/babl/babl-ref-pixels.inc b/babl/babl-ref-pixels.inc new file mode 100644 index 0000000..b706da7 --- /dev/null +++ b/babl/babl-ref-pixels.inc @@ -0,0 +1,4140 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005 Øyvind Kolås + * 2013 Daniel Sabo + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +/* THIS IS A GENERATED FILE - DO NOT EDIT */ + +static const int babl_num_path_test_pixels = 3072; + +static const double babl_path_test_pixels[12288] = { +0.7718567535150, 0.7514902249684, 0.9248924855724, 0.0955070830395, +0.1025725035475, 0.4075078840402, 0.6785853950673, 0.9634626577438, +0.9553271694832, 0.1067870907051, 0.3603431430461, 0.5144157584358, +0.2521084366609, 0.1242231042703, 0.2321393006631, 0.7137176574737, +0.7002526473721, 0.6853307782138, 0.3886525502376, 0.9672617432509, +0.4827699570371, 0.5637687419372, 0.9882396813427, 0.5632248975165, +0.6371306197891, 0.7984740379259, 0.1965256124719, 0.5864613962297, +0.8423190181341, 0.2221470797538, 0.1378166187265, 0.7468119350946, +0.0261717611114, 0.6141757711834, 0.9736373051878, 0.0627091038333, +0.1666384582252, 0.1287442646589, 0.0216836552237, 0.6522226997894, +0.0957444552778, 0.1219656272428, 0.2355313558297, 0.3820267982697, +0.4349323992780, 0.3478528919387, 0.2461887315131, 0.4676706564928, +0.1980661788015, 0.1351850461844, 0.0331836701525, 0.6348412817506, +0.6078847472593, 0.6808361358386, 0.6989537881217, 0.0214233510296, +0.6422913356881, 0.2450153670483, 0.4793101737645, 0.8954794010592, +0.6798358967900, 0.4846103533565, 0.4671624468021, 0.6171267924910, +0.0930224513137, 0.7060076579014, 0.0987861240743, 0.4407997515243, +0.5024965775677, 0.2596609095389, 0.8347519230259, 0.1204697792979, +0.5379539348827, 0.5982410328455, 0.3816265367817, 0.0702832783900, +0.2626565495798, 0.9728863341608, 0.9460939252498, 0.6278152682948, +0.0007009459663, 0.4607227283813, 0.1080713798795, 0.9792775954023, +0.7025045685947, 0.6085856936912, 0.1415588637542, 0.8070251680012, +0.2379958300097, 0.3447959038172, 0.8536010607395, 0.6208690375187, +0.7615632590659, 0.9178317267996, 0.8294062571737, 0.3207635070760, +0.0486621605459, 0.8545857103796, 0.6238393842354, 0.9281923817136, +0.5288745851856, 0.5511587385792, 0.1142466194528, 0.4585913067956, +0.1236884240637, 0.0668285196027, 0.1493997709590, 0.4958731562346, +0.0747712906798, 0.3863449736435, 0.0397148532978, 0.0954936957431, +0.9548114016442, 0.0754722371118, 0.8470677020247, 0.1477862331773, +0.6094956032976, 0.6573159697732, 0.6840579308030, 0.9886265657789, +0.8584224981528, 0.8474914333073, 0.0021118735904, 0.5376589910768, +0.7597105120121, 0.6199857567530, 0.7653231596413, 0.8315181307641, +0.8477538506723, 0.8083726730237, 0.4745714666669, 0.3891625434110, +0.0846912418887, 0.3766284353922, 0.3595314111372, 0.5888180861197, +0.6044248783050, 0.2083796659524, 0.4434569554606, 0.5089311820962, +0.6309580424013, 0.6791961689848, 0.5947246395958, 0.4831718087584, +0.4304189069338, 0.5857694435798, 0.7546684060966, 0.4417923411549, +0.9763853275107, 0.0399145097658, 0.2430854128874, 0.4387263364339, +0.0767154172420, 0.8348078256635, 0.8874059430731, 0.2451972864779, +0.0418916451940, 0.8364259292541, 0.4547935819508, 0.6527291022487, +0.5181831347375, 0.8896454958663, 0.6447986018121, 0.9293650490834, +0.5132611950456, 0.6028743770918, 0.2662739312585, 0.0043300124837, +0.1929026950118, 0.1176860728849, 0.8112540430442, 0.7097308867191, +0.8477710237949, 0.8238607374131, 0.7968822418698, 0.4059786826400, +0.9902769844002, 0.2781899302631, 0.4096301805273, 0.5515506479664, +0.8979128803582, 0.9666623119110, 0.3181044400288, 0.6527155938804, +0.8582394848849, 0.9746282976003, 0.8014701371088, 0.2055103826362, +0.1856287672117, 0.9001311305445, 0.8110542268544, 0.2562637185940, +0.4601828411502, 0.7038119024149, 0.7897766259451, 0.4558528282008, +0.7657814434570, 0.9734440361957, 0.3066862790411, 0.0560505567380, +0.5239190042596, 0.9586841389344, 0.0911301086150, 0.1179403216196, +0.4395629979854, 0.3716900280545, 0.7825448758819, 0.8880123504847, +0.8448906502895, 0.4298399823857, 0.6498799583176, 0.1921750564092, +0.1734947809826, 0.7428035301821, 0.3965022938310, 0.9679843988120, +0.4542361490681, 0.0317342658675, 0.7174318277824, 0.1979724304741, +0.9843388823719, 0.6398649167455, 0.9318653964120, 0.5284860541711, +0.7776925790951, 0.4445217230565, 0.3436768186948, 0.7216420218915, +0.7683034193554, 0.5434740220865, 0.4179657587865, 0.6503630977358, +0.3971082178862, 0.2922224236150, 0.5021581605553, 0.5090958674015, +0.4768780928463, 0.8366712158717, 0.6639124516695, 0.2847030364371, +0.2817768078678, 0.3217687426702, 0.2665111977917, 0.3137924095214, +0.8609859220968, 0.4552715893161, 0.0645722723867, 0.6630134916226, +0.3104901538745, 0.3152220711649, 0.4870058551836, 0.7820041001691, +0.1405132725558, 0.2948290362464, 0.9550869879104, 0.4188712511300, +0.9491269038753, 0.9182058516509, 0.7393507593029, 0.2987638061395, +0.6664123854909, 0.7174303227651, 0.4616798737374, 0.1573165180894, +0.2485410702641, 0.0635206029115, 0.0096527459145, 0.9638380342926, +0.9873576075711, 0.7254191631104, 0.9001918192488, 0.6735651975840, +0.8297165086631, 0.2691344149733, 0.0471879053149, 0.1667030165748, +0.8937642783363, 0.6907024302942, 0.7244060042894, 0.1117601781673, +0.6302831101372, 0.2042544322108, 0.0059245009934, 0.2114118590073, +0.2597752945776, 0.7707963831587, 0.4990834684573, 0.9610114889038, +0.3957507453839, 0.2089021979873, 0.6890022343439, 0.2384342272945, +0.1145201419082, 0.0621631308748, 0.9263325212180, 0.1506821076156, +0.6095504647165, 0.3630612121723, 0.1256837337863, 0.9359852671325, +0.1925785696099, 0.5969080718220, 0.0884803752827, 0.0258755525695, +0.2474284587649, 0.0222950778074, 0.8660424867952, 0.1356682805976, +0.8018603500919, 0.1411927371012, 0.7129975081016, 0.5904484910846, +0.6799334979988, 0.4321434602291, 0.3454471693120, 0.7189220095607, +0.0829648645981, 0.9397087930421, 0.2029398429221, 0.8445306377693, +0.0426241848816, 0.4787156104477, 0.1486109905637, 0.8919420772660, +0.0109287784486, 0.1571443267898, 0.5408787413225, 0.0749435113161, +0.6924380281439, 0.6204792431651, 0.5202055389621, 0.6665624751088, +0.7443541953081, 0.8850165977539, 0.2173873145214, 0.6086859142448, +0.6738782919356, 0.9917826540730, 0.9073116755613, 0.0834298008510, +0.3392311922923, 0.4757386420275, 0.1329753907085, 0.6203091831972, +0.3229531973242, 0.0191646902911, 0.9078821022566, 0.4784225600205, +0.0027640215134, 0.4059180623879, 0.9588734833332, 0.1108219447130, +0.1824279852130, 0.0453882063950, 0.8846336728356, 0.1074844734312, +0.0920748883356, 0.1933567636615, 0.2025325331849, 0.4255124136924, +0.3314239863918, 0.7845129164795, 0.8138360068266, 0.7227380726127, +0.1146531217334, 0.0757781812343, 0.6695295137677, 0.0312233208824, +0.1971503720606, 0.7885314141347, 0.0675608353073, 0.5768411888633, +0.6789587865020, 0.5363815643528, 0.2642700556965, 0.2005362260158, +0.2829741022005, 0.0019119833605, 0.5555462546440, 0.1721521574874, +0.6219042114084, 0.2857381237139, 0.4078300457484, 0.5144197375115, +0.7179761318108, 0.8043321966214, 0.3311263305746, 0.2924637181184, +0.2563969359064, 0.8100510206120, 0.9976889602829, 0.5336588637594, +0.8427482875263, 0.5878209227639, 0.5945639366259, 0.8115249666439, +0.8409346392569, 0.9574014092597, 0.6635991039982, 0.2640934503936, +0.9316961657869, 0.0380850108518, 0.7459328229287, 0.7311599393055, +0.1823550356470, 0.6106549518232, 0.5744665756703, 0.0102028781596, +0.6444325678257, 0.4653291378474, 0.6125669351837, 0.1300128298486, +0.3128606990505, 0.2663367787685, 0.7510672620270, 0.0203969809322, +0.6158524558953, 0.0308368308613, 0.0706689749242, 0.0821935921359, +0.8798829013854, 0.8722493922674, 0.8408878514734, 0.0683579347415, +0.6995452380271, 0.7226311884460, 0.4600703145657, 0.4354517876336, +0.8548293578694, 0.5404798772840, 0.6800325972401, 0.1236694180983, +0.4361682983284, 0.7865255231906, 0.5785648881358, 0.4259654201688, +0.2830442936546, 0.6185233344410, 0.3971804745482, 0.1530314633404, +0.0301443901985, 0.9274768614804, 0.0838524718228, 0.0097474092663, +0.9171133259857, 0.3430050897147, 0.1938136397832, 0.8349197338498, +0.3328405494489, 0.5329657818810, 0.3738419205760, 0.2644826147074, +0.6501815592172, 0.2127234503686, 0.4052151736828, 0.2147297715837, +0.9889549063467, 0.3497267972444, 0.9353546388146, 0.8652854882485, +0.0413526552922, 0.8437842637504, 0.8902066745284, 0.6153872355890, +0.6218030260046, 0.4775209540862, 0.6303097864754, 0.4687715621985, +0.0372376702899, 0.9048473196592, 0.0960442880616, 0.0274902605580, +0.0148164937342, 0.0673820604884, 0.8323241806740, 0.1798967598844, +0.2906204346989, 0.9319298197198, 0.4103871502031, 0.0261378199915, +0.9989588423627, 0.6234609841478, 0.4648956011352, 0.7842290707790, +0.7353962626007, 0.6491404015800, 0.8361844345164, 0.8701107748179, +0.3869263079888, 0.7243511689475, 0.9988671988244, 0.7715390728654, +0.3578454346200, 0.4282789637466, 0.5681354322322, 0.8890738728871, +0.2259354792656, 0.9796484606246, 0.9057999178329, 0.1984452187076, +0.1817409653132, 0.2631731495555, 0.8844957798182, 0.0018442054288, +0.7429577800180, 0.1965574590473, 0.3305552105096, 0.7168199600265, +0.5251714314917, 0.0335782142512, 0.1284872787672, 0.7409423607127, +0.4634936547202, 0.5241302733888, 0.6570391983991, 0.5933828799023, +0.2647627048496, 0.1988899168553, 0.1732706745031, 0.4932236324499, +0.0612117452832, 0.6516890133040, 0.9232410858028, 0.1721378728618, +0.6898217367427, 0.4190571803688, 0.0799679765850, 0.4913765180350, +0.9876120998466, 0.9157572160083, 0.3987056405277, 0.9857678944179, +0.0000213799067, 0.1693530646941, 0.1789303655638, 0.2832014203459, +0.2504279363204, 0.7429791603903, 0.3659105242071, 0.5094855760734, +0.0877806824109, 0.7755993678121, 0.7765573746416, 0.4943978029743, +0.9268202054905, 0.5512743371312, 0.2997296412008, 0.4335965730406, +0.6451381890313, 0.1915829103401, 0.7501642544522, 0.4730003157039, +0.1647818573587, 0.7063499343145, 0.8432719236441, 0.6734053397893, +0.9090077941814, 0.8546035941013, 0.1254071142177, 0.9232399002291, +0.8073141755570, 0.8966198935623, 0.7703608101096, 0.5241127552111, +0.4587767512811, 0.8073355554637, 0.0659729577908, 0.9492911756734, +0.9262812849722, 0.7092046876015, 0.5503147153884, 0.4318834819979, +0.7604686630706, 0.0140619673832, 0.4848040554136, 0.3268720900299, +0.2575340118527, 0.6872888680954, 0.5653363045144, 0.7845336966145, +0.9889058987558, 0.9026722008841, 0.8788717784355, 0.3155005585009, +0.6453836013774, 0.1536877556488, 0.6090221351986, 0.7221437016139, +0.2585420041618, 0.5543913950931, 0.0082913497501, 0.7344292494163, +0.7279433350675, 0.0658561792531, 0.4510112881898, 0.7786521598597, +0.9488677284442, 0.1867200858829, 0.8731917351825, 0.5169842464463, +0.7503785401352, 0.8751490134164, 0.8959247734844, 0.4235064501052, +0.1652625245812, 0.5108472027401, 0.8892109807996, 0.3807288284324, +0.7700478438148, 0.4227965368995, 0.1981360708355, 0.4545472848483, +0.7991515508849, 0.7589537421050, 0.3254687373179, 0.0770078488053, +0.6689201219328, 0.4445351517967, 0.9126414977539, 0.9344908725165, +0.6995850068981, 0.9274621260946, 0.9989265473555, 0.9209328475040, +0.9669220815259, 0.4275283414999, 0.9933183058134, 0.4499378350796, +0.2900164901698, 0.9157898099701, 0.6142484273828, 0.8665100405302, +0.8909020292996, 0.0403950303050, 0.7909388229209, 0.5101732008672, +0.1346970876375, 0.0561645538808, 0.5512422330450, 0.6801498032548, +0.8263861531515, 0.9047449314523, 0.4789610907803, 0.7493783038805, +0.7389207006148, 0.6255377035707, 0.6636986730917, 0.8044298280982, +0.4972730178839, 0.4078408220819, 0.0700728549017, 0.5763401708455, +0.5189372373367, 0.1968580247820, 0.3353029477109, 0.0689994017915, +0.1951312931232, 0.4858593183969, 0.6243863662818, 0.3286212530586, +0.7488079945318, 0.4851477837587, 0.4016491279014, 0.2386347936646, +0.8727377536114, 0.6397100233658, 0.5255428140636, 0.1925879503566, +0.8261633509892, 0.0074348412489, 0.6958745772465, 0.0767850466430, +0.9792654961251, 0.6525495036750, 0.9121797727012, 0.1748356675612, +0.1522186161728, 0.7181861962742, 0.2780872067800, 0.5758784457929, +0.4171594639389, 0.6494916340567, 0.1260270178905, 0.3481600616817, +0.7899512191256, 0.9360967012756, 0.8463496588386, 0.4613299656014, +0.7093708187851, 0.9850825122488, 0.4219560192069, 0.4707360251205, +0.0161930974648, 0.4581788128513, 0.4702302955418, 0.8236051475739, +0.0725581562484, 0.8889308515419, 0.0978888357514, 0.9957731096054, +0.9685990810248, 0.8987215072376, 0.8963656927908, 0.7937634134636, +0.3844239103535, 0.9478645766842, 0.5512710104470, 0.8085454650263, +0.1775182784430, 0.5366425265263, 0.6660507724928, 0.8293582172270, +0.2534077559846, 0.5946777423819, 0.1861341605830, 0.7920777903833, +0.5032198440764, 0.0433589746446, 0.5307744431918, 0.0324838189559, +0.7763356099726, 0.2125906623959, 0.0284414864278, 0.9527304628644, +0.4944448915750, 0.7925287074375, 0.6707694752471, 0.4986717824352, +0.5624217244621, 0.5670030478234, 0.6814595585137, 0.7686583114642, +0.3863707158651, 0.5310208050213, 0.4657245545954, 0.5778252508388, +0.8463537818037, 0.7707946262186, 0.4788853817055, 0.0169955645767, +0.9370139445816, 0.0238720602467, 0.3074371527449, 0.1449361537327, +0.5260551322839, 0.1904217001006, 0.6185498026286, 0.4935713133279, +0.1020547082192, 0.0292749763603, 0.2337806747452, 0.1493242458204, +0.7608939436082, 0.8783903181918, 0.2418656387561, 0.2622221611730, +0.6812934254675, 0.2553388351832, 0.6709190251636, 0.9126351144689, +0.9302038345161, 0.2437151494640, 0.8223418830067, 0.3523785836773, +0.3050620021788, 0.3165745499155, 0.7747359544852, 0.2880664376021, +0.3985574899235, 0.1514157839825, 0.0873691761342, 0.2536213357251, +0.8883776422070, 0.3355714340394, 0.1752878442292, 0.3948063288791, +0.9431618926782, 0.4144327740252, 0.5259931341400, 0.7938376468578, +0.0219959695926, 0.0452166004317, 0.4437077503855, 0.7597738088853, +0.5982085036106, 0.7828899136665, 0.9236069186235, 0.6855733896073, +0.9469045274644, 0.2795019286124, 0.0382287483840, 0.5945259437871, +0.1486370685271, 0.8771083615148, 0.5232170780763, 0.8605706313907, +0.5515743682867, 0.4536990711716, 0.1936829114303, 0.2979530320959, +0.6758584164436, 0.9501318582101, 0.6051148551540, 0.2810520875645, +0.5742403457753, 0.5642360581850, 0.2857032917839, 0.7804026993832, +0.5714702343435, 0.5174022384535, 0.9786688322102, 0.8116964259239, +0.1079499717373, 0.5934662039361, 0.5626188388852, 0.4223765825957, +0.0807517008301, 0.7061584753479, 0.3763561171369, 0.4862257575086, +0.2751554969117, 0.0276562278288, 0.9856604039602, 0.4145848655210, +0.8068305136668, 0.4237925654388, 0.9047645893436, 0.5088774815709, +0.3794995878728, 0.3584048814878, 0.8774916366104, 0.0984475003083, +0.2630091902162, 0.0553580038507, 0.3085367392323, 0.4826064912987, +0.4059364564744, 0.8372495364571, 0.6195940620357, 0.5942400310162, +0.0206394763760, 0.9774066908180, 0.3546517744449, 0.5982628942459, +0.4034963703731, 0.1285894481133, 0.5708728947541, 0.9172706133301, +0.3618138774120, 0.4842480712031, 0.8347479234611, 0.9472290118911, +0.3292858080609, 0.6369693743237, 0.5119042990319, 0.8204083269557, +0.5151163886837, 0.1361163212620, 0.0607619392969, 0.4166688883755, +0.4208600672059, 0.8946159770222, 0.4945212032155, 0.9382535763729, +0.3972979734639, 0.6838692578878, 0.9499739808729, 0.8030579424477, +0.1678309366889, 0.8032344299384, 0.5211187938792, 0.5695680429086, +0.7930411811886, 0.1884704130648, 0.7806411207563, 0.8757705683241, +0.2987430264702, 0.1965375515616, 0.3170598611781, 0.3515140150448, +0.9722161111293, 0.6605569038822, 0.6807856227647, 0.1518077841735, +0.6093588101721, 0.3015019187245, 0.2975262777403, 0.1926899217966, +0.2965417934100, 0.1244751983902, 0.4376182399865, 0.3582882175028, +0.7351973856498, 0.7174018606159, 0.0190911749467, 0.9321394432020, +0.5386331987281, 0.1324953586480, 0.4012711180380, 0.9690651562852, +0.7981604797757, 0.7064641354170, 0.9357297885864, 0.9223899119172, +0.0678849234562, 0.5912016609643, 0.8949345484818, 0.7163709088771, +0.3638021933678, 0.3666279503920, 0.7877392125259, 0.2119944091942, +0.6612147566216, 0.3360183040314, 0.0271848538086, 0.4685248348250, +0.6829993495173, 0.2705735663281, 0.6375202227559, 0.3247111320145, +0.0072779054787, 0.9795411429273, 0.3950487651839, 0.0751384622767, +0.3832050959501, 0.7424752911285, 0.6969430030775, 0.4141399401306, +0.0206040325671, 0.9218382946783, 0.8749706497765, 0.0982141211155, +0.5270713467743, 0.8187645128084, 0.6283024296296, 0.8107004378972, +0.7352313868400, 0.5949562702304, 0.4099661733070, 0.5232369776458, +0.6662302201922, 0.0990335797421, 0.9615842206225, 0.1977053853672, +0.3134802064455, 0.3274449768138, 0.4350518837734, 0.9887690748967, +0.1477105688060, 0.9964795559628, 0.5980185431419, 0.0725721060636, +0.4072072484564, 0.1549884742848, 0.9760206984244, 0.9930673083258, +0.7711778221518, 0.7904123444066, 0.8974637654133, 0.6729637010363, +0.5831348521556, 0.7917818551845, 0.7122506390848, 0.7724344147241, +0.8637900463602, 0.1102061984642, 0.6105463675272, 0.3405530682488, +0.2182179257359, 0.5990214327346, 0.7051624691604, 0.0205125403686, +0.6555157637482, 0.8844481459281, 0.6980550129423, 0.6667466893172, +0.2056790027794, 0.9689959701938, 0.2118931222762, 0.1331068962501, +0.8029789737440, 0.3533895715854, 0.9654755256909, 0.8099116658838, +0.6144599246860, 0.2101862217347, 0.5083780458702, 0.9414962236497, +0.1782762250762, 0.3856377463721, 0.0005985661413, 0.4058418108178, +0.0534022730093, 0.7614110772318, 0.1774196010909, 0.7128492052261, +0.8084785089868, 0.9171923193695, 0.8716172761617, 0.7879659686182, +0.2435264337079, 0.0266964342569, 0.5162137521041, 0.5767797448564, +0.3473756608308, 0.8990421979218, 0.9111445806507, 0.2142687645807, +0.9329493683451, 0.5530546636102, 0.8680381676499, 0.1230377024613, +0.7750099165249, 0.7359283420890, 0.9064442351956, 0.8335136933408, +0.8206640914179, 0.3894698407452, 0.9461145638237, 0.4148222806001, +0.6595623347254, 0.9989403164941, 0.7751075875829, 0.9467131299650, +-0.2595068427080, -0.2870353917997, -0.2396486062741, -0.0474728113261, +-0.7912515861873, -0.4510283341869, -0.3698430728958, -0.3680313305780, +-0.6393605566767, -0.5477251524794, -0.4243318994643, -0.8536293212574, +-0.3901496168180, -0.2919848953802, -0.6486829550232, -0.5131873192793, +-0.9471310944982, -0.4572002484730, -0.7389302322357, -0.7806447873733, +-0.4176637164399, -0.1721211779733, -0.7212719068496, -0.8324859970401, +-0.8284442135265, -0.5969996250221, -0.7826513372281, -0.7751573434915, +-0.0550165614369, -0.1688818788011, -0.5980593089937, -0.0075437496451, +-0.2057392463115, -0.3145234046106, -0.4559172710664, -0.8377079157334, +-0.6793896652196, -0.9969908329644, -0.7655517387975, -0.8257603439622, +-0.7030709580067, -0.3187502214307, -0.5447159849781, -0.1898836382618, +-0.9740437278403, -0.0932205748247, -0.6107351172765, -0.1933989400013, +-0.1821513465523, -0.9211748223385, -0.5504208237633, -0.3496653495122, +-0.0468500736388, -0.5998150629922, -0.0932959998461, -0.2716927306129, +-0.8834910876506, -0.8752942876310, -0.1968146880142, -0.8759473375398, +-0.6325819127413, -0.9385076495532, -0.0441761664321, -0.7948739974736, +1.6741462185393, 1.1616788404815, 1.7469689463018, 1.4999065625015, +1.7915335687769, 1.9947565533196, 1.1646880079828, 1.9814172075044, +1.4265730825377, 1.0884626103046, 1.6760063314233, 1.6199720230047, +1.7156058646346, 1.4525293551630, 1.9952420354799, 1.0652712136811, +1.1731284806380, 1.5334545176166, 1.5313545328245, 1.4448212117165, +1.5621111949729, 1.1262784065335, 1.9336394546244, 1.4380585325128, +1.9419507691366, 1.6786201073223, 1.2509841189026, 1.7368247661445, +1.7067145149720, 1.3093688559296, 1.7401124582347, 1.2068079524705, +1.4684986111096, 1.3808607330457, 1.4710476964112, 1.4870814040709, +1.2557077269329, 1.2600321794208, 1.3756172858996, 1.6357357043939, +1.1168948310040, 1.6822808099362, 1.3484947897254, 1.0516236173229, +1.7885580364561, 1.8325006956386, 1.1348101646336, 1.3437368247396, +1.1042232299709, 1.9616865175598, 1.3659552132552, 1.6661646974581, +1.0364194335586, 1.6663344249438, 1.0879649236277, 1.2995946674140, +1.5457569954664, 1.9783702026952, 1.3449545322661, 1.3389490429959, +1.5721483941060, 1.2524715099728, 1.2877390581592, 1.0850669900352, +0.0406470047499, 0.6333322430185, 0.7587867545703, 0.0000000000000, +0.3006791841708, 0.0089495284525, 0.3945224589643, 0.0000000000000, +0.6491739738962, 0.0605731457754, 0.6502301858972, 0.0000000000000, +0.9929107986358, 0.1774679772451, 0.3325109953678, 0.0000000000000, +0.7814688350919, 0.0099686724180, 0.4673211600014, 0.0000000000000, +0.7431553521860, 0.3759238856732, 0.1334858574595, 0.0000000000000, +0.8311202758137, 0.6755185535529, 0.2377090874304, 0.0000000000000, +0.1700693183439, 0.7119379871115, 0.9040435123742, 0.0000000000000, +0.7158263138103, 0.6903081893410, 0.2489980441746, 0.0000000000000, +0.9682978237831, 0.9780472475002, 0.3340650342098, 0.0000000000000, +0.6016300663360, 0.7368340016049, 0.9062134283158, 0.0000000000000, +0.6105795952541, 0.1313564601035, 0.9468604330657, 0.0000000000000, +0.6711527410295, 0.7815866464663, 0.2475396167708, 0.0000000000000, +0.8486207182746, 0.1140976413684, 0.8967135906670, 0.0000000000000, +0.8585893911582, 0.5814188018355, 0.8896243893027, 0.0000000000000, +0.2345132763658, 0.7149046592949, 0.6710932239290, 0.0000000000000, +0.2453688509974, 0.9100318299187, 0.9526137467253, 0.4142485756493, +0.1056553028085, 0.4154381698069, 0.6219698165646, 0.8566572586338, +0.2903252524744, 0.4397203370182, 0.1312644831516, 0.3122780054399, +0.7011923732707, 0.0271592540793, 0.3459337653340, 0.0995623069348, +0.5403338151706, 0.3117719680591, 0.1585157141828, 0.2927941979341, +0.0542000020175, 0.4370474053719, 0.9829247095543, 0.9401023606491, +0.6901348180557, 0.6356188038530, 0.3266717942090, 0.8315454273632, +0.4120135933217, 0.9246480948872, 0.3505234626823, 0.9977650181380, +0.1597944671101, 0.6573824447847, 0.8346799243403, 0.3031372089419, +0.7689277463448, 0.2654497699186, 0.0728206141260, 0.4566497409049, +0.3036474042123, 0.0592529988192, 0.7051701074025, 0.2040850972776, +0.3438980702050, 0.0048397774831, 0.0864122528985, 0.0511038722708, +0.1850303277304, 0.8842318853756, 0.3166117455422, 0.2449279670813, +0.1310818819940, 0.2392303297479, 0.3212792907475, 0.2995364546308, +0.6457161030945, 0.8212167000497, 0.8748491336009, 0.6479510849565, +0.5285098047594, 0.0577296959505, 0.7458647944712, 0.2253725958175, +0.0371944592508, 0.6883042718695, 0.7151121407352, 0.5805447188115, +0.9920178526044, 0.8061222055955, 0.9537540422537, 0.7879327548612, +0.7100280214613, 0.2956652563511, 0.8653752044148, 0.6589241491905, +0.1967154243946, 0.0539260912006, 0.3005050338341, 0.9517874573133, +0.9166532344728, 0.3817457521249, 0.9381579770419, 0.6171167798420, +0.9073883522802, 0.0477351160011, 0.6209760818728, 0.2594372673237, +0.7211978108255, 0.5531044549090, 0.8689518165164, 0.4958252150080, +0.1953613288679, 0.2497076151193, 0.6108341513252, 0.6148166105220, +0.1138790464559, 0.2325557881187, 0.9380118869888, 0.3259462915947, +0.5506900775017, 0.1058968985946, 0.0386779937142, 0.8917659287768, +0.8558406554423, 0.2607180984974, 0.4015621549457, 0.9040531981290, +0.3191839686219, 0.0525560793712, 0.3146441901637, 0.7020671892455, +0.5122394340635, 0.2358372026290, 0.4343018314961, 0.2528021667399, +0.5511031279113, 0.4196277858781, 0.2835723190958, 0.0552779129032, +0.7673407456686, 0.2723009382711, 0.9727322412528, 0.1525241351465, +0.9095126837071, 0.9627020750021, 0.5220085533904, 0.5835663921123, +0.3517863686903, 0.0233917296973, 0.1952578626551, 0.4600204399135, +0.1379890544983, 0.9024764461920, 0.1292886282919, 0.2339358563693, +0.2329179724832, 0.9938297099405, 0.1631945446894, 0.5308507837033, +0.7306409015929, 0.5521019411050, 0.0463857888460, 0.4778387348530, +0.5359655332453, 0.2428803351907, 0.7879391437340, 0.4806876203421, +0.2240355975107, 0.0870686606909, 0.6625081210688, 0.0715114623641, +0.2188067535026, 0.9913763436449, 0.3593695989621, 0.6352403618559, +0.3413985918003, 0.1283194372097, 0.9540784181813, 0.8813781523525, +0.3832721372057, 0.6931849604906, 0.1517111669070, 0.1493362803708, +0.8118505793679, 0.5212611917040, 0.5956614066826, 0.2809997956646, +0.2366946857593, 0.0447685513854, 0.5150909011788, 0.7588559513720, +0.0421643099013, 0.9673355873522, 0.5968704924904, 0.5614766900248, +0.4563210985886, 0.5781298431466, 0.2102159220773, 0.3848096357588, +0.5079644050021, 0.6803566960992, 0.6651985038375, 0.8727240431461, +0.9059462546864, 0.7267711585047, 0.6717330392784, 0.0245681023340, +0.7751477378305, 0.2473448460211, 0.8550905957143, 0.6258114569941, +0.2878015582859, 0.1584198745705, 0.9405298069774, 0.0068017626213, +0.2950471641007, 0.0996521371881, 0.6796810662745, 0.5361912131944, +0.7562486570125, 0.5317418498601, 0.1444206885735, 0.1947719669876, +0.1261008163570, 0.7984129669137, 0.4990774367466, 0.7412911810639, +0.5820174015043, 0.5824219149456, 0.3765428095947, 0.7092933588239, +0.0663094153005, 0.0899818060407, 0.2627786110448, 0.0417413129666, +0.5603231073172, 0.9722556699869, 0.8167529650111, 0.9345116503232, +0.6786453228810, 0.3354708446821, 0.2196005155424, 0.6718435602597, +0.6963215352485, 0.9664468811669, 0.4938907192526, 0.1601303220541, +0.3683437520491, 0.9913686993492, 0.0660990178893, 0.1735717850614, +0.9518108875266, 0.1245924085959, 0.5231105487436, 0.2105197064628, +0.7314813438484, 0.0779117038836, 0.9230053755096, 0.0221879850245, +0.3412894976052, 0.3134987453527, 0.6603336188292, 0.2995481846386, +0.8576238801971, 0.4075989129057, 0.4034805513935, 0.9231122298739, +0.8920770766642, 0.4179469870487, 0.3798545824270, 0.2202335159389, +0.7595854204891, 0.5707223990796, 0.7534178317308, 0.5994550979694, +0.4208803355791, 0.4559069552719, 0.5371692802464, 0.2473085505177, +0.8137880050641, 0.7892240876282, 0.4472756546211, 0.6032682981357, +0.9925741888548, 0.7655988921251, 0.9138164962241, 0.9703862033646, +0.1363700554410, 0.7240555322375, 0.8435105960087, 0.8368218712680, +0.4269564442462, 0.4776595530462, 0.0375542771246, 0.5038442148379, +0.6612683449226, 0.2845803239777, 0.8852584659519, 0.4410348289837, +0.8645681458826, 0.5533454211212, 0.7025273110264, 0.2651130479132, +0.7032536928091, 0.6241535659061, 0.1240678202007, 0.4559451422915, +0.2645053981172, 0.1241340279226, 0.0800605211780, 0.6612371004472, +0.4977223786980, 0.0782934027157, 0.9133581155508, 0.5273361757991, +0.6639964821115, 0.4902965670872, 0.8438922953065, 0.8271746113092, +0.1912471052218, 0.8003665375525, 0.2143520993247, 0.6874028908496, +0.6929412054331, 0.6182035499337, 0.2780260901330, 0.2519063764493, +0.4283976035325, 0.3542095503557, 0.9027838739114, 0.1632845556192, +0.0612563267635, 0.2929657494151, 0.9075549714768, 0.6053111849377, +0.6928598916590, 0.7645100200384, 0.9171193153211, 0.0316227912119, +0.5245160118325, 0.9573652902420, 0.8886440479609, 0.9971798364991, +0.6291767743552, 0.0222383905306, 0.0356586924920, 0.8020021635117, +0.5669538786481, 0.2931732564667, 0.5125349576178, 0.8795509877985, +0.9787934338575, 0.7582009838699, 0.0935397935535, 0.7268870569425, +0.5348504397715, 0.6717346388249, 0.3764045333380, 0.3715658841522, +0.8844995921871, 0.9632480437696, 0.0259441887149, 0.2791884072494, +0.9651219518693, 0.9457559189507, 0.2562137927190, 0.9334991606574, +0.1705129440737, 0.6579818435283, 0.7102659385233, 0.1733331075745, +0.4009121495303, 0.6950289559062, 0.6153471333046, 0.5989099864843, +0.5305568135951, 0.0300889234199, 0.7172673464367, 0.6510058257966, +0.9566893609970, 0.0975106917776, 0.3232621798866, 0.2298023040545, +0.7883678580580, 0.9354827943889, 0.8557116756475, 0.4168019739058, +0.5113046162349, 0.3232182973638, 0.6072174332138, 0.2321162089855, +0.5666607821205, 0.3958042079563, 0.2864663406678, 0.6331616219288, +0.7160132414270, 0.5317827339898, 0.3415601264413, 0.5426801333868, +0.6507360514490, 0.8865261855007, 0.1897645770524, 0.0518260649647, +0.4561175356880, 0.0516482005136, 0.5815551409412, 0.8051117103571, +0.5286247914325, 0.9866743492832, 0.0817371239335, 0.2988224873779, +0.8218012781915, 0.4853141519638, 0.0841850405951, 0.4049993042857, +0.1720129252281, 0.6101691357839, 0.4207969463527, 0.9398967167083, +0.6611760010296, 0.6833175414630, 0.9333874331477, 0.0280143791009, +0.7625339072023, 0.2278367831501, 0.0791217489536, 0.2198537738155, +0.4725079403597, 0.4785471481637, 0.7596195171399, 0.4206818753950, +0.7544958040838, 0.1232439913430, 0.3650733331987, 0.9493840941924, +0.2454509615178, 0.2106133393061, 0.1748921918566, 0.9466284746056, +0.6616286205415, 0.7740757529503, 0.1972876885893, 0.2566293162557, +0.2213694454270, 0.4834298982673, 0.2593899044485, 0.2814727291844, +0.7082012299021, 0.3933823706551, 0.0935990335856, 0.6801868508012, +0.2468402400831, 0.3693772309317, 0.0766999116525, 0.0269864662676, +0.5765035364667, 0.0093741472854, 0.5972140140818, 0.1558216606061, +0.3062176244828, 0.0490114763607, 0.4879212954491, 0.3568335307561, +0.7996231032534, 0.0607134281009, 0.1722554681693, 0.8529946291135, +0.6037769762817, 0.0450740643056, 0.2713267674070, 0.3471476600259, +0.7500871856464, 0.2654055963575, 0.8191498172559, 0.4686144559964, +0.7587265725055, 0.9714566310735, 0.7488354946248, 0.0785397212387, +0.8694209949437, 0.4669278019420, 0.3648390017286, 0.8424345282104, +0.5973605744528, 0.1162612345611, 0.8363050328737, 0.4415389133811, +0.7903525772460, 0.1738641104539, 0.1256353818465, 0.4335190464899, +0.4665513064091, 0.0965702012631, 0.2228755868147, 0.6135566777613, +0.7422787154756, 0.2661744091968, 0.1572836293640, 0.3951310549840, +0.8972248532331, 0.3460556912916, 0.3112484735023, 0.4286103972367, +0.2089380115312, 0.6473120384139, 0.6114612881148, 0.1303982902925, +0.2027313104843, 0.9676645840368, 0.6187686694873, 0.3602967822739, +0.4251465841314, 0.0721523049623, 0.4345923859787, 0.9836076712159, +0.7044164653422, 0.0225071581185, 0.1884135395235, 0.2708974183867, +0.9276055995969, 0.4947690421225, 0.1963712685725, 0.3140489218356, +0.8143779108368, 0.3941569055403, 0.5913392438513, 0.4192468558528, +0.1772332699863, 0.5566566258467, 0.6603313147371, 0.7486228732153, +0.1019780780664, 0.0744581232194, 0.9027123176040, 0.9715797882395, +0.8744703875270, 0.3109160895976, 0.7217701616333, 0.5141736052531, +0.3241465014052, 0.0772016975457, 0.2785806736343, 0.3405388306549, +0.9840704779998, 0.7492930860023, 0.1493540025080, 0.7131730596131, +0.6518164643328, 0.6884869428764, 0.7718002441208, 0.3377675424971, +0.3874183685460, 0.5794220634640, 0.1832559849989, 0.9681715131589, +0.5232181015998, 0.2017962789171, 0.9735789690044, 0.7745952288502, +0.6054900710497, 0.7004513720518, 0.7584529052295, 0.6339102832758, +0.1753388271552, 0.7074681491160, 0.7749094952712, 0.6611652223678, +0.8372184875595, 0.0498092142166, 0.0183842382479, 0.4966796564388, +0.0101379710297, 0.1613649884990, 0.1270109122279, 0.2969649118823, +0.6141324572331, 0.9942084494951, 0.9106580745013, 0.2763649147359, +0.6506298313153, 0.2659489211002, 0.6826953919058, 0.6824583186221, +0.6405466052892, 0.0380481993957, 0.8453709845642, 0.8659513769047, +0.4528602359131, 0.1637647068891, 0.2398444783128, 0.8189499531029, +0.6594626054445, 0.0583503064971, 0.8642160789409, 0.9982973835423, +0.1358052297196, 0.8348014325997, 0.7658184556131, 0.6391255737465, +0.0811676057434, 0.9730237172791, 0.8846106472819, 0.7842026943267, +0.2879864737801, 0.0913055772387, 0.1343887057781, 0.0116215590442, +0.7275050984358, 0.9021189314789, 0.0855140262682, 0.0450467798137, +0.6341607950787, 0.3781349292854, 0.1680678521134, 0.7682094181740, +0.8323887897806, 0.2747073999023, 0.4161831286811, 0.0134388366777, +0.6543249905362, 0.2852490256937, 0.4384721067913, 0.6560276074596, +0.9418137590130, 0.3137875959807, 0.3435993321909, 0.3026881852665, +0.8936204821307, 0.0776189887326, 0.1485890281147, 0.1094177878040, +0.0448212339752, 0.9747880878741, 0.0506427055461, 0.0331996749310, +0.2300781916036, 0.3328077082209, 0.0660936646471, 0.1850314113242, +0.9198171095549, 0.9575832900394, 0.2349266392341, 0.1516076909153, +0.4164333280252, 0.5539779041679, 0.3357182193248, 0.4029944913476, +0.4079289549999, 0.2488221178059, 0.8286853040702, 0.7519013480059, +0.5698455961281, 0.0622539455361, 0.5340711434996, 0.2671574108615, +0.9870882634945, 0.5116593551411, 0.3760415415168, 0.8776704756905, +0.5578302450282, 0.8807087451595, 0.5892783438737, 0.5246305696315, +0.8249524612096, 0.6026514790033, 0.8554968330336, 0.6399210494198, +0.0731981885960, 0.0550306523475, 0.9354591872243, 0.9215904976807, +0.5733803178060, 0.9930152981510, 0.0126139419212, 0.1703858259927, +0.1002335092520, 0.9898136458312, 0.5469932018532, 0.3483321612460, +0.6428359163193, 0.5081624642518, 0.2386357631714, 0.3756785054578, +0.6503773823615, 0.2126815124474, 0.5704164097879, 0.7727069066710, +0.4710885209362, 0.6374656453903, 0.7243408675885, 0.9464579513047, +0.9535402604162, 0.0289187654988, 0.5181743905499, 0.3136192109965, +0.2952617203329, 0.7784927211602, 0.6315702445021, 0.3736712231178, +0.7374152577191, 0.3684599089289, 0.8335233735077, 0.5670294317263, +0.1944694766749, 0.3107955750594, 0.3614752066142, 0.8461373158945, +0.2841469139253, 0.2947029859269, 0.3006092208906, 0.9084684084675, +0.3119518907331, 0.9269828302446, 0.8028654506443, 0.5392449840620, +0.3197398112713, 0.9623292730946, 0.1396643422263, 0.3732818599666, +0.1776244203456, 0.7908283322076, 0.5997949180192, 0.8640052098148, +0.4916405312212, 0.1311646807618, 0.8197470977063, 0.1179693081034, +0.0183467730034, 0.7869022520198, 0.9096574019220, 0.4513173417427, +0.5893180908586, 0.7557620311881, 0.1553621604831, 0.7431807754297, +0.4253057755648, 0.7837875675335, 0.0665576057819, 0.5168373675630, +0.9064118112002, 0.7094526894900, 0.0784905534603, 0.3671668266725, +0.2546378636056, 0.2183637014676, 0.6364355197346, 0.8813560041046, +0.6401050717757, 0.5743776748769, 0.1806929740965, 0.7760998619609, +0.8984572006848, 0.8177294921213, 0.3652060066188, 0.7804878921157, +0.6362704460678, 0.3900977314404, 0.9488941728831, 0.1849531038594, +0.6017323497691, 0.6546172190712, 0.1769999829945, 0.8585515748051, +0.8491995115062, 0.1910504401620, 0.4103792497937, 0.3323621439433, +0.8441036827136, 0.2745052866053, 0.9748380076954, 0.4769368560412, +0.9346845647947, 0.7505154934481, 0.9839579765610, 0.0533285606901, +0.3964933573252, 0.1893224284003, 0.9688791949157, 0.6203934958300, +0.9300600611279, 0.0365984286352, 0.7637001032772, 0.1495721685465, +0.3138592137554, 0.8285172613470, 0.8543279212221, 0.1289061098960, +0.6617736679789, 0.9501296598232, 0.2186149923218, 0.8032220936395, +0.7279771197252, 0.2635060172824, 0.6047468788944, 0.3956149757819, +0.4920629842636, 0.5771766307657, 0.4545564574444, 0.0151261282224, +0.4827230258299, 0.3361666669772, 0.8516819173711, 0.4293944651398, +0.4560333888307, 0.4174075906246, 0.0866821599597, 0.8356398934664, +0.2051335234219, 0.8525267466216, 0.6067300190249, 0.0555613548754, +0.4993362317324, 0.1351935840841, 0.8891251752568, 0.3704301218365, +0.5466751896528, 0.8131954459535, 0.9637108454312, 0.7434530960133, +0.5779408135349, 0.2084488571661, 0.7633251053110, 0.1823258377529, +0.3831981124278, 0.3059179327944, 0.4719548749141, 0.3680719837398, +0.3559057970326, 0.8752610966914, 0.8830945635601, 0.9265113323585, +0.5704163739320, 0.8386288233281, 0.2114277632029, 0.7347764804656, +0.3536712785036, 0.0264497622971, 0.2560364134871, 0.2981099236282, +0.2331965538828, 0.5588048019255, 0.8789765089187, 0.8627664325120, +0.5115547797231, 0.7325327860809, 0.6939983864753, 0.7681016841755, +0.8400350691937, 0.0582299689102, 0.5457282315687, 0.6577092314408, +0.6771253206195, 0.4179758822629, 0.2666788265420, 0.3090533364141, +0.6651450333489, 0.0603234325816, 0.7238938150573, 0.7386337014561, +0.3417648586173, 0.0210508303815, 0.9355845292730, 0.6069883781518, +0.4451222161041, 0.9121812325493, 0.8596796537096, 0.1470122924759, +0.9784824992430, 0.7987934946077, 0.9386309948464, 0.1157160667310, +0.5857091874749, 0.2116790526601, 0.3575982960675, 0.8176075037651, +0.7093059139835, 0.0972639667323, 0.9442118387410, 0.0515966820771, +0.7989934067237, 0.5493409827116, 0.1554939361082, 0.4899400698440, +0.1608064636406, 0.4761187268776, 0.9673168654401, 0.4221727626501, +0.2981990581836, 0.8259514969894, 0.5364421594592, 0.6912106800318, +0.6190389807425, 0.6399639168009, 0.8470023273709, 0.4720266882666, +0.8223980473459, 0.0641611963809, 0.5521451488846, 0.7066819806149, +0.3083836465647, 0.8008805461232, 0.8629546909886, 0.4907761432653, +0.2721496691332, 0.8940928340396, 0.0125595987833, 0.2205529870561, +0.4467115073682, 0.9814555831167, 0.9913568012376, 0.9567714375242, +0.5690234995303, 0.2457049136263, 0.5307965658283, 0.1468507368801, +0.1893241103689, 0.7298299631708, 0.7218236405038, 0.4981134308028, +0.7302924877639, 0.4875231685524, 0.5557814596946, 0.2582657994974, +0.1094657672148, 0.3493314685064, 0.1274870848877, 0.4027837870656, +0.1704083770376, 0.9318638150263, 0.4134926648873, 0.6796322337723, +0.4970003429321, 0.4787920236023, 0.7327443606838, 0.2764473558760, +0.7020753969914, 0.7691500120653, 0.3728848576419, 0.7453039594671, +0.5110923952940, 0.1487869038939, 0.7506055951820, 0.3642416584139, +0.7795155913474, 0.0801158943587, 0.3944918175202, 0.2814021605446, +0.3745812570558, 0.9688397017162, 0.8099458575295, 0.1163154575584, +0.7685111038240, 0.1048737443541, 0.4563628702687, 0.3657273167585, +0.2634821889286, 0.8779768715044, 0.4542052128605, 0.5838499551564, +0.1441452336238, 0.4338905659662, 0.8098406860651, 0.8676978782135, +0.2878890057504, 0.6411455765558, 0.9126825895685, 0.5425850462832, +0.6498091051587, 0.9899644027417, 0.4102955881554, 0.2855674467448, +0.4423033434163, 0.1609014999871, 0.1387513061700, 0.1609011828717, +0.6495585812487, 0.2218189342980, 0.2410173943457, 0.5332431236902, +0.4166905686337, 0.0241398378388, 0.1906586360143, 0.0509632514096, +0.2308714609737, 0.1852016719921, 0.1290135821928, 0.6470215062830, +0.4509166732668, 0.4943536499023, 0.0631785430308, 0.5832187955190, +0.4156042753791, 0.5950619068905, 0.9282442158685, 0.8730192290959, +0.1264942517162, 0.7034932811295, 0.2362074829807, 0.8409268054370, +0.8074042544735, 0.7763033573405, 0.6934576834056, 0.6465030711361, +0.3654521128002, 0.2497075974241, 0.9372048573276, 0.8322089895756, +0.2291855030829, 0.0150106935832, 0.4715265321878, 0.1782222516733, +0.3092066740194, 0.6458760717166, 0.0391505314220, 0.6621851682021, +0.7513829091337, 0.5400781349931, 0.8310777441743, 0.1681641136148, +0.7672755163011, 0.2022995819348, 0.0344317848954, 0.8942562872052, +0.8036028057354, 0.1828797912145, 0.7973614888253, 0.9626760007640, +0.6800720429421, 0.9300970579172, 0.8863730723441, 0.0335689713403, +0.4120397443939, 0.4874762969499, 0.7064004147921, 0.5798307552840, +0.8218275233274, 0.7774918571941, 0.7371838943740, 0.6436052716540, +0.8708955942983, 0.0510130264103, 0.7925025507773, 0.2087104260962, +0.9998171958140, 0.1801022678521, 0.6968890981269, 0.8316530821992, +0.4222231290407, 0.7512001049478, 0.7201804033109, 0.5279668418355, +0.7172881885047, 0.1894986448761, 0.9534996868826, 0.7546121882063, +0.7844301470483, 0.5208909942400, 0.3723784360906, 0.7508611757079, +0.8385822632530, 0.4645021895247, 0.4509880516916, 0.2587515079690, +0.8009937376720, 0.2506220071812, 0.9519784864746, 0.1573884660180, +0.8978728069448, 0.6228212609993, 0.0281138639097, 0.6891623808486, +0.6522694964205, 0.7687684012432, 0.6738342874096, 0.8206164146870, +0.8986902273720, 0.6520866917689, 0.9488706690953, 0.3707233850708, +0.4236632596812, 0.3209133559470, 0.4032867962510, 0.6690510719405, +0.1076476583759, 0.1409514481858, 0.5104120008230, 0.3567864831336, +0.1415419444170, 0.8920778054241, 0.6618424424258, 0.8827904369136, +0.2702189596697, 0.9801242076699, 0.3565799949489, 0.1128304936517, +0.9977208618064, 0.0712126968760, 0.2307462143855, 0.3085584809578, +0.0794764925165, 0.8955936687512, 0.6940339578753, 0.2588600782952, +0.7385916303557, 0.7317459889370, 0.6643620695287, 0.3678682448193, +0.2822838100988, 0.6372818572620, 0.3838326802402, 0.6132327381583, +0.1439059596248, 0.7059470697799, 0.9581952132090, 0.7871194769568, +0.3513976500143, 0.2515536180006, 0.8468985179658, 0.4686072135664, +0.6215714535776, 0.4929395944313, 0.1436314229591, 0.5087409599259, +0.8087698993314, 0.8917904132473, 0.4730638016356, 0.5002114179079, +0.9626700943162, 0.8064907606721, 0.9630031105890, 0.7038100160210, +0.0249053128180, 0.0421465863670, 0.7020844289577, 0.6570370679987, +0.9796792366447, 0.7634969431737, 0.7738925753040, 0.3664464980208, +0.9448447320353, 0.2619630462779, 0.4007787999701, 0.1577252550785, +0.8275812262798, 0.0887506911944, 0.9679101160578, 0.3589740127134, +0.3235495934838, 0.1789788758284, 0.3403043091950, 0.8148086340236, +0.9841471505278, 0.9451210475271, 0.6719184702597, 0.4839357326198, +0.8487922874507, 0.7929170493935, 0.8369114603088, 0.1449822714296, +0.4569516384308, 0.8114623813012, 0.5994078100656, 0.7999145704321, +0.6679387370441, 0.4818569512488, 0.8536089676682, 0.3014922385577, +0.7852267975850, 0.6476179732232, 0.2453538939568, 0.6275015425065, +0.0051067061746, 0.7300715296204, 0.9095810195010, 0.6461326939269, +0.6922997686510, 0.8326879324544, 0.8188222208148, 0.8774911350931, +0.6430622626297, 0.0158493621349, 0.0116668078171, 0.1591265300098, +0.8285675495065, 0.6272094126917, 0.9609704096620, 0.6835852780769, +0.5977964399372, 0.6773598364915, 0.4201264620852, 0.7978818695051, +0.3210265102429, 0.0547480779024, 0.4888222173270, 0.0195342716852, +0.9699327270360, 0.9889652472869, 0.5366050291511, 0.3424311845295, +0.4280916165691, 0.7551595241554, 0.6365832200444, 0.7819589231079, +0.4236553741729, 0.4331983227437, 0.4852310533101, 0.5461642390798, +0.4631798041347, 0.1159551423583, 0.2658862547324, 0.3040532741249, +0.9611383406264, 0.1062420662987, 0.1318045044932, 0.2775530625496, +0.8906567836602, 0.7897058896672, 0.7334514789905, 0.0927749136895, +0.1731122122952, 0.4884532231318, 0.4670657256930, 0.1535779406100, +0.2983191270839, 0.4941387230037, 0.5432013010342, 0.9558879430200, +0.8617652528276, 0.2682518536543, 0.4831039698250, 0.0798063297196, +0.6658514289492, 0.2898568689310, 0.0234113773440, 0.1196871898694, +0.8126957052446, 0.0895068026565, 0.7230551916748, 0.5086424311198, +0.2664945084911, 0.2758755089137, 0.2054619454804, 0.9889414464072, +0.4300413641287, 0.2276328486519, 0.3821175752124, 0.3372664499736, +0.2691469948129, 0.3206981473233, 0.0173387378535, 0.1155690537372, +0.4402924061009, 0.4422592071082, 0.8091513704551, 0.4844044635465, +0.4321590007433, 0.7386115331848, 0.9363979301119, 0.3523526710236, +0.5391890898064, 0.2939242531052, 0.0068633863734, 0.4195018999369, +0.5389171948372, 0.2050405182899, 0.5837811220362, 0.0302747637174, +0.2957777591868, 0.3516128996162, 0.2945473214120, 0.3068363132453, +0.8372757168660, 0.5622722676779, 0.6274884085299, 0.5000092668925, +0.1251750374796, 0.2673170805291, 0.7899051163299, 0.0096059832767, +0.2916483172642, 0.3943220322925, 0.5880152278524, 0.8072438541834, +0.7495192688655, 0.7319407233651, 0.8365812394007, 0.3971665978419, +0.1924810689839, 0.1816782691431, 0.4705522560843, 0.7729791695126, +0.5076904061752, 0.7316701587903, 0.4756025222482, 0.4774156424577, +0.3662199570640, 0.0466076010124, 0.9367106770802, 0.0593836438187, +0.7312672649190, 0.6619977162508, 0.3982205006286, 0.2312579980266, +0.0353148924351, 0.5685429817850, 0.2242699834631, 0.0257089091585, +0.8214189535107, 0.1604899299147, 0.8358600623141, 0.0141750993273, +0.8210418880084, 0.1130672703092, 0.5548119622072, 0.4238752901665, +0.1643723706549, 0.5705611568739, 0.8450079936744, 0.3913932016079, +0.7929758917508, 0.3568534396388, 0.7522394260169, 0.3155602492930, +0.2872255920839, 0.3006662979259, 0.0885235979634, 0.2278419482651, +0.2564922730701, 0.6534455496135, 0.3472738989383, 0.0252342745779, +0.7712033087254, 0.9877595379892, 0.3154432653987, 0.7454943995669, +0.5538883486548, 0.8065182016261, 0.5563025193085, 0.5397132493275, +0.8160378717892, 0.3753073021655, 0.9670081315408, 0.3921625816227, +0.9132132953560, 0.6370797593319, 0.4883745724747, 0.5218200937481, +0.6489428154421, 0.0775856655452, 0.2076409157401, 0.3333825661491, +0.1877222900222, 0.4419187071928, 0.4344391051840, 0.9598803422227, +0.5481969777253, 0.4749478821060, 0.7425850051188, 0.5229627031474, +0.8353533031584, 0.8046892507955, 0.1283934312539, 0.0898589035915, +0.9835499464458, 0.6065566118837, 0.7924487887847, 0.4438366971183, +0.7409138892502, 0.5374382946349, 0.4130748130442, 0.3487513076275, +0.9019030378675, 0.5569517605738, 0.9127455968003, 0.3800829441194, +0.7345027354241, 0.8151163327578, 0.1940315199057, 0.4011201692750, +0.3615527774028, 0.3834455504005, 0.8927019983030, 0.4016724356458, +0.8501038061688, 0.5492750674250, 0.8253642575933, 0.3271411030214, +0.6578081658379, 0.3983007838942, 0.0242229495310, 0.5679492622465, +0.5964530779032, 0.4931614689963, 0.2029900342240, 0.1526163807849, +0.3441901306362, 0.5800030238833, 0.0997180804143, 0.9954388230086, +0.8928758375779, 0.0851040194207, 0.1174413185182, 0.5127928934585, +0.4313070841279, 0.7947788754454, 0.6420557804602, 0.0301869148529, +0.2377597355460, 0.1658098190864, 0.6098952077375, 0.8360873003658, +0.8297383090620, 0.5993125134145, 0.5492553699525, 0.5025972060406, +0.9425688897923, 0.6798421152308, 0.1485875803738, 0.3746196270802, +0.3254269111554, 0.6003770551646, 0.0781428986593, 0.1728105299048, +0.2765717558919, 0.9218799890587, 0.0935385236952, 0.2811329328833, +0.7060494975681, 0.6207618865281, 0.5018830129420, 0.1932566041095, +0.6495112463131, 0.5989253351460, 0.7058659059489, 0.6193243314602, +0.1840089858435, 0.0808183304411, 0.3937042101257, 0.3479216859433, +0.5061966234381, 0.4217687218551, 0.2466281495274, 0.0035994173976, +0.1705031465602, 0.3359349325001, 0.0210812348039, 0.7958835194800, +0.3424793455482, 0.1130720358868, 0.0157770472652, 0.1696688151777, +0.3750528788078, 0.6679062567036, 0.7134490910514, 0.0939199459245, +0.0002442188562, 0.6516246346997, 0.5897862452966, 0.8069876152123, +0.7109935892331, 0.7062937168899, 0.2723865207622, 0.0916692577729, +0.3261741126544, 0.3605048355463, 0.3052190515703, 0.9782524271767, +0.7025226790935, 0.5101830989635, 0.4413231659873, 0.6989232616960, +0.4838348349947, 0.2087193025317, 0.9319518208187, 0.6879513155147, +0.1227018703347, 0.6543379815548, 0.5446542350318, 0.9530330556226, +0.6543512282215, 0.4651812158829, 0.7674100174417, 0.5604312822970, +0.2878467227741, 0.0294041065636, 0.1330874721208, 0.4808591080275, +0.8145429756560, 0.2880909420960, 0.6810287417290, 0.7228737178831, +0.9316676892022, 0.5255365648891, 0.9943846589860, 0.9534152624912, +0.9985269717865, 0.2578418018566, 0.8860414004354, 0.2996037100906, +0.0153158810061, 0.7010496504144, 0.7680249008201, 0.3273645659570, +0.6530097763301, 0.4991507160008, 0.9097689529461, 0.6999767211731, +0.0148544693435, 0.7757116466648, 0.1534886970899, 0.4544231875122, +0.4017578225591, 0.6692056975650, 0.2408928625476, 0.9208987145316, +0.0968540520858, 0.6896045453332, 0.6986098045942, 0.3739803346684, +0.3330538078831, 0.9113970282075, 0.9776954874292, 0.3796385458576, +0.2716838555744, 0.2647214970853, 0.4369335926310, 0.9720801459495, +0.6503395585578, 0.2702108268953, 0.5225632989419, 0.3229749926007, +0.9905649204695, 0.6656554395639, 0.9712604777754, 0.2905881992963, +0.3354526177679, 0.6435746963339, 0.1648061555646, 0.8810294302558, +0.2391935671862, 0.3503070871114, 0.4192863425330, 0.3182948526546, +0.0341595397490, 0.6409513897453, 0.0195127846764, 0.6601792050806, +0.0977611346626, 0.1310135918348, 0.3305559346129, 0.7181225892706, +0.2803315675260, 0.4308149425456, 0.0424106195767, 0.3082514220421, +0.8023192048084, 0.5520154235661, 0.6955364396309, 0.4793442122076, +0.5086879374034, 0.4526587629005, 0.8222262504614, 0.2180997381071, +0.6745161580269, 0.4992528574072, 0.1183142024643, 0.7934867277711, +0.6014152106836, 0.0099687753292, 0.1428275532754, 0.2831203580290, +0.2222931008890, 0.8406087778698, 0.3602758624406, 0.5621138962741, +0.0979112359220, 0.2564526406380, 0.4815601671494, 0.3797886471170, +0.1203675238045, 0.1956723705845, 0.3874662329384, 0.8121161022280, +0.9092210651884, 0.4006990913305, 0.6264873135958, 0.4298768525151, +0.5401234913339, 0.7115402695311, 0.9527145148966, 0.3220237527611, +0.5684274926635, 0.0488114282716, 0.1641990324316, 0.7749407653580, +0.5656335929249, 0.2429436502247, 0.5480642861445, 0.2825132348959, +0.2530057352283, 0.1670488031428, 0.2529124255539, 0.6908918394199, +0.9929769355771, 0.4752988365829, 0.0076575810125, 0.6131882884601, +0.3013338499243, 0.0908881714991, 0.7317514772209, 0.4892177481620, +0.5490945626745, 0.4217013737288, 0.2865605420836, 0.1192177096937, +0.2350716084405, 0.4583156273972, 0.8224004655249, 0.9130478556794, +0.5500557448482, 0.7751950997744, 0.1698558964626, 0.7751149799559, +0.6165681637901, 0.1184832375117, 0.8240065280460, 0.3340549288942, +0.0629626531447, 0.1822017562493, 0.3614268877364, 0.3720708137248, +0.2275276017503, 0.3159683883730, 0.3492505598577, 0.6143393137559, +0.8461258890322, 0.2205045368618, 0.7912672249560, 0.3569081408702, +0.6422364118706, 0.1474597389565, 0.3113927083609, 0.5230187021769, +0.5110011061239, 0.1913309740794, 0.5691611126853, 0.5979532509101, +0.1666765577005, 0.7460727145644, 0.6496466014765, 0.3915615777446, +0.1535574268333, 0.7167323025487, 0.5212678138731, 0.8195024984048, +0.7173451556439, 0.7701255910891, 0.8352155400604, 0.3452743419191, +0.8109817415527, 0.7803078087886, 0.9523273473384, 0.1966424277968, +0.6584860476006, 0.0385093428374, 0.0962761971617, 0.3015779067304, +0.4105621238288, 0.5046119366328, 0.2590138796992, 0.8875434221176, +0.1683598389702, 0.0527985356994, 0.6520716755893, 0.5704065885257, +0.6127943660192, 0.6793609450941, 0.2441295097788, 0.2212327878090, +0.7132786096601, 0.7794709237197, 0.4254336596585, 0.8937761117210, +0.2919758149851, 0.8668360364935, 0.4962032258027, 0.9467014735316, +0.5280611936599, 0.0093209706290, 0.6369616271169, 0.3314187658631, +0.8908668811856, 0.3390429347470, 0.7896287794177, 0.5892889744552, +0.7734483986969, 0.5493529287862, 0.3775522775844, 0.8859049765793, +0.2069727453436, 0.1840105220601, 0.0539648649534, 0.6365661572835, +0.9272693283517, 0.3753325843137, 0.2368090577595, 0.7060365405427, +0.3747146792592, 0.5400636939053, 0.0546935294078, 0.4809385680039, +0.4268286621323, 0.0879932884537, 0.3195346171593, 0.4801271890663, +0.1471566088252, 0.7188044775831, 0.9548293249471, 0.8157378434277, +0.1810799260536, 0.6752178024851, 0.7281254482121, 0.5917909520640, +0.4036592037434, 0.0719468067735, 0.0142607367664, 0.5177542271641, +0.0283791711686, 0.1771076019747, 0.6212997355598, 0.3918130143507, +0.3813011405902, 0.2353519169778, 0.3611181240348, 0.6752646005132, +0.0788657497982, 0.3085704689420, 0.6106845012916, 0.5979271822599, +0.1455052193000, 0.4535804290574, 0.8486341628472, 0.6653780306994, +0.9839066234342, 0.5723338818980, 0.5415737175111, 0.1681687800065, +0.0881939935909, 0.1310632317937, 0.2911383590154, 0.4964030419925, +0.5370180339259, 0.2692739196444, 0.8062810342788, 0.0192638067618, +0.2123547849303, 0.9406772376693, 0.3412207268836, 0.8205417710452, +0.6377850629565, 0.2407339560989, 0.1177848391783, 0.9625204624434, +0.0768301454730, 0.0190862030811, 0.4760858730767, 0.4789029636788, +0.7521484050677, 0.1556958952712, 0.3276566720231, 0.0867703743683, +0.3444596148769, 0.8976536248334, 0.6092763243286, 0.1762908348703, +0.6472530833666, 0.3283662378454, 0.4699875062657, 0.1508500413740, +0.7803896720430, 0.7354470774231, 0.4594294696392, 0.7611258652812, +0.0862522740319, 0.3174077055032, 0.0047209966018, 0.2657105034523, +0.3084621859288, 0.2986070589622, 0.2580849431726, 0.3459417234855, +0.8547727460297, 0.9462472488853, 0.5393410150611, 0.3758697823509, +0.1021972625061, 0.9316028915027, 0.9653334519664, 0.0154268881378, +0.4692809588598, 0.8543456675738, 0.0872987863083, 0.2929901239895, +0.8474251520109, 0.8137405737367, 0.7519992919415, 0.6965751106369, +0.9831126630228, 0.4946782353775, 0.1421068111165, 0.2219867977416, +0.8672467842080, 0.7635023346001, 0.2301253123349, 0.6015362807557, +0.5807880328879, 0.9534990582399, 0.0809100401033, 0.2348463089368, +0.7148647656268, 0.8892502188167, 0.2521061167364, 0.3389949832759, +0.8068740199352, 0.5696375116565, 0.8354974672364, 0.7914471317974, +0.0938210422610, 0.9090712824413, 0.5012404026935, 0.8008309187371, +0.2851142996387, 0.5631020011208, 0.7634169500151, 0.5885391894675, +0.7374030396982, 0.1325394516497, 0.3768425743919, 0.5154162414909, +0.1204856657984, 0.7205157022553, 0.6272176870272, 0.5189493855084, +0.0921893078332, 0.9877324500064, 0.4840180368554, 0.8573429993621, +0.9039230602346, 0.6729773407210, 0.9412315077806, 0.5649280769587, +0.9847847563144, 0.6187878253957, 0.5622275590721, 0.1933376240513, +0.1985559445799, 0.7916587757839, 0.1884253365865, 0.3977250258428, +0.2782049287475, 0.2923769868409, 0.7007300582252, 0.6896657397457, +0.9795632492656, 0.5633192283862, 0.8554789884274, 0.4641470077746, +0.7512709483277, 0.7169662884981, 0.6958586800359, 0.2323215623537, +0.1804193654938, 0.8717566141262, 0.4374819907534, 0.3230763665974, +0.4864281041019, 0.2726086737926, 0.8594890641326, 0.9215000276088, +0.9940581959645, 0.3903511638708, 0.9455860145137, 0.8007205714475, +0.9055385994285, 0.9788429518132, 0.0091389888009, 0.5078135735857, +0.8872300655987, 0.1040945435428, 0.7705017271314, 0.1975643258530, +0.9353787926656, 0.1654349938805, 0.3964715308493, 0.4712317848910, +0.4842720811648, 0.9149420419312, 0.7287542222667, 0.2519505188111, +0.7476892688999, 0.2355430290268, 0.6319083299636, 0.4246129023026, +0.9908903478602, 0.9281086348594, 0.1072996431530, 0.0693903202514, +0.7675092782674, 0.4773184514965, 0.2007173081863, 0.9667887072856, +0.6541168958201, 0.7615674737662, 0.8676696153673, 0.1463033222343, +0.0743729300212, 0.5596554952486, 0.7404104251137, 0.8768086046338, +0.9821439371361, 0.9616029956199, 0.6637500387913, 0.5109121522451, +0.3121720879861, 0.9175227298017, 0.1270379890348, 0.0602215691750, +0.2804051131384, 0.7964441696165, 0.8324647712672, 0.8557922113015, +0.5337634214823, 0.0280943820384, 0.0319871981777, 0.4643731007652, +0.1060755481506, 0.5246537688769, 0.9562030168978, 0.1392868413307, +0.3032236468528, 0.8735848268837, 0.0019722203733, 0.1569203246184, +0.7464504399088, 0.9573405431385, 0.6351523001842, 0.8696418357406, +0.8864748775430, 0.8208233699300, 0.5169960379214, 0.3755627252979, +0.2409676458877, 0.8686188142135, 0.7824263650842, 0.1807460762471, +0.7652565654205, 0.5531397338738, 0.7861415435496, 0.9094643541190, +0.0829794151164, 0.0456616780933, 0.3495839030247, 0.6186063143511, +0.5208579429988, 0.6167428365987, 0.0737560601317, 0.3815711016681, +0.1868794011822, 0.6269334916151, 0.1413966050099, 0.0299590765638, +0.0130106611238, 0.4901030485007, 0.5005183180331, 0.1433688253832, +0.5112333430495, 0.7594611010325, 0.4474435911735, 0.1356706177516, +0.1451857048763, 0.3977082201269, 0.5802844709625, 0.9644396290949, +0.2721751897001, 0.3861533507640, 0.2663270343404, 0.3627108355810, +0.6710748922411, 0.0374317546549, 0.9392930851035, 0.0524685774243, +0.6704480893307, 0.7540543073574, 0.0830934327483, 0.2888769876626, +0.1868085699094, 0.1913060323295, 0.3707971434904, 0.1568494933456, +0.6555625743491, 0.3736879715573, 0.8182395239446, 0.5121937485003, +0.4544284592636, 0.6685732354729, 0.8637910200580, 0.3187578415120, +0.2756742393950, 0.9656618027788, 0.4280343360398, 0.3112346107658, +0.3710296425834, 0.4208599442713, 0.3633700224400, 0.0083188065366, +0.6821656346704, 0.6432048322834, 0.8070132955010, 0.6296970567804, +0.0351833673358, 0.3532405264458, 0.6806365869383, 0.7463063801389, +0.9205795130323, 0.7056314571321, 0.1072948333376, 0.7637300196866, +0.9902857253283, 0.1073880829417, 0.8969374894616, 0.4780919768280, +0.0339348539868, 0.6458482992118, 0.4810760544991, 0.7151770129405, +0.6561016848572, 0.4883633132504, 0.3144215342190, 0.3448670740914, +0.7507746772611, 0.9317759242522, 0.4540251155635, 0.7424558707245, +0.4470921947840, 0.1218043193788, 0.3526358680579, 0.8173951384692, +0.9059555432321, 0.1292578289887, 0.7650091516622, 0.1596491630933, +0.2093757578215, 0.9411389110336, 0.4824983554345, 0.4456457381349, +0.0678851651344, 0.1299552703881, 0.6467703677000, 0.5897931887721, +0.2588848691708, 0.0581708904627, 0.2373433533299, 0.5437078566960, +0.0632864814546, 0.2928197231576, 0.7040191896744, 0.7184194078289, +0.7608965946179, 0.7193881663118, 0.7811830364080, 0.0184407238934, +0.0526032899751, 0.5116712714134, 0.6511640900984, 0.2352081519716, +0.1634491212496, 0.4996954847591, 0.6334755912579, 0.0037999581563, +0.8441304810551, 0.0694046644817, 0.6289533142135, 0.3984847424545, +0.7012448584201, 0.0535062384110, 0.0105435750496, 0.1114516691824, +0.2010217989800, 0.7691300235545, 0.1834615087991, 0.6573139427497, +0.1392242699579, 0.4599066681508, 0.8273009140172, 0.4208048625946, +0.5497608275850, 0.2025107518781, 0.7527263913083, 0.5313201036916, +0.7691175792222, 0.3106574217373, 0.9218989181900, 0.5339094272507, +0.5768629664447, 0.8217208691974, 0.8223286931507, 0.5730630082884, +0.8542890268631, 0.7403120876943, 0.3214163539565, 0.4558042839429, +0.0618213368868, 0.6984195074525, 0.8097167521760, 0.9503696681701, +0.4775742695097, 0.7630661953069, 0.7519257458634, 0.8202603272257, +0.3561921167915, 0.6785960684896, 0.5321962188614, 0.9353872546625, +0.8908172361044, 0.4954163872150, 0.1385027361747, 0.3594971324129, +0.4251385547338, 0.4405780632238, 0.6979271390931, 0.8912291274831, +0.1928890646402, 0.1942561334904, 0.7512354849611, 0.6198260568175, +0.0293684615890, 0.7697520310850, 0.0159770026877, 0.5735641781118, +0.2877630243487, 0.8836574884521, 0.5100641187793, 0.3373933566443, +0.1400411977153, 0.3495843612354, 0.5820769954389, 0.3197808704897, +0.2693899954992, 0.6176154672250, 0.1126505565423, 0.3340027408367, +0.0043439073508, 0.6255821122907, 0.2962115357147, 0.6448467754036, +0.3259433993725, 0.8951611439209, 0.1209984990400, 0.4347142718894, +0.4387516949506, 0.7510819541063, 0.3357392066790, 0.8189256381332, +0.6605388697519, 0.6316407595908, 0.9453380875966, 0.0869746916401, +0.2987084464630, 0.6899073313409, 0.4013927906758, 0.9613150902844, +0.2312377794791, 0.5864714708116, 0.5735648197930, 0.9114569094551, +0.4896445560686, 0.3712789771945, 0.9360558325127, 0.1556418147663, +0.6935531639930, 0.7590345515679, 0.9888944448851, 0.0487063885893, +0.7198202520236, 0.6978970713438, 0.3846166633929, 0.2851059801342, +0.3245408005661, 0.0457636509304, 0.5930582147991, 0.5056151628986, +0.0157721131182, 0.7632924955167, 0.7968456050366, 0.9287974219438, +0.7034987824520, 0.6763109828701, 0.3949332551076, 0.7421836926333, +0.7077829547728, 0.0022072289149, 0.3662183137453, 0.7963260457834, +0.0954249483046, 0.9390207342520, 0.5886786997266, 0.9397831335383, +0.5734409203629, 0.5850695043733, 0.3102997114464, 0.5247345317736, +0.5843001360001, 0.2669940838902, 0.3441040554755, 0.2991941558659, +0.2343358813014, 0.3041203875580, 0.9648911556997, 0.7287207188684, +0.4867467915112, 0.5588766823331, 0.3498840389540, 0.5579493700331, +0.8889133361582, 0.5025189046294, 0.3221691773842, 0.1467296435250, +0.5134284778095, 0.5924121186102, 0.1788298870338, 0.7171024324918, +0.4848313343175, 0.2212114321167, 0.5946193475251, 0.5450482012448, +0.7080325790253, 0.5802562826221, 0.1602321663686, 0.1832980467860, +0.7697260336809, 0.2814734989225, 0.1653257865297, 0.4705318778150, +0.2381505608736, 0.3540261692153, 0.5484675832784, 0.5094298420052, +0.0713081080799, 0.4724864421750, 0.6581465567733, 0.5133587385124, +0.1547602392522, 0.5580549000567, 0.0313631240425, 0.0080305952616, +0.0706347339184, 0.0436735749448, 0.0605738042205, 0.3535323018923, +0.7844518929648, 0.5840632121936, 0.6360856935550, 0.2394036917199, +0.4140030878661, 0.2692832268166, 0.8052746443102, 0.2307050406144, +0.4360386880282, 0.1220356664257, 0.8495395099044, 0.9655068106789, +0.5242951384393, 0.2057647212435, 0.4035091653483, 0.0148652959684, +0.4653354866734, 0.7624456993129, 0.5597908904589, 0.9519767486267, +0.2259680424938, 0.5366435952190, 0.2349321410223, 0.2179374472322, +0.6198275674227, 0.3807282817460, 0.0946984948100, 0.2662952655304, +0.3946759907504, 0.6904623013411, 0.4244018571565, 0.1552722990305, +0.2911925913259, 0.1791278832495, 0.2745255130690, 0.0604875502458, +0.0453069675925, 0.7051956791921, 0.4484111105317, 0.0798001573793, +0.3128159159388, 0.4813456560864, 0.8272313456178, 0.2979506199704, +0.1827172591270, 0.8371110543781, 0.6871103773299, 0.2307405105004, +0.4648387150210, 0.6480527458005, 0.5995567532254, 0.2469012677888, +0.1007841597781, 0.6908067575147, 0.1846963405538, 0.8344888947133, +0.4346671348599, 0.7206117272007, 0.0715350392608, 0.2793948353638, +0.5564244466631, 0.8293431256103, 0.4110740280762, 0.4959368964173, +0.7653996989901, 0.8476170379890, 0.0084710088598, 0.6855995416109, +0.7548327393619, 0.8107066665826, 0.5528127167154, 0.4568821193915, +0.6107845728336, 0.0676486548351, 0.2920523222033, 0.3800440618675, +0.2260639673220, 0.7935018319606, 0.9047597096789, 0.9791626999989, +0.3388053566864, 0.6909026823430, 0.4415545772955, 0.5043164624387, +0.9056457536787, 0.4395895164644, 0.3817094393921, 0.6262509183149, +0.9491813750701, 0.3403128880729, 0.1602012431995, 0.4532444786528, +0.2568748128865, 0.5056058217332, 0.1696560136833, 0.5712752717413, +0.6350091419346, 0.0222745114110, 0.3532228592565, 0.1781270225430, +0.2860796378395, 0.3898418808309, 0.8329811779936, 0.9060355764376, +0.1041961997301, 0.8968642106731, 0.4574905356660, 0.1250335001969, +0.8665667077836, 0.3302601670522, 0.6903660421681, 0.3622502448793, +0.7581715377784, 0.2053720640044, 0.0211628489295, 0.1319206194635, +0.8561167674400, 0.6638172909915, 0.6449615809345, 0.4028722883216, +0.3764380954096, 0.8052981420445, 0.0041301790644, 0.8051628241340, +0.3519132152907, 0.6333129082962, 0.3109039633120, 0.1737861927477, +0.5701623990062, 0.9869223572253, 0.6555874197071, 0.6641268230342, +0.6136020978976, 0.8562420368456, 0.3767642375905, 0.4885685977007, +0.1965050181358, 0.7177982976277, 0.7531062475187, 0.8342547732565, +0.5753929086846, 0.0630717254537, 0.0480584642142, 0.4434722892211, +0.4720936014653, 0.3335644459974, 0.2684437894581, 0.0692213131437, +0.7185681945265, 0.3282103684397, 0.9973817374545, 0.9134053703926, +0.1752981088009, 0.0950062894705, 0.1335085104841, 0.0015119160533, +0.1085392963647, 0.5272113240916, 0.7283191982323, 0.4444124737961, +0.8724752151745, 0.6787016953708, 0.5141336808513, 0.3839066174738, +0.7251526912326, 0.4860773126064, 0.5349437322165, 0.8908979184418, +0.7315222684906, 0.9216577093683, 0.2038756097685, 0.2880499792695, +0.3211553871264, 0.3069151771753, 0.9847294348221, 0.2519340739827, +0.1665785942071, 0.7932489890574, 0.6404796231727, 0.2531732242802, +0.6393732762148, 0.8851467887336, 0.1214593570314, 0.6378613601615, +0.6993803417773, 0.8146713850157, 0.9801530786698, 0.2549678675155, +0.0923788934445, 0.8079196381420, 0.3418827086416, 0.7084722764364, +0.7469143074690, 0.9648541090846, 0.4866213335128, 0.8560163894929, +0.3096150445331, 0.4720669987016, 0.4509314212254, 0.0215650652636, +0.9067411054423, 0.0411373125581, 0.3937247076043, 0.6548070314596, +0.6316273667066, 0.2278964925687, 0.3480524897333, 0.3784541424264, +0.6263934730675, 0.7982059609137, 0.0211454811604, 0.9885321133717, +0.3975727061730, 0.2657667492823, 0.6833527496473, 0.1426048381918, +0.3719781038221, 0.0969530474846, 0.0804381338323, 0.6635058278514, +0.2783372319668, 0.4643569972666, 0.9048726856266, 0.4223208429396, +0.4130590839372, 0.0252515394358, 0.4292111058855, 0.3914940186737, +0.5349495585705, 0.7226741284703, 0.4973185381374, 0.8801425275766, +0.2694973877023, 0.4416906635471, 0.7638114414941, 0.8910432457417, +0.1003960436678, 0.9011247544089, 0.6695871561158, 0.1118639307618, +0.8333374759338, 0.7267895172009, 0.6993307153226, 0.6907326372763, +0.0461892918899, 0.2309101816411, 0.9925562664832, 0.3826834645042, +0.4953152427894, 0.4181673957120, 0.3278632291257, 0.0729943998498, +0.6242299334259, 0.7736524752219, 0.8825243929785, 0.2327359142866, +0.1918780259750, 0.0372890168975, 0.7989040146577, 0.3117354988641, +0.1872657976054, 0.7268275845455, 0.7599631458334, 0.2962225523294, +0.6356385176236, 0.4567631857734, 0.1685182476270, 0.5237745868618, +0.5288380410191, 0.7360345617570, 0.3578879397166, 0.8381054042085, +0.4399021190777, 0.3621755164872, 0.4628240784923, 0.0572186545735, +0.5283747443596, 0.4860914109676, 0.5930856981283, 0.4553803445098, +0.1536848415405, 0.0236899871489, 0.9042588066795, 0.9209489272539, +0.0985186980565, 0.7779147749664, 0.7973424623708, 0.7867831996581, +0.8924690288922, 0.2903967240315, 0.8152037918638, 0.5962464765628, +0.0989415236278, 0.0797348260319, 0.0172243081113, 0.5751669372316, +0.0238479594811, 0.7345800417171, 0.5364980118053, 0.1857425557383, +0.9516046065612, 0.5526860009659, 0.4706146030084, 0.8943859519876, +0.3888190255448, 0.3915067256389, 0.9148615174530, 0.9334386815007, +0.4288961423696, 0.9171937699044, 0.8775981366064, 0.5079472155813, +0.5686401424783, 0.5825809839100, 0.9408837570534, 0.7818569432860, +0.3344726950556, 0.6671588405348, 0.3604957584108, 0.7382262189585, +0.7508664875062, 0.2269417234822, 0.9575555645663, 0.1756995502746, +0.1605224279503, 0.8498080115997, 0.3066765499798, 0.9747798726777, +0.7375605133071, 0.1843703878971, 0.5843880528511, 0.8431745617851, +0.9884413368946, 0.6891651198683, 0.7370563888629, 0.0550026553939, +0.1598651209659, 0.3772603619738, 0.0806718450415, 0.6519179058503, +0.7401269244683, 0.5887612638011, 0.2944541314125, 0.9582699816480, +0.9735641074244, 0.3087670664809, 0.1713422472455, 0.2353378884659, +0.7075375563966, 0.3080368024800, 0.9759259070158, 0.5318380061220, +0.9082613433284, 0.4584040434372, 0.5349785259622, 0.9334814711164, +0.6848296377272, 0.0687837712787, 0.3082120545712, 0.8416550759420, +0.9476027628163, 0.4223901505686, 0.2531541591758, 0.8926001074224, +0.6421284534233, 0.9360440992452, 0.1115552699713, 0.9902105480387, +0.1504970966608, 0.8019935748549, 0.3133044607534, 0.1922271150128, +0.8430964810974, 0.8906240211290, 0.3907548381904, 0.6077585926316, +0.0939350910922, 0.8166605880562, 0.1993910876100, 0.5620970854359, +0.1087984652765, 0.8014726474888, 0.1246973900705, 0.1753169941601, +0.5013309919747, 0.0170598081393, 0.2598766909260, 0.6596759164984, +0.4606888529196, 0.1861606292362, 0.0858435794180, 0.5680887454972, +0.3292082861668, 0.4082916152702, 0.6085507802705, 0.3389977385937, +0.9123331657203, 0.9713367400557, 0.3443357145155, 0.7201060502418, +0.2653987674347, 0.0628302619154, 0.7733303144450, 0.6576401752688, +0.7261822376056, 0.1084952480665, 0.9534542830444, 0.1640851521697, +0.3281623648145, 0.8201173291635, 0.9251558365883, 0.1528453701887, +0.7095291426915, 0.4369608300910, 0.6215899761867, 0.0498532261932, +0.4495554126099, 0.2108601346663, 0.4540206382303, 0.8814666671126, +0.8788619567076, 0.9102442655294, 0.3970207639025, 0.5398642181139, +0.7256775944148, 0.2080702428744, 0.3185358803340, 0.0055715437073, +0.3205117701183, 0.6380107596694, 0.1794069824644, 0.6628715948494, +0.1168224486135, 0.5859105375530, 0.7008410215847, 0.9527372969094, +0.8071406748179, 0.8430046862192, 0.6944057860851, 0.6542953041635, +0.6694148484009, 0.1353030391668, 0.6631220149170, 0.6195616222078, +0.1661786577507, 0.3789439910925, 0.5722638692578, 0.2847119911037, +0.5661487251363, 0.6157340703605, 0.5898041257587, 0.0262845070224, +0.9923964338342, 0.4450106818439, 0.5259783354243, 0.9868248896612, +0.5073858106078, 0.7180740277833, 0.6530809247182, 0.8445142162240, +0.7852252036264, 0.8278975807260, 0.3560847869870, 0.8324879071827, +0.7112211122695, 0.9020476522399, 0.4138081182790, 0.0569258081060, +0.7277755261063, 0.5183617866218, 0.7450523379934, 0.1082139038985, +0.6928863440141, 0.3971903740415, 0.6536648257885, 0.4081743529105, +0.2522132020687, 0.8590650017648, 0.7761343651340, 0.2259286945806, +0.3527633800883, 0.8183619272049, 0.4747990721254, 0.3659384904271, +0.8452916233080, 0.3451598134568, 0.2633726085831, 0.0007774070840, +0.7489414400183, 0.3526774339158, 0.0632338407744, 0.9164535333013, +0.4762444358674, 0.5341666431791, 0.1805750141761, 0.4193186277614, +0.7025970363536, 0.1874655476713, 0.4362142949534, 0.5943831324551, +0.5894409858572, 0.4303725619942, 0.7058273347587, 0.1812666329468, +0.5854208551279, 0.2823273294057, 0.8275629365014, 0.3594921600816, +0.9696357920624, 0.8376340571966, 0.1413923307049, 0.6036973011697, +0.6169688103800, 0.3223991716851, 0.6559959839359, 0.6161914028303, +0.8358221258204, 0.4622604332223, 0.6675589851418, 0.9193685929847, +0.1501114532119, 0.5847635658387, 0.8149378671380, 0.7307928259162, +0.5898960137693, 0.6263558890793, 0.1189302085521, 0.9955128817798, +0.7364111369180, 0.2924930501229, 0.8138214367506, 0.5551445039712, +0.8791409315910, 0.3258521223095, 0.7228656121170, 0.5196487710437, +0.1541258493225, 0.4645617862533, 0.6081794517153, 0.5504285481528, +0.3657631852505, 0.1237616409193, 0.3021958429842, 0.7495717824202, +0.8775604194391, 0.9827319956304, 0.4461608126043, 0.9581918269201, +0.8445126231967, 0.7133825452595, 0.4449924283870, 0.1137197972805, +0.2554431768392, 0.9946240764086, 0.2981461106325, 0.2599302955251, +0.9722208231558, 0.8453391906085, 0.6209799650223, 0.4170763191847, +0.9544501728166, 0.7086319596081, 0.1378322402657, 0.4348014013072, +0.4111264005355, 0.8335911039419, 0.0344840814520, 0.8606978528484, +0.3922353155875, 0.5652522498580, 0.2981528897295, 0.6426635331673, +0.5585405591682, 0.7579985008379, 0.6890138907773, 0.6003487327138, +0.2488945001964, 0.4361009786074, 0.7407304960027, 0.1351747029159, +0.4456532194492, 0.0934071229274, 0.1494835234012, 0.1857229239241, +0.8647059532184, 0.7010963962884, 0.0880311988704, 0.4476296340337, +0.1438125651999, 0.8369267763742, 0.5464355868969, 0.7090111638927, +0.5449656795454, 0.0982627375509, 0.5455587355166, 0.6842678271626, +0.2227063501359, 0.9560920805466, 0.9318538414928, 0.5800428174343, +0.8303554634705, 0.6149416657234, 0.5213443299389, 0.2300067307567, +0.3455329236321, 0.3888960221731, 0.3729401660957, 0.2103582207162, +0.2993935860225, 0.5944274242941, 0.8249970007804, 0.1136706616327, +0.4221101577497, 0.7450468054717, 0.6878345472216, 0.9744805241816, +0.4848769099847, 0.2868161109680, 0.4461432017601, 0.7758657465577, +0.6768466153540, 0.6286894751846, 0.1237428868766, 0.9925787886570, +0.2493444393619, 0.2218122948994, 0.7269522127355, 0.6693016223932, +0.8888127845194, 0.4720507899635, 0.1779043749803, 0.6588060537627, +0.9096069256354, 0.7191682475243, 0.0869924552212, 0.6992487049192, +0.5736032834154, 0.2551398492675, 0.1080642696973, 0.4599326217826, +0.9075417946594, 0.8729968694379, 0.8495672735616, 0.9330612704777, +0.3132675664096, 0.3296519519434, 0.6180436749095, 0.5374018203176, +0.0567656643953, 0.7981444768599, 0.6164680629114, 0.0641868762040, +0.4095125721812, 0.7336122797493, 0.4268339515789, 0.7402109497880, +0.8125922180771, 0.6588570115431, 0.9554245746487, 0.1537861643144, +0.8325776545483, 0.7014050025965, 0.1309078010409, 0.1333289491634, +0.6778328785104, 0.7421845797180, 0.4205732496551, 0.2179002567278, +0.4616987898302, 0.2514361614601, 0.9973244289855, 0.5286375193524, +0.3842935223991, 0.3692405840239, 0.1244330308980, 0.8468917020815, +0.8066635820114, 0.6975610888086, 0.6988925359672, 0.7424767058075, +0.0555715482009, 0.8634292464067, 0.4957055652028, 0.3153605988786, +0.0763256810961, 0.4650841203821, 0.5970415256904, 0.9225395172474, +0.6857950495024, 0.8889178991732, 0.1239411319252, 0.5524661003391, +0.4727491896938, 0.5183727035850, 0.5903229013040, 0.2548489329661, +0.5395336703116, 0.1505820677386, 0.2605572833030, 0.0108961509591, +0.1047734139044, 0.0012324596761, 0.4020182296643, 0.2578817118229, +0.2689279659041, 0.4890669363034, 0.3704730437000, 0.5264512605623, +0.3847261785458, 0.0755915474499, 0.1866280246464, 0.0693655796672, +0.6048731070966, 0.4402977267468, 0.9390207938566, 0.6823335903149, +0.0885284189547, 0.6811987881927, 0.9053818475946, 0.5360623190813, +0.2841719120202, 0.7743234689228, 0.5701166869002, 0.0293229790541, +0.1713357391634, 0.7569211021796, 0.2926961720421, 0.1604395882042, +0.8111351676337, 0.7108694094749, 0.9075031699182, 0.5532534553452, +0.8359726596791, 0.9159085815381, 0.7121018696167, 0.3095213991169, +0.1519404925182, 0.1049006251175, 0.4049755173758, 0.0825749128510, +0.2739371318714, 0.5366666710641, 0.1804921725674, 0.5916035420222, +0.6555752855053, 0.8788102389680, 0.9769643982765, 0.1195129659583, +0.9116692244595, 0.7441037044600, 0.5600090266950, 0.8823462454054, +0.2905653017995, 0.1958411360140, 0.5184271729171, 0.1301257135952, +0.3643768003045, 0.4619010409629, 0.9527622381937, 0.8111233454249, +0.1697868067631, 0.1755119674725, 0.1727704499721, 0.8602654081119, +0.9674472329055, 0.0057594664422, 0.0914205485449, 0.8848723195888, +0.0879996079430, 0.1193877249581, 0.1106600915597, 0.4963960659208, +0.4106652305511, 0.3619367398144, 0.6560543964878, 0.2911522645928, +0.5153650392384, 0.0662405155908, 0.2407469787825, 0.6330187942986, +0.9308817190728, 0.4270342632323, 0.8103442205164, 0.8007560054775, +0.1398947379272, 0.2214470204066, 0.6228753992463, 0.3287713929679, +0.4359030450861, 0.5042715386973, 0.6833480613694, 0.5756376374399, +0.7409908309304, 0.6056898518492, 0.6797835061698, 0.8561185118072, +0.2676001206355, 0.7084380633703, 0.6114493182914, 0.7712040551804, +0.0132616744438, 0.3555997285785, 0.8278257887940, 0.7221094103167, +0.1168989786491, 0.4239269049950, 0.7175364688586, 0.4838801848161, +0.7590394526529, 0.6322640178875, 0.4901674210514, 0.9582834476411, +0.6292830340701, 0.6899211717257, 0.0592982806541, 0.3005116411021, +0.2578113168747, 0.7691777724629, 0.9113681921323, 0.6821736799004, +0.4508347648433, 0.6937143619609, 0.2734493106946, 0.5947162535017, +0.7244368715791, 0.1918255953080, 0.2994042138101, 0.9532328168644, +0.6329629419525, 0.9920369926803, 0.9002636591439, 0.9108535321014, +0.2119696318228, 0.6462246163963, 0.3476367207932, 0.7280894474723, +0.0234566363615, 0.3288686104719, 0.0701515213913, 0.0651731891861, +0.8608305835448, 0.7824960894801, 0.9611326283594, 0.5603189424427, +0.7026045884484, 0.4901136171492, 0.4724172607401, 0.0204309085479, +0.9785017059085, 0.9604159057887, 0.2592913891465, 0.3837854524068, +0.4859735167054, 0.4293364702861, 0.6541302672839, 0.5327406998411, +0.8643880131954, 0.2104103878189, 0.6211620660597, 0.9535344810940, +0.2495151717446, 0.4973509546823, 0.2024473800335, 0.5214257247380, +0.6152572904784, 0.4614848035674, 0.1435755710786, 0.5500841012923, +0.7740460349126, 0.6387139273056, 0.7903534140393, 0.2137270924699, +0.7719169504810, 0.6348766179918, 0.4212100163201, 0.7514860419331, +0.2774127290013, 0.4745215384637, 0.1249902346753, 0.8936272770602, +0.9170223241286, 0.2559144349098, 0.4349374437867, 0.3842816242875, +0.0426021916990, 0.4029958403683, 0.6852509051958, 0.0890677110707, +0.8278386955279, 0.9069902048944, 0.6134062286529, 0.3064129707899, +0.3659377095131, 0.0773538668069, 0.4043411595767, 0.8158536086864, +0.7616438231252, 0.9811950004572, 0.5388386703743, 0.5479167306553, +0.0806781254153, 0.5356898575722, 0.6199089272972, 0.3291920839479, +0.9347462202118, 0.8525950758963, 0.1705664750983, 0.0411189431516, +0.6798383340611, 0.2121589487475, 0.3271166143600, 0.2955567097736, +0.8511217692174, 0.5968606581897, 0.4680733836573, 0.7620540581467, +0.4597372596430, 0.8937239613820, 0.9998564985580, 0.1533242888531, +0.4291163354316, 0.2875759551709, 0.8007141658108, 0.6132627267452, +0.7529720555772, 0.7950540449447, 0.3649298219778, 0.2050553249219, +0.2329605763000, 0.5146158782368, 0.7762490449363, 0.9037684928178, +0.4372769149194, 0.3136387021810, 0.0503057353433, 0.3961579717678, +0.5164289206809, 0.3720231346656, 0.1662337776116, 0.2208722104416, +0.2554044501183, 0.1962672542763, 0.5841820838788, 0.4933503919716, +0.2055797559235, 0.1065262188700, 0.7931279124660, 0.0522554670704, +0.4062471373036, 0.6653170160322, 0.0002501797864, 0.7929844110240, +0.0060196705191, 0.8353634727352, 0.9528929712031, 0.8009643460628, +0.2215912850674, 0.7589917265619, 0.6304175176799, 0.3178227927153, +0.8028245343840, 0.4545518618331, 0.2736076043330, 0.4066665621505, +0.5447855505835, 0.2401014488377, 0.7681905640141, 0.3239133401420, +0.4277747335973, 0.0612144707987, 0.6121245839690, 0.9344243416257, +0.2485621344524, 0.6831791837156, 0.2574817255407, 0.1963066673820, +0.8435940485651, 0.4541418908416, 0.7897054025855, 0.0506096375410, +0.5909199284347, 0.2498411858686, 0.1194589064081, 0.7899555828376, +0.3901746698609, 0.5969395989538, 0.0852046581382, 0.0723518771456, +0.1222887379687, 0.6117659553940, 0.3559313250500, 0.7156221758181, +0.9534522699907, 0.9251132723527, 0.0663178167615, 0.6295389298487, +0.7689327219356, 0.4982378201085, 0.1652147207247, 0.8345083807756, +0.9736459720757, 0.1967074550673, 0.5594522913729, 0.7773393046937, +0.8675436544547, 0.2222081065281, 0.8798866387829, 0.8169340169136, +0.4595476237403, 0.7111377030197, 0.6763499973697, 0.6695920413684, +0.8681607809235, 0.0504675517094, 0.9609788888884, 0.7958089037779, +0.7618057228447, 0.2583354503188, 0.6474071506632, 0.0461835465609, +0.6328774055619, 0.8840944608134, 0.8701014057128, 0.0033384757132, +0.7709276027842, 0.5863296750869, 0.8092077327004, 0.9364192224743, +0.7517617581188, 0.5398603247199, 0.0845674947298, 0.9744224534251, +0.4609538025507, 0.7254077297288, 0.7365677797871, 0.6440197861027, +0.2860464594728, 0.3284974570053, 0.9476158362569, 0.6164544185700, +0.4197747364732, 0.7455940832131, 0.0396351595594, 0.6239658331610, +0.0467975945430, 0.2879355169311, 0.7960616349224, 0.0006140479821, +0.4468072608331, 0.8086033173877, 0.5462709677155, 0.4434687851199, +0.3527915954370, 0.0796846659294, 0.6926977777354, 0.4163723729627, +0.4763279633952, 0.1237191977555, 0.6660143410163, 0.5019055099701, +0.3946016218488, 0.2280897210483, 0.6635795224754, 0.7505818362118, +0.0166017203669, 0.8555554248651, 0.9534974507771, 0.4001473022626, +0.5250791197294, 0.3026481798397, 0.1840528814048, 0.9011132870340, +0.2243020889462, 0.9448538566683, 0.0482422625871, 0.2236880409642, +0.2877726821638, 0.2710996834892, 0.2327893731337, 0.8443038975095, +0.1954327138120, 0.7345799434625, 0.0797030008769, 0.7790603408492, +0.2743062885824, 0.5482243092490, 0.8142646093919, 0.7724007786123, +0.2308607861543, 0.7506342519776, 0.6719435070045, 0.4802789504082, +0.7356703317425, 0.6254624080031, 0.9787239730259, 0.3355230294799, +0.8333347099057, 0.7522720521094, 0.4810178324026, 0.9322214233373, +0.8887587547716, 0.3584138296351, 0.0549202314834, 0.6650707138074, +0.9474663915799, 0.1130608432521, 0.3032676858377, 0.1031624940704, +0.3151173998206, 0.2352390732780, 0.3841605272070, 0.5360570589714, +0.2362643062306, 0.5105501136326, 0.9698190167406, 0.4638635280839, +0.2643625760751, 0.5105705948130, 0.0587744224159, 0.7840836261325, +0.0662409584346, 0.4952233622294, 0.2612048463250, 0.7307179294204, +0.1721502422225, 0.8019112901771, 0.1206857697669, 0.2399288188852, +0.2667743159769, 0.0054849516626, 0.5541833418208, 0.6017036026352, +0.7122660673746, 0.1555330707485, 0.3638987812977, 0.6091035733042, +0.2032235261068, 0.6597324584889, 0.2685939140006, 0.6671664671354, +0.1166179688259, 0.5183409259274, 0.8949715322326, 0.6527544412076, +0.6488741741743, 0.3528822755222, 0.0288910390944, 0.8647905485075, +0.8183833909307, 0.9132367502494, 0.8634528703352, 0.0876654615103, +0.3645865355453, 0.8846243498310, 0.4084601120131, 0.1246577166601, +0.1308494844152, 0.5367367777679, 0.6865356395424, 0.5291458822457, +0.8498225546674, 0.3976238003921, 0.5422217298961, 0.2407189813632, +0.5732869783292, 0.5620886220420, 0.5531568711405, 0.9061205111938, +0.4745052263488, 0.7765105044360, 0.2218210800652, 0.8217507856068, +0.9815831608053, 0.5911231956403, 0.2948514298978, 0.1167926118322, +0.4114079305024, 0.6304573345140, 0.9440054711625, 0.3237424689921, +0.9321160576921, 0.2297913209674, 0.5436940847634, 0.8074583410320, +0.4813000785565, 0.2967025932375, 0.1144156703327, 0.9521541967765, +0.0416702912383, 0.6121495629717, 0.8334393710054, 0.8009513103408, +0.2817816116297, 0.8914928459057, 0.0097733633638, 0.3756611004358, +0.3846810196455, 0.8550685899589, 0.4535814674821, 0.5629302345044, +0.7921951598451, 0.8591862464599, 0.6315790939292, 0.6754025480130, +0.2501729923534, 0.7737783201848, 0.4503094416346, 0.9264305238269, +0.2017732528978, 0.6615809228558, 0.4042356546988, 0.3943149123314, +0.9000839357730, 0.1338893105899, 0.8913722438232, 0.9479297394622, +0.8067392244966, 0.3813840143296, 0.4305919038274, 0.0057879141559, +0.6396923752686, 0.8484095157350, 0.9935335773013, 0.2640312743671, +0.5662371751695, 0.9214739868983, 0.7399023611750, 0.0033069401995, +0.8688863766700, 0.9509181948150, 0.7765425763915, 0.1934838286571, +0.3345521932163, 0.6610815360495, 0.8101044408093, 0.4081216698550, +0.6547287943097, 0.5847251855697, 0.4348598562343, 0.2604138819782, +0.7870252499296, 0.8565020476731, 0.2463061079599, 0.8390955109331, +0.1434662654733, 0.6871091852370, 0.9903913582630, 0.1376783513174, +0.6850145359919, 0.9502054899699, 0.0684931991009, 0.4209832616248, +0.0653337166018, 0.3247069107949, 0.7986150052392, 0.0620267764023, +0.7320011950713, 0.6315708917713, 0.2461808972276, 0.5385173664142, +0.4308451430084, 0.6008875712756, 0.5824890865863, 0.0227234731534, +0.6530074093738, 0.7653973362247, 0.2619691068595, 0.3925935269299, +0.5359244735613, 0.3077362032178, 0.3501225213288, 0.6968289630938, +0.7341069810717, 0.3229497230253, 0.1642382504252, 0.5964286292886, +0.5756128698474, 0.8775732465450, 0.0100589082623, 0.1546296082226, +0.1405788837655, 0.2606274058393, 0.8277787365149, 0.0785521073633, +0.1649111072369, 0.2059126008330, 0.5853343166343, 0.6263937412884, +0.8542386874809, 0.8969123023082, 0.8374834926042, 0.8315152143275, +0.8125661061204, 0.2850838304894, 0.4977998731182, 0.4199725787248, +0.4565979430716, 0.4655735150285, 0.0504811662484, 0.7597689804434, +0.9970323173315, 0.9925224170985, 0.7733097182463, 0.4006036880429, +0.0921775768940, 0.7311392979376, 0.3154721396582, 0.9375479691371, +0.4040831557494, 0.6677904472071, 0.6087125444825, 0.3255310479205, +0.0628850213545, 0.5446620395149, 0.9284178530464, 0.4364912805317, +0.3452673830768, 0.2277961290571, 0.7505746403479, 0.5137521692150, +0.0080307112113, 0.1995060705578, 0.1247084308996, 0.5880581329521, +0.3822772844612, 0.8205968173317, 0.4845899010471, 0.6225083044835, +0.9356747553384, 0.8388752275328, 0.2861703318945, 0.5350710672955, +0.9970280192779, 0.9327070726700, 0.8313976441656, 0.0594800501407, +0.4724008317443, 0.0892055957062, 0.6638463701419, 0.1468697838238, +0.7090501946905, 0.8764839874937, 0.7569960429133, 0.2725589141588, +0.1991660647090, 0.7719352165106, 0.4211460270086, 0.6854138954940, +0.7597787998429, 0.5444334477859, 0.9997313455677, 0.1717206668908, +0.7469480804852, 0.7678095115199, 0.7439395183436, 0.1244397760017, +0.7636004866863, 0.1292253644807, 0.5884063283859, 0.2285294189251, +0.9340567108868, 0.6992752415590, 0.9681005924792, 0.8745766607460, +0.9463680200029, 0.9310847296990, 0.6319823137633, 0.7994982361791, +0.5683875980640, 0.4187688517472, 0.0202903249396, 0.2958286839052, +0.4627002633469, 0.2774377927545, 0.2952528387752, 0.7772863683185, +0.8881195331403, 0.6618663280559, 0.0493730087994, 0.7163988657838, +0.1735441299032, 0.6478983325175, 0.2062997758418, 0.0491043539015, +0.1787687131105, 0.9204922108541, 0.4157078435718, 0.9502392941854, +0.8786908327037, 0.9423691997968, 0.0497175748692, 0.0041141719577, +0.8173164035274, 0.8127475431248, 0.6416444408901, 0.0178181668826, +0.5694554385587, 0.7636844230647, 0.7438322723582, 0.2736267546535, +0.5414089651506, 0.1378430361570, 0.1824532743462, 0.7641225972977, +0.1941049789051, 0.0041092284974, 0.4152808289115, 0.4777061135870, +0.5137581916124, 0.0822245115797, 0.6659755565533, 0.4646538377109, +0.8225146265805, 0.6873023219813, 0.7301228445629, 0.8722753323951, +0.1499448596267, 0.0012833392254, 0.6077945323697, 0.1458306876690, +0.6753302745872, 0.0286356918647, 0.9436525390221, 0.6575121072389, +0.8589237341000, 0.4926466776489, 0.8413832349895, 0.5852969794466, +0.3493381041798, 0.4283791721931, 0.2563311002480, 0.5852155068820, +0.9164904886468, 0.8907470693303, 0.5662222088157, 0.4387843750598, +0.4461568754381, 0.1105954670862, 0.8948562978277, 0.9815030377272, +0.4331071863105, 0.9599150670506, 0.1928199791316, 0.5608318543811, +0.0687735108979, 0.2556218124254, 0.6472173885662, 0.9229428236945, +0.9125240281748, 0.2187183709902, 0.2569051516507, 0.2550119204703, +0.7858546701194, 0.5878543022963, 0.2473540628549, 0.2005576902072, +0.6739528047265, 0.6447784037538, 0.0805009794796, 0.0887372978445, +0.7756164547874, 0.0232909084406, 0.0731575759468, 0.3368320797276, +0.6208828220241, 0.6921069429685, 0.9140379782366, 0.6393797847626, +0.3697261295140, 0.0670396969966, 0.8027024105204, 0.8088942755986, +0.9184652128809, 0.8028333162902, 0.0269547640472, 0.9955223896520, +0.9291840735493, 0.9872387237787, 0.0584551282499, 0.6741721526134, +0.5159179705735, 0.8417081012585, 0.2059570943033, 0.3153602803663, +0.5420484554684, 0.3017726402272, 0.4295624030892, 0.4533111576239, +0.8468954622964, 0.2160012597293, 0.9465510444467, 0.5100633825688, +0.6590884046904, 0.6225119170838, 0.2392921686355, 0.0197086199279, +0.9622244220051, 0.2799712262489, 0.3146188595866, 0.1533301464065, +0.1128436588276, 0.3319505515191, 0.3470109237111, 0.1173212696413, +0.0481378399060, 0.0313088712428, 0.1347838673437, 0.3739656877583, +0.5085992759599, 0.9773219134553, 0.0185475950216, 0.1932389955936, +0.6778158469488, 0.0245172465334, 0.8190300142481, 0.2245046893249, +0.7586557994404, 0.2198643019515, 0.3262898867607, 0.2485924168716, +0.2925495506695, 0.6055512617368, 0.4358655621465, 0.2728409307417, +0.8284878771885, 0.9516379553599, 0.2280631783549, 0.6751577307820, +0.6600033080485, 0.7907122987279, 0.2316091816088, 0.5426820379415, +0.9525857930782, 0.7728469668761, 0.1226628497814, 0.5786201053199, +0.4506857131844, 0.0007236325185, 0.8041558385846, 0.2574467171251, +0.0472081224654, 0.9592849891443, 0.9780455464395, 0.8227034336062, +0.0456679770936, 0.7250239698799, 0.9838022356777, 0.7970755602219, +0.5829330531801, 0.8043237765340, 0.9448882718314, 0.3100921224384, +0.0559115638285, 0.8754826043153, 0.4098750378051, 0.3807538335122, +0.1806202541015, 0.8843994410170, 0.8271205592095, 0.6379382161600, +0.6373498456727, 0.8406235621500, 0.6751117397449, 0.0587297403527, +0.0552213066515, 0.5899356382852, 0.6134705285604, 0.7977745895264, +0.2403297998199, 0.5059070198359, 0.5906592712694, 0.4176263666794, +0.3657803769995, 0.2875379227509, 0.4651920085145, 0.5687048172432, +0.7590863666307, 0.4114483540931, 0.0125618921651, 0.4489942441923, +0.3382039975087, 0.3420194193451, 0.2157721306271, 0.9574501639965, +0.2635853845922, 0.3941155613373, 0.2175020231947, 0.6256471684322, +0.1033523227569, 0.4442056386937, 0.2785150023543, 0.0446225824042, +0.7514013311599, 0.7407021688953, 0.2848292003781, 0.9536267420992, +0.3159260956179, 0.8066226378114, 0.3306378067148, 0.8982997289385, +0.4900018947618, 0.5562558954378, 0.3125296571816, 0.9212970779842, +0.2267159098884, 0.8557822722270, 0.8437938181887, 0.7777216661618, +0.8138058743504, 0.9858022765190, 0.2672306258544, 0.8563557103539, +0.1086499249137, 0.1520098713934, 0.3278216953985, 0.4830027564815, +0.5899463014630, 0.3722353095059, 0.5461254327307, 0.5453237190588, +0.7782671767186, 0.6932986242200, 0.8164409481997, 0.8246404350850, +0.9995698770506, 0.5296685078785, 0.4340007926496, 0.1012701481121, +0.6859356773486, 0.3154959722029, 0.3362911452243, 0.7646385998300, +0.4265424685676, 0.1759375721104, 0.8717518681063, 0.6488208028715, +0.5719013961833, 0.6532583784560, 0.0317198438718, 0.7155456858294, +0.7819532266734, 0.3857072700680, 0.6390606545094, 0.2989504697262, +0.5122060685010, 0.8906031515871, 0.5377171414614, 0.9668823499078, +0.9084830092771, 0.1021523694983, 0.2628384606274, 0.0838425737265, +0.1805495564735, 0.6867501855301, 0.7954509941840, 0.0792794083614, +0.9940903861979, 0.1801194330585, 0.2164186929429, 0.2294517863679, +0.2015306410387, 0.6800260635466, 0.4956154057270, 0.5527098386328, +0.0829129587314, 0.6280731096063, 0.8559636356570, 0.3673672733676, +0.1866339487893, 0.6548143549146, 0.2813314875967, 0.8876834795287, +0.8872744915482, 0.9685871754627, 0.0405216245169, 0.9203921421060, +0.6620813401705, 0.3994805600492, 0.8591903265841, 0.5782387659784, +0.2013081951073, 0.5705643489820, 0.5016329295475, 0.1220287867459, +0.5265357100994, 0.3818577515808, 0.2573145340464, 0.2970839232658, +0.0264430656221, 0.5206260958317, 0.5619771851050, 0.4737332274549, +0.4249598637339, 0.2279737066608, 0.2006521589126, 0.0575925903663, +0.9442992736326, 0.5078728224653, 0.8560468162671, 0.0566157941039, +0.0577704450385, 0.1309332224219, 0.1626871773799, 0.1373783033981, +0.7814475683409, 0.9450449365867, 0.0995203974189, 0.2032088018969, +0.0807395107489, 0.4435289080457, 0.3445254961702, 0.9587107244687, +0.1432423489835, 0.2820477063218, 0.0140932565621, 0.8461584261833, +0.7451410180634, 0.6697780590829, 0.6639054579027, 0.2714077906084, +0.2834752329083, 0.7715840836855, 0.1904041549146, 0.2258826425420, +0.4476721083967, 0.7084350966422, 0.9995577903462, 0.3910563138272, +0.9929829095458, 0.3919713815637, 0.2163079191075, 0.8556046061477, +0.5822038983843, 0.0507533541186, 0.5229046039856, 0.3789950964875, +0.5811357258731, 0.3636514662596, 0.9957982911709, 0.6224250018701, +0.1864822125931, 0.6618752366220, 0.8071803743053, 0.3403237868754, +0.0926814214758, 0.3297245620423, 0.9439229429438, 0.8212736308674, +0.8337110433884, 0.8378224395392, 0.9995026211252, 0.6078284008465, +0.5809630898670, 0.1171862762967, 0.6094065232246, 0.1899067755742, +0.4645689192529, 0.0286351977981, 0.8256213729389, 0.6089643131052, +0.4209243880682, 0.4575518283330, 0.4206065793618, 0.0419292915808, +0.5659361852174, 0.0031282864526, 0.5083051829172, 0.9435111838130, +0.8444272604978, 0.1470719106249, 0.3667797527121, 0.5041034736224, +0.9952337578848, 0.0309094730909, 0.8089471472469, 0.1739601270174, +0.3606984905716, 0.0879151788950, 0.3606340351331, 0.7528700901907, +0.5500434318325, 0.1944095334943, 0.9257376188998, 0.3601366557927, +0.1441084542983, 0.1310065212338, 0.3115958097910, 0.5351441416587, +0.1791464743107, 0.6086773735511, 0.1596417190319, 0.1372171827300, +0.5237594817410, 0.6000708628446, 0.0662292018841, 0.5802482983937, +0.0786378579580, 0.0896956664928, 0.6031991492972, 0.5745343848013, +0.1439390285611, 0.9230651184558, 0.2367675771177, 0.9699789020093, +0.7985848145553, 0.1391727864459, 0.9539745915467, 0.0457147243646, +0.6747452824725, 0.1592833046612, 0.2270879653409, 0.3146086262141, +0.6879697254337, 0.2247887138393, 0.3536928381555, 0.1528255837750, +0.8025058311422, 0.8320781801977, 0.3557952350731, 0.6652886484122, +0.0956852520330, 0.9816523054529, 0.4407555532831, 0.5154369541050, +0.0815191395029, 0.6194447342397, 0.5817231678319, 0.5069847551673, +0.1549012186727, 0.1601569974609, 0.7091404007325, 0.1849223166634, +0.9916227026804, 0.2988402472338, 0.0832221159168, 0.9459079783158, +0.3518053336776, 0.7902075167700, 0.4380130336797, 0.0371967069978, +0.8179265832612, 0.0265506156844, 0.9494908214312, 0.6651009994862, +0.9684723075332, 0.5058963086949, 0.2513393295237, 0.3031836591210, +0.1225715182361, 0.7709781382098, 0.3379744884269, 0.6071345645968, +0.2857147968773, 0.2182567702691, 0.7526304436627, 0.7787300417101, +0.5192759281580, 0.3672339363802, 0.8377015045088, 0.3343536110289, +0.4927498830914, 0.6741771468307, 0.5273909343068, 0.5468419052413, +0.6478097572214, 0.4843725853061, 0.9730173940645, 0.6106130502236, +0.0761314267647, 0.9996150908990, 0.2745801016104, 0.4110304277442, +0.5272545816969, 0.8940580100259, 0.0261657061177, 0.2240709225759, +0.8846396002381, 0.4957268892302, 0.3999543182552, 0.2775050356414, +0.5166588483922, 0.0072111180086, 0.2667050269743, 0.7379288066821, +0.3536890816659, 0.8023736452695, 0.2254678887434, 0.0193354701713, +0.6100112980278, 0.8729650098239, 0.1696075811841, 0.0631693927865, +0.3076115652489, 0.1027611806536, 0.5471421561889, 0.6969985154909, +0.9311899775319, 0.9554213229359, 0.5871337659597, 0.5201595497877, +0.0857847896804, 0.0073214038309, 0.9550364133693, 0.8617138675701, +0.2587071551283, 0.6130393718430, 0.9013794143225, 0.9812021199526, +0.0392625387941, 0.1433467553665, 0.1087662606075, 0.3013337321120, +0.3948067582188, 0.5559213871862, 0.1505578733750, 0.3754712875818, +0.4391951553706, 0.7484958398847, 0.3582950319901, 0.3760257621184, +0.2249011286650, 0.0492064529328, 0.6214608492430, 0.5279026131741, +0.6887625547539, 0.5325126939139, 0.1519676340520, 0.1686030049662, +0.6008152675819, 0.6199525322858, 0.4879340163842, 0.7391014000117, +0.4241725492404, 0.6866000572623, 0.6272739361167, 0.4429704297534, +0.8299870825512, 0.6828797043687, 0.2996394286396, 0.5286533499736, +0.7838769772946, 0.8692496213453, 0.8262264597352, 0.4084056892471, +0.3528100952286, 0.1786837350478, 0.4251710080659, 0.9767843335759, +0.3113686527644, 0.7920052505992, 0.9271795749325, 0.7834660400560, +0.7172434286760, 0.5362697814294, 0.8412117039977, 0.5486404237098, +0.7322807375958, 0.4060059829643, 0.0687824753433, 0.9931793380497, +0.9996869214809, 0.3330960047120, 0.0259585147844, 0.5567164917275, +0.1818858008747, 0.4238594702556, 0.0196960619742, 0.6532324513668, +0.7277411803267, 0.0118728829603, 0.1067391746243, 0.3193354906139, +0.9097499674697, 0.5116181571556, 0.8811225043056, 0.9329656343595, +0.0897595514961, 0.2625600626983, 0.6903018922034, 0.3062935119058, +0.1661218899144, 0.4011282047262, 0.0545653128319, 0.6174814666703, +0.8889563544136, 0.8833653185905, 0.9373979861557, 0.8957770168296, +0.5628969532265, 0.6212370920094, 0.2893713010891, 0.0061804610333, +0.9685622677061, 0.5625838742417, 0.9543330967214, 0.3153298163392, +0.2933646493095, 0.1504480681151, 0.9864433449630, 0.9740291586956, +0.0261481530155, 0.0211058291705, 0.1623209515411, 0.0931825191216, +0.3497369677526, 0.9358981209509, 0.5327239863261, 0.0434434553811, +0.8405073447342, 0.4394965192487, 0.1984581831835, 0.2230258780639, +0.1488005128451, 0.0066292341829, 0.8406247239749, 0.2530234960155, +0.7842031711639, 0.0377568667930, 0.8899945527734, 0.7780227101306, +0.4946956697361, 0.3471001239247, 0.6589939588024, 0.1793658533969, +0.5873562137537, 0.4632579369765, 0.9096839986321, 0.6133270555238, +0.9893098622511, 0.8807208630632, 0.6137060055573, 0.8961273431294, +0.8194704124795, 0.0154580148009, 0.9018266922337, 0.7760269570984, +0.6575765561581, 0.1692073797664, 0.9513561357518, 0.4345506780942, +0.4028378149508, 0.4980839004266, 0.6087038994807, 0.1498143184696, +0.2273513326549, 0.5516383277958, 0.5047131346095, 0.4493286229900, +0.5740735407798, 0.0115545038188, 0.5893951945889, 0.3947076869173, +0.8617162089151, 0.0687692100502, 0.3586546277435, 0.2483891533913, +0.1644659685737, 0.4490724222032, 0.5320271474924, 0.2683386259099, +0.9217601096825, 0.1537758303591, 0.3297932852664, 0.1457331525840, +0.6661706555943, 0.7412305216963, 0.1692338456256, 0.2316199770345, +0.2704042998470, 0.3237472112867, 0.9104379019283, 0.1205899809117, +0.9684704239333, 0.6732421147978, 0.8218311121789, 0.5191418009434, +0.7212519337056, 0.1958217565882, 0.2248804421280, 0.3265442463227, +0.0626647896425, 0.2953254740198, 0.2073762604070, 0.8142756367169, +0.8343695145260, 0.9243809985576, 0.3640946840700, 0.5660308881505, +0.0418549836808, 0.9988354830997, 0.3734534207608, 0.8961218315624, +0.9348666830616, 0.9636150933633, 0.1526113134588, 0.7032467060272, +0.4424351399962, 0.6010373381903, 0.7048456150595, 0.3218451590845, +0.1344253169999, 0.7128394398432, 0.9247845499426, 0.6152835165222, +0.0731599075129, 0.1028957404675, 0.3860815541754, 0.7466156616558, +0.4252376330203, 0.7944118412186, 0.2987174970558, 0.6109619963034, +0.0721246456132, 0.4879024226628, 0.0897373147727, 0.5060937574627, +0.3499538304051, 0.9064941601392, 0.4122834212204, 0.4538319993084, +0.4889835475427, 0.3918088145516, 0.9053296427733, 0.7857368419812, +0.3797861148509, 0.4238502301387, 0.3554239074492, 0.0579409557664, +0.6755530385652, 0.8222212553128, 0.0248875683289, 0.0602695220431, +0.6962877794617, 0.8099783555651, 0.5350606946904, 0.9496721182715, +0.5321042451691, 0.7694476869746, 0.9128740964983, 0.9211422493314, +0.7176853510168, 0.9573418781894, 0.5638595281932, 0.2115915930884, +0.1074288418085, 0.7898099966300, 0.4452443008522, 0.6535968429659, +0.6432645635881, 0.4573826726793, 0.6963041563035, 0.8575277220726, +0.6595747548433, 0.1322481106651, 0.8491914872309, 0.6016337986112, +0.2648849167232, 0.0393608692285, 0.5560983408038, 0.2046153942145, +0.5306580269386, 0.9404379552884, 0.8615821245413, 0.5809859091327, +0.3177850680974, 0.2269458059347, 0.7504163108535, 0.3966428192317, +0.8748819999745, 0.8498893132666, 0.9963934933750, 0.6632904068862, +0.2138498636027, 0.5925673505257, 0.8072311914560, 0.5602530211025, +0.1100032134494, 0.3212787058769, 0.3823773466900, 0.2524754918425, +0.6803153016047, 0.7532677770375, 0.7786613785562, 0.0786815025279, +0.8324682595359, 0.3398900559823, 0.8855158877026, 0.6278528653215, +0.0226001371735, 0.0973531757935, 0.3792509252109, 0.4416142280407, +0.6374758689839, 0.5532581641121, 0.0377911310819, 0.2408330497522, +0.4514978483559, 0.9552609370813, 0.7802039705125, 0.7882074419354, +0.3368504840587, 0.3263798478648, 0.8051502498822, 0.7765974634218, +0.8648569327150, 0.5507003476614, 0.9189471988561, 0.6123814408725, +0.3800060480740, 0.9748601461644, 0.8719790535383, 0.3013245450805, +0.2784932964847, 0.0603213492130, 0.7281279227362, 0.6506404316289, +0.0552580380138, 0.1109615560206, 0.4002114051954, 0.6136438099731, +0.0202953796928, 0.0778581751873, 0.2083147318141, 0.7794623304063, +0.0343133043658, 0.6577712486767, 0.6311163392994, 0.2461058628960, +0.1879177723024, 0.4858111527217, 0.6130321852924, 0.4113203093462, +0.0305638755814, 0.5247682563610, 0.8121910010521, 0.4181824351746, +0.0324627440574, 0.8954208087620, 0.0754686040224, 0.7311381994426, +0.5980880891895, 0.4124687921314, 0.8702809544607, 0.9474476575607, +0.2120526867043, 0.8765813856742, 0.4727901413444, 0.5984088771969, +0.6524638769461, 0.2673107247182, 0.9875429416949, 0.8730015465398, +0.4419635364050, 0.6727592566389, 0.3451688999055, 0.1958576735090, +0.3876055485511, 0.4762768412364, 0.3305305053156, 0.9762852396706, +0.3617451253169, 0.5755233213191, 0.9620879939581, 0.9435626906080, +0.5054171935215, 0.3923090013640, 0.1002915772145, 0.7742789945445, +0.1232078387976, 0.5378799380445, 0.2877298096603, 0.1757601812369, +0.7564196408523, 0.7212959279871, 0.9503487301759, 0.1580107636554, +0.2961404175945, 0.9684723280223, 0.5978773131957, 0.4231388715204, +0.7812779283995, 0.9486042945406, 0.2357830522749, 0.5854202548905, +0.5572371918509, 0.2232414643388, 0.6213635511796, 0.5809519526460, +0.8954567466376, 0.9448427404020, 0.6995183055753, 0.9518940564952, +0.4358852936122, 0.2572018719545, 0.5203660612555, 0.6616062995333, +0.7964178201726, 0.9413024875993, 0.6495108733184, 0.6206576389357, +0.0952514461685, 0.9196256589702, 0.4791824251782, 0.9372406829788, +0.8526700264088, 0.8516710874865, 0.6409215864916, 0.4295311548885, +0.8242191545778, 0.1488104440033, 0.8201434150432, 0.2387988996873, +0.6368784194984, 0.6054970825117, 0.0974147380783, 0.0559264668524, +0.6706723452875, 0.1941156108836, 0.8287385468505, 0.7187782892579, +0.1898631514934, 0.5661290919250, 0.1389583512856, 0.5282568524258, +0.2799820510112, 0.6257484451056, 0.8233309638795, 0.6593244125411, +0.4100825192454, 0.0763998711837, 0.5670509322393, 0.4728418367323, +0.4757645123060, 0.5053339654139, 0.9960255301539, 0.0462333569518, +0.8757460163328, 0.3284345382491, 0.3570050524347, 0.6369471166455, +0.2330749343303, 0.6999651704449, 0.4772449822525, 0.1771484670123, +0.2934380095887, 0.8699533538287, 0.3054622524909, 0.5746597207965, +0.6624576513015, 0.9641103553419, 0.0640689647124, 0.1342007988757, +0.8623517285391, 0.8523208027949, 0.5302394468012, 0.2030273159980, +0.8264122469474, 0.1423337795503, 0.4780692479005, 0.3535704102151, +0.0913535370917, 0.2364947657271, 0.2187336507341, 0.0451201796742, +0.8517062970678, 0.5671180493977, 0.7418287311410, 0.2147591804223, +0.2759822505880, 0.7274523129349, 0.8955525876468, 0.0988337835757, +0.9474572906957, 0.5090571849183, 0.4274174829141, 0.3727975698993, +0.8670805347464, 0.2408952998188, 0.3790105387471, 0.7328797354050, +0.6461068194574, 0.5295381855823, 0.2050056546950, 0.4430795034594, +0.0888155112457, 0.5084585475309, 0.3818589883772, 0.7352451014962, +0.9050484159519, 0.9152277581930, 0.6507923270812, 0.8599282362777, +0.0842851582376, 0.9964019530436, 0.1517225234544, 0.8695259778153, +0.9923850386368, 0.9359914553054, 0.5635200019756, 0.8935512550611, +0.8318701595216, 0.2683672887591, 0.6634437682403, 0.4590725896224, +0.8237409865594, 0.7793274497517, 0.7774244741432, 0.0908612506887, +0.5995145158840, 0.6908215208402, 0.0202227491048, 0.1564350124246, +0.9604735057617, 0.2456213348758, 0.2203597059568, 0.2252284042655, +0.4621469301461, 0.0492890170074, 0.7540798824067, 0.6022186943340, +0.2743981868375, 0.3671953460980, 0.9645167752004, 0.4048722094879, +0.0097905532503, 0.3586833450751, 0.3635972986760, 0.1162392986548, +0.3861898902739, 0.0021755914214, 0.2946748003804, 0.9271173011172, +0.0489798188438, 0.2180600493299, 0.2705428801805, 0.9581185686207, +0.2044023662826, 0.8727208054032, 0.9973874990816, 0.0479673538580, +0.2428386519863, 0.8039168821666, 0.5635423257777, 0.0176102477208, +0.3861207260686, 0.2033121577479, 0.0495382165767, 0.7839020322002, +0.2084903084713, 0.8482676566803, 0.2526011747553, 0.8036180994490, +0.3333572481449, 0.4828884953088, 0.2154630023127, 0.2171179494900, +0.5061776016402, 0.3431478013951, 0.8415718408495, 0.5790603009886, +0.0943652089193, 0.8923674919141, 0.3453233928165, 0.1362466407643, +0.6638336273207, 0.1433450277631, 0.1104275407784, 0.6158662734627, +0.1254252875808, 0.8682359940690, 0.0160658331663, 0.1078150393943, +0.3635101906785, 0.3682639395670, 0.6721528757700, 0.5796081589440, +0.5253091917957, 0.7496309172128, 0.5715760973150, 0.7216910928123, +0.0412952215603, 0.7337995002669, 0.5978985734274, 0.8241772720703, +0.3924218762631, 0.3746524697052, 0.2166879951100, 0.8133615757401, +0.1945064762582, 0.8985994783689, 0.7178002715659, 0.0582598354939, +0.6789899373795, 0.2888716851775, 0.7909669698174, 0.0631236639168, +0.0092095499901, 0.3428235647002, 0.4322167134062, 0.9013945110614, +0.0278907050508, 0.1346348375709, 0.2110595583036, 0.4482825465725, +0.6049035264202, 0.3914008961950, 0.5028987776036, 0.8832124340735, +0.8986521469889, 0.1302127177502, 0.1410318129421, 0.0744748744529, +0.5522919616440, 0.9399473685492, 0.8640122180171, 0.7389303863695, +0.1389600486210, 0.9447138379071, 0.3145998377887, 0.0807002131272, +0.0955237732714, 0.3334665253449, 0.8433133158103, 0.0324001088889, +0.5356747962235, 0.7745137106509, 0.6223382105224, 0.6342802856277, +0.5028374700355, 0.5448843462136, 0.1173372748854, 0.0545549234629, +0.2116092672626, 0.5307281755520, 0.6795191842502, 0.3283968331890, +0.2568928358410, 0.8165127936828, 0.9221290717470, 0.1824179613881, +0.8020912705930, 0.1555449823642, 0.9467255118986, 0.0631608842235, +0.8914379425773, 0.3543832317714, 0.0954923504477, 0.8107377294501, +0.4424922975909, 0.0303979911983, 0.2990970692127, 0.4100921887020, +0.7766906706508, 0.5380160708623, 0.3638645165432, 0.1424103850231, +0.0407576505285, 0.3123654664086, 0.3125297815132, 0.9862027270655, +0.7582638900533, 0.5435951205639, 0.8572498126222, 0.4298670563986, +0.7191869577948, 0.9698731573158, 0.0743232956502, 0.5367689964067, +0.0596132511551, 0.9760797941015, 0.7863859505329, 0.9964523673972, +0.5438491914160, 0.8617045217481, 0.1316247760000, 0.7331114619659, +0.6372093156153, 0.4352871335276, 0.2160877530538, 0.2271171269133, +0.6575952077553, 0.0797016127406, 0.4656851247259, 0.5151848227322, +0.8157523683346, 0.4342858779404, 0.6177176840686, 0.8295496412690, +0.3601145215147, 0.8565100188630, 0.7466513443490, 0.9302474655817, +0.1406701529122, 0.1183784111023, 0.4001051389613, 0.6039011565055, +0.4708808020087, 0.8598571107070, 0.0882515679525, 0.4744284350772, +0.6077489804513, 0.5304940536295, 0.8359369043428, 0.8746375189510, +0.1946788072561, 0.1515981714016, 0.3921985749119, 0.9675616808085, +0.1234711506979, 0.8318881228715, 0.5868853053948, 0.6082863284314, +0.8821200713898, 0.7810663584532, 0.9115897356121, 0.0525704296551, +0.4595548843311, 0.6978724392587, 0.2153522359279, 0.5293074192150, +0.5659047363167, 0.8196694063114, 0.5543824576560, 0.9620035802769, +0.4289160312288, 0.7065748892289, 0.9380478174137, 0.9544875966173, +0.9009369043172, 0.8997968337032, 0.5664319999360, 0.0262993853662, +0.3699305841559, 0.5086858843028, 0.4302908868670, 0.4023689038131, +0.4307757897446, 0.5646093914121, 0.6602840561700, 0.8224894617789, +0.2997397907543, 0.5542469404425, 0.3964975138179, 0.2471693610992, +0.8373946686449, 0.1818598616784, 0.3353132984300, 0.3080872494299, +0.5126691141690, 0.2969495529760, 0.8797323009371, 0.5506655343579, +0.3886023547447, 0.0785738504858, 0.1166189588218, 0.4341147581274, +0.0809661611360, 0.8175183859735, 0.7851487397147, 0.0546667757699, +0.7539496434638, 0.9819030654532, 0.7173152192111, 0.3515807391850, +0.9700955678570, 0.1238802271541, 0.4905889497560, 0.1476061056124, +0.3980423665596, 0.4008713571359, 0.6884896190318, 0.1508730054604, +0.3930743818139, 0.6977821573139, 0.9551182980440, 0.0849871323840, +0.8410971308318, 0.2304690504589, 0.8796420194579, 0.2904315960083, +0.1934890780568, 0.3537662445352, 0.5274186034349, 0.7593743199293, +0.6987043380266, 0.5820914328015, 0.4323400950210, 0.6440375622567, +0.5690695739207, 0.7796704996283, 0.3996098183094, 0.2174888347357, +0.2645311431328, 0.3230192169189, 0.7615735646158, 0.1169250375204, +0.4030355193666, 0.2346267105241, 0.4468994445386, 0.2521625139062, +0.2203761954887, 0.8010778859263, 0.6354980681257, 0.1353890631047, +0.8810479617124, 0.6134505777682, 0.4988600432402, 0.5906163657040, +0.1378763816961, 0.7221450920786, 0.8439196282271, 0.3785020622325, +0.0153757929874, 0.3313654597529, 0.0759113366138, 0.3713382311963, +0.7257402663705, 0.7140801310139, 0.9134568925544, 0.5082514316348, +0.4299917483842, 0.2948098402912, 0.4937506301765, 0.3130667108638, +0.5074867086986, 0.6945228915170, 0.6178290572100, 0.2553241947923, +0.2001175643877, 0.9105222285309, 0.9291496025068, 0.0647285012830, +0.1552640354052, 0.4204937603420, 0.7116001139915, 0.5646476701669, +0.5889622189984, 0.0363119966520, 0.0339443376446, 0.2104601567660, +0.2492021966023, 0.7268386011603, 0.7584570891962, 0.8778639658717, +0.3426198569791, 0.2645779895897, 0.0582040604475, 0.8343684258099, +0.2847276638657, 0.0683601233495, 0.9786581206036, 0.9716609534676, +0.7277329455725, 0.7147194122498, 0.3631699636407, 0.4724087507801, +0.0457275221337, 0.2352196538054, 0.4092423033012, 0.9809990208508, +0.9030395755093, 0.2458450865214, 0.1457418818705, 0.3383919053424, +0.0678021526280, 0.0583036104489, 0.6663388468634, 0.8573419963277, +0.5781471499140, 0.6567643720921, 0.0946156075665, 0.7002831845080, +0.6874411221069, 0.8273493465164, 0.3836029727867, 0.8530726967627, +0.4134679862361, 0.0300609786203, 0.0919273356404, 0.4418070332342, +0.5429942070241, 0.6981956501017, 0.0984211019699, 0.0705854562440, +0.4425900864613, 0.2707271521309, 0.4129150618859, 0.4615910656106, +0.1605492705296, 0.4883176085950, 0.5059468059363, 0.8221573656528, +0.5090306841345, 0.0635888460388, 0.7341626951164, 0.6516886882725, +0.1007847260222, 0.5768328367625, 0.1218924564877, 0.4005015419798, +0.0695807603512, 0.6789318764019, 0.2335972083889, 0.2165080640542, +0.0590072144098, 0.7570218824581, 0.5062812224525, 0.6172001811756, +0.6687940148026, 0.4724752006458, 0.7870828615441, 0.5982085585586, +0.3470950291246, 0.2117882213610, 0.1706708507476, 0.8855039635140, +0.4057432778206, 0.7896851155859, 0.4825153734919, 0.5835859126335, +0.6401508672350, 0.5662925488159, 0.2780027237153, 0.9884621794282, +0.4126669603459, 0.1491815509038, 0.6298813948547, 0.0121654183660, +0.9682819158622, 0.5134516868337, 0.7260143881319, 0.7517738513424, +0.5768117776964, 0.0378626757478, 0.1923835627699, 0.9596115965208, +0.2968733433154, 0.6358189921062, 0.7948845586716, 0.6986647852225, +0.4674713827984, 0.9656673581180, 0.1082941922863, 0.5819674197500, +0.8625509561331, 0.8145664119229, 0.1774555790133, 0.2789650430339, +0.6484331319334, 0.2682942334881, 0.6042515270432, 0.6599709525052, +0.8944196695902, 0.2885839987027, 0.8345867823039, 0.8822542507584, +0.2162420280353, 0.3070866294704, 0.4377655500722, 0.4644681766929, +0.1233915337936, 0.1845239434319, 0.8205383163041, 0.1637799377385, +0.7115866642965, 0.7002033114900, 0.2223866191797, 0.0129218786084, +0.5992385971356, 0.0084600071462, 0.3360223031305, 0.0172711773856, +0.7232815389164, 0.0667099799340, 0.9741273657298, 0.4443164958825, +0.8115538972484, 0.5858324945838, 0.8812763918570, 0.1515829442775, +0.3677821691929, 0.4599870287161, 0.8541267285376, 0.4855279189001, +0.1531816870687, 0.2622018383174, 0.7485710274189, 0.6887135103758, +0.3501165147638, 0.3694237151041, 0.5692884682535, 0.1863365770254, +0.4027486631660, 0.4735080490231, 0.5539476585360, 0.3898267840919, +0.7936054555669, 0.1143353269968, 0.1737113600474, 0.7763342777157, +0.9540501595261, 0.3928440522369, 0.1227953341430, 0.5097336636436, +0.2485056441503, 0.6773316979768, 0.4595540321709, 0.0969226994072, +0.8263583429280, 0.0600595409330, 0.2631641925607, 0.3408304240279, +0.8060044310084, 0.1941405116553, 0.5200465696492, 0.1172909206326, +0.4549541740934, 0.9591861180771, 0.4563423504384, 0.2686175966024, +0.4154576023181, 0.8050706888573, 0.3286098327155, 0.0256308182262, +0.6588917689672, 0.8182062654841, 0.2785787374147, 0.8825574912515, +0.9620237615714, 0.4524972240685, 0.9325415924809, 0.4522900979278, +0.1522596260310, 0.9160739206318, 0.8453412763054, 0.0553369266239, +0.6457257325043, 0.4007652701814, 0.5934056181430, 0.3048953084764, +0.9738607313362, 0.4720840749666, 0.4608248111144, 0.8565698107037, +0.2494889773659, 0.7798651623446, 0.6662245866220, 0.9808713807635, +0.1481977548209, 0.7044431514593, 0.7390512799560, 0.1225669365947, +0.9502186039231, 0.5636553576047, 0.5095138398509, 0.0676611126716, +0.2403826751934, 0.6091103724246, 0.3818616226231, 0.7880925777313, +0.3697401417278, 0.2024064362992, 0.0616075960275, 0.3144032151040, +0.2118441808093, 0.5219997677589, 0.1184803564653, 0.9069488727986, +0.5684557853120, 0.8575699133135, 0.9227650384059, 0.7118859746083, +0.3644612298182, 0.5423165161825, 0.3296539878145, 0.3835898490546, +0.1184455110312, 0.6139502071840, 0.3221816780615, 0.9958785744365, +0.1288940706891, 0.2666432658521, 0.3183933581777, 0.0612329580175, +0.6159997752942, 0.0791126741465, 0.8302986234568, 0.8279071980286, +0.5265634611838, 0.8563824504876, 0.6882230470368, 0.2121602460799, +0.6567795153972, 0.8963036029117, 0.0587888863211, 0.7498306430643, +0.8891552178604, 0.8686236962064, 0.4183033702049, 0.1772692427865, +0.7246582576654, 0.4576110027067, 0.7261936090543, 0.3410684081451, +0.0517261708396, 0.0891194870179, 0.9999275188893, 0.0558475964031, +0.3833421549682, 0.1701716818708, 0.7030696942020, 0.3221091969507, +0.8493702499426, 0.5122362256573, 0.4368149477229, 0.0214630519140, +0.4792738172595, 0.4653700252368, 0.5913488998038, 0.2671135711796, +0.0294025894391, 0.0058372779777, 0.3217524752588, 0.2795719463749, +0.5578106048320, 0.6861821048363, 0.9021408808893, 0.3805413620456, +0.6615126592394, 0.4469658222268, 0.5548058010427, 0.3204442506286, +0.3368470065002, 0.3861709164391, 0.9045768249336, 0.2809994096314, +0.2266135403079, 0.3885731773398, 0.4752904034570, 0.9045043438228, +0.1998231491073, 0.6099556952761, 0.5587448592106, 0.1783600971933, +0.2626733776474, 0.0491933985842, 0.1221919204677, 0.9955598069334, +0.9931127671120, 0.7419471949069, 0.5145634238210, 0.7135408202715, +0.2168572611254, 0.0225153560855, 0.7477844728845, 0.8363158995455, +0.9703696044024, 0.7746678659574, 0.7086974609218, 0.6499253533082, +0.5445026715959, 0.6318822631761, 0.2216336881843, 0.2635032614989, +0.0307148560093, 0.8813496780961, 0.0180531791495, 0.1262105126522, +0.6717036797999, 0.2573283963172, 0.2699228549702, 0.4933435826066, +0.8242275206485, 0.8715268289072, 0.8672840915934, 0.8286677141807, +0.7030168323326, 0.0869008982959, 0.9207202274914, 0.9894760120611, +0.2715995503923, 0.6961295989790, 0.8288480932027, 0.4352836513125, +0.2265579189298, 0.4884568115177, 0.7186449550645, 0.5766325660872, +0.6908456774852, 0.1969275228665, 0.2631246770095, 0.4273424155206, +0.6109688783116, 0.2353483486154, 0.8288097860426, 0.4847583651937, +0.3402065473330, 0.6416837343209, 0.1166980262458, 0.8468629651921, +0.2152885949310, 0.0119102266673, 0.8990121311038, 0.3866208812160, +0.7557722342926, 0.0395161151139, 0.8834370555745, 0.7662962222315, +0.2394409339127, 0.4587890661595, 0.1264170134097, 0.8041572830659, +0.5318976726997, 0.5110404843050, 0.1549186646728, 0.9552651070781, +0.3009060347923, 0.7584555916295, 0.9994972958227, 0.8735636197373, +0.7473803380259, 0.9917517122774, 0.9553831149616, 0.2626219723665, +0.6310558657307, 0.3583492158718, 0.2271000604271, 0.7841929005385, +0.7304189678889, 0.9712624130637, 0.0000329497270, 0.3437980866729, +0.6653413030623, 0.9457075628199, 0.9831726401966, 0.8990450808308, +0.6707669779057, 0.4211135368893, 0.9852236783994, 0.8666096953054, +0.0669057979560, 0.9102079118184, 0.8799026030488, 0.1116406913435, +0.9083848869933, 0.5988034706557, 0.4212483956577, 0.0348212672560, +0.6833676638470, 0.2092909213199, 0.3572590622852, 0.4207456910148, +0.0968350768540, 0.4307480014072, 0.2010426335973, 0.3126421767811, +0.7719407811630, 0.7278909425847, 0.7890972172791, 0.4281426940244, +0.6881752478369, 0.5023597485862, 0.6991533556483, 0.7891301670061, +0.5489356902190, 0.3535165504336, 0.4480673114062, 0.6823259953793, +0.5449316806835, 0.2197026681247, 0.7746300873228, 0.4332909893400, +0.6893539571619, 0.6118374791051, 0.1299105794774, 0.6545326899060, +0.9719046666156, 0.5977388436896, 0.2106409492952, 0.5511589756008, +0.8805421883615, 0.6552723299969, 0.8070297650094, 0.5679000115804, +0.4362150926312, 0.9773772656812, 0.0860203309385, 0.0080723981411, +0.6642477152237, 0.2081558733285, 0.7052682078002, 0.8751175482176, +0.0867475578965, 0.3524229625950, 0.7105156219148, 0.4044215629829, +0.5918739221952, 0.6356832485812, 0.7059395130286, 0.1585829328553, +0.1351022893261, 0.1368056028787, 0.8553859167059, 0.4805695998858, +0.5364554713184, 0.8244562464880, 0.7486430819839, 0.9852964961833, +0.5271840428594, 0.5083601379340, 0.4221950897119, 0.9592840312791, +0.2372972528624, 0.4077262307553, 0.1636324674653, 0.2292248542557, +0.1247703466214, 0.6735123454935, 0.3851034959709, 0.2496527988695, +0.4947932667540, 0.7890180618451, 0.8816682188221, 0.0903717037711, +0.7507667735921, 0.5815408251162, 0.1414410239744, 0.5921838402712, +0.3279501364231, 0.3426406953217, 0.2172240732318, 0.8473805370030, +0.0579064851896, 0.4630524257492, 0.4794462982004, 0.0726099894720, +0.1873734109976, 0.5943619569737, 0.2875086717715, 0.2280893797186, +0.9389286162047, 0.7145574538571, 0.1027220944421, 0.7097037614834, +0.5160073607769, 0.1762258686015, 0.1222836841467, 0.2663545619074, +0.5977588843544, 0.6407777078640, 0.8497382140950, 0.5073871805833, +0.3235902722569, 0.0925521506428, 0.4297957692434, 0.7314064324514, +0.4186173302208, 0.0743570453834, 0.6740929757590, 0.5712367936835, +0.9639270384628, 0.7465674671096, 0.4169977411707, 0.8913170489908, +0.1245334190896, 0.0218335236524, 0.2096198923931, 0.8964440393711, +0.2068323256480, 0.3119068300873, 0.6161954806262, 0.4971285646302, +0.9852721369757, 0.1457609413870, 0.0264642834787, 0.7189175750683, +0.6561351482087, 0.5012794977526, 0.3219868099885, 0.1487479676254, +0.9031314560692, 0.2538940320974, 0.1420572051509, 0.1717250236178, +0.1430897676121, 0.2267217283262, 0.3464461832058, 0.5718529743943, +0.9118562079556, 0.5617070982986, 0.3010787737095, 0.0205391584991, +0.6145205542513, 0.8757832459527, 0.3082745649425, 0.7180765148802, +0.0150230215001, 0.7390539733409, 0.8976167696051, 0.5178944573355, +0.2327298243683, 0.2218553476137, 0.0509608029625, 0.5138122497656, +0.2261730540666, 0.2180019613439, 0.3676162890008, 0.0774250864412, +0.8613281230728, 0.8823082027409, 0.7192814590965, 0.6896030994549, +0.4331916381760, 0.7644595791420, 0.1362022343726, 0.8613386642473, +0.5031875765432, 0.5762814062537, 0.9911813074682, 0.4826484175784, +0.0103365955922, 0.4150437840331, 0.1379885040866, 0.2922600807120, +0.9641575263646, 0.6248571498435, 0.2908270295201, 0.4462630690291, +0.7022560488909, 0.9791805483304, 0.3639111227188, 0.1884437991252, +0.4922970121225, 0.9349858737248, 0.2010358954785, 0.4148719256813, +0.2582552834685, 0.7184700661891, 0.1529878346031, 0.5686521844792, +0.7336079574812, 0.1195834065413, 0.6007782684643, 0.8722692936995, +0.2196289204152, 0.1667995951915, 0.8840429856833, 0.7369805033025, +0.1674843729322, 0.7228164969584, 0.7430810014452, 0.8752242926858, +0.3273325740953, 0.1778209685245, 0.1378602805258, 0.8810695055318, +0.6171311096368, 0.2914901004599, 0.8026781183680, 0.4286873105116, +0.5814611663024, 0.3193871580620, 0.2706706483246, 0.1665892406211, +0.0403587278167, 0.0737581779592, 0.2543730313212, 0.4717065438031, +0.2796301591581, 0.2986140117508, 0.7922282446140, 0.4073608659242, +0.1299870154494, 0.0132381161737, 0.4181974182921, 0.3930065126126, +0.1774646957300, 0.3496159363303, 0.1800377118308, 0.3022404035098, +0.8041882188079, 0.3449490686622, 0.0724324328231, 0.9231187132761, +0.6389800243261, 0.1315207924375, 0.5227700376524, 0.2102927138146, +0.4920373966415, 0.2561111334973, 0.4230108928974, 0.3254481555547, +0.1653880845594, 0.0734985624782, 0.5754982915593, 0.6936815412220, +0.2372321888046, 0.2057468128417, 0.1472567409031, 0.8298713233461, +0.3324914976640, 0.5168623484284, 0.5043608245926, 0.9394849855171, +0.2247986459289, 0.4624785135791, 0.5301004646020, 0.9225582428847, +0.6332568897089, 0.4022633416589, 0.8120944499094, 0.7101381764329, +0.0948195960814, 0.4374451080512, 0.7472124103211, 0.8845268827325, +0.5954306035281, 0.7337996204075, 0.5689659004886, 0.2699824475078, +0.6856583346080, 0.0874679997039, 0.9899107539048, 0.9919767938517, +0.3952803683445, 0.8510464196331, 0.1609665621822, 0.5654090454641, +0.2477082881367, 0.6325125571492, 0.0567932320092, 0.3082233030853, +0.4837122990208, 0.5801997862664, 0.1493749051119, 0.5611540566018, +0.3896135461468, 0.7085109449497, 0.0426782993799, 0.6794753701796, +0.7392996315562, 0.0228704353901, 0.1107742861429, 0.8547727492893, +0.1279691439718, 0.8341192281033, 0.4603155434412, 0.8579866964640, +0.0212582373159, 0.7233997474999, 0.5679188480451, 0.0292814439299, +0.1232386469484, 0.7069165719240, 0.8108677472039, 0.5578296019499, +0.2800576124713, 0.5185190152929, 0.5579629910914, 0.9718343093860, +0.1759102792367, 0.5277659006080, 0.1510315719764, 0.6147562231006, +0.9798818477336, 0.6596225782575, 0.1079656864088, 0.3004064775540, +0.0054167346123, 0.3694953934147, 0.3681335227416, 0.1506439857886, +0.3368945053485, 0.7447163666341, 0.3923658292705, 0.4789078088845, +0.8819628166416, 0.4648636493203, 0.5788355942717, 0.8526813727118, +0.7045840438011, 0.9032210539576, 0.1882633963545, 0.1467544418512, +0.9709654524787, 0.8278226907495, 0.6101376258815, 0.9991311435584, +0.7828568400735, 0.2510230644844, 0.3463417055767, 0.1681006165073, +0.7977797555727, 0.9587671193102, 0.7787889655581, 0.4973732780187, +0.0373986377555, 0.7776616028406, 0.6183896975677, 0.8867546519669, +0.4654310291938, 0.0428153723678, 0.1471569957897, 0.9865232203093, +0.3922041977719, 0.8023255345422, 0.7875317390019, 0.5395228250602, +0.5131217751247, 0.2741670139479, 0.2671891833968, 0.3663673328079, +0.4545837228441, 0.2177058184602, 0.1773880679055, 0.4554525797514, +0.9556263102943, 0.4255491748571, 0.0455285092096, 0.7875256937870, +0.8892434928050, 0.7384831499022, 0.6765722398071, 0.3918702147863, +0.3421158564007, 0.6870232479121, 0.6972502692124, 0.4553612048996, +0.3021631861581, 0.3795144941562, 0.4646848502870, 0.3156399663145, +0.1513646711369, 0.7675942153519, 0.4223298669897, 0.6118418465424, +0.5762289387995, 0.5435688689088, 0.5699197494285, 0.2098616055259, +0.2925615121110, 0.0893507134585, 0.8177358833224, 0.8371089328253, +0.7826496445493, 0.7471452349551, 0.3070565319187, 0.9951239512279, +0.7444552563804, 0.7382759543780, 0.1726944098122, 0.3525850411284, +0.3046278540532, 0.6336987487197, 0.4767591042802, 0.8492666496193, +0.4896493393414, 0.6467437104540, 0.3207219966318, 0.1740093730269, +0.3972486929955, 0.7918125254995, 0.0262582046102, 0.7854068469188, +0.6584496771258, 0.5486133645981, 0.5594067408514, 0.4485880715999, +0.9664354231052, 0.2346786154596, 0.0921822330412, 0.1293264898142, +0.9050420671259, 0.2589969347506, 0.3240293289181, 0.9099181163637, +0.9836709024309, 0.6876917112096, 0.0061421697057, 0.6310858613025, +0.0281032286715, 0.7281261583455, 0.4259676655875, 0.1788365795179, +0.0767361424289, 0.3327310827247, 0.3618249070653, 0.9027267698677, +0.4679537501503, 0.5663854817703, 0.9794747931787, 0.6825469036971, +0.4543210689231, 0.8652024436114, 0.3581980068042, 0.0057329973233, +0.0469312374699, 0.1127707460489, 0.4138158077438, 0.9176047476556, +0.4159161571487, 0.0133666601094, 0.3474493615085, 0.5059980407851, +0.3025645517290, 0.3209582238090, 0.2723635948600, 0.6714786908922, +0.4573423440835, 0.2862354536942, 0.0086499350186, 0.2785057645657, +0.3373443700081, 0.4854455727550, 0.0143616120398, 0.4346176006061, +0.0587334223365, 0.4140805124371, 0.8181766554798, 0.3761865191051, +0.8033844459818, 0.5266871724868, 0.9804659942074, 0.7976514486585, +0.2562687482016, 0.2577055149049, 0.3918896156325, 0.3386640005459, +0.3117034641615, 0.3031999856714, 0.3704762609538, 0.8057054233764, +0.3894043128888, 0.7276196213102, 0.3165666457808, 0.7179256224623, +0.8674360056722, 0.6919688646179, 0.0485778446535, 0.5889302406408, +0.4918453802782, 0.3247783492900, 0.9782043187778, 0.0572277796721, +0.3687524494570, 0.8291897502864, 0.8102239225107, 0.9925659308175, +0.4260520257177, 0.4274858717935, 0.2432702622578, 0.6284005775249, +0.5624002570111, 0.2294364716995, 0.9541730442802, 0.2237362559995, +0.1517680828235, 0.8186690052127, 0.4871419866044, 0.3460626599128, +0.5755438695548, 0.4634715469850, 0.1218689904184, 0.8576182475582, +0.0273658763745, 0.9649481829093, 0.1910911678295, 0.4384356361993, +0.2968967926208, 0.8948018820466, 0.6569170470615, 0.2396690129487, +0.6276872957254, 0.7887421733647, 0.2195802313367, 0.6351213653735, +0.6582047309066, 0.9964397451824, 0.6179319231854, 0.0298041533818, +0.0849384414428, 0.0842567566243, 0.4239256165102, 0.8612021859089, +0.7241613207032, 0.6473386984539, 0.3136932283238, 0.3780986607904, +0.6584534620207, 0.8759294035267, 0.4660077032009, 0.8008352149282, +0.0263123293530, 0.2339973311098, 0.3394009505116, 0.5878766936194, +0.7701611312899, 0.0536782061931, 0.1989455135534, 0.5304921183411, +0.4909839259884, 0.0670579239107, 0.9484800882398, 0.8558625610805, +0.1978644724925, 0.1186712217138, 0.8558000972754, 0.1680603191108, +0.3349342054384, 0.8560692038648, 0.1151109664306, 0.4737320199952, +0.9171352441968, 0.4198726473469, 0.9403259604891, 0.5390365834064, +0.0548544028098, 0.6412965644343, 0.0672113453351, 0.2540191883473, +0.1210957421554, 0.7133078648305, 0.5172259674953, 0.5332190490017, +0.3871190363481, 0.1474080719740, 0.9473051959403, 0.8566269180070, +0.0021132701086, 0.1572801671723, 0.2010862781671, 0.1462507094938, +0.3176266855177, 0.4930971960971, 0.2243380910830, 0.1495663659412, +0.5538702083537, 0.5154911580102, 0.6117684178109, 0.0801381878928, +0.2659159676479, 0.8888044137921, 0.3715603614094, 0.7268793847071, +0.5659055097801, 0.1830512113790, 0.3086770606733, 0.3118863214328, +0.9091074554758, 0.6207599125899, 0.8243477758134, 0.3758884064741, +0.1982006608500, 0.0302031971655, 0.3340677769548, 0.3415737428430, +0.4276236823889, 0.5853196971981, 0.1776112691395, 0.2813729728951, +0.5282639137135, 0.4297369524975, 0.7425998643705, 0.3786975473066, +0.0470761433463, 0.8458905992312, 0.9228341485946, 0.9669379559192, +0.2614819506470, 0.6009463517000, 0.3613817567757, 0.5346025664055, +0.0448284396179, 0.5273979182948, 0.4897507654921, 0.7329421186507, +0.1743162321739, 0.6107339498637, 0.7104491296739, 0.7984278261654, +0.8763706478646, 0.0834236871840, 0.2314938619880, 0.5347969050216, +0.8469346123035, 0.0745713082489, 0.1136268848151, 0.5655616394084, +0.6699357017269, 0.2745582942267, 0.6598910054471, 0.2912381539546, +0.3694288252710, 0.1981996149748, 0.7042952467242, 0.4024908698176, +0.1617319607929, 0.4165049686173, 0.0440902137403, 0.6271293948531, +0.1384140887011, 0.4232139114399, 0.0174513203173, 0.4054719705160, +0.3056299115092, 0.1832425287847, 0.9506118297347, 0.5072020858094, +0.1958578634988, 0.4799461441487, 0.7939764786484, 0.6610609589429, +0.5910319795790, 0.0722285113634, 0.5633698313326, 0.0254703401707, +0.9682348705680, 0.4379665914168, 0.1467998196123, 0.6769967161478, +0.2091816948770, 0.6381705718293, 0.7125248856435, 0.8066908255251, +0.0439495267551, 0.5786105201480, 0.8363701868040, 0.4168201319020, +0.2859323705947, 0.2056814875480, 0.9951154887653, 0.8804604005443, +0.5197688944264, 0.4243464597614, 0.6288953994535, 0.0125668086170, +0.2405681876655, 0.8253988064012, 0.6075889885461, 0.5795072287226, +0.4270358068994, 0.4364260511642, 0.3053449500843, 0.4015654667288, +0.5457114975647, 0.0180677864785, 0.5086545625276, 0.8687147814169, +0.4621452076650, 0.5139463676670, 0.4560343778953, 0.6554543826056, +0.5853793954409, 0.6713269025419, 0.1521169390306, 0.1685592635388, +0.8689475259133, 0.6293289221960, 0.2499374222243, 0.9884871258347, +0.2576197196066, 0.1548798960423, 0.8350104102097, 0.2450529105240, +0.0434130374544, 0.7773886140331, 0.5792263558038, 0.4639058091975, +0.5883808106130, 0.2839812251199, 0.6027874199687, 0.1868153438842, +0.7768471514698, 0.0154166175124, 0.7204072767498, 0.9081323700529, +0.8845162214174, 0.3225586485688, 0.0334844039909, 0.2290618388118, +0.6580780454250, 0.3466614286167, 0.8365050162359, 0.4895187818862, +0.9771090806355, 0.2434574408659, 0.0179883306930, 0.9886219552665, +0.5129786639069, 0.8460566060832, 0.8727863630619, 0.2679257529173, +0.1717025815377, 0.7705983835136, 0.0009365016599, 0.7077967728059, +0.7669782018135, 0.2151156194578, 0.5479869970810, 0.5801628579293, +0.0589067866369, 0.3553590124265, 0.4990968445777, 0.1507744170496, +0.4485659601393, 0.8357539381067, 0.3707756299389, 0.2195041208619, +0.8937788158161, 0.3330821810910, 0.1583125862099, 0.4042600339298, +0.9834395572466, 0.5518568612411, 0.6797436101733, 0.9948176024458, +0.9656576942493, 0.9605486374165, 0.7953143021070, 0.6977319408663, +0.3758974375091, 0.4786363576905, 0.8066052430340, 0.6681006647032, +0.3877046026232, 0.5476000190469, 0.2492347407384, 0.8075417451596, +0.9479961548690, 0.1546828039711, 0.7627156385047, 0.7972217378194, +0.4813166039443, 0.0069029415058, 0.5100418163976, 0.2618124830824, +0.2850774798007, 0.9298825640836, 0.8426568796126, 0.8808174463365, +0.9957870682682, 0.1788562956168, 0.2629647451746, 0.0009694658224, +0.6404402957486, 0.9792266255148, 0.7307131568579, 0.9427083553480, +0.1941281227368, 0.6060979895322, 0.9397752624656, 0.5260274584992, +0.5539222501935, 0.5700255602459, 0.0847343467571, 0.7463805054996, +0.1311908253148, 0.9416268528167, 0.1176255792927, 0.3339690874955, +0.1421537004142, 0.0791869797181, 0.0963096563221, 0.8803412177974, +0.4871689190563, 0.6234703048242, 0.0860899212240, 0.6063514731854, +0.9297162671246, 0.7722463993226, 0.5533528684421, 0.9287468013022, +0.7590259684990, 0.9255033349271, 0.9511026949394, 0.8163176136167, +0.2078433093651, 0.3994662642476, 0.9047299599763, 0.6818158513316, +0.5908857274758, 0.4019714321019, 0.0055642533142, 0.8445052224419, +0.4242676880324, 0.1448079772037, 0.9719969928134, 0.0902986005369, +0.9699637894379, 0.5554585133472, 0.0864348295547, 0.0896225716405, +0.7890959590623, 0.1121174898521, 0.6346454935310, 0.1827444858769, +0.6494822155915, 0.2762648781185, 0.7355877946762, 0.7207354147549, +0.1052582762694, 0.5791984822504, 0.0485112769755, 0.2889406626527, +0.6814298227809, 0.8642842447685, 0.5047018171776, 0.9996139719149, +0.2539369986644, 0.8892731321460, 0.2637505085504, 0.4094317766882, +0.3596133628672, 0.8448227261402, 0.2912445637822, 0.2693147623303, +0.3528641277705, 0.7838810508996, 0.9896307033438, 0.2632415561300, +0.2588100187754, 0.3228279172083, 0.3393395642467, 0.0760655324329, +0.6947204720670, 0.0479059773720, 0.4349454070604, 0.9739850577777, +0.4594738639237, 0.3442026876585, 0.3241708554906, 0.1705332012710, +0.3722961039153, 0.5647321401931, 0.9234011699089, 0.3726821324661, +0.8375347637746, 0.0537259262305, 0.4290163849616, 0.4281029866208, +0.9620816558423, 0.0914717619733, 0.9429990583765, 0.6927668935120, +0.4974851782888, 0.3216950182438, 0.9362944885792, 0.2342436221588, +0.0019907238902, 0.8503493065249, 0.1055760691434, 0.9259251914573, +0.4189006907022, 0.2608007426657, 0.1731772232676, 0.4449156333902, +0.7786558315990, 0.1136211623035, 0.3087067200377, 0.6081226303280, +0.0055597079944, 0.2381296950570, 0.4578238499620, 0.6328775759939, +0.8093280064917, 0.3778558123754, 0.8028618357158, 0.3812250198709, +0.9246451137237, 0.6468627698006, 0.4315817386059, 0.2318782202117, +0.6088244191412, 0.8867267695659, 0.7383345322396, 0.3745807969824, +0.6005542113448, 0.1063095969643, 0.2084217873441, 0.6746290203531, +0.7589134898777, 0.6025449352351, 0.9566589034892, 0.3139978564875, +0.7379587566191, 0.1778141801142, 0.8633456779008, 0.1298361262911, +0.8049299739324, 0.5166145877524, 0.2914353428834, 0.1720523979385, +0.1304842122507, 0.8104896819268, 0.7547442832751, 0.7492591928454, +0.7894843387369, 0.9398122192080, 0.1883454938365, 0.5576061185252, +0.9945080298905, 0.7141294519948, 0.5866749885430, 0.6199272329081, +0.9996385406701, 0.6033324485660, 0.6008562210951, 0.3250095203170, +0.1232758649268, 0.6001927520149, 0.7096420455303, 0.8092780089049, +0.7961370753106, 0.8821893552701, 0.2027376867844, 0.6663009490195, +0.2381357626236, 0.5340958319298, 0.0600035349187, 0.0660833646851, +0.1006980706475, 0.0430657360903, 0.0507104192165, 0.3514388778021, +0.3630608205512, 0.2311822828982, 0.8535554180171, 0.8054547024916, +0.6618281447617, 0.1525451588223, 0.1709945016406, 0.0419009118536, +0.0826790105005, 0.6563361741865, 0.8666746112828, 0.7576694906492, +0.2768088403516, 0.0823175511706, 0.2596686222868, 0.4675308319123, +0.6356116163710, 0.4000847057440, 0.6825103031856, 0.9693106678172, +0.9513313546550, 0.4317486916817, 0.2822740605484, 0.8852479899699, +0.6937164737348, 0.1894671168129, 0.9658445236114, 0.3422775954671, +0.8220096453195, 0.7944145443823, 0.2325328529033, 0.0165549423623, +0.1279891827740, 0.1850704654050, 0.0255968268149, 0.0860882709204, +0.9542608195703, 0.7898173275356, 0.3376156246930, 0.1965913289211, +0.6718210674225, 0.0369398296051, 0.4461535012564, 0.2042902355102, +0.6751327908948, 0.9486299082398, 0.1192573807758, 0.7058221235433, +0.6870156739312, 0.3107444072658, 0.3487146135181, 0.8017676839613, +0.9732662695336, 0.6383470281206, 0.7424930989474, 0.6309886740665, +0.7248925644555, 0.6669827428027, 0.8278141453992, 0.7083376220932, +0.1464352687571, 0.5469022093093, 0.4613972867194, 0.0603469978368, +0.6835854429210, 0.2744244515311, 0.7319726751800, 0.4869941139999, +0.2738785349177, 0.6378462620256, 0.0642417786011, 0.0695882994074, +0.2162174029351, 0.9456996023402, 0.6747860916307, 0.5103952798575, +0.5958111563678, 0.8913501942956, 0.8943295101143, 0.7940434728721, +0.8740327972332, 0.2828268298334, 0.2020946010957, 0.2430441231667, +0.6529253216707, 0.8472990667668, 0.9211738584196, 0.9445877000431, +0.8093350011899, 0.3778178856605, 0.5142818091038, 0.7489880033531, +0.4626732098231, 0.9557702704127, 0.9247200954355, 0.9756790962888, +0.7262810695573, 0.1462586522783, 0.2301947214781, 0.6566927701499, +0.8048317804024, 0.0001596040093, 0.7841049143039, 0.2944365005449, +0.2529344778754, 0.0210491833375, 0.9458592063495, 0.4588910054690, +0.0832328391649, 0.8487456347089, 0.9123993776331, 0.8401887164638, +0.0590816778406, 0.9572656368638, 0.1315724640766, 0.1144939782631, +0.8017343253837, 0.7120069995113, 0.8045647031649, 0.0527463220305, +0.2945256076262, 0.6110693265735, 0.0898248847061, 0.3188465118030, +0.6712377498258, 0.7571988174492, 0.5668395965206, 0.0145449796759, +0.0914708180779, 0.3975188189175, 0.9034574697276, 0.7970343179987, +0.1464533890348, 0.8963025989459, 0.3976784229268, 0.6875623835658, +0.1837263452745, 0.3993878669103, 0.9173517822834, 0.3435376292763, +0.9442451377140, 0.2669591844394, 0.2481335011535, 0.8297511594509, +0.4324522877263, 0.0033268150889, 0.2242248208375, 0.3797059656958, +0.3476360358054, 0.2341866131100, 0.7153338146002, 0.0287895235367, +0.8197036794479, 0.6421616434316, 0.8452559396835, 0.8051586993063, +0.2091298532715, 0.4909414288080, 0.3993604608808, 0.4120955357384, +0.9903803141743, 0.3006006718150, 0.8884602481911, 0.3028179301428, +0.6296762999285, 0.1368337027434, 0.1969032702953, 0.2861386706522, +0.9440062115639, 0.8134026452030, 0.5362215696537, 0.1142550521131, +0.1640610365030, 0.8882513488123, 0.0803618296424, 0.7843550712729, +0.3333761744822, 0.5965133242293, 0.8915781639011, 0.3045866504799, +0.4120706768763, 0.6810122102876, 0.8306999373393, 0.6069119780357, +0.0880514118299, 0.2317743558585, 0.3231738532536, 0.6759558765571, +0.0253522442772, 0.2971812655670, 0.7227157851321, 0.7225343141344, +0.8973147035098, 0.0157325579858, 0.5977819373821, 0.6111760328576, +0.9089402597905, 0.5269910034384, 0.1525662607292, 0.7946852076774, +0.4731429011902, 0.8529464708888, 0.3403936481757, 0.6887878303830, +0.7253421287636, 0.6372039376931, 0.7411978192354, 0.4207554778181, +0.2396879602408, 0.0587183027802, 0.2337172619224, 0.6327759826708, +0.7403730758188, 0.6517586371171, 0.7397305130678, 0.0644171987960, +0.7854386804558, 0.8284244876487, 0.8835329934412, 0.0629043658557, +0.2174248104996, 0.8107909247329, 0.1256057527501, 0.6062487781077, +0.5180728973439, 0.1147395135438, 0.8265234827187, 0.7233876901322, +0.6678775733653, 0.4270131566688, 0.6417305169821, 0.9790897434480, +0.4028796429759, 0.1410204745554, 0.2799596270919, 0.9821241656235, +0.6539334285324, 0.1282217712739, 0.7782244122486, 0.0211574458616, +0.0763588729670, 0.8936213887733, 0.1869400740540, 0.0119416737053, +0.9895749534432, 0.8167319487858, 0.5453800258904, 0.9266705871218, +0.0351617965080, 0.7750136334333, 0.6451564359689, 0.4289130188659, +0.4941498788512, 0.2525866070076, 0.5858045577006, 0.7707621891847, +0.3914177829360, 0.0122227761951, 0.3673261205514, 0.4123280399536, +0.9911808031570, 0.0592953558356, 0.4392359328639, 0.0090566375335, +0.7403530062830, 0.3940604456673, 0.2003158303910, 0.7191955604214, +0.9904819168106, 0.3942864348154, 0.5222822174068, 0.9785402431053, +0.6358928785827, 0.0668407893120, 0.2879078231230, 0.7092222914608, +0.2622008674136, 0.6254678315602, 0.8835727380978, 0.8332878490134, +0.2994913627857, 0.2973626639216, 0.4004814645278, 0.5287291740667, +0.3986140617163, 0.7936412416369, 0.5499492709292, 0.9862860222283, +0.9263320294797, 0.7900318446523, 0.8058640178320, 0.9172753919462, +0.9642955111173, 0.9175128321711, 0.8493272004879, 0.2450999506959, +0.0281832735185, 0.7046485169347, 0.3115732773727, 0.0496430308789, +0.5430777862403, 0.0186651898635, 0.0989349512844, 0.8338554947795, +0.2201306234208, 0.1789706643573, 0.0855059796411, 0.3868427748731, +0.4978078913399, 0.4823314913001, 0.8044384959174, 0.9690787177389, +0.1912059817422, 0.7972992541256, 0.7796941552217, 0.2049199599796, +0.2469188176314, 0.5898200434585, 0.5909404957625, 0.3296434261508, +0.6419044638248, 0.1732508466454, 0.3798518876451, 0.3968045131288, +0.2788221185463, 0.6061999744765, 0.0907636783508, 0.2291790876673, +0.2361924505030, 0.3070053920648, 0.3108484914111, 0.4023369557235, +0.7966262175686, 0.7792702367433, 0.3256705823940, 0.4097834426955, +0.3802552793083, 0.0167568409893, 0.9582409011006, 0.4111765620351, +0.9675993565319, 0.8780631711139, 0.4990883322894, 0.7626793965524, +0.6084259131963, 0.1588053378085, 0.6753624247738, 0.2787824870454, +0.6631074336651, 0.8553447308277, 0.7486253812670, 0.2663029200706, +0.3576563561138, 0.3050118970242, 0.0285955770074, 0.1284772684465, +0.5216962115474, 0.6364784751257, 0.9112118719664, 0.1193592553583, +0.6318438056073, 0.7578886620504, 0.9434838671905, 0.2220603629118, +0.6803310111539, 0.4284700231759, 0.5371588983280, 0.2691544491188, +0.2580791950496, 0.0605862904622, 0.4452268641653, 0.4953997989629, +0.2230976830344, 0.2256785511159, 0.9386494615761, 0.9443151964547, +0.8803148064205, 0.8315235966963, 0.3844838889243, 0.6140118858842, +0.2615865381721, 0.5434222396200, 0.6868683270583, 0.1331092697257, +0.8348231598897, 0.6192428942859, 0.8484341366442, 0.7154639045314, +0.9817063710567, 0.3565193709715, 0.2557213689460, 0.7596460081449, +0.4683596852554, 0.6135501766640, 0.1144080325563, 0.1992052361365, +0.1469667293816, 0.1486906964093, 0.0420201993743, 0.6515669308843, +0.4315622595286, 0.4050459244312, 0.2092769868715, 0.4872470635396, +0.7619383338662, 0.6546599425630, 0.6307244755471, 0.1479264479819, +0.1483176337314, 0.6422531398210, 0.4861835387937, 0.0152083640058, +0.8885157703834, 0.4099041719036, 0.1856753789753, 0.1730518658520, +0.7937555237644, 0.7233389298075, 0.0291470661895, 0.0341095156195, +0.4840736712721, 0.7754618948211, 0.0798583007789, 0.2848684351355, +0.8458332646852, 0.9524333569931, 0.3890120710195, 0.1942663333352, +0.9182793339334, 0.9927999940667, 0.1011240529367, 0.4310322703938, +0.4583274877902, 0.3498415929963, 0.3978459184979, 0.3104010398082, +0.0437787580508, 0.2202658211907, 0.0045015350936, 0.0285703935793, +0.6637369402050, 0.1920963917822, 0.8625189614773, 0.4906850743530, +0.0823038556065, 0.5522527101227, 0.6020005641514, 0.0481943399870, +0.9160160654765, 0.8760593798366, 0.2755916394645, 0.6311476303410, +0.5497162740443, 0.4000897367485, 0.6515212741920, 0.3554499402435, +0.4715656151397, 0.3955495382638, 0.3525230932760, 0.0405333447459, +0.7640481860209, 0.3898449486074, 0.3883495318649, 0.4536471462127, +0.8147658444078, 0.2223756733455, 0.7396865416037, 0.7861954503628, +0.2348731505847, 0.8585446024586, 0.4426414945361, 0.7441880766974, +0.3533547960005, 0.8986100907897, 0.0506409937752, 0.3051604555478, +0.2837891878019, 0.4356586516070, 0.4508628004467, 0.6526415579266, +0.0819043801548, 0.1998052532784, 0.3117180309779, 0.7264544403769, +0.0037726494501, 0.6316206541991, 0.5998949900269, 0.9632393051699, +0.4060652290499, 0.4753382645898, 0.0271701919973, 0.9524180833029, +0.2017151742250, 0.1701134146052, 0.8651832131972, 0.4155197243278, +0.3490578310327, 0.0164810181672, 0.3924890879507, 0.6048697543353, +0.1402910380346, 0.5839309816174, 0.8750256206258, 0.8351305824868, +0.5783081723276, 0.4936458340351, 0.4825410724071, 0.9256666148667, +0.6598583127651, 0.8620973605952, 0.9293044856420, 0.9334038728538, +0.2042618213241, 0.7417626933855, 0.0619026134079, 0.2410225166199, +0.6142156862720, 0.2080344712399, 0.3733833471189, 0.6617976034348, +0.8160732639097, 0.0202809148563, 0.6833727358297, 0.4005535395819, +0.1534257028966, 0.0177884376691, 0.1903943294615, 0.5485559490270, +0.4180139994333, 0.5024835339293, 0.0342694563019, 0.5828834174121, +0.8349616913288, 0.5583050374679, 0.0864145155467, 0.9092950769278, +0.5023594603419, 0.4132698636564, 0.0519508710373, 0.5689555879538, +0.2222778732992, 0.1622177731070, 0.2753672237859, 0.9812553571450, +0.9990674406286, 0.4265396946233, 0.9039804664925, 0.3372698371938, +0.6779173527276, 0.6132831264349, 0.6345741658633, 0.2773638131457, +0.8665028507200, 0.4939906161716, 0.6335640412912, 0.3179469016930, +0.4068417876991, 0.0199285531509, 0.5117790543063, 0.8239583707526, +0.4553435870704, 0.8248557871323, 0.5224120875459, 0.5460485106083, +0.1777821905808, 0.2903052783992, 0.3831608246002, 0.6088266030926, +0.4163670523168, 0.6801416509227, 0.7035751420556, 0.4351116956375, +0.3162122025696, 0.6386449256161, 0.8423594240296, 0.9789423658414, +0.0237037032022, 0.3152796427325, 0.0651846202394, 0.7463398900564, +0.0177056873300, 0.7016210559297, 0.9285627691674, 0.6997587861026, +0.3860851802798, 0.8842085380499, 0.1956116721014, 0.5621268099929, +0.2534392365503, 0.7929269679789, 0.9041370916665, 0.7073907264077, +0.0353757813738, 0.7087828236207, 0.6177827546456, 0.4265491787468, +0.4360552748833, 0.2131579719545, 0.9990881020199, 0.0009435787801, +0.6816056089856, 0.8524223272001, 0.8932996228772, 0.7026632436098, +0.4819989364976, 0.9978178115551, 0.4910672528162, 0.7356590469068, +0.2560106586926, 0.5057026396998, 0.3130974538220, 0.5562518730556, +0.8037870325166, 0.2737163464882, 0.2073236956295, 0.2416602225237, +0.1103260936729, 0.1898722123308, 0.1579248840725, 0.4029353677309, +0.4886111540201, 0.3637653302233, 0.9827991803097, 0.0620619752733, +0.6015255137354, 0.5239869353939, 0.0725481533783, 0.6005819349552, +0.7742994990080, 0.0375807881530, 0.7371449073484, 0.0716362553982, +0.3661035766667, 0.4559051079936, 0.8900031158188, 0.6304445302256, +0.9373222412250, 0.8481025131643, 0.4537229190831, 0.3810703681694, +0.0084805954287, 0.1933328994519, 0.3538051528641, 0.7668203733707, +0.9640642162245, 0.8122676284110, 0.4670492459401, 0.5611288484936, +0.6870361057515, 0.0743903094318, 0.0021398402760, 0.6249741304782, +0.5855209555409, 0.1756472597717, 0.4381556396550, 0.9849390210514, +0.5823400484316, 0.1870464688107, 0.6996341951655, 0.5107037930334, +0.0672236322738, 0.3566395474396, 0.2246272574294, 0.4367791025139, +0.4957007409519, 0.4333272089406, 0.8125446554332, 0.1146303727825, +0.0330879469556, 0.4330229817112, 0.2814297216392, 0.2662675740506, +0.1963637225313, 0.0415685428500, 0.6263558811631, 0.6352348745033, +0.7183792575814, 0.1604279382901, 0.8538361712610, 0.0934051271032, +0.8409150321227, 0.4054153628673, 0.2348182477219, 0.8559760115370, +0.1836776804103, 0.4264359871980, 0.5810626226389, 0.6729738873769, +0.7174759203184, 0.7660177288419, 0.6134824564743, 0.2806968178045, +0.9527400866862, 0.7846995525922, 0.1226572758158, 0.8381097139037, +0.2014695052996, 0.4484408271725, 0.2180267610671, 0.9352019312490, +0.1346913572097, 0.2345574522552, 0.8814638088837, 0.4994564827063, +0.6012248166843, 0.3310550797410, 0.2761259951052, 0.5078196895811, +0.9859381779032, 0.3196040738000, 0.4914830184968, 0.1299621659005, +0.3992751535956, 0.8268532095602, 0.7250194371329, 0.7263012662187, +0.5867788771106, 0.5829528340059, 0.2532891967582, 0.3060820593061, +0.7048813666705, 0.3042547969633, 0.3489705623821, 0.8667716532325, +0.4068297694469, 0.6576214528911, 0.0889543490899, 0.4716278386636, +0.8064375933290, 0.6082992747465, 0.1060622795979, 0.3069811101570, +0.4953457775970, 0.9411289505386, 0.8428567274673, 0.9875260884815, +0.2489448884730, 0.0965705942812, 0.2721840298139, 0.1189827221068, +0.4899683145294, 0.2348830659105, 0.4161746680812, 0.7636670483107, +0.4472761645202, 0.8892434681250, 0.0617362750050, 0.1411941047484, +0.1817971245301, 0.0340550411651, 0.4721963016652, 0.3150254717632, +0.2927947022453, 0.8866784912006, 0.3383098385941, 0.8211668640474, +0.7342452983066, 0.6996244721579, 0.5442999436261, 0.4272641876839, +0.6378883112398, 0.5406828911699, 0.3079237464387, 0.6503622232240, +0.2697631960128, 0.1332340888368, 0.4818118412429, 0.1507804734403, +0.5176629193675, 0.5187080844858, 0.2298046831180, 0.7539958710568, +0.7871734564133, 0.0076312334312, 0.7535911503963, 0.6459793511992, +0.1303528971646, 0.2344496204678, 0.8968747015562, 0.8153274254013, +0.1902378663375, 0.3121500216947, 0.2685046616329, 0.3690710027558, +0.0340786879110, 0.4830325690485, 0.1988285128953, 0.6068145002270, +0.3934906797453, 0.7683239862175, 0.1826570407407, 0.7431284565214, +0.6413612610853, 0.0313789905195, 0.3090068769218, 0.4905807871793, +0.5448145887557, 0.9111244570981, 0.1646130793563, 0.7908187181646, +0.0403971136736, 0.0624775076576, 0.4298325411183, 0.3944177624744, +0.9987511164503, 0.8275705700869, 0.0701087410888, 0.1834236910489, +0.3360544449352, 0.1291040131492, 0.0620201900890, 0.9669834426450, +0.9373393524146, 0.5262923117384, 0.4412540353095, 0.3305248517220, +0.3832110042606, 0.9714180403256, 0.0093248803212, 0.6400825482048, +0.6825627082412, 0.7767016840059, 0.7397420260775, 0.1919819210619, +0.8395676206982, 0.3239239688608, 0.8080806749910, 0.0487489025336, +0.3671115168217, 0.3843822089882, 0.2350484254933, 0.9726937543474, +0.8483046576606, 0.4075086304953, 0.4468597171115, 0.6648809666116, +0.4839519008454, 0.8470557741109, 0.2350792001165, 0.5169684582003, +0.6276242419275, 0.8200063457806, 0.9761597872601, 0.2970993902055, +0.0574963698431, 0.5649635938764, 0.3462986570533, 0.4174138221040, +0.5476054584364, 0.4407073745694, 0.5363816337364, 0.3556235373745, +0.3248725618817, 0.2301681666775, 0.2174090581096, 0.2761236593482, +0.9981834874480, 0.1644401821142, 0.5540921355384, 0.0254897326350, +0.4540215276433, 0.3652950038040, 0.5488223915681, 0.7891405614974, +0.5126505664143, 0.3023261853039, 0.7728036342993, 0.9956821086796, +0.3049822241557, 0.9966024672597, 0.1493819589491, 0.0078828339502, +0.5429555683131, 0.9326064660831, 0.8166088130402, 0.1255417457435, +0.5185310074680, 0.6004519381562, 0.4975700599596, 0.1629074696279, +0.3100753530441, 0.0661364654387, 0.0411593122599, 0.0339516932303, +0.2840581034702, 0.6349479149258, 0.2963046321163, 0.2585683708352, +0.6395373291520, 0.2822415904525, 0.7993880975057, 0.8503967681203, +0.3438925968222, 0.0935588563297, 0.6475365942565, 0.3482104886082, +0.4282230620404, 0.8565431632365, 0.3958850416336, 0.4203402280902, +0.6708087467918, 0.7332052861961, 0.8531456304962, 0.5452670005827, +0.8326619126986, 0.2137643146393, 0.6658117522792, 0.6697544430707, +0.1973335050034, 0.3511929197010, 0.8142162527955, 0.1633818117731, +0.1139439358907, 0.5074088580475, 0.4173293856053, 0.8553755655211, +0.5640307853762, 0.3980020393608, 0.1423567729734, 0.7136340177216, +0.2899553586216, 0.2035681140626, 0.6802436302790, 0.9417448704791, +0.7481204526257, 0.6338479554438, 0.2971269708579, 0.3277802240699, +0.2382790130741, 0.1763435142005, 0.4903911182146, 0.6930120124915, +0.0132911908502, 0.9090877598660, 0.9095488008622, 0.3435367482451, +0.7387423644488, 0.8459531040145, 0.1228520740396, 0.5753605526757, +0.7924438918906, 0.9360758694522, 0.1971460232498, 0.9370683268351, +0.3281094265767, 0.9063878277812, 0.4434847274998, 0.6144754088551, +0.5275863704866, 0.8921402119529, 0.3043898671420, 0.5858415004731, +0.3124137210252, 0.8175417291082, 0.0957083260155, 0.9846334974210, +0.0858473088992, 0.0605341731853, 0.4513896840864, 0.3928352968734, +0.2853175505462, 0.3241263219733, 0.2368776878514, 0.9417808023010, +0.7217870409236, 0.2986087413964, 0.2332140813736, 0.1464264882479, +0.2931344822483, 0.4605294049068, 0.1445618449452, 0.3560661554132, +0.9561832775158, 0.0855783736732, 0.3966052738934, 0.3417078686607, +0.4259315014006, 0.2842927036268, 0.9919662019200, 0.8400900013932, +0.2809895655517, 0.9535178718872, 0.1764329155797, 0.2963560685964, +0.6649765384686, 0.5934032865769, 0.7710596005298, 0.2721412415952, +0.1642300864515, 0.7508238473678, 0.6539374602278, 0.2224492841505, +0.0372416358615, 0.4495476369977, 0.0749501693411, 0.8908151480792, +0.6642304065936, 0.7590286767851, 0.7481563783941, 0.3081642507148, +0.2344260919999, 0.9573648888419, 0.2195580812262, 0.8927182238049, +0.4562533565128, 0.1906093690501, 0.0429432620494, 0.6161633551196, +0.3312655321002, 0.8821848579134, 0.4749020731425, 0.0349094635038, +0.9234762303175, 0.6122550976520, 0.8357027298006, 0.6513349887223, +0.8292116144808, 0.5884527683204, 0.2056583842289, 0.6067623298647, +0.7504109920703, 0.9934417009323, 0.3392766152226, 0.8595958444567, +0.7223910357442, 0.7876526279317, 0.4429893374643, 0.4142267845637, +0.0838639387320, 0.3866214418721, 0.5466813042512, 0.1911457153927, +0.3824027401313, 0.3182900307320, 0.3439863302484, 0.7662393854774, +0.4218390562673, 0.8386560966441, 0.5088994002477, 0.3869295922978, +0.6351364616468, 0.7531045883676, 0.7208409545575, 0.9838014733902, +0.1633060132914, 0.5586126914986, 0.3653596860195, 0.5565436838924, +0.4306139142395, 0.9925176277722, 0.1470654593534, 0.5710180702484, +0.9005688596054, 0.1810249058441, 0.9859593282388, 0.4863420745760, +0.6200943810959, 0.6229598948839, 0.9686775337759, 0.4289486652375, +0.2815982225731, 0.7039583198279, 0.0095813362904, 0.5153588375614, +0.7404972588366, 0.6640009627044, 0.0222483505598, 0.3535676665388, +0.5149492237321, 0.1623363146383, 0.5026570593485, 0.5311477508075, +0.7800416973327, 0.1500856849133, 0.9154409034715, 0.2234980134403, +0.8518186592738, 0.9433477106240, 0.7086983764119, 0.2808005890254, +0.3421059098756, 0.2824325730477, 0.9358653383962, 0.8557638357653, +0.3507733314069, 0.2426747690154, 0.4634574788918, 0.9218246661694, +0.9474938497634, 0.9708677125028, 0.8656346638993, 0.4321350122020, +0.2287836662628, 0.2290920718709, 0.6748260318650, 0.8752160001896, +0.2282221327667, 0.9692809255651, 0.8930930345753, 0.6970743824249, +0.6192481068984, 0.7431713564988, 0.1316172397377, 0.3957500934581, +0.3278587317690, 0.3992898037654, 0.8932570414121, 0.0470581427436, +0.4577192526579, 0.1796773905771, 0.3426375143894, 0.6019554173583, +0.2003275180237, 0.7998251629993, 0.4621099636248, 0.2785028523200, +0.3577024542530, 0.5511008494306, 0.0424999315490, 0.9255674425166, +0.7833505956379, 0.3051963035507, 0.5219685614677, 0.9081345959139, +0.8938689757576, 0.0121342619006, 0.5342883754216, 0.1967945933327, +0.8231315034549, 0.1220911085243, 0.9814151874657, 0.4273814099968, +0.1600905699470, 0.4423796103533, 0.8652624650231, 0.1130324267377, +0.3604749233278, 0.4879493017159, 0.8416694141187, 0.7585195064352, +0.4628097803624, 0.8181941764514, 0.6676266927587, 0.1843069280425, +0.0553040984344, 0.6631372988518, 0.6180193389850, 0.1297366559178, +0.5686538659822, 0.4130065526874, 0.2142381478167, 0.6605192705339, +0.9330013030828, 0.3520044616200, 0.7182028567038, 0.7362067097501, +0.6798726416565, 0.8268702783747, 0.3641387235206, 0.2524912316597, +0.4585863372584, 0.5030041451114, 0.9489613868990, 0.3455539105207, +0.5727433578916, 0.6186769072053, 0.9453837554648, 0.8142238519221, +0.9713600976259, 0.9332182812193, 0.1066262089213, 0.7870531691178, +0.9039895575978, 0.4341698775227, 0.7514124572051, 0.7742529016800, +0.0299510662583, 0.9592936560322, 0.0973071759088, 0.3694317957244, +0.0477520334757, 0.5986049322405, 0.3723002087196, 0.3115453241912, +0.3429942966173, 0.9807533365585, 0.9506093938605, 0.0905030649577, +0.6603020274361, 0.0228669382738, 0.8076236144675, 0.3147481169155, +0.5708088528229, 0.1188883646945, 0.5258710833853, 0.7565850013665, +0.2583080070365, 0.1435522102488, 0.7375652718998, 0.4712548383843, +0.6184443820354, 0.2296681041967, 0.0767704910025, 0.8441914808211, +0.1976147439320, 0.5224339396332, 0.6638379821851, 0.8281829486732, +0.0726904818195, 0.2275658101903, 0.4817275951997, 0.7611451580940, +0.9445308688770, 0.1204425152952, 0.8261707428965, 0.8540278039193, +0.0915282532068, 0.2875251654943, 0.1011958513880, 0.7767801362913, +0.6654044672220, 0.7518302806429, 0.3103921037681, 0.9088194663212, +0.3075180250721, 0.2362133195792, 0.8707186453374, 0.8362631871534, +0.4524753975926, 0.5658260321085, 0.3797655298280, 0.6082839172372, +0.2847189690381, 0.0709197796280, 0.7954941367710, 0.4565360208305, +0.2204772761187, 0.4823337134357, 0.5933537192612, 0.4593321184904, +0.9291091183802, 0.2931677584039, 0.7098995236260, 0.0750813139952, +0.3128504023481, 0.8736399867915, 0.4136102736991, 0.5360702660568, +0.4236255914083, 0.4043786555549, 0.1611651518201, 0.5148061255528, +0.3078204422760, 0.0890300581646, 0.1562089357321, 0.4715572555883, +0.6352114983067, 0.6153384673481, 0.3252433777439, 0.0269275810695, +0.1615449279368, 0.0876868954337, 0.1811644994566, 0.7050089075719, +0.4359907542523, 0.4462638974405, 0.1586066750617, 0.9766586362276, +0.8270417087837, 0.6564680303710, 0.9285976108762, 0.7519603943229, +0.1745674000935, 0.7561508266982, 0.9496357887749, 0.6384971340366, +0.8780521880267, 0.4874178024416, 0.6297908130241, 0.3632460624740, +0.2625132204325, 0.3016777789694, 0.8917964579965, 0.7909559653098, +0.0749329743324, 0.5703336631741, 0.3907078371340, 0.0480053932630, +0.4209601219841, 0.7101444726391, 0.1856721300565, 0.7159512148779, +0.3434952652750, 0.5825050499209, 0.7978313685385, 0.3668366295131, +0.7083984379230, 0.7794860195273, 0.0287689468957, 0.9564380436002, +0.5958636918086, 0.5354401462411, 0.4359540498983, 0.9573665577720, +0.7488359006815, 0.7704310919020, 0.2915909724737, 0.3855898382075, +0.7123377503419, 0.6268880882426, 0.2578488938780, 0.9213817854977, +0.1976507446718, 0.9748509712400, 0.9285658672119, 0.1496453514088, +0.0352249182925, 0.2725837194699, 0.5451846339485, 0.3192737038803, +0.0976933935181, 0.4561850402766, 0.9827281921090, 0.7308567640050, +0.7369976037820, 0.4411886587931, 0.0386900901975, 0.7805595601818, +0.0248255948652, 0.4453960412393, 0.2206746783204, 0.0674590370932, +0.0422185659605, 0.6206892866738, 0.9808361874804, 0.6566287282187, +0.1938089445205, 0.7910544671077, 0.3911203781101, 0.2724271594884, +0.7986146233969, 0.9061466953280, 0.4179425548846, 0.6489692719881, +0.6657821259768, 0.9962653680687, 0.8809976661024, 0.3465084220965, +0.1570390631245, 0.7010070447349, 0.2688490870729, 0.4261822995852, +0.0321368388981, 0.2547324566425, 0.1571920845458, 0.2515772791820, +0.2633412123021, 0.7691344426801, 0.6959211159013, 0.1958821747433, +0.5732245219747, 0.2881668071673, 0.2145304834538, 0.9165957942217, +0.4677938299569, 0.6154430879352, 0.9088560938411, 0.1953666704685, +0.9489457434737, 0.6616027749430, 0.4064975545772, 0.2999764714856, +0.1709485315582, 0.7475603664050, 0.5677494698054, 0.8244401099274, +0.8749294350273, 0.8367306575350, 0.7438257340080, 0.4487471354421, +0.2642521002629, 0.0319684976861, 0.5377377018043, 0.0126748210810, +0.8908119615590, 0.2963889391610, 0.2867009547943, 0.6949297868157, +0.8992178644516, 0.1541531733955, 0.0655233818411, 0.9826220706956, +0.4754205362291, 0.4724423859606, 0.4423199805628, 0.2800538652949, +0.6511525454238, 0.9432143661860, 0.0878854734301, 0.3511760739382, +0.3188231379347, 0.6000982884318, 0.6048171406634, 0.4943830284730, +0.6213137454453, 0.4897716694930, 0.3476586543711, 0.1725666100032, +0.1041592094601, 0.4962431800069, 0.3265023265623, 0.0914843883791, +0.5591698151823, 0.3684113097230, 0.5282116781586, 0.8642400288322, +0.7975347031828, 0.4499817762757, 0.6648002488840, 0.8149126329529, +0.0103774960201, 0.6967525671687, 0.6041349501368, 0.7303236307252, +0.3976310046379, 0.4857980322492, 0.1691949526636, 0.0464549302340, +0.7514634545666, 0.0487835495960, 0.4290123979696, 0.2570804260937, +0.2063961486362, 0.0702865920357, 0.6488818384935, 0.0338295386330, +0.0880248807781, 0.8277098945471, 0.5600582615286, 0.9965404928646, +0.7508006169232, 0.1921840902382, 0.3239530740883, 0.8865605885566, +0.6670773847341, 0.3099704316398, 0.5605953999612, 0.8521647522469, +0.9557192795704, 0.4646120874512, 0.7599522079155, 0.2253956488452, +0.4105420882863, 0.9660967755905, 0.1613646541542, 0.3640871575866, +0.5876400333772, 0.8081730929241, 0.4518948073741, 0.3305596068178, +0.9147367444424, 0.3391034874782, 0.8569566425201, 0.8809072058093, +0.5023789734125, 0.1211328926129, 0.4093900799795, 0.5058384805479, +0.8560089295991, 0.5904038541906, 0.9488427871600, 0.9694483415081, +0.1249606130295, 0.6068095460566, 0.7825879448944, 0.2727958612483, +0.5685789932351, 0.7920379982293, 0.9167799776964, 0.3431833443899, +0.0408193427328, 0.5242982728054, 0.2566500852148, 0.6767321856118, +0.7485743466525, 0.4513614310191, 0.4903950479303, 0.4180147398347, +0.8231970611136, 0.3362143795640, 0.2595345234776, 0.9422898557700, +0.6223296465456, 0.7379338050903, 0.6753178675078, 0.1164911659977, +0.0541562880642, 0.1247086194925, 0.8590666977032, 0.0847079470217, +0.0807053456459, 0.9101652181289, 0.7151124741487, 0.8079094848632, +0.8408837629673, 0.2056659586754, 0.5169747637198, 0.4977004185774, +0.1104869265624, 0.4094627562023, 0.9977039569047, 0.4337547414162, +0.6723687819542, 0.1513062692952, 0.9337610290077, 0.2543540421195, +0.3664459317766, 0.4209431281411, 0.6026677007799, 0.4241560764723, +0.9786933902552, 0.1896429924246, 0.7571575081708, 0.8622022242575, +0.5171833222346, 0.6010230368008, 0.9275767975150, 0.4324753752130, +0.5945529796158, 0.5713396102988, 0.7257316562933, 0.7866434952182, +0.9385445485537, 0.6752583252616, 0.4815048279620, 0.4408441299763, +0.4322343330980, 0.7794283115209, 0.8809242839371, 0.9984795921475, +0.1329822824956, 0.5427212596604, 0.1888910672576, 0.8786282408417, +0.5468081722720, 0.8053510644498, 0.6940275289556, 0.1226520957996, +0.1588974535274, 0.9132541045143, 0.2262941921252, 0.2966952292699, +0.4159270750433, 0.1375908433169, 0.1028970964732, 0.9834517002960, +0.8171173892064, 0.9331103972779, 0.7386138801177, 0.0304738939882, +0.9051896663872, 0.4116703683565, 0.5044500075767, 0.4643455364110, +0.9844344272206, 0.8437342149409, 0.0869286931525, 0.9859548355387, +0.8464812174656, 0.4166687598530, 0.6231625259962, 0.9678529770895, +0.9347056890534, 0.9794634999612, 0.9593900195134, 0.8120535932537, +0.9501127777389, 0.4815138608597, 0.7848145639453, 0.6534175484690, +0.9945604563665, 0.1090102308006, 0.3947679649083, 0.0111087560705, +0.5281389558353, 0.4104875314098, 0.2466010745832, 0.4976650618472, +0.4495604906462, 0.3452563445760, 0.3435979282221, 0.9852149547009, +0.8340027713375, 0.3547501570334, 0.7569267129325, 0.8480479357988, +0.8117083827088, 0.8184371980924, 0.1984843715087, 0.8438554060850, +0.6337004902930, 0.6581896001744, 0.2351059579454, 0.8216468975049, +0.8479135254621, 0.5684061788807, 0.6376530996699, 0.1944959769931, +0.4335764196858, 0.7980263032010, 0.0499200392747, 0.4224676636152, +0.9423530664958, 0.4281368755866, 0.9070365340016, 0.4446880046486, +0.1388525628200, 0.4704920218654, 0.8386244069965, 0.1536376081191, +0.0302702705517, 0.5884130534662, 0.8157483664415, 0.1822223352186, +0.4165304845276, 0.8642730418892, 0.9431632104996, 0.5726750789083, +0.9632944790476, 0.2282388667708, 0.6827102399816, 0.1416475815427, +0.1123121744545, 0.5969949688748, 0.8864284669452, 0.9178161979270, +0.9465492302303, 0.9602257003822, 0.1654011472899, 0.5240815666151, +0.6600091916788, 0.3801256494504, 0.7582520031176, 0.2153211870302, +0.8189261452383, 0.6023622577090, 0.8082625250371, 0.6652885366535, +0.8291092672521, 0.9577787080583, 0.0728542791087, 0.6468869320335, +0.4612777239928, 0.8593795378038, 0.5461917610588, 0.8886026455502, +0.6310025531012, 0.8778082085204, 0.7236525796930, 0.4893549715585, +0.3241790166703, 0.5942970321487, 0.1060470748255, 0.4063628192089, +0.5165571083857, 0.4364911911248, 0.1912920005579, 0.9924755422363, +0.5720143353436, 0.4631063381504, 0.3967168910414, 0.3566931483134, +0.8202574308125, 0.2320235265568, 0.8432319876008, 0.1549688936933, +0.2983814437400, 0.6391835755851, 0.8343857842658, 0.6514945121722, +0.7958427084591, 0.1274907105265, 0.5969622831777, 0.9072400633745, +0.6325090153294, 0.2571204319862, 0.9868702487959, 0.1431540437709, +0.1168856467665, 0.2635115684306, 0.1349286400410, 0.7105228280232, +0.2334512566372, 0.4410646634368, 0.8578086005793, 0.2409757148665, +0.4057937489849, 0.7500083650230, 0.8775558545615, 0.0491006006715, +0.4292416392962, 0.9778080843286, 0.2131147027077, 0.2742727456029, +0.7078412024806, 0.2494990696430, 0.2098316104197, 0.0563466898428, +0.9514574575943, 0.0062226457550, 0.8886826452281, 0.0442173942198, +0.6287989721768, 0.7473001655877, 0.1337133567472, 0.4856449279402, +0.8311064331006, 0.2613079870405, 0.0044205971083, 0.1205836050774, +0.3803249524815, 0.9479920798670, 0.5248195554711, 0.1393492371493, +0.4317287567219, 0.6137762091187, 0.3890567428381, 0.3826281555847, +0.5408853425369, 0.8375225057069, 0.3637845741416, 0.2666125969340, +0.6332459671578, 0.9701269822987, 0.8153305900355, 0.5768992768493, +0.0693795946750, 0.3410871691727, 0.2196260514761, 0.0251621999895, +0.5939536246443, 0.0208370518036, 0.3473098149278, 0.1083086967041, +0.6016067767523, 0.2227525963554, 0.7681372178570, 0.4810231716749, +0.9119070525802, 0.4327132093872, 0.4840605838616, 0.7725578149653, +0.3915082949174, 0.2922320045960, 0.3807052887886, 0.0088801388670, +0.0363746285608, 0.8232370516394, 0.9060082137147, 0.7697620316268, +0.8466920647056, 0.5772599710977, 0.6607595568806, 0.2697927873907, +0.5012523469055, 0.4799380313977, 0.5473869529308, 0.4760901464504, +0.8753217015766, 0.5706319415805, 0.8210252005705, 0.7670130048725, +0.6493581871732, 0.4692753257553, 0.5914689933841, 0.1683350150326, +0.1321640257408, 0.2509649634599, 0.6920279225763, 0.3596062107755, +0.1849686448392, 0.0440710778553, 0.6836781733128, 0.1760885059722, +0.8341454937282, 0.5764769397566, 0.3363030824514, 0.0643834616357, +0.5121040835567, 0.8705201222890, 0.3997139909303, 0.2423112957004, +0.5365636942613, 0.3587961477967, 0.4477800929210, 0.0604735478109, +0.7621800507243, 0.0378160407011, 0.8387341791944, 0.9951670463174, +0.8280943943318, 0.6375017518352, 0.6084479822817, 0.6597593792992, +0.5595231864413, 0.4774525810394, 0.1067770771248, 0.1999169756658, +0.9748935056733, 0.6916872121821, 0.7284175449649, 0.7988049997011, +0.4764791794477, 0.1598621505126, 0.7357582900374, 0.4120957178120, +0.3143726681892, 0.3106246727103, 0.7363390902692, 0.0720613720231, +0.1965266290105, 0.8264767517459, 0.1811447945336, 0.1360530811996, +0.6240919337720, 0.7330903232717, 0.1852728990769, 0.6289248879202, +0.6837664571049, 0.3862719840306, 0.7709063644385, 0.0240070778057, +0.5792713219203, 0.5118608509711, 0.0237737354002, 0.3793543462545, +0.9293558126918, 0.1387945083616, 0.9893134324762, 0.1305508125250, +0.1298266943217, 0.9042493178995, 0.8304817205437, 0.7177309769754, +0.6383013826042, 0.6063058737695, 0.0641114679464, 0.5662400105811, +0.9365036398808, 0.9526740507934, 0.9169305469454, 0.8004505586813, +0.7270002289335, 0.1330302684256, 0.7791508020736, 0.0980753410133, +0.9884307789562, 0.3510921622399, 0.8661205916973, 0.9644237011505, +0.0163813019248, 0.6721972355955, 0.7373641462705, 0.6370269556702, +0.8916886946613, 0.5956526238451, 0.1840580865667, 0.7611378816707, +0.8911024955526, 0.8210445068875, 0.7344471322067, 0.1733715185772, +0.1311688628659, 0.0209291894086, 0.7252938243213, 0.5649288527504, +0.5898558509489, 0.7694702454700, 0.6272350631781, 0.7894052927333, +0.6422409511368, 0.5263594903640, 0.7221442962634, 0.5441656096578, +0.4657187990219, 0.3692411796047, 0.6593897587896, 0.5012950978714, +0.1625373056915, 0.4541495775125, 0.7203333423102, 0.5255103500213, +0.2188353697857, 0.1789186076163, 0.1263468131080, 0.4576974881150, +0.4837764182518, 0.1105240639814, 0.7745712314614, 0.3104048996747, +0.0739472159529, 0.3748789133387, 0.9315685708688, 0.5090183636681, +0.4462676869921, 0.2051160788187, 0.3958081027473, 0.6568623947244, +0.5672087755833, 0.0361235374753, 0.9745863242888, 0.0230431654598, +0.1980257179579, 0.2094497262544, 0.5624830278393, 0.6967306200865, +0.7473831366503, 0.6637445169798, 0.5786909058591, 0.2218727861633, +0.7567217362843, 0.9099204423418, 0.1178940940266, 0.2990242477036, +0.5546458068093, 0.9755571060700, 0.0888390494924, 0.2442409071346, +0.3724286441563, 0.0384222245954, 0.0860811695857, 0.8634102809538, +0.6745121347134, 0.4463758601092, 0.4133011379341, 0.0176497399889, +0.8321524066069, 0.1207798217054, 0.6514919389279, 0.8091092406814, +0.3228088828376, 0.3993611817245, 0.1569033591807, 0.6260782632167, +0.9412591736490, 0.5208346007954, 0.6088109079789, 0.7193863874857, +0.4865260615416, 0.6886423098336, 0.1845791173096, 0.1875018133724, +0.5467141189364, 0.2432477973603, 0.5985627517097, 0.3024732118018, +0.5508120821560, 0.1013599257457, 0.2188049029646, 0.6874018012022, +0.3225358125393, 0.9232407263123, 0.1397821503411, 0.3048860725504, +0.3621925289567, 0.9970479472527, 0.3696165864214, 0.5530832887409, +0.6471867881004, 0.1943449350979, 0.1178277684924, 0.0211085248837, +0.9941175156246, 0.9699956714036, 0.5937061168224, 0.2747311281388, +0.3900188381737, 0.9353766888079, 0.4908302717334, 0.2025170243357, +0.9778826013104, 0.8765448997154, 0.6240189986415, 0.6754093895086, +0.9099835515534, 0.5245967197812, 0.1197926966100, 0.2225817498856, +0.6434836721250, 0.4607956332438, 0.6259566455269, 0.3385975995746, +0.3188220846089, 0.9660194846643, 0.3840363590904, 0.7657387963337, +0.7747614708612, 0.6810146135655, 0.9630674314513, 0.7536529455118, +0.3556263280826, 0.4219482584959, 0.8753595491291, 0.0808951999438, +0.6715826902872, 0.3497438432415, 0.3919439294338, 0.4690656654858, +0.5581835906758, 0.0616015279952, 0.2851205315837, 0.8827742016328, +0.1317212801109, 0.5360661915206, 0.9381464277106, 0.9091395302253, +0.3965367234296, 0.0417048311987, 0.0606629108361, 0.0579391238549, +0.4523583526967, 0.0400203950890, 0.5025004644424, 0.6866195568287, +0.6401897690446, 0.7711804373056, 0.0060398792876, 0.8865368235328, +0.0500025102170, 0.4149512394401, 0.4521950504054, 0.9691073107389, +0.7966202650203, 0.4056288382996, 0.8368994979360, 0.3275545990689, +0.1116176285369, 0.4682029548419, 0.7553726815411, 0.2288434273698, +0.9496327433501, 0.6698012192127, 0.5298044828371, 0.0404932131248, +0.5258900339370, 0.0813540229953, 0.2058674102676, 0.4679509100821, +0.9531498779325, 0.9224267573666, 0.1230588541939, 0.2665303211038, +0.5120961421691, 0.4055082301635, 0.9624471524555, 0.6255593186363, +0.9375943420164, 0.1522859107481, 0.1766886670034, 0.9684870317432, +0.9564383169433, 0.9875968526991, 0.5672371501882, 0.6288837178745, +0.6329800750283, 0.7530585814980, 0.3932256905330, 0.4041366476585, +0.1890915851989, 0.7445977035652, 0.2212615358742, 0.1485983720741, +0.2190169283277, 0.1387243280833, 0.4143989223123, 0.7510660187113, +0.8867966541493, 0.7449069622648, 0.2200783515443, 0.6202663325799, +0.9686965248402, 0.8399465316161, 0.6673337191657, 0.3431372057382, +0.5982679024331, 0.4807926665436, 0.2454547617796, 0.6297808711556, +0.0510271461918, 0.5358622444495, 0.6330785772917, 0.4221434287830, +0.6044523746727, 0.0074654631351, 0.5234590966829, 0.2003157270142, +0.0652831588244, 0.2374324497010, 0.7605240446332, 0.9166847872160, +0.7328515992187, 0.2543747440234, 0.9820301532662, 0.9817855809730, +0.0166954076927, 0.9518685280121, 0.3930990725724, 0.3964290755784, +0.9563146298548, 0.9034920618420, 0.6967754898112, 0.6131774241166, +0.9938900801325, 0.9250111542293, 0.7434385934581, 0.3641092089769, +0.4110367835551, 0.5921579825655, 0.4058038203073, 0.9888933552377, +0.2391981241476, 0.4620639302125, 0.1280202265494, 0.0388823971333, +0.5681641099826, 0.8436504992860, 0.4695293933477, 0.6514793232323, +0.2118390180226, 0.6334472692727, 0.0810829485213, 0.2300534375152, +0.4595421769002, 0.9446906177069, 0.8878220132961, 0.0631131013218, +0.8940985095194, 0.4762375850585, 0.8965591452534, 0.2809210854028, +0.9574438435759, 0.8504131393742, 0.3797296464349, 0.5933346345990, +0.1120615941994, 0.9513339237083, 0.7754242931378, 0.1231682394273, +0.2201105105784, 0.5230983782202, 0.5434919058082, 0.1812281134451, +0.3229914551242, 0.4593086351917, 0.9851623084327, 0.6715121323576, +0.6847451388299, 0.8911555651068, 0.3029591340120, 0.4546917013147, +0.4471551838551, 0.8965841573181, 0.5246028339139, 0.3840420825333, +0.6933459326128, 0.9066973612209, 0.8412747745594, 0.4124248472100, +0.3311685534805, 0.5874444421322, 0.3829349458138, 0.7378339193472, +0.8858328321417, 0.2886123970564, 0.4378575810408, 0.7626645922487, +0.3945099871580, 0.9978944263411, 0.2399463202990, 0.2132818737129, +0.4549503579992, 0.6146204982021, 0.5209928040956, 0.7834382261072, +0.9608468133774, 0.7779418131234, 0.0739291329281, 0.5061551120627, +0.7609303494733, 0.6455919522073, 0.6690973777646, 0.3768882669401, +0.6061250588885, 0.2080855328627, 0.5421761090598, 0.1937002116785, +0.1212848020351, 0.2994709910357, 0.1147828936180, 0.3834508831536, +0.2603824316805, 0.4524533555156, 0.8869154331679, 0.4977178394318, +0.5380548879216, 0.1462152633566, 0.7410657525719, 0.3247730137430, +0.7644502985126, 0.9325648750796, 0.1441096892320, 0.9810120728710, +0.1712576053903, 0.2194006560461, 0.5471853728160, 0.6651024937933, +0.9980027726842, 0.1321044187677, 0.9973424691695, 0.6211145057441, +0.8601400586125, 0.7589331216919, 0.7776963709750, 0.6664398469340, +0.7033233627227, 0.4662651170354, 0.9670186550203, 0.3198724795691, +0.5795193880701, 0.8246081647578, 0.7657361080710, 0.0818015481726, +0.9774245549820, 0.8399018197506, 0.2770615198077, 0.6526515412390, +0.9991393452506, 0.5154794424379, 0.9861170831072, 0.0181272723796, +0.7953292656668, 0.7635896437632, 0.4480443175175, 0.1302267718735, +0.6163441960776, 0.9665868715228, 0.9829902998093, 0.9952296903335, +0.6467726154471, 0.6143469682961, 0.0986912898248, 0.9803327689787, +0.1962601399032, 0.5069126735939, 0.3732800899880, 0.8763876607997, +0.4221002927153, 0.8995835026259, 0.9731777906293, 0.3402987445427, +0.3915654390080, 0.0016196803197, 0.7241916669180, 0.7389138982347, +0.0193804586396, 0.3689899939899, 0.8415215000704, 0.0012531862600, +0.9578653550511, 0.0185198038903, 0.8844694364278, 0.8276385827119, +0.3277434438131, 0.7531946202522, 0.7821094476535, 0.3325137534796, +0.7454325155101, 0.9440876398907, 0.7197814913093, 0.7650997469970, +0.6948604414681, 0.3922051304915, 0.5584346077211, 0.8184727811341, +0.2720134417862, 0.8911205813713, 0.8991178040854, 0.9317146977092, +0.6112094924837, 0.6941137349671, 0.7907040835315, 0.8722955942491, +0.5161489367095, 0.0027749310261, 0.6957334152869, 0.5148957499838, +0.3648934976034, 0.5355293953491, 0.3717649250160, 0.5372549153572, +0.5887481149234, 0.3227588521888, 0.5540491992394, 0.2562343614438, +0.1012583934242, 0.9164915587364, 0.0759534724410, 0.3361586464272, +0.6142077448844, 0.8466909089343, 0.8605791981614, 0.7957349637503, +0.3507285031261, 0.3090681858869, 0.2388960394258, 0.4190138058825, +0.0103094372946, 0.6227419453779, 0.2001887672582, 0.1380138430456, +0.5057886007735, 0.6215189297784, 0.3168556798794, 0.9908928507897, +0.5498440100578, 0.0219375370172, 0.6242938608044, 0.0125890947006, +0.2522931472642, 0.9147375081269, 0.5574669323664, 0.9960587862861, +0.4476747780329, 0.8410412621875, 0.2374963598500, 0.1115161316057, +0.1091847960414, 0.5489331714571, 0.7575328209240, 0.3134498322911, +0.0371258240366, 0.7233925409258, 0.3956240803914, 0.6181120186197, +0.7725339628628, 0.3878543276283, 0.0324607263470, 0.6345201198172, +0.2235423443949, 0.7828434001574, 0.0105962725406, 0.2326494936052, +0.3400410471205, 0.7293309451683, 0.4043623294702, 0.3274519524199, +0.0247149760950, 0.8898850576439, 0.7512684821856, 0.0286561902746, +0.4202515456920, 0.2770081233592, 0.8046225653052, 0.3087354140863, +0.3555687574463, 0.8679263241905, 0.1180493850811, 0.0421189246895, +0.4936942246248, 0.4647535534877, 0.4168594951820, 0.8755822060050, +0.4470036949250, 0.5308200486614, 0.1881460939479, 0.8124835755734, +0.4532563143658, 0.2195376577878, 0.9186743762897, 0.2206068202949, +0.2567226007845, 0.6767986587606, 0.0023810574796, 0.9292706488302, +0.4353995776900, 0.5967636483706, 0.4061296034633, 0.4067433874154, +0.4661334992694, 0.4601145537850, 0.4866487055489, 0.1573980851832, +0.3333901950779, 0.8863850454271, 0.7371226771442, 0.2912712703884, +0.7307542682303, 0.6889589525242, 0.7543113691520, 0.8551720622253, +0.9836544399074, 0.2244484923894, 0.1537125055463, 0.1711708638683, +0.5624654202547, 0.4306581343667, 0.7552685410507, 0.3418585994941, +0.6032135657050, 0.0157217341548, 0.6501957921545, 0.6739429173404, +0.0593202370495, 0.8599361669551, 0.6925203929155, 0.6525768500998, +0.2560480810963, 0.4947198147395, 0.4566998148601, 0.0986499959131, +0.2346197903317, 0.7221815803657, 0.9548343685245, 0.9433485204090, +0.5471291069626, 0.5680099854097, 0.6085666253271, 0.6919570452031, +0.5340488583474, 0.2778833747273, 0.2569689379339, 0.3628779940134, +0.7525400434400, 0.5177032977891, 0.5023318671167, 0.4106814434802, +0.9315433255078, 0.3150054632290, 0.9483614321558, 0.2576004081674, +0.2511340739444, 0.5347568907471, 0.3307271973839, 0.5985572243103, +0.1218975857468, 0.3104543109939, 0.3946930572366, 0.0232475898337, +0.7947413920400, 0.3779456668431, 0.8051741257334, 0.8513928720967, +0.4519655385297, 0.0293611819061, 0.1001272467431, 0.7600084937923, +0.0715718660837, 0.9990946454923, 0.5973711677815, 0.7086938725359, +0.2650215487299, 0.6056207244311, 0.2769780202196, 0.8543401057154, +0.0369102950380, 0.0175615917042, 0.1233240217545, 0.7793098873362, +0.6702426782205, 0.9684536205458, 0.3325670549332, 0.0716854539102, +0.6865418421508, 0.9213767521649, 0.5032105112929, 0.6632942523171, +0.7492964406262, 0.8084394278975, 0.2318310626931, 0.8979035685295, +0.7970136817531, 0.5440378322005, 0.1863850942749, 0.0370051879608, +0.9952062140197, 0.2489792198171, 0.5733990145723, 0.2865123414837, +0.0251102871378, 0.0667780796377, 0.2480738648437, 0.1707701818881, +0.3043617723996, 0.2901318358677, 0.6723988045344, 0.5250518850633, +0.8674082801991, 0.3412720674375, 0.3076934280375, 0.7957228262889, +0.3035547352878, 0.5376509579540, 0.3097256879833, 0.6402604829707, +0.7108397673400, 0.9900965774386, 0.4590277096531, 0.8129361992762, +0.7278639603070, 0.4601362075005, 0.7985360053361, 0.6908587723462, +0.2714334406291, 0.5248776415944, 0.0041740397011, 0.9849210996111, +0.7483432361616, 0.2666396541831, 0.7738568614115, 0.5775730542734, +0.5469826113186, 0.7734535232994, 0.3334177342865, 0.0219307262553, +0.8015393646441, 0.8513443837181, 0.0635853587015, 0.0058165383552, +0.0115392697097, 0.6689476448432, 0.1926164511557, 0.3712787867390, +0.3152783379496, 0.3150940049976, 0.2065986023315, 0.5023421391390, +0.3564850843309, 0.0261181048239, 0.3051905819705, 0.6656263124503, +0.0886476864520, 0.0843490446379, 0.4862543127901, 0.1037265868409, +0.0680014062990, 0.3600811270811, 0.6092266862324, 0.4904283524912, +0.4050142738991, 0.8163446424605, 0.6267207817299, 0.3830835476439, +0.9659550543716, 0.9519968852177, 0.5897981652942, 0.9601385160164, +0.0246623107347, 0.7674944185500, 0.8033412689359, 0.6533835239957, +0.4982998587649, 0.0362015804444, 0.4364420629276, 0.9959577200915, +0.3086669777095, 0.8135781967144, 0.3512955854420, 0.6430406657248, +0.7602127547191, 0.6651520620404, 0.8396963015384, 0.6564861674125, +0.8163789663540, 0.8488604411710, 0.7495011066783, 0.3259506138628, +0.7418113405545, 0.8843803726530, 0.2089415677865, 0.3587277929106, +0.7958008650671, 0.1468256139880, 0.7007250146478, 0.8356623495164, +0.9439067039378, 0.7617559189730, 0.0988224987401, 0.2905231794764, +0.8981214873018, 0.9685690146725, 0.5292503375231, 0.9021637676759, +0.6087330657098, 0.3964213456011, 0.0047705946512, 0.9656924004507, +0.0125523470401, 0.9174000434193, 0.2099995418498, 0.3560661800932, +0.3756464572510, 0.7727651017591, 0.5825521054596, 0.0496958433882, +0.6907810045829, 0.1920254236050, 0.6216255424645, 0.3320532116723, +0.6662294597673, 0.4325923446718, 0.0764057957923, 0.8305671107166, +0.0676539899165, 0.4620303248344, 0.5794179586598, 0.7771308109058, +0.5804042250758, 0.0115606933886, 0.2237862433418, 0.6782404578655, +0.7187289813155, 0.4785257123776, 0.9801297080611, 0.7530365808648, +0.3409664823399, 0.3274620465596, 0.8749470579787, 0.9849003027123, +0.1346424432167, 0.3535188298456, 0.2448620899789, 0.0849465998285, +0.1594674066452, 0.5102889004677, 0.1262839311391, 0.8274141954386, +0.5784765843202, 0.8502484116937, 0.7023143240727, 0.7479094740692, +0.5558509307708, 0.2447060436219, 0.2828407558998, 0.7787201203307, +0.5404991724251, 0.6235049206873, 0.7067363684563, 0.8622587150253, +0.6835591926629, 0.1209033970353, 0.6350656145416, 0.9305226122637, +0.6000956248492, 0.4022881735127, 0.5994291094129, 0.6151953221370, +0.5593227672201, 0.9410621071891, 0.7297502205380, 0.4743761673916, +0.8020265054898, 0.6939652104368, 0.2945809365691, 0.9746123105169, +0.1687743417773, 0.9614939121350, 0.2042541104389, 0.4208648681738, +0.6852885548423, 0.7472509260975, 0.8117423233631, 0.9065684349772, +0.9568417942882, 0.2411394851474, 0.9919569697194, 0.0945830792629, +0.6292159499737, 0.4973409662476, 0.8646444058347, 0.6986933381756, +0.1149053420475, 0.3127751421708, 0.6182443632829, 0.4997100199106, +0.6920496400874, 0.7150009668968, 0.7150633161492, 0.2176734726958, +0.4194258462728, 0.2513724068419, 0.6560630736202, 0.4448135362215, +0.3715088783631, 0.2214523512970, 0.9453376172787, 0.9506440106550, +0.0561601617635, 0.5402832201404, 0.1829462629664, 0.1495917272519, +0.0892716655923, 0.7414487166058, 0.2875341457722, 0.9946885867951, +0.9781844532016, 0.0461134594149, 0.9825882017531, 0.2794911150259, +0.3469426270327, 0.6074004027096, 0.5434544256625, 0.8472326075878, +0.3793722611756, 0.4618479690803, 0.9201755453461, 0.1616987884798, +0.0800523967855, 0.0714219007974, 0.1768489355114, 0.6352388610296, +0.7835560197865, 0.4994782430583, 0.3227943076393, 0.8329120095972, +0.4177236521699, 0.1550648976839, 0.7209305943553, 0.2681319244523, +0.8985654436511, 0.4738838139334, 0.6953481178243, 0.9038768573217, +0.2623733781569, 0.9878371092434, 0.2153325305392, 0.9828822635966, +0.0451533389488, 0.2405578313584, 0.0339505681926, 0.1979207318266, +0.7391037828005, 0.3920959664472, 0.8479582340680, 0.5774049938551, +0.4033726395124, 0.1184760435105, 0.8539439355274, 0.7681337789484, +0.8637048806360, 0.4834250362978, 0.1898979447735, 0.0307928710388, +0.7808241773307, 0.6472608999569, 0.9829032793561, 0.5126922524128, +0.6077107305674, 0.1985478290350, 0.8023257976409, 0.7038338732458, +0.4805561781305, 0.5062761737529, 0.6724316429684, 0.4976739149995, +0.0856849053342, 0.7429295562873, 0.4941132829963, 0.8877641735076, +0.1054688450440, 0.1308382442830, 0.9834873876458, 0.5280638511889, +0.5995794001965, 0.8445726278446, 0.5229342107302, 0.8314456217137, +0.4076710172965, 0.0029520397088, 0.9630486713550, 0.3768781462577, +0.6656388685413, 0.2713758974668, 0.4863770760067, 0.1529466156629, +0.1731142281429, 0.4464630454064, 0.9186367974238, 0.4692803553628, +0.2186365091329, 0.7808249587104, 0.6450108744414, 0.7209625945990, +0.2052066904517, 0.6991926872633, 0.2871011324632, 0.3174425169441, +0.3092782661828, 0.2908915957859, 0.4421222430850, 0.7812144154595, +0.2570552519788, 0.4147471112268, 0.4217298400690, 0.4256096307308, +0.3215421970568, 0.8566346521753, 0.2593197386057, 0.9446640512648, +0.3753150256236, 0.7292132143533, 0.8595866918841, 0.2223684099607, +0.8152441232536, 0.0409538936992, 0.0005891113545, 0.3459637678908, +0.6401885029116, 0.9883583513966, 0.4874169391056, 0.9192259087782, +0.4498703304910, 0.8588250120444, 0.7691833101069, 0.1324278130813, +0.8374988575641, 0.6550770209427, 0.5580176988421, 0.0562844421045, +0.4257495721922, 0.1467771232812, 0.9459686167287, 0.0001399414614, +0.3123625071311, 0.6828048241710, 0.5615242349736, 0.3676984563319, +0.0432123830743, 0.6339047041880, 0.5394394763463, 0.8208439735793, +0.7449899356556, 0.4185274091635, 0.3631179180756, 0.3990261677648, +0.2829329377426, 0.5602340584436, 0.4594813028627, 0.3637070294301, +0.0793260550496, 0.9231214406542, 0.5485924098401, 0.9468982424340, +0.3740601615859, 0.5291963855406, 0.7819464522330, 0.3177757194814, +0.3401040925365, 0.2115590186843, 0.1842734060177, 0.3399641506094, +0.4979404790783, 0.7658536647287, 0.3583361419655, 0.1302420222807, +0.7407043505184, 0.8103029862094, 0.4486584888998, 0.9198603769391, +0.3871241325453, 0.7839167335927, 0.4442076903974, 0.9880979652461, +0.1710326379030, 0.1321140682009, 0.2024441422906, 0.8073256084730, +0.6088236875873, 0.4539655756457, 0.6923481266444, 0.6619254456190, +0.5587162555003, 0.6881497426369, 0.3770870162999, 0.2409405360189, +0.4989976191423, 0.9327764170863, 0.2173461281775, 0.1590334680672, +0.5318615569416, 0.8391017116788, 0.1443354353049, 0.4016195341952, +0.4225319542096, 0.0298020355542, 0.6049553759419, 0.5026715777361, +0.0417118291565, 0.1632363042623, 0.8401050217636, 0.0536138643760, +0.0916383201683, 0.4288359621674, 0.9471530383207, 0.2843127116954, +0.8115226257646, 0.2626709580713, 0.5609500303683, 0.1495971801456, +0.4942386930316, 0.4203463128863, 0.7166365337170, 0.2532981565470, +0.2527570180841, 0.0529549480662, 0.1084960555232, 0.0937235495512, +0.7274617178959, 0.7517546372263, 0.9857313656182, 0.3258421837007, +0.6327383781936, 0.2593232743718, 0.5908563484395, 0.1300668004575, +0.2494255887575, 0.0552703324031, 0.2891253099261, 0.1958117239158, +0.4135430433850, 0.2911374179139, 0.2185066366654, 0.1292303316897, +0.3152568551317, 0.5051813635534, 0.7199733800813, 0.1656596745204, +0.5342215669966, 0.1267794804307, 0.7678523216247, 0.2809234099839, +0.5782124048929, 0.0284602595626, 0.5471257937826, 0.4844888553417, +0.9814640330064, 0.8309694229769, 0.0814152076288, 0.6556218493058, +0.1972133737044, 0.7089257504367, 0.5827240597376, 0.0671465727813, +0.3693921320929, 0.8299517518980, 0.9682490252742, 0.1735804077115, +0.3866046664243, 0.6188177208504, 0.8852220843012, 0.2573743347346, +0.2693883954870, 0.8001477102750, 0.9099551387643, 0.1037287209666, +0.9108519288296, 0.5846452506188, 0.3053290733627, 0.6299285188457, +0.5576702503290, 0.4450734953606, 0.7114247315151, 0.0731813949874, +0.9141723741378, 0.1358826547563, 0.4735337549232, 0.2585505248320, +0.6220955357990, 0.8956364066785, 0.9668520781989, 0.5549489630176, +0.7231565456480, 0.8193089095034, 0.6045621566496, 0.5495761374708, +0.8301855166583, 0.0925486772752, 0.6492606614014, 0.5728111814581, +0.6382114662035, 0.2167901826169, 0.7113663981256, 0.5344827452369, +0.2512500548043, 0.9075998621562, 0.0169378924262, 0.6213215364243, +0.3954483612419, 0.1621019836339, 0.4922451123093, 0.3222669662546, +0.4622203681908, 0.9531186115710, 0.6071754789945, 0.2036698433588, +0.6356581969353, 0.3763927418629, 0.0890012658616, 0.0807092339176, +0.6054294815312, 0.2577537322686, 0.2720291480757, 0.0558533435948, +0.4494024861834, 0.3285860267135, 0.0770626417720, 0.8765913051910, +0.2608060479447, 0.2795880023761, 0.4211347039887, 0.7263233031734, +0.7538226380729, 0.8990175146139, 0.4963781854587, 0.1325011016487, +0.8355830441395, 0.0050726928772, 0.8066173763045, 0.5133160778849, +0.5025323319726, 0.2310314049157, 0.1671746765111, 0.2988624881482, +0.8550593894231, 0.9647527001634, 0.1841500160211, 0.7743501555055, +0.3290046259430, 0.4907175858928, 0.3411454420263, 0.2731512823483, +0.4897658948273, 0.9344341074743, 0.7484713186270, 0.6131745901020, +0.5518572631068, 0.9391683814764, 0.2630201337221, 0.8255339603990, +0.8166559393595, 0.8126633110515, 0.2187563833868, 0.6841548377109, +0.2284506467303, 0.5704785774324, 0.7116808251998, 0.7151345688455, +0.8171606896525, 0.0640336904042, 0.5755512703096, 0.5182982010386, +0.5170761018605, 0.3196930211595, 0.2950650957856, 0.7427259468207, +0.7523663941549, 0.3721354912837, 0.2844457208572, 0.4792151118066, +0.2387657529855, 0.0813710200979, 0.8628530771764, 0.6255911628835, +0.4368583552711, 0.7285316478128, 0.0158051271065, 0.6113243953378, +0.9629800990051, 0.9887156183779, 0.6677000288235, 0.2788252612943, +0.6015909810558, 0.7796360383647, 0.8013789294294, 0.8864564126760, +0.0313579552022, 0.8300416277861, 0.3501146153315, 0.5130597541635, +0.6683918319961, 0.8485186448547, 0.8940753186560, 0.9256658856411, +0.6683555257825, 0.1854679333910, 0.1682116655485, 0.1891404139759, +0.0782485492892, 0.4207219199374, 0.5576034246746, 0.4526573864057, +0.0317808967232, 0.3170143022747, 0.5020929400353, 0.4204565018511, +0.7967233284361, 0.4686392524599, 0.0455459496218, 0.5178980671418, +0.5997023911214, 0.7597034274413, 0.4573548703722, 0.7132459789111, +0.7717935539651, 0.2012933717115, 0.5393394653403, 0.2587337993359, +0.8151199658472, 0.8031515091672, 0.0313349994977, 0.8894540806717, +0.1145507316638, 0.4835117973776, 0.6516701535562, 0.9254103181536, +0.2725392050448, 0.7829062574463, 0.6689797307686, 0.8198818191047, +0.6470396572943, 0.3507877543339, 0.2036281769181, 0.2265831554432, +0.2236191840952, 0.6788205540175, 0.6678020566086, 0.7057211169534, +0.4265939851415, 0.0203425120657, 0.1474598060117, 0.7133480066961, +0.8635484761854, 0.0262963757973, 0.7800459395070, 0.6048146768496, +0.2088394845877, 0.6353420296848, 0.2275897475088, 0.3193854043816, +0.1843350646944, 0.0239594499692, 0.4384935383864, 0.2589247470065, +0.9100455105817, 0.2988857963583, 0.5074712473468, 0.0901636914770, +0.4030341335586, 0.1825847156265, 0.0817920538046, 0.1764509781154, +0.9911413481418, 0.0500737903873, 0.5333724699604, 0.2854202307227, +0.9145225332652, 0.2147605317714, 0.7288943444048, 0.2011745265690, +0.4811688272660, 0.3411165179411, 0.2351030438371, 0.8763541508822, +0.3345343877257, 0.3447173029858, 0.3674128937383, 0.0151489833440, +0.8539273887192, 0.5433738727790, 0.9800593331363, 0.5950026412471, +0.5087165629997, 0.0382624529480, 0.5673333227482, 0.4185528710571, +0.2512555482105, 0.4187620731158, 0.3371482497720, 0.0748045700951, +0.7043605342993, 0.6542896817691, 0.6013467887423, 0.4189403035766, +0.3358937852717, 0.6955018819754, 0.7043634721564, 0.1347192587027, +0.3096119665120, 0.2504163180713, 0.9102624137468, 0.4332578160955, +0.1605144409279, 0.7907807937780, 0.5915328360123, 0.1453654575839, +0.5539483705321, 0.4950488286535, 0.1354980967639, 0.9589457297506, +0.5341103004916, 0.4078757587857, 0.0384227009669, 0.1155574294345, +0.6805605942759, 0.0428268630257, 0.4461382121994, 0.6057560241808, +0.2022267650823, 0.9318161424863, 0.4615889366072, 0.7832864619714, +0.1976549835865, 0.9065872993817, 0.5861058237898, 0.0629357248838, +0.7237271115760, 0.5335487688582, 0.6020891813571, 0.2904692954805, +0.6577170522221, 0.0333390780880, 0.7839650869295, 0.5123515946382, +0.3344436517611, 0.8182314931500, 0.8241198718660, 0.3754979224761, +0.0751753975987, 0.8883920227589, 0.3132803218035, 0.9596179686299, +0.9574590469512, 0.6092856985560, 0.2962677810789, 0.3517030227704, +0.5256924547840, 0.6380196407614, 0.6521125615817, 0.7424059932783, +0.1766372230726, 0.7279192198664, 0.5698357827821, 0.1137014977232, +0.4464109015867, 0.3742922066591, 0.6345065192480, 0.1559416061062, +0.7489472947777, 0.1701380131627, 0.9078409759830, 0.2365957001395, +0.0673039849230, 0.4066643469998, 0.2034770912507, 0.6918060624468, +0.9872149317466, 0.4017476366841, 0.2248958396841, 0.0275969626511, +0.8898791847238, 0.0623903288796, 0.2901396589773, 0.5381761614877, +0.3288134333346, 0.8473382312094, 0.6716760274357, 0.5864074405219, +0.4374900867406, 0.8545058885843, 0.4853578719708, 0.3237885890174, +0.2111352608591, 0.6141273098132, 0.5824251079850, 0.0551936542872, +0.4535273269068, 0.6575461624458, 0.9884195169380, 0.2169316267674, +0.5880665544365, 0.2024746216845, 0.8276841756085, 0.8962604924553, +0.0587582295103, 0.6553705393595, 0.6091389686843, 0.0311612663936, +0.3722109698561, 0.0459731607912, 0.0571181760436, 0.8340348083684, +0.9336652755428, 0.2620901541142, 0.1083634896708, 0.3472578350209, +0.1038281061239, 0.2624787088775, 0.1094283848579, 0.7800395175722, +0.6499799115816, 0.5413181928645, 0.1169845969961, 0.5947862568287, +0.9163413322141, 0.8611151724407, 0.1554455026777, 0.6994097049811, +0.0401255111397, 0.3698686586553, 0.5186613344209, 0.1438650191500, +0.3775067764230, 0.6281920655762, 0.5723432803398, 0.3463455100294, +0.0155170569269, 0.4362650059332, 0.2835626049356, 0.1814822485584, +0.6879386160001, 0.3877280267830, 0.4822381667244, 0.3406807809792, +0.3706411739675, 0.6216038915429, 0.6498181808972, 0.5906016568610, +0.3540328225838, 0.4744692800913, 0.8840826004204, 0.7592465657551, +0.7004769019319, 0.0040127336998, 0.0157874724901, 0.0010671969508, +0.3150979943178, 0.6168182336804, 0.8651279061405, 0.1712329751678, +0.7301347501251, 0.3552235054575, 0.9866868928013, 0.3837892400957, +0.7405124216995, 0.1076415265480, 0.9834155714993, 0.5590301726754, +0.6076589569485, 0.7560294786263, 0.5439065324813, 0.2669781759693, +0.6167463560667, 0.2955975724829, 0.1437575049436, 0.0261446992057, +0.5528222511303, 0.9873875300341, 0.9172014640259, 0.7935756858408, +0.8023512609314, 0.9068550737141, 0.4618568096598, 0.8012840639806, +0.6488772577834, 0.5028281628633, 0.9108678074139, 0.4776442821499, +0.1597849531843, 0.9639752521012, 0.1196463960780, 0.7759957130887, +0.6653634615547, 0.8899197033094, 0.3191987575587, 0.1063332884136, +0.5695925045617, 0.4058758827885, 0.9975612298574, 0.3026143285924, +0.5676124615444, 0.1772514610445, 0.1619053609492, 0.5414677623387, +0.0992385512680, 0.1843588171454, 0.4728490335275, 0.3056628658928, +0.1913345610683, 0.6520608023983, 0.1717463467139, 0.3900504975533, +0.1112474380579, 0.9936858224653, 0.5589158761124, 0.6336031563737, +0.2457793961492, 0.7601246958413, 0.4965139848630, 0.4697836830606, +0.7224936698202, 0.4055643493336, 0.7240999479425, 0.6161603809410, +0.3459130336279, 0.3878571309093, 0.2954840521773, 0.0432987050355, +0.8345130443734, 0.9155055381896, 0.7937330136978, 0.2930452820347, +0.2613012400741, 0.4021255054521, 0.0927569987684, 0.9556383746470, +0.9556565298492, 0.3605397913421, 0.5864843225975, 0.5656060322959, +0.3918338252193, 0.1469910909175, 0.0126005932747, 0.7582306693114, +0.0413001524477, 0.5030812632773, 0.1406769129171, 0.5715164693871, +0.2533512782554, 0.2870795485969, 0.2632059591185, 0.6371908977801, +0.0306046116308, 0.9758449480756, 0.6926438979305, 0.9873059070610, +0.2811732316768, 0.3765176452587, 0.3637020785193, 0.9881279501077, +0.1130734659327, 0.1156862755845, 0.2920231829826, 0.1574350917514, +0.9503862140469, 0.3743747060068, 0.5178117810366, 0.3847801817510, +0.8625267724798, 0.9060427438962, 0.7349144973489, 0.1042961031684, +0.3190315600108, 0.2543605972335, 0.0530338343480, 0.7475150910893, +0.8309016450452, 0.3603317124584, 0.7574418609764, 0.1937107472651, +0.0079537262246, 0.0842529228349, 0.6474112610553, 0.0206478196292, +0.3281831086279, 0.0385583378554, 0.0600978709106, 0.3400551585201, +0.5812350416469, 0.6093563403046, 0.4150759831141, 0.4237999494298, +0.0918793473821, 0.6943085075795, 0.7250426163548, 0.7070991660967, +0.3471505005598, 0.0422655609633, 0.0686832135863, 0.2428543969257, +0.5511128015589, 0.2096772725739, 0.9483083048595, 0.8035977109352, +0.1950528860069, 0.8701443620353, 0.4640378702730, 0.0013421387418, +0.2421275504130, 0.0259545305865, 0.2304760740281, 0.2214797307837, +0.2179424936035, 0.2500812766375, 0.1102074538871, 0.8778873355491, +0.5941052742275, 0.5461256022314, 0.2886396144930, 0.1703053247977, +0.4108147632381, 0.1753403154087, 0.1554819425361, 0.7037155976071, +0.1233789553509, 0.5026941106202, 0.8696488234539, 0.8805245588909, +0.7419297475097, 0.4705294559107, 0.5449596715835, 0.9383320370402, +0.4946101151847, 0.2930425490686, 0.6802067289502, 0.4932679764429, +0.3657243295413, 0.6896630016573, 0.1631869106382, 0.1442445987576, +0.2715503197497, 0.6078518799543, 0.7156175322438, 0.3936629846663, +0.9961303109285, 0.4894928138189, 0.8579331565918, 0.8258249861308, +0.8502883682262, 0.5902355851560, 0.0356184155846, 0.1465727706191, +0.0716249165459, 0.2611031309986, 0.7655759005647, 0.1911003581207, +0.5735567601274, 0.1950038723624, 0.7637972416188, 0.6352247235529, +0.8020248891795, 0.3154865076372, 0.6655333282731, 0.3087569127366, +0.4899846555153, 0.2966350043642, 0.6085290567058, 0.3457400567577, +0.1653789515446, 0.8557089850566, 0.9862980060216, 0.7717159673440, +0.5277405239305, 0.4369292717599, 0.4635608645452, 0.7019155377997, +0.4680667912904, 0.5238708343934, 0.9264220855787, 0.3214940206713, +0.1531408592840, 0.3183551590510, 0.1141064190837, 0.9620405011634, +0.5149070432013, 0.2247657758299, 0.5794582900496, 0.8796823201141, +0.6520124444049, 0.0884638033288, 0.4197696481923, 0.3432555312027, +0.4310430332232, 0.4540373331187, 0.4039503109660, 0.0853029764655, +0.7841953345501, 0.9210276892041, 0.7506723374830, 0.0124793672061, +0.4388858808386, 0.9495742860947, 0.7767366737950, 0.7369703430389, +0.5617915590116, 0.9666264047691, 0.3865035573889, 0.2402975383402, +0.2749661436654, 0.0298583503020, 0.4904972386968, 0.3129256425020, +0.4842859778946, 0.4281070029494, 0.3482135093530, 0.6046036582462, +0.2709273306052, 0.9991930210959, 0.6528727787793, 0.9276717998682, +0.1579454034371, 0.9229397750101, 0.0876568239590, 0.0726424269716, +0.5040865021311, 0.5889884366603, 0.3769771081288, 0.4916071349250, +0.8646197886507, 0.2882818362155, 0.5100161253987, 0.1276494451462, +0.5270503375340, 0.3035056690236, 0.2378561223102, 0.2867527991937, +0.9372853226668, 0.0888418960799, 0.2701320733270, 0.6243596796991, +0.3652329698043, 0.2122514658665, 0.1187002463819, 0.7606293120238, +0.3945855556031, 0.8495189476989, 0.6403584688159, 0.4669137562005, +0.3658736741011, 0.6655128862083, 0.8487119687948, 0.2932312471295, +0.4279759276789, 0.5238190775382, 0.5884526612183, 0.9363687927538, +0.0930792140277, 0.9320624298100, 0.1128075141985, 0.9654297693472, +0.9095764387909, 0.9576990026784, 0.2203442660255, 0.6228236395972, +0.0825600675692, 0.4366267758592, 0.2612046712363, 0.4582003883357, +0.2919660565872, 0.0198453897703, 0.5254686724047, 0.5313367445633, +0.1110826745215, 0.6571990263915, 0.2320968556367, 0.6441689187866, +0.1656865715821, 0.5056682301246, 0.5067179740904, 0.8724553244526, +0.2917987347077, 0.5315602456832, 0.1711811163329, 0.3554299424195, +0.7250635464327, 0.7197746623865, 0.0553793232215, 0.7596337775512, +0.7910104770172, 0.8181427604603, 0.6518370921965, 0.1681868374200, +0.3303817460921, 0.7005869158081, 0.7758417631387, 0.8721813582220, +0.5683831789384, 0.4129418136612, 0.1372136912016, 0.0370464339094, +0.3068512823930, 0.8603492355255, 0.4327872038972, 0.6626823636064, +0.5373393839865, 0.4179339569146, 0.5175482614513, 0.6648840595339, +0.3796961774955, 0.7030259555685, 0.9236021875048, 0.0242662350760, +0.8544170809232, 0.6714949126688, 0.2345862007861, 0.0947833033720, +0.4581523614275, 0.5794806268902, 0.3912695745897, 0.2899655240076, +0.9152880245425, 0.2491628384447, 0.3976233868849, 0.0431066663205, +0.2105115839329, 0.2456697701689, 0.9497497542527, 0.1734651495579, +0.7496458090607, 0.7788947628713, 0.6586115842958, 0.0869634449887, +0.7562828472612, 0.0564970909881, 0.6392439979311, 0.0913987877273, +0.1810584944585, 0.2936222307820, 0.4744310479026, 0.1567922589168, +0.4928165383138, 0.5607546719540, 0.9966481863505, 0.3980332349418, +0.5211999111442, 0.3472336187713, 0.2322495841571, 0.2312343871366, +0.6666258255330, 0.9793522730374, 0.9267142456615, 0.6235191592125, +0.4978027821043, 0.5819138500755, 0.2285151110163, 0.3243376325464, +0.2652283097921, 0.7083143660372, 0.8275836202444, 0.1782648648034, +0.5775939918019, 0.0148741183872, 0.4872091284428, 0.4861952040746, +0.2832453852907, 0.3338768390631, 0.0713712093753, 0.1264531259083, +0.9438354926854, 0.4643038797492, 0.6274990698451, 0.5458022577436, +0.8553816433323, 0.4366520309991, 0.0250585512375, 0.6241472561956, +0.8808272950728, 0.3765815540108, 0.7838856497704, 0.2573081358603, +0.0349375275126, 0.5474531201401, 0.3559338265825, 0.7105998954319, +0.7627138024022, 0.5327403096169, 0.1293669697500, 0.5844489375988, +0.4431457940690, 0.0279421121943, 0.2410546756541, 0.9569505904601, +0.8547169304708, 0.0207397858709, 0.0428162305815, 0.7282638040969, +0.6599896981660, 0.1379623152958, 0.3546166249340, 0.1141874404225, +0.6062629505090, 0.6038251903857, 0.6022661950450, 0.9821156947790, +0.8846328821427, 0.4616445933756, 0.0404772209192, 0.6273247462825, +0.5349627661216, 0.7654601767498, 0.8382261478520, 0.8243628711553, +0.7786089120333, 0.5699002936342, 0.3129132968899, 0.1941599739688, +0.3992308566343, 0.5413227139699, 0.1026406027855, 0.4422802666399, +0.0719590825364, 0.8423766511690, 0.5692648261642, 0.3436952784395, +0.7262684976339, 0.9266760130071, 0.8631164370399, 0.6120810572114, +0.1998487558215, 0.3862581953342, 0.0646383278373, 0.2177330615082, +0.2942292686991, 0.8061117067962, 0.9900833857200, 0.6669045228823, +0.8549234777945, 0.1788621508418, 0.2677562997061, 0.0305606066392, +0.3001424215269, 0.3898862434504, 0.9443223275916, 0.1059824470924, +0.6995158911215, 0.0787513330946, 0.9597865370846, 0.2572356240159, +0.4061224183096, 0.0987467472901, 0.6200740470644, 0.0624271394044, +0.8014199304401, 0.4780815008460, 0.9411233984591, 0.1893388732287, +0.0219728960758, 0.5276884276083, 0.4047575133875, 0.8042398350333, +0.1363003636414, 0.2218216523630, 0.9139466229425, 0.4693958412248, +0.9345906148360, 0.4305296323404, 0.0279333586935, 0.9040300081968, +0.4016721059576, 0.7895140921648, 0.6093917831822, 0.2956896583995, +0.8109497347898, 0.7018145274845, 0.1794003351496, 0.5537141107739, +0.2016140116386, 0.5104656254456, 0.7805658605791, 0.1391868717685, +0.5899787804065, 0.6077364299482, 0.6092123732014, 0.4006399071778, +0.3545756062281, 0.3913987103810, 0.0858179303286, 0.5503357711948, +0.9599712849408, 0.3765485023039, 0.9190871379893, 0.4905754437161, +0.7370637686630, 0.0962716481165, 0.5983701546669, 0.8330337604662, +0.9219931722255, 0.6716543830334, 0.5268012804570, 0.6263035133604, +0.6899071744130, 0.3236652777175, 0.4611684751982, 0.1361930636392, +0.7797556825819, 0.5008569087371, 0.0254798047363, 0.6405688103477, +0.2066855720275, 0.9813696942205, 0.0113225341827, 0.8060456653154, +0.1708706781132, 0.7966643528997, 0.5891061237031, 0.6205349073841, +0.1654994972821, 0.5254462843414, 0.1880630628150, 0.6749240540317, +0.9401839612705, 0.1254707817572, 0.9019947871109, 0.1071502008043, +0.1266684546725, 0.6772477294678, 0.2217424298738, 0.5003649413122, +0.8847367739699, 0.0486616264324, 0.3489021125012, 0.7485437103308, +0.4506393975814, 0.5746439479173, 0.3723269041499, 0.8100705876993, +0.2038523737359, 0.2303950796977, 0.0755008566545, 0.3978067088862, +0.7073582982213, 0.4105379457635, 0.2117647734525, 0.0868233908372, +0.4757949507217, 0.8782289763346, 0.2072022981975, 0.8008708971557, +0.5024155622825, 0.6412944480038, 0.4036752606759, 0.3952653614782, +0.8060349886334, 0.4425995230873, 0.7667652297610, 0.3056700473212, +0.7370513699656, 0.9327034433059, 0.1198472525551, 0.9885076596348, +0.2788199522900, 0.6217881434699, 0.9813650697383, 0.4687493650563, +0.7514986823087, 0.7294593498714, 0.1964320913872, 0.3536919734225, +0.3587563388789, 0.9553510560446, 0.9598544300347, 0.2719329480417, +0.9724901006429, 0.0661146366345, 0.3658890018081, 0.1716192030216, +0.9683566614838, 0.4482850508989, 0.9443436129691, 0.5730913000056, +0.6536889205005, 0.4707722233007, 0.0895794989027, 0.3480188731793, +0.8448523882985, 0.4597239091339, 0.9133717468536, 0.8563447286637, +0.5019683639994, 0.5819037577984, 0.3924273519741, 0.0332189989431, +0.7274843951350, 0.7807883162893, 0.2036919008026, 0.3737924217124, +0.6720569402315, 0.4789830774437, 0.5102476656950, 0.4001239921898, +0.6417212987513, 0.0308132786447, 0.4343341330226, 0.4701020952641, +0.3733144348363, 0.6142113989285, 0.0969279152793, 0.8002231348307, +0.3892904014277, 0.3416710958544, 0.0624964493618, 0.0412715282483, +0.0084206769282, 0.0429793219282, 0.8124433196208, 0.1520759482645, +0.7590340649518, 0.8532730652267, 0.5027032310621, 0.7258150660087, +0.2689230042831, 0.2610024284855, 0.4351768225595, 0.8951305830363, +0.0389927155520, 0.9964073998837, 0.0417907443092, 0.6388687233622, +0.0221405052683, 0.7110496557835, 0.4753904768617, 0.5520384100042, +0.7099477447150, 0.6638618040196, 0.7418629348939, 0.9097246098843, +0.8800623784215, 0.0832621790856, 0.2780732024825, 0.8387908501731, +0.4926456005744, 0.2693527798491, 0.4249332749401, 0.3405696518442, +0.9631916601039, 0.5010662775026, 0.3123321017774, 0.2373765940952, +0.7101659154101, 0.7222257245901, 0.3543393422637, 0.8150353328395, +0.4283848877197, 0.9790889201588, 0.9832281530757, 0.7895161648232, +0.5770573073891, 0.4673776032717, 0.9754963195769, 0.0250188969192, +0.3606114053915, 0.5991978126574, 0.1784272590552, 0.4508867959729, +0.7590810436565, 0.0705591496409, 0.2630596162114, 0.9202901939490, +0.8817024705381, 0.6391434220779, 0.1538213287265, 0.5411328186938, +0.8161311982275, 0.3743480706468, 0.9084962019271, 0.5787546041323, +0.0358636356126, 0.7793228583314, 0.8754143481494, 0.2208283032388, +0.0192698543050, 0.7460295510227, 0.5015485824559, 0.2297536899474, +0.5097956324507, 0.4476547424903, 0.7251184707159, 0.4847767355315, +0.1515015853343, 0.0868529393742, 0.9150323457620, 0.7006147898271, +0.0137497978349, 0.5121129911915, 0.6860507520316, 0.0934596043515, +0.4902431864712, 0.7728308419570, 0.5826721408324, 0.9491103682430, +0.3152480736912, 0.3719456570092, 0.4119742635693, 0.7364934700245, +0.5412987682695, 0.1313792714530, 0.7462937276560, 0.3204704650307, +0.8514617657529, 0.5771624038821, 0.9107021297844, 0.6217080758054, +0.8970274477718, 0.8707316205235, 0.3231919544391, 0.4122507122402, +0.7489252149821, 0.4068230797568, 0.3183863625482, 0.0483104251550, +0.3268783126617, 0.9004268007821, 0.4936760195967, 0.2334187078445, +0.1288371394057, 0.3406281104966, 0.4125397915079, 0.1797267711627, +0.7317054018992, 0.6190803258769, 0.1134589519880, 0.9952119323403, +0.8459036805881, 0.0469534751246, 0.9910259828861, 0.5254332155573, +0.3590277858819, 0.3872024483919, 0.1783327470433, 0.7373197105421, +0.5012855886022, 0.2104895511691, 0.9643648522740, 0.0890348763620, +0.3358672318681, 0.3983130359083, 0.0812211712269, 0.2875568067131, +0.6330262420853, 0.0847924463846, 0.8051361161308, 0.3996075337751, +0.4785389064246, 0.9599045547470, 0.9852192471666, 0.2988121352619, +0.3929709705491, 0.6073760458303, 0.3005326647780, 0.3977590382089, +0.9394248327890, 0.1246763719826, 0.2264563717071, 0.4139916172316, +0.9548020646697, 0.7853285133770, 0.1716298475729, 0.2174823541276, +0.4389974709782, 0.3138298500859, 0.1725309613033, 0.3499625946162, +0.4244526202904, 0.9402830600460, 0.5243194017207, 0.1368958135773, +0.0051481067227, 0.7603198521586, 0.3385960954887, 0.6055405729476, +0.4425443464157, 0.6381743488080, 0.8451122985432, 0.1437322111538, +0.2280905834530, 0.9210832533059, 0.5980789030893, 0.8303315457098, +0.3126031846332, 0.6210615540021, 0.5284592986705, 0.8986115678673, +0.9723980249709, 0.2520280174222, 0.7457379264504, 0.7549156703776, +0.2673303681739, 0.9272000891749, 0.0373565303336, 0.9173677740234, +0.3467833052142, 0.7063278391521, 0.2410299392608, 0.2098874916369, +0.3708899134634, 0.7712359255046, 0.6466108987325, 0.7653493409815, +0.1289392053750, 0.3760380201861, 0.5315557771975, 0.9852069946868, +0.2069996209848, 0.5714835522564, 0.0142123685285, 0.3766680757406, +0.5109028394850, 0.4350902044378, 0.4925668050966, 0.6122912716178, +0.7759417741447, 0.8235060241183, 0.0561517584399, 0.0210261033015, +0.7192574584481, 0.7483397986499, 0.0755340410748, 0.8018896848903, +0.3227780635109, 0.9865878266220, 0.6755398873592, 0.1128905714084, +0.6819191671358, 0.6695613687251, 0.6929156653084, 0.9165698266200, +0.3247335582621, 0.0528090805993, 0.4407972942296, 0.3395265640409, +0.3490211467021, 0.4536727636371, 0.4288471007854, 0.9723530714271, +0.0553507409316, 0.5560207676869, 0.0251563154278, 0.4430594697795, +0.5387492242915, 0.5662535804167, 0.9911109725903, 0.5177231205244, +0.8491524154549, 0.3146909979706, 0.3897596045350, 0.0472627305646, +0.5781842174838, 0.5684098734373, 0.0630307961549, 0.4652936456098, +0.6551405101340, 0.9009622809947, 0.5549976995937, 0.7385706835140, +0.5874399284774, 0.3370596768041, 0.5705236492541, 0.2479133644364, +0.9836740149109, 0.9121734867395, 0.3898687574034, 0.0113209430181, +0.2617753279683, 0.3326951611474, 0.3658462503766, 0.8187158586545, +0.9087256867945, 0.3171260688999, 0.8887159292999, 0.3910025658044, +0.9270896319892, 0.4474749106204, 0.8833796497823, 0.8798269014246, +0.7384328994613, 0.7762420469784, 0.7621659085910, 0.2731392538516, +0.5637673877942, 0.3166171164795, 0.3446519199501, 0.8251967047458, +0.1475629835145, 0.2189078974626, 0.2175793970086, 0.8996496195438, +0.7994239897465, 0.7350029124576, 0.5559675747324, 0.7881030467283, +0.7645521903245, 0.7830980041917, 0.6471763987314, 0.9458363321358, +0.4040252149124, 0.0263275178272, 0.1157931653391, 0.0130226486423, +0.8843359955979, 0.3127509012412, 0.3434535871928, 0.0045090941733, +0.4999724903609, 0.8114256271214, 0.7602258118616, 0.2268332365094, +0.3475884242671, 0.2384053893566, 0.5876676736342, 0.5223917199869, +0.8319692126624, 0.9113558120613, 0.5550225063018, 0.9323195935843, +0.5607049495730, 0.9795321961770, 0.1302637095238, 0.7726019033103, +0.6320676159263, 0.3601289393195, 0.7145351081689, 0.6862312842562, +0.3747341555426, 0.3966198062508, 0.1432269430455, 0.3617115069002, +0.2635292025579, 0.7787593704549, 0.4229473240780, 0.2590201083846, +0.9932341477802, 0.1478651976901, 0.0915102712305, 0.7664009112708, +0.3741278026133, 0.4932066376755, 0.9592908248116, 0.8517360830920, +0.4792780910988, 0.7217162268803, 0.7316120274978, 0.5469584979801, +0.0592364361786, 0.3112473032955, 0.6330720389416, 0.2866345333339, +0.4495670322560, 0.6199413862172, 0.2907794994725, 0.7633357484654, +0.3670261140759, 0.0816346477166, 0.9800703255367, 0.0053146071757, +0.3823173769667, 0.7417602700841, 0.4782544539674, 0.1232972681165, +0.6676026893163, 0.6458465795246, 0.5205196400734, 0.9012017785111, +0.4637659943960, 0.6608368370965, 0.7937117776804, 0.6120299117696, +0.2999611000065, 0.8378937974749, 0.1540434743064, 0.7530026020263, +0.1722900346724, 0.7792391911052, 0.5596100238895, 0.8856555018042, +0.9560178108309, 0.2315264713166, 0.0904864944008, 0.1926820623654, +0.3865806010489, 0.4055848426212, 0.8514678575338, 0.3812659938732, +0.9548354507214, 0.7536067155905, 0.4872194908034, 0.8315381826048, +0.8666757228163, 0.3371528272224, 0.4953669852090, 0.9654739447709, +0.6279165365863, 0.5342784121327, 0.9829994072127, 0.0158866248168, +0.5297137859881, 0.0916825309823, 0.1951152487635, 0.7767111844275, +0.2348142248740, 0.8296748859946, 0.9295763284571, 0.3491587230699, +0.6818684147121, 0.4071042595464, 0.6089140770998, 0.4891863518810, +0.0806665649082, 0.6378862250773, 0.6386307308630, 0.6994005715006, +0.3216367700704, 0.4672471659571, 0.0434710676984, 0.4900985879312, +0.4961645028070, 0.2764722207917, 0.2208538810820, 0.5306905585018, +0.7321074915734, 0.3628402256234, 0.6136250480142, 0.7162208662910, +0.3733356387230, 0.3600240276940, 0.8971186377560, 0.5966244547612, +0.4413926091238, 0.9030494251768, 0.4517065586763, 0.0922338860539, +0.8704692390144, 0.6762068339978, 0.7327243107058, 0.3812828866678, +0.0410389583749, 0.5523376532608, 0.0833110935443, 0.3416383873400, +0.2120404123385, 0.1217055232831, 0.1902238778724, 0.7219418244073, +0.7643855040727, 0.5336771824088, 0.5889526897059, 0.2336949455709, +0.5260274370788, 0.2605500068797, 0.8101494032006, 0.8098065707878, +0.0203989055103, 0.2581349281865, 0.6233902325031, 0.4237744512147, +0.6127427558474, 0.3937345446990, 0.6181589558805, 0.5205088697935, +0.4511484012246, 0.0541353645055, 0.2967839694101, 0.0698655145568, +0.3711466674559, 0.3216176397733, 0.7303421989690, 0.0295082796502, +0.5355951164549, 0.4121856258308, 0.8739552930342, 0.8136532925133, +0.2978741164775, 0.7476355287934, 0.5338911495795, 0.0641791709066, +0.9326504096075, 0.0622596205502, 0.2813127112022, 0.1228438388197, +0.5152365651518, 0.4586778462206, 0.3228096274300, 0.0914621139371, +0.4667087292609, 0.5356354711278, 0.7168127744071, 0.9461998599331, +0.4048372448445, 0.0794514846427, 0.9293700158267, 0.3349717302876, +0.2556622644214, 0.8559856460690, 0.1335868491482, 0.2261539847712, +0.6775823401648, 0.6268089318773, 0.1776032858424, 0.8639290481172, +0.1157377493175, 0.2131774566198, 0.0389945577080, 0.0515585784109, +0.6957295461072, 0.4136118662607, 0.9608129854132, 0.5728857072875, +0.3335878105525, 0.6283799552491, 0.4758714868109, 0.2421256961497, +0.7448809737083, 0.8488243757043, 0.0870578014697, 0.7986811142409, +0.1388423056988, 0.2115897025036, 0.3844598463664, 0.8038705758768, +0.5399838464986, 0.5436795505433, 0.2910411871462, 0.3138298617275, +0.2885570844116, 0.7956461113857, 0.3996651966123, 0.4246280362944, +0.6288270608656, 0.9661394245765, 0.4224550427974, 0.5772684824547, +0.0343353073273, 0.7445648106488, 0.1793168807306, 0.4614496005054, +0.3822555622935, 0.7300648534345, 0.1581766764439, 0.1401298661437, +0.4327292770300, 0.7158433728459, 0.3584448086836, 0.6340481632548, +0.2493731855645, 0.1776102502726, 0.5646677485503, 0.4455026101533, +0.2629574566441, 0.3882154917290, 0.3891999527762, 0.9491275949167, +0.1048691757512, 0.8029413031428, 0.9318950422722, 0.6802411399224, +0.9088287208736, 0.3934262601628, 0.5985874140629, 0.3315602384189, +0.4824920573656, 0.5376557817392, 0.3595656847393, 0.0210424568602, +0.6790124316136, 0.5168273651585, 0.2822205919224, 0.5388825654699, +0.0744454311554, 0.0612679939071, 0.2468922181273, 0.4403972683663, +0.0508396364985, 0.5071747081853, 0.7771113667531, 0.6053370268109, +0.2909067097543, 0.3002128225287, 0.6847849584579, 0.3417791148377, +0.7542260506909, 0.5538641663985, 0.6884283142576, 0.0739849107684, +0.9518835949487, 0.8590952264420, 0.3568054690756, 0.6203233560642, +0.9764353404643, 0.8607123153567, 0.2525214866048, 0.9553928836041, +0.1509697363484, 0.4589273973643, 0.3983680966303, 0.6120871713441, +0.1209859564532, 0.8299821684277, 0.9757547625228, 0.6805886885527, +0.8279840074610, 0.1954313876086, 0.8912501623348, 0.2226469806501, +0.0101406434598, 0.8788236444252, 0.7026060957939, 0.6683615286222, +0.4613759645547, 0.3010473532141, 0.1790364664882, 0.3873910537862, +0.4877881363443, 0.2156020147799, 0.8549115196126, 0.8674647807458, +0.1671098713610, 0.4396717308274, 0.0746972412219, 0.2117169882225, +0.9393058991708, 0.1435452113596, 0.3003840461841, 0.3272187278267, +0.3793408313670, 0.0902756350535, 0.6024726091896, 0.6987521428143, +0.8008743518968, 0.5003267878202, 0.9202578034812, 0.5782273712467, +0.4798694939724, 0.6288583593577, 0.6957581758945, 0.8115079653503, +0.7857553254747, 0.4900101374323, 0.5076820033173, 0.3983642712228, +0.5541832500855, 0.2471312895637, 0.7910574906464, 0.6867184698054, +0.8576859980159, 0.0419713859642, 0.4627333048092, 0.6459690097933, +0.8646492738578, 0.0247958693769, 0.4816431172572, 0.5374305460311, +0.4807793057900, 0.8039551725630, 0.1683410807365, 0.7820271634413, +0.3490410611727, 0.8601201371570, 0.8942308076165, 0.7708136899261, +0.6259965759823, 0.1499154126038, 0.3604469249772, 0.8144886110977, +0.4545693716288, 0.1058660694891, 0.7787737719616, 0.0562051004061, +0.9731742446186, 0.2403246966378, 0.5958762069214, 0.2864557748132, +0.0329027064298, 0.5273574942385, 0.4874559866672, 0.3869336971021, +0.4876198370418, 0.8905887049113, 0.5693288806683, 0.9501892914764, +0.8329991609012, 0.3522691104339, 0.9153845742882, 0.0509719974599, +0.8545393449508, 0.3137784662255, 0.1562242825312, 0.0837256545591, +0.8649437007797, 0.2035804056579, 0.1738986033825, 0.0504550896820, +0.5905506287657, 0.4909402767620, 0.3534958182618, 0.5343455283597, +0.4187253650365, 0.0451199999289, 0.5968063462511, 0.1322695902233, +0.5796162502745, 0.3918996096551, 0.2854446970324, 0.1926825531724, +0.7230899747103, 0.6125189571700, 0.9192571038936, 0.7729006836996, +0.5395579815561, 0.2107098112864, 0.5031076616156, 0.4885859840962, +}; + +static const int babl_num_conversion_test_pixels = 128; + +static const double *babl_conversion_test_pixels = babl_path_test_pixels; + +static const int babl_num_format_test_pixels = 256; + +static const double *babl_format_test_pixels = babl_path_test_pixels; + +static const int babl_num_model_test_pixels = 512; + +static const double babl_model_test_pixels[2048] = { +0.8805994549210, 0.8520863149558, 1.0948494798014, -0.0662900837447, +-0.0563984950336, 0.3705110376563, 0.7500195530942, 1.1488477208413, +1.1374580372765, -0.0504980730128, 0.3044804002645, 0.5201820618101, +0.1529518113252, -0.0260876540216, 0.1249950209283, 0.7992047204632, +0.7803537063209, 0.7594630894994, 0.3441135703326, 1.1541664405512, +0.4758779398519, 0.5892762387121, 1.1835355538798, 0.5885148565231, +0.6919828677047, 0.9178636530963, 0.0751358574606, 0.6210459547215, +0.9792466253877, 0.1110059116553, -0.0070567337829, 0.8455367091324, +-0.1633595344440, 0.6598460796568, 1.1630922272630, -0.1122072546334, +0.0332938415153, -0.0197580294776, -0.1696428826869, 0.7131117797052, +-0.0659577626111, -0.0292481218601, 0.1297438981616, 0.3348375175776, +0.4089053589892, 0.2869940487142, 0.1446642241183, 0.4547389190899, +0.0772926503221, -0.0107409353418, -0.1535428617865, 0.6887777944509, +0.6510386461630, 0.7531705901740, 0.7785353033703, -0.1700073085586, +0.6992078699634, 0.1430215138677, 0.4710342432703, 1.0536711614829, +0.7517702555059, 0.4784544946991, 0.4540274255229, 0.6639775094874, +-0.0697685681608, 0.7884107210619, -0.0616994262960, 0.4171196521340, +0.5034952085947, 0.1635252733545, 0.9686526922363, -0.0313423089829, +0.5531355088358, 0.6375374459836, 0.3342771514944, -0.1016034102540, +0.1677191694117, 1.1620408678251, 1.1245314953497, 0.6789413756127, +-0.1990186756472, 0.4450118197338, -0.0487000681687, 1.1709886335633, +0.7835063960326, 0.6520199711677, -0.0018175907441, 0.9298352352017, +0.1331941620136, 0.2827142653441, 0.9950414850353, 0.6692166525262, +0.8661885626922, 1.0849644175195, 0.9611687600432, 0.2490689099063, +-0.1318729752357, 0.9964199945314, 0.6733751379295, 1.0994693343991, +0.5404244192599, 0.5716222340109, -0.0400547327660, 0.4420278295139, +-0.0268362063108, -0.1064400725562, 0.0091596793426, 0.4942224187284, +-0.0953201930483, 0.3408829631009, -0.1443992053831, -0.0663088259596, +1.1367359623018, -0.0943388680435, 0.9858947828346, 0.0069007264482, +0.6532938446166, 0.7202423576825, 0.7576811031241, 1.1840771920905, +1.0017914974139, 0.9864880066302, -0.1970433769734, 0.5527225875076, +0.8635947168170, 0.6679800594542, 0.8714524234978, 0.9641253830698, +0.9868553909412, 0.9317217422331, 0.4644000533337, 0.3448275607754, +-0.0814322613559, 0.3272798095491, 0.3033439755921, 0.6243453205676, +0.6461948296270, 0.0917315323333, 0.4208397376448, 0.5125036549347, +0.6833412593619, 0.7508746365788, 0.6326144954342, 0.4764405322617, +0.4025864697074, 0.6200772210118, 0.8565357685352, 0.4185092776169, +1.1669394585150, -0.1441196863279, 0.1403195780424, 0.4142168710074, +-0.0925984158612, 0.9687309559289, 1.0423683203023, 0.1432762010690, +-0.1413516967284, 0.9709963009558, 0.4367110147312, 0.7138207431481, +0.5254563886325, 1.0455036942128, 0.7027180425370, 1.1011110687168, +0.5185656730638, 0.6440241279286, 0.1727835037619, -0.1939379825229, +0.0700637730165, -0.0352394979611, 0.9357556602618, 0.7936232414067, +0.9868794333129, 0.9534050323783, 0.9156351386177, 0.3683701556960, +1.1863877781603, 0.1894659023683, 0.3734822527382, 0.5721709071529, +1.0570780325015, 1.1533272366753, 0.2453462160404, 0.7138018314325, +1.0015352788388, 1.1644796166404, 0.9220581919523, 0.0877145356907, +0.0598802740964, 1.0601835827623, 0.9354759175961, 0.1587692060316, +0.4442559776102, 0.7853366633809, 0.9056872763232, 0.4381939594812, +0.8720940208398, 1.1628216506740, 0.2293607906575, -0.1215292205669, +0.5334866059634, 1.1421577945082, -0.0724178479390, -0.0348835497326, +0.4153881971796, 0.3203660392763, 0.8955628262346, 1.0432172906786, +0.9828469104054, 0.4017759753399, 0.7098319416446, 0.0690450789728, +0.0428926933757, 0.8399249422550, 0.3551032113634, 1.1551781583369, +0.4359306086953, -0.1555720277855, 0.8044045588953, 0.0771614026638, +1.1780744353207, 0.6958108834437, 1.1046115549768, 0.5398804758395, +0.8887696107332, 0.4223304122790, 0.2811475461727, 0.8102988306481, +0.8756247870976, 0.5608636309211, 0.3851520623011, 0.7105083368302, +0.3559515050407, 0.2091113930611, 0.5030214247774, 0.5127342143621, +0.4676293299848, 0.9713397022203, 0.7294774323373, 0.1985842510120, +0.1944875310149, 0.2504762397383, 0.1731156769083, 0.2393093733300, +1.0053802909355, 0.4373802250425, -0.1095988186587, 0.7282188882717, +0.2346862154243, 0.2413108996308, 0.4818081972570, 0.8948057402367, +-0.0032814184219, 0.2127606507450, 1.1371217830745, 0.3864197515819, +1.1287776654255, 1.0854881923112, 0.8350910630241, 0.2182693285953, +0.7329773396873, 0.8044024518712, 0.4463518232323, 0.0202431253252, +0.1479574983697, -0.1110711559239, -0.1864861557197, 1.1493732480097, +1.1823006505996, 0.8155868283546, 1.0602685469483, 0.7429912766176, +0.9616031121284, 0.1767881809626, -0.1339369325591, 0.0333842232048, +1.0512699896708, 0.7669834024119, 0.8141684060051, -0.0435357505658, +0.6823963541921, 0.0859562050951, -0.1917056986092, 0.0959766026102, +0.1636854124086, 0.8791149364221, 0.4987168558402, 1.1454160844653, +0.3540510435375, 0.0924630771822, 0.7646031280815, 0.1338079182123, +-0.0396718013285, -0.1129716167752, 1.0968655297052, 0.0109549506618, +0.6533706506031, 0.3082856970412, -0.0240427726992, 1.1103793739855, +0.0696099974539, 0.6356713005508, -0.0761274746042, -0.1637742264028, +0.1463998422708, -0.1687868910696, 1.0124594815133, -0.0100644071633, +0.9226044901286, -0.0023301680583, 0.7981965113423, 0.6266278875184, +0.7519068971984, 0.4050008443207, 0.2836260370368, 0.8064908133850, +-0.0838491895627, 1.1155923102589, 0.0841157800910, 0.9823428928770, +-0.1403261411657, 0.4702018546267, 0.0080553867892, 1.0487189081724, +-0.1846997101720, 0.0200020575058, 0.5572302378515, -0.0950790841575, +0.7694132394015, 0.6686709404311, 0.5282877545470, 0.7331874651523, +0.8420958734313, 1.0390232368554, 0.1043422403300, 0.6521602799428, +0.7434296087098, 1.1884957157022, 1.0702363457858, -0.0831982788086, +0.2749236692092, 0.4660340988385, -0.0138344530081, 0.6684328564761, +0.2521344762538, -0.1731694335924, 1.0710349431592, 0.4697915840288, +-0.1961303698812, 0.3682852873431, 1.1424228766665, -0.0448492774017, +0.0553991792982, -0.1364565110470, 1.0384871419698, -0.0495217371963, +-0.0710951563302, 0.0706994691262, 0.0835455464588, 0.3957173791694, +0.2639935809486, 0.8983180830713, 0.9393704095573, 0.8118333016577, +-0.0394856295732, -0.0939105462720, 0.7373413192748, -0.1562873507646, +0.0760105208848, 0.9039439797885, -0.1054148305698, 0.6075776644086, +0.7505423011028, 0.5509341900940, 0.1699780779751, 0.0807507164221, +0.1961637430806, -0.1973232232953, 0.5777647565015, 0.0410130204824, +0.6706658959718, 0.2000333731994, 0.3709620640478, 0.5201876325161, +0.8051665845351, 0.9260650752699, 0.2635768628044, 0.2094492053657, +0.1589557102690, 0.9340714288568, 1.1967645443961, 0.5471224092632, +0.9798476025368, 0.6229492918695, 0.6323895112762, 0.9361349533015, +0.9773084949596, 1.1403619729636, 0.7290387455975, 0.1697308305510, +1.1043746321017, -0.1466809848075, 0.8443059521002, 0.8236239150277, +0.0552970499058, 0.6549169325525, 0.6042532059384, -0.1857159705766, +0.7022055949560, 0.4514607929864, 0.6575937092572, -0.0179820382120, +0.2380049786707, 0.1728714902759, 0.8514941668378, -0.1714442266950, +0.6621934382535, -0.1568284367941, -0.1010634351061, -0.0849289710098, +1.0318360619395, 1.0211491491744, 0.9772429920627, -0.1042988913619, +0.7793633332380, 0.8116836638244, 0.4440984403920, 0.4096325026870, +0.9967611010171, 0.5566718281976, 0.7520456361361, -0.0268628146624, +0.4106356176597, 0.9011357324669, 0.6099908433901, 0.3963515882363, +0.1962620111165, 0.6659326682174, 0.3560526643675, 0.0142440486766, +-0.1577978537221, 1.0984676060725, -0.0826065394481, -0.1863536270272, +1.0839586563799, 0.2802071256005, 0.0713390956965, 0.9688876273897, +0.2659767692285, 0.5461520946334, 0.3233786888064, 0.1702756605904, +0.7102541829041, 0.0978128305160, 0.3673012431559, 0.1006216802172, +1.1845368688854, 0.2896175161421, 1.1094964943405, 1.0113996835479, +-0.1421062825909, 0.9812979692506, 1.0462893443398, 0.6615421298247, +0.6705242364064, 0.4685293357207, 0.6824337010656, 0.4562801870780, +-0.1478672615941, 1.0667862475229, -0.0655379967138, -0.1615136352188, +-0.1792569087722, -0.1056651153162, 0.9652538529435, 0.0518554638381, +0.2068686085785, 1.1047017476078, 0.3745420102843, -0.1634070520119, +1.1985423793078, 0.6728453778070, 0.4508538415892, 0.8979206990907, +0.8295547676410, 0.7087965622120, 0.9706582083230, 1.0181550847451, +0.3416968311843, 0.8140916365264, 1.1984140783541, 0.8801547020116, +0.3009836084680, 0.3995905492453, 0.5953896051251, 1.0447034220419, +0.1163096709719, 1.1715078448744, 1.0681198849660, 0.0778233061907, +0.0544373514384, 0.1684424093778, 1.0382940917454, -0.1974181123997, +0.8401408920251, 0.0751804426663, 0.2627772947134, 0.8035479440370, +0.5352400040884, -0.1529905000483, -0.0201178097260, 0.8373193049977, +0.4488911166083, 0.5337823827443, 0.7198548777587, 0.6307360318632, +0.1706677867894, 0.0784458835975, 0.0425789443043, 0.4905130854298, +-0.1143035566035, 0.7123646186257, 1.0925375201239, 0.0409930220065, +0.7657504314397, 0.3866800525164, -0.0880448327810, 0.4879271252490, +1.1826569397853, 1.0820601024116, 0.3581878967388, 1.1800750521850, +-0.1999700681306, 0.0370942905718, 0.0505025117893, 0.1964819884843, +0.1505991108485, 0.8401708245464, 0.3122747338900, 0.5132798065028, +-0.0771070446247, 0.8858391149369, 0.8871803244982, 0.4921569241640, +1.0975482876867, 0.5717840719837, 0.2196214976812, 0.4070352022569, +0.7031934646439, 0.0682160744761, 0.8502299562330, 0.4622004419855, +0.0306946003021, 0.7888899080404, 0.9805806931018, 0.7427674757050, +1.0726109118539, 0.9964450317418, -0.0244300400952, 1.0925358603208, +0.9302398457798, 1.0552678509873, 0.8785051341534, 0.5337578572956, +0.4422874517936, 0.9302697776492, -0.1076378590929, 1.1290076459427, +1.0967937989611, 0.7928865626421, 0.5704406015437, 0.4046368747971, +0.8646561282988, -0.1803132456636, 0.4787256775790, 0.2576209260419, +0.1605476165938, 0.7622044153336, 0.5914708263201, 0.8983471752602, +1.1844682582582, 1.0637410812377, 1.0304204898097, 0.2417007819012, +0.7035370419284, 0.0151628579084, 0.6526309892780, 0.8110011822595, +0.1619588058265, 0.5761479531304, -0.1883921103498, 0.8282009491828, +0.8191206690944, -0.1078013490456, 0.4314158034657, 0.8901130238036, +1.1284148198219, 0.0614081202361, 1.0224684292555, 0.5237779450248, +0.8505299561892, 1.0252086187830, 1.0542946828782, 0.3929090301473, +0.0313675344136, 0.5151860838361, 1.0448953731195, 0.3330203598053, +0.8780669813408, 0.3919151516594, 0.0773904991697, 0.4363661987876, +0.9188121712389, 0.8625352389470, 0.2556562322451, -0.0921890116726, +0.7364881707060, 0.4223492125153, 1.0776980968554, 1.1082872215231, +0.7794190096573, 1.0984469765324, 1.1984971662976, 1.0893059865056, +1.1536909141362, 0.3985396780998, 1.1906456281387, 0.4299129691114, +0.2060230862377, 1.0821057339581, 0.6599477983359, 1.0131140567423, +1.0472628410194, -0.1434469575730, 0.9073143520892, 0.5142424812141, +-0.0114240773075, -0.1213696245669, 0.5717391262631, 0.7522097245568, +0.9569406144120, 1.0666429040333, 0.4705455270924, 0.8491296254327, +0.8344889808607, 0.6757527849990, 0.7291781423284, 0.9262017593375, +0.4961822250375, 0.3709771509147, -0.1018980031376, 0.6068762391838, +0.5265121322714, 0.0756012346948, 0.2694241267952, -0.1034008374919, +0.0731838103725, 0.4802030457557, 0.6741409127946, 0.2600697542820, +0.8483311923446, 0.4792068972621, 0.3623087790619, 0.1340887111305, +1.0218328550560, 0.6955940327121, 0.5357599396891, 0.0696231304992, +0.9566286913849, -0.1895912222516, 0.7742244081452, -0.0925009346998, +1.1709716945751, 0.7135693051450, 1.0770516817817, 0.0447699345857, +0.0131060626419, 0.8054606747839, 0.1893220894920, 0.6062298241100, +0.3840232495144, 0.7092882876793, -0.0235621749533, 0.2874240863544, +0.9059317067759, 1.1105353817858, 0.9848895223741, 0.4458619518419, +0.7931191462991, 1.1791155171483, 0.3907384268896, 0.4590304351687, +-0.1773296635492, 0.4414503379918, 0.4583224137585, 0.9530472066035, +-0.0984185812522, 1.0445031921587, -0.0629556299480, 1.1940823534476, +1.1560387134347, 1.0582101101327, 1.0549119699071, 0.9112687788491, +0.3381934744949, 1.1270104073579, 0.5717794146257, 0.9319636510368, +0.0485255898202, 0.5512995371368, 0.7324710814899, 0.9611015041178, +0.1547708583785, 0.6325488393347, 0.0605878248162, 0.9089089065366, +0.5045077817070, -0.1392974354975, 0.5430842204686, -0.1545226534617, +0.8868698539617, 0.0976269273542, -0.1601819190011, 1.1338226480101, +0.4922228482050, 0.9095401904124, 0.7390772653460, 0.4981404954093, +0.5873904142470, 0.5938042669528, 0.7540433819192, 0.8761216360499, +0.3409190022111, 0.5434291270298, 0.4520143764336, 0.6089553511743, +0.9848952945251, 0.8791124767061, 0.4704395343878, -0.1762062095926, +1.1118195224143, -0.1665791156546, 0.2304120138429, 0.0029106152257, +0.5364771851974, 0.0665903801409, 0.6659697236800, 0.4909998386591, +-0.0571234084932, -0.1590150330956, 0.1272929446433, 0.0090539441486, +0.8652515210515, 1.0297464454685, 0.1386118942586, 0.1671110256422, +0.7538107956545, 0.1574743692565, 0.7392866352290, 1.0776891602565, +1.1022853683225, 0.1412012092495, 0.9512786362093, 0.2933300171482, +0.2270868030503, 0.2432043698818, 0.8846303362793, 0.2032930126429, +0.3579804858928, 0.0119820975754, -0.0776831534122, 0.1550698700152, +1.0437286990898, 0.2698000076552, 0.0454029819208, 0.3527288604308, +1.1204266497495, 0.3802058836353, 0.5363903877960, 0.9113727056009, +-0.1692056425704, -0.1366967593956, 0.4211908505397, 0.8636833324394, +0.6374919050548, 0.8960458791331, 1.0930496860729, 0.7598027454502, +1.1256663384501, 0.1913027000573, -0.1464797522623, 0.6323363213019, +0.0080918959380, 1.0279517061207, 0.5325039093068, 1.0047988839470, +0.5722041156014, 0.4351786996402, 0.0711560760025, 0.2171342449343, +0.7462017830211, 1.1301846014942, 0.6471607972156, 0.1934729225903, +0.6039364840854, 0.5899304814590, 0.1999846084975, 0.8925637791364, +0.6000583280809, 0.5243631338348, 1.1701363650943, 0.9363749962935, +-0.0488700395678, 0.6308526855106, 0.5876663744392, 0.3913272156340, +-0.0869476188379, 0.7886218654870, 0.3268985639917, 0.4807160605121, +0.1852176956764, -0.1612812810397, 1.1799245655443, 0.3804188117294, +0.9295627191335, 0.3933095916143, 1.0666704250810, 0.5124284741992, +0.3312994230219, 0.3017668340829, 1.0284882912545, -0.0621734995684, +0.1682128663027, -0.1224987946090, 0.2319514349252, 0.4756490878182, +0.3683110390642, 0.9721493510400, 0.6674316868500, 0.6319360434226, +-0.1711047330737, 1.1683693671452, 0.2965124842229, 0.6375680519443, +0.3648949185223, -0.0199747726414, 0.5992220526558, 1.0841788586621, +0.3065394283768, 0.4779472996844, 0.9686470928456, 1.1261206166475, +0.2610001312853, 0.6917571240532, 0.5166660186447, 0.9485716577380, +0.5211629441572, -0.0094371502332, -0.1149332849844, 0.3833364437257, +0.3892040940883, 1.0524623678310, 0.4923296845017, 1.1135550069220, +0.3562171628495, 0.7574169610429, 1.1299635732220, 0.9242811194268, +0.0349633113644, 0.9245282019137, 0.5295663114309, 0.5973952600720, +0.9102576536640, 0.0638585782907, 0.8928975690589, 1.0260787956538, +0.2182402370583, 0.0751525721863, 0.2438838056493, 0.2921196210627, +1.1611025555810, 0.7247796654351, 0.7530998718706, 0.0125308978430, +0.6531023342410, 0.2221026862143, 0.2165367888364, 0.0697658905153, +0.2151585107740, -0.0257347222537, 0.4126655359811, 0.3016035045039, +0.8292763399097, 0.8043626048622, -0.1732723550747, 1.1049952204828, +0.5540864782194, -0.0145064978928, 0.3617795652532, 1.1566912187993, +0.9174246716860, 0.7890497895838, 1.1100217040209, 1.0913458766841, +-0.1049611071613, 0.6276823253500, 1.0529083678745, 0.8029192724279, +0.3093230707149, 0.3132791305488, 0.9028348975362, 0.0967921728719, +0.7257006592703, 0.2704256256439, -0.1619412046680, 0.4559347687550, +0.7561990893242, 0.1788029928593, 0.6925283118582, 0.2545955848203, +-0.1898109323298, 1.1713576000982, 0.3530682712575, -0.0948061528126, +0.3364871343302, 0.8394654075799, 0.7757202043085, 0.3797959161828, +-0.1711543544061, 1.0905736125496, 1.0249589096871, -0.0625002304383, +0.5378998854840, 0.9462703179318, 0.6796234014815, 0.9349806130561, +0.8293239415760, 0.6329387783226, 0.3739526426298, 0.5325317687041, +0.7327223082691, -0.0613529883611, 1.1462179088715, 0.0767875395141, +0.2388722890238, 0.2584229675394, 0.4090726372828, 1.1842767048554, +0.0067947963284, 1.1950713783480, 0.6372259603987, -0.0983990515109, +0.3700901478390, 0.0169838639987, 1.1664289777942, 1.1902942316561, +0.8796489510125, 0.9065772821692, 1.0564492715786, 0.7421491814508, +0.6163887930179, 0.9084945972583, 0.7971508947188, 0.8814081806137, +1.0093060649043, -0.0457113221501, 0.6547649145381, 0.2767742955483, +0.1055050960302, 0.6386300058284, 0.7872274568245, -0.1712824434840, +0.7177220692475, 1.0382274042993, 0.7772770181192, 0.7334453650440, +0.0879506038911, 1.1565943582713, 0.0966503711867, -0.0136503452499, +0.9241705632415, 0.2947454002196, 1.1516657359673, 0.9338763322373, +0.6602438945604, 0.0942607104286, 0.5117292642182, 1.1180947131096, +0.0495867151067, 0.3398928449209, -0.1991620074022, 0.3681785351449, +-0.1252368177870, 0.8659755081246, 0.0483874415273, 0.7979888873165, +0.9318699125815, 1.0840692471173, 1.0202641866264, 0.9031523560654, +0.1409370071911, -0.1626249920403, 0.5226992529457, 0.6074916427990, +0.2863259251631, 1.0586590770905, 1.0756024129109, 0.0999762704130, +1.1061291156831, 0.5742765290543, 1.0152534347099, -0.0277472165542, +0.8850138831348, 0.8302996789246, 1.0690219292739, 0.9669191706772, +0.9489297279850, 0.3452577770433, 1.1245603893532, 0.3807511928402, +0.7233872686156, 1.1985164430917, 0.8851506226161, 1.1253983819510, +0.8366904202088, 0.7981504514805, 0.8644919512162, 1.1335380641434, +0.0922477793378, 0.5685603321384, 0.6822196979459, 0.6847561371907, +0.3048952206526, 0.4331847865289, 0.6059353407500, 0.0049189502396, +0.6537905364548, 0.7912211464677, 0.2918438629675, 0.4815377530090, +-0.1259835322974, 0.5599196521379, 0.1654976748701, 0.1070972976773, +0.6152707969841, 0.9590303508374, 0.1902193304106, 0.0345196041439, +0.0401781010629, 0.3642005249691, 0.1042881278807, 0.1147797191119, +1.1229768139883, 0.9635653696785, 0.3627169674089, 1.1894387504968, +0.9119650551639, 0.7596672335452, 0.5617158205070, 0.0272089179732, +0.2488544686925, -0.1957871661502, 0.1282275656835, 0.0439355184529, +0.2157006587906, 0.7537496899971, 0.4373976210306, 0.9341629064335, +-0.1636612189764, 1.0694911952454, 0.3449708358128, 0.9292414839981, +0.9449881148268, -0.0896447512739, 0.4294108467314, 0.7104685106829, +1.1344098969057, 0.3602589118109, 1.0693856002155, 0.8196301771419, +-0.0368875227109, -0.0254120026833, 0.9244594367801, -0.0263262725558, +0.3143853221621, -0.1139107093745, 1.1381533669951, 0.0871764035370, +0.7438047059550, 0.0263503766741, 0.8457565248226, 0.4998691875021, +0.9081469962877, 1.1926591746475, 0.0305632111759, 1.1739840905061, +0.3972023155527, -0.0761523455736, 0.7464088639926, 0.6679608322065, +0.8018482104884, 0.4335410972282, 1.1933388496718, -0.1086203008465, +0.0423798728932, 0.5468363246633, 0.5438963459543, 0.4227496964032, +0.5869556729621, -0.0232102308530, 1.1070952364742, 0.4132819455179, +1.1187310767913, 0.7500681502512, 0.1513777664636, 0.8315546726024, +0.7894003209609, 0.2331163983015, 0.8361574415286, 0.0895311334587, +0.4558980555534, 0.3332050262639, 0.4594667749756, 0.4819139656992, +0.1579908177061, 0.1640450511892, 0.3258642002595, 0.6900299861515, +-0.0363472365943, 0.7551931339107, 0.2878927056156, -0.1277269357479, +0.9039812510386, 0.9655009738940, -0.0112657695130, 0.2812315546354, +-0.0540874780408, 1.1463611245837, 0.3123372985573, 0.7326305764414, +-0.1490127930180, 0.7328681949213, -0.0768491069213, 0.2194325343796, +0.5640597936530, 1.1697182837733, 0.2829363451726, 0.2745286601943, +0.6010077517484, 0.1534601139619, 0.2028346814228, -0.0809062139508, +0.3523314425500, -0.1430941933501, 0.6866651402259, 0.8623014563985, +-0.1151975959145, 0.7103222602561, 0.2209508578391, -0.1874706601666, +1.1900751180901, 0.0484551681431, 0.2655153935149, 0.7088435634546, +-0.0131197995567, 0.8940563691287, -0.1860438586148, 0.4542496240019, +0.7457259749741, 0.1327927224025, 0.8404174930604, 0.3262934399425, +0.0380970456815, 0.7967131819561, 1.0656609173239, 0.9635683861391, +0.2676910478937, 0.8021568393345, 0.7664314650774, 0.1485972618445, +0.8315676022468, 1.0686987996421, 1.1556169532964, 1.1692661465003, +0.6548114333557, -0.0161009558551, 1.1256046062920, 0.6422820928703, +1.0553990269338, 0.7396138374412, 0.8942213050529, 0.1465554634792, +0.6139863225697, 1.0454741450238, 0.9880690055844, -0.0402633020842, +0.1283185869122, 0.8008665230129, 0.7395305135006, 1.0020251476215, +0.1435163913963, 1.0740445618862, 1.1336592454154, 0.3799480059091, +-0.0520825760682, 0.3816134377297, 0.6707577431904, 0.9993201620874, +0.2064553534642, 0.4156084718255, -0.0162297235877, 0.2371892076159, +0.7816693225790, -0.1619770442890, 0.2843072714677, -0.0606127702913, +0.5564673412389, 0.2364807552828, 0.0219219998559, 0.2099118771078, +-0.1241199971755, 0.4118663675207, 1.1760945933760, 1.1161433049087, +0.7661887452780, 0.6898663253942, 0.2573405118926, 0.9641635983084, +0.3768190306503, 1.0945073328421, 0.2907328477552, 1.1968710253932, +0.0237122539541, 0.7203354226986, 0.9685518940764, 0.2243920925187, +0.8764988448827, 0.1716296778860, -0.0980511402237, 0.4393096372668, +0.2251063658973, -0.1170458016531, 0.7872381503634, 0.0857191361886, +0.2814572982869, -0.1932243115237, -0.0790228459421, -0.1284545788208, +0.0590424588225, 1.0379246395258, 0.2432564437591, 0.1428991539138, +-0.0164853652085, 0.1349224616470, 0.2497910070465, 0.2193510364831, +0.7040025443323, 0.9497033800696, 1.0247887870412, 0.7071315189391, +0.5399137266632, -0.1191784256693, 0.8442107122597, 0.1155216341445, +-0.1479277570489, 0.7636259806173, 0.8011569970293, 0.6127626063362, +1.1888249936462, 0.9285710878338, 1.1352556591552, 0.9031058568056, +0.7940392300459, 0.2139313588915, 1.0115252861807, 0.7224938088667, +0.0754015941524, -0.1245034723191, 0.2207070473678, 1.1325024402386, +1.0833145282619, 0.3344440529749, 1.1134211678586, 0.6639634917788, +1.0703436931923, -0.1331708375985, 0.6693665146219, 0.1632121742532, +0.8096769351557, 0.5743462368726, 1.0165325431230, 0.4941553010112, +0.0735058604151, 0.1495906611670, 0.6551678118553, 0.6607432547308, +-0.0405693349617, 0.1255781033661, 1.1132166417843, 0.2563248082326, +0.5709661085023, -0.0517443419675, -0.1458508088001, 1.0484723002876, +0.9981769176192, 0.1650053378963, 0.3621870169240, 1.0656744773805, +0.2468575560706, -0.1264214888804, 0.2405018662291, 0.7828940649437, +0.5171352076890, 0.1301720836806, 0.4080225640945, 0.1539230334358, +0.5715443790758, 0.3874789002293, 0.1970012467341, -0.1226109219355, +0.8742770439360, 0.1812213135796, 1.1618251377539, 0.0135337892051, +1.0733177571899, 1.1477829050030, 0.5308119747466, 0.6169929489572, +0.2925009161665, -0.1672515784238, 0.0733610077171, 0.4440286158789, +-0.0068153237024, 1.0634670246688, -0.0189959203913, 0.1275101989170, +0.1260851614764, 1.1913615939167, 0.0284723625651, 0.5431910971846, +0.8228972622300, 0.5729427175470, -0.1350598956156, 0.4689742287942, +0.5503517465435, 0.1400324692670, 0.9031148012276, 0.4729626684789, +0.1136498365149, -0.0781038750327, 0.7275113694964, -0.0998839526902, +0.1063294549036, 1.1879268811028, 0.3031174385469, 0.6893365065983, +0.2779580285204, -0.0203527879065, 1.1357097854538, 1.0339294132935, +0.3365809920880, 0.7704589446869, 0.0123956336698, 0.0090707925191, +0.9365908111150, 0.5297656683856, 0.6339259693557, 0.1933997139304, +0.1313725600631, -0.1373240280605, 0.5211272616503, 0.8623983319208, +-0.1409699661382, 1.1542698222931, 0.6356186894866, 0.5860673660348, +0.4388495380240, 0.6093817804052, 0.0943022909082, 0.3387334900623, +0.5111501670029, 0.7524993745389, 0.7312779053726, 1.0218136604046, +1.0683247565610, 0.8174796219065, 0.7404262549898, -0.1656046567325, +0.8852068329627, 0.1462827844295, 0.9971268340001, 0.6761360397917, +0.2029221816002, 0.0217878243987, 1.1167417297683, -0.1904775323302, +0.2130660297410, -0.0604870079367, 0.7515534927843, 0.5506676984721, +0.8587481198175, 0.5444385898041, 0.0021889640029, 0.0726807537827, +-0.0234588571002, 0.9177781536792, 0.4987084114452, 0.8378076534894, +0.6148243621061, 0.6153906809238, 0.3271599334325, 0.7930107023534, +-0.1071668185793, -0.0740254715430, 0.1678900554627, -0.1415621618468, +0.5844523502441, 1.1611579379817, 0.9434541510155, 1.1083163104524, +0.7501034520334, 0.2696591825549, 0.1074407217593, 0.7405809843636, +0.7748501493478, 1.1530256336336, 0.4914470069536, 0.0241824508757, +0.3156812528687, 1.1879161790888, -0.1074613749550, 0.0430004990860, +1.1325352425373, -0.0255706279658, 0.5323547682410, 0.0947275890479, +0.8240738813877, -0.0909236145629, 1.0922075257135, -0.1689368209657, +0.2778052966473, 0.2388982434938, 0.7244670663609, 0.2193674584941, +1.0006734322760, 0.3706384780680, 0.3648727719508, 1.0923571218235, +1.0489079073299, 0.3851257818682, 0.3317964153978, 0.1083269223144, +0.8634195886848, 0.5990113587114, 0.8547849644231, 0.6392371371571, +0.3892324698107, 0.4382697373807, 0.5520369923450, 0.1462319707248, +0.9393032070898, 0.9049137226794, 0.4261859164695, 0.6445756173900, +1.1896038643967, 0.8718384489752, 1.0793430947137, 1.1585406847105, +-0.0090819223826, 0.8136777451326, 0.9809148344122, 0.9715506197752, +0.3977390219447, 0.4687233742647, -0.1474240120256, 0.5053819007731, +0.7257756828916, 0.1984124535687, 1.0393618523327, 0.4174487605772, +1.0103954042356, 0.5746835895696, 0.7835382354369, 0.1711582670785, +0.7845551699328, 0.6738149922685, -0.0263050517190, 0.4383231992080, +0.1703075573641, -0.0262123609084, -0.0879152703508, 0.7257319406260, +0.4968113301773, -0.0903892361980, 1.0787013617711, 0.5382706461187, +0.7295950749561, 0.4864151939221, 0.9814492134291, 0.9580444558328, +0.0677459473106, 0.9205131525735, 0.1000929390546, 0.7623640471894, +0.7701176876063, 0.6654849699072, 0.1892365261862, 0.1526689270291, +0.3997566449455, 0.2958933704979, 1.0638974234759, 0.0285983778669, +-0.1142411425310, 0.2101520491811, 1.0705769600675, 0.6474356589128, +0.7700038483227, 0.8703140280537, 1.0839670414496, -0.1557280923034, +0.5343224165655, 1.1403114063387, 1.0441016671453, 1.1960517710988, +0.6808474840973, -0.1688662532572, -0.1500778305112, 0.9228030289164, +0.5937354301073, 0.2104425590534, 0.5175489406649, 1.0313713829179, +1.1703108074005, 0.8614813774179, -0.0690442890250, 0.8176418797195, +0.5487906156801, 0.7404284943549, 0.3269663466732, 0.3201922378131, +1.0382994290620, 1.1485472612775, -0.1636781357991, 0.1908637701491, +1.1511707326170, 1.1240582865309, 0.1586993098067, 1.1068988249204, +0.0387181217031, 0.7211745809397, 0.7943723139327, 0.0426663506043, +0.3612770093425, 0.7730405382686, 0.6614859866265, 0.6384739810780, +0.5427795390332, -0.1578755072122, 0.8041742850114, 0.7114081561153, +1.1393651053958, -0.0634850315114, 0.2525670518412, 0.1217232256763, +0.9037150012812, 1.1096759121444, 0.9979963459065, 0.3835227634681, +0.5158264627288, 0.2525056163094, 0.6501044064994, 0.1249626925797, +0.5933250949687, 0.3541258911389, 0.2010528769349, 0.6864262707003, +0.8024185379978, 0.5444958275857, 0.2781841770179, 0.5597521867416, +0.7110304720285, 1.0411366597010, 0.0656704078734, -0.1274435090495, +0.4385645499633, -0.1276925192809, 0.6141771973177, 0.9271563944999, +0.5400747080054, 1.1813440889965, -0.0855680264931, 0.2183514823291, +0.9505217894681, 0.4794398127494, -0.0821409431669, 0.3669990260000, +0.0408180953194, 0.6542367900974, 0.3891157248938, 1.1158554033916, +0.7256464014415, 0.7566445580482, 1.1067424064068, -0.1607798692588, +0.8675474700832, 0.1189714964102, -0.0892295514649, 0.1077952833417, +0.4615111165035, 0.4699660074292, 0.8634673239959, 0.3889546255530, +0.8562941257173, -0.0274584121199, 0.3111026664782, 1.1291377318693, +0.1436313461250, 0.0948586750286, 0.0448490685992, 1.1252798644478, +0.7262800687581, 0.8837060541304, 0.0762027640251, 0.1592810427580, +0.1099172235978, 0.4768018575743, 0.1631458662279, 0.1940618208582, +0.7914817218629, 0.3507353189172, -0.0689613529802, 0.7522615911217, +0.1455763361163, 0.3171281233044, -0.0926201236866, -0.1622189472254, +0.6071049510534, -0.1868761938004, 0.6360996197146, 0.0181503248486, +0.2287046742759, -0.1313839330950, 0.4830898136287, 0.2995669430585, +0.9194723445547, -0.1150012006587, 0.0411576554371, 0.9941924807589, +0.6452877667943, -0.1368963099722, 0.1798574743699, 0.2860067240363, +0.8501220599050, 0.1715678349005, 0.9468097441582, 0.4560602383949, +0.8622172015078, 1.1600392835029, 0.8483696924748, -0.0900443902659, +1.0171893929211, 0.4536989227187, 0.3107746024201, 0.9794083394946, +0.6363048042340, -0.0372342716145, 0.9708270460231, 0.4181544787335, +0.9064936081443, 0.0434097546355, -0.0241104654149, 0.4069266650858, +0.4531718289727, -0.0648017182317, 0.1120258215405, 0.6589793488658, +0.8391902016658, 0.1726441728755, 0.0201970811096, 0.3531834769776, +1.0561147945263, 0.2844779678082, 0.2357478629033, 0.4000545561314, +0.0925132161437, 0.7062368537794, 0.6560458033607, -0.0174423935904, +0.0838238346781, 1.1547304176515, 0.6662761372823, 0.3044154951835, +0.3952052177839, -0.0989867730527, 0.4084293403702, 1.1770507397023, +0.7861830514791, -0.1684899786340, 0.0637789553328, 0.1792563857414, +1.0986478394357, 0.4926766589716, 0.0749197760014, 0.2396684905699, +0.9401290751715, 0.3518196677565, 0.6278749413918, 0.3869455981939, +0.0481265779809, 0.5793192761854, 0.7244638406320, 0.8480720225014, +-0.0572306907071, -0.0957586274928, 1.0637972446456, 1.1602117035353, +1.0242585425378, 0.2352825254366, 0.8104782262866, 0.5198430473543, +0.2538051019673, -0.0919176234360, 0.1900129430881, 0.2767543629169, +1.1776986691997, 0.8490103204032, 0.0090956035112, 0.7984422834583, +0.7125430500659, 0.7638817200269, 0.8805203417691, 0.2728745594960, +0.3423857159644, 0.6111908888496, 0.0565583789985, 1.1554401184225, +0.5325053422397, 0.0825147904840, 1.1630105566061, 0.8844333203903, +0.6476860994695, 0.7806319208726, 0.8618340673213, 0.6874743965862, +0.0454743580173, 0.7904554087624, 0.8848732933797, 0.7256313113149, +0.9721058825832, -0.1302671000968, -0.1742620664529, 0.4953515190144, +-0.1858068405584, 0.0259109838986, -0.0221847228809, 0.2157508766352, +0.6597854401263, 1.1918918292932, 1.0749213043018, 0.1869108806303, +0.7108817638414, 0.1723284895403, 0.7557735486681, 0.7554416460709, +0.6967652474049, -0.1467325208461, 0.9835193783899, 1.0123319276666, +0.4340043302784, 0.0292705896447, 0.1357822696379, 0.9465299343441, +0.7232476476222, -0.1183095709040, 1.0099025105172, 1.1976163369592, +-0.0098726783925, 0.9687220056396, 0.8721458378584, 0.6947758032450, +-0.0863653519593, 1.1622332041907, 1.0384549061947, 0.8978837720574, +0.2031810632922, -0.0721721918658, -0.0118558119106, -0.1837298173382, +0.8185071378101, 1.0629665040704, -0.0802803632246, -0.1369345082608, +0.6878251131102, 0.3293889009996, 0.0352949929588, 0.8754931854436, +0.9653443056929, 0.1845903598632, 0.3826563801536, -0.1811856286513, +0.7160549867507, 0.1993486359712, 0.4138609495078, 0.7184386504434, +1.1185392626182, 0.2393026343730, 0.2810390650672, 0.2237634593732, +1.0510686749830, -0.0913334157743, 0.0080246393606, -0.0468150970744, +-0.1372502724348, 1.1647033230237, -0.1291002122355, -0.1535204550966, +0.1221094682450, 0.2659307915093, -0.1074688694940, 0.0590439758538, +1.0877439533769, 1.1406166060551, 0.1288972949278, 0.0122507672814, +0.3830066592353, 0.5755690658351, 0.2700055070547, 0.3641922878866, +0.3711005369998, 0.1483509649282, 0.9601594256983, 0.8526618872083, +0.5977838345793, -0.1128444762495, 0.5476996008995, 0.1740203752061, +1.1819235688923, 0.5163230971975, 0.3264581581235, 1.0287386659667, +0.5809623430394, 1.0329922432234, 0.6249896814232, 0.5344827974841, +0.9549334456934, 0.6437120706047, 0.9976955662471, 0.6958894691877, +-0.0975225359656, -0.1229570867135, 1.1096428621140, 1.0902266967530, +0.6027324449284, 1.1902214174113, -0.1823404813103, 0.0385401563898, +-0.0596730870473, 1.1857391041637, 0.5657904825945, 0.2876650257444, +0.6999702828470, 0.5114274499525, 0.1340900684400, 0.3259499076409, +0.7105283353061, 0.0977541174263, 0.5985829737031, 0.8817896693394, +0.4595239293107, 0.6924519035464, 0.8140772146238, 1.1250411318266, +1.1349563645827, -0.1595137283017, 0.5254441467698, 0.2390668953951, +0.2133664084661, 0.8898898096242, 0.6841983423029, 0.3231397123649, +0.8323813608067, 0.3158438725005, 0.9669327229107, 0.5938412044169, +0.0722572673449, 0.2351138050831, 0.3060652892599, 0.9845922422524, +0.1978056794954, 0.2125841802976, 0.2208529092469, 1.0718557718545, +0.2367326470263, 1.0977759623424, 0.9240116309021, 0.5549429776869, +0.2476357357798, 1.1472609823324, -0.0044699208832, 0.3225946039532, +0.0486741884838, 0.9071596650906, 0.6397128852269, 1.0096072937407, +0.4882967437097, -0.0163694469334, 0.9476459367888, -0.0348429686552, +-0.1743145177953, 0.9016631528277, 1.0735203626908, 0.4318442784398, +0.6250453272020, 0.8580668436634, 0.0175070246763, 0.8404530856015, +0.3954280857907, 0.8973025945468, -0.1068193519054, 0.5235723145882, +1.0689765356802, 0.7932337652860, -0.0901132251556, 0.3140335573414, +0.1564930090478, 0.1057091820546, 0.6910097276284, 1.0338984057465, +0.6961471004859, 0.6041287448276, 0.0529701637351, 0.8865398067453, +1.0578400809587, 0.9448212889698, 0.3112884092663, 0.8926830489620, +0.6907786244949, 0.3461368240165, 1.1284518420363, 0.0589343454032, +0.6424252896767, 0.7164641066997, 0.0477999761923, 1.0019722047271, +0.9888793161087, 0.0674706162268, 0.3745309497111, 0.2653070015206, +0.9817451557991, 0.1843074012475, 1.1647732107736, 0.4677115984576, +1.1085583907126, 0.8507216908274, 1.1775411671854, -0.1253400150339, +0.3550907002553, 0.0650513997604, 1.1564308728820, 0.6685508941619, +1.1020840855791, -0.1487621999107, 0.8691801445881, 0.0094010359651, +0.2394028992576, 0.9599241658859, 0.9960590897110, -0.0195314461456, +0.7264831351705, 1.1301815237525, 0.1060609892505, 0.9245109310953, +0.8191679676153, 0.1689084241953, 0.6466456304522, 0.3538609660947, +0.4888881779690, 0.6080472830720, 0.4363790404221, -0.1788234204887, +0.4758122361618, 0.2706333337681, 0.9923546843195, 0.4011522511957, +0.4384467443630, 0.3843706268744, -0.0786449760565, 0.9698958508530, +0.0871869327906, 0.9935374452702, 0.6494220266349, -0.1222141031745, +0.4990707244254, -0.0107289822822, 1.0447752453595, 0.3186021705710, +0.5653452655139, 0.9384736243349, 1.1491951836036, 0.8408343344186, +0.6091171389488, 0.0918284000325, 0.8686551474354, 0.0552561728541, +0.3364773573989, 0.2282851059121, 0.4607368248798, 0.3153007772357, +0.2982681158456, 1.0253655353679, 1.0363323889842, 1.0971158653019, +0.5985829235048, 0.9740803526594, 0.0959988684840, 0.8286870726518, +0.2951397899050, -0.1629703327841, 0.1584509788819, 0.2173538930795, +0.1264751754359, 0.5823267226956, 1.0305671124861, 1.0078730055168, +0.5161766916123, 0.8255459005132, 0.7715977410654, 0.8753423578457, +0.9760490968712, -0.1184780435257, 0.5640195241962, 0.7207929240171, +0.7479754488673, 0.3851662351681, 0.1733503571587, 0.2326746709797, +0.7312030466884, -0.1155471943857, 0.8134513410802, 0.8340871820385, +0.2784708020643, -0.1705288374659, 1.1098183409822, 0.6497837294125, +0.4231711025458, 1.0770537255691, 1.0035515151934, 0.0058172094663, +}; + +static const int babl_num_type_test_pixels = 512; + +static const double babl_type_test_pixels[2048] = { +98.7976644499217, 96.1907487959558, 118.3862381532724, 12.2249066290562, +13.1292804540737, 52.1610091571515, 86.8589305686107, 123.3232201912083, +122.2818776938514, 13.6687476102583, 46.1239223098959, 65.8452170797834, +32.2698798925941, 15.9005573465957, 29.7138304848754, 91.3558601566385, +89.6323388636263, 87.7223396113712, 49.7475264304073, 123.8095031361140, +61.7945545007449, 72.1623989679675, 126.4946792118692, 72.0927868821159, +81.5527193330008, 102.2046768545195, 25.1552783963994, 75.0670587173975, +107.8168343211603, 28.4348262084810, 17.6405271969924, 95.5919276921041, +3.3499854222638, 78.6144987114773, 124.6255750640415, 8.0267652906602, +21.3297226528310, 16.4792658763375, 2.7755078686287, 83.4845055730476, +12.2552902755585, 15.6116002870778, 30.1480135462005, 48.8994301785247, +55.6713471075852, 44.5251701681526, 31.5121576336735, 59.8618440310759, +25.3524708865920, 17.3036859116069, 4.2475097795238, 81.2596840640808, +77.8092476491859, 87.1470253873370, 89.4660848795744, 2.7421889317884, +82.2132909680779, 31.3619669821868, 61.3517022418565, 114.6213633355784, +87.0189947891137, 62.0301252296335, 59.7967931906678, 78.9922294388489, +11.9068737681521, 90.3689802113776, 12.6446238815061, 56.4223681951046, +64.3195619286595, 33.2365964209831, 106.8482461473198, 15.4201317501348, +68.8581036649915, 76.5748522042180, 48.8481967080609, 8.9962596339156, +33.6200383462105, 124.5294507725767, 121.1000224319752, 80.3603543417344, +0.0897210836828, 58.9725092328026, 13.8331366245789, 125.3475322114991, +89.9205847801271, 77.8989687924734, 18.1195345605349, 103.2992215041533, +30.4634662412403, 44.1338756886003, 109.2609357746602, 79.4712368023913, +97.4800971604325, 117.4824610303540, 106.1640009182338, 41.0577289057233, +6.2287565498747, 109.3869709285847, 79.8514411821270, 118.8086248593445, +67.6959469037577, 70.5483185381388, 14.6235672899632, 58.6996872698421, +15.8321182801538, 8.5540505091446, 19.1231706827521, 63.4717639980241, +9.5707252070171, 49.4521566263643, 5.0835012221166, 12.2231930551227, +122.2158594104535, 9.6604463503046, 108.4246658591668, 18.9166378466956, +78.0154372220931, 84.1364441309760, 87.5594151427780, 126.5442004197017, +109.8780797635569, 108.4789034633333, 0.2703198195763, 68.8203508578336, +97.2429455375499, 79.3581768643848, 97.9613644340827, 106.4343207378100, +108.5124928860518, 103.4717021470292, 60.7451477333648, 49.8128055566050, +10.8404789617474, 48.2084397302048, 46.0200206255633, 75.3687150233280, +77.3663844230428, 26.6725972419011, 56.7624902989541, 65.1431913083155, +80.7626294273709, 86.9371096300600, 76.1247538682654, 61.8459915210707, +55.0936200875294, 74.9784887782198, 96.5975559803646, 56.5494196678276, +124.9773219213715, 5.1090572500178, 31.1149328495911, 56.1569710635380, +9.8195734069774, 106.8554016849284, 113.5879607133511, 31.3852526691674, +5.3621305848295, 107.0625189445273, 58.2135784897085, 83.5493250878292, +66.3274412464013, 113.8746234708813, 82.5342210319518, 118.9587262826780, +65.6974329658306, 77.1679202677533, 34.0830632010862, 0.5542415979105, +24.6915449615063, 15.0638173292688, 103.8405175096544, 90.8455535000402, +108.5146910457475, 105.4541743888772, 102.0009269593288, 51.9652713779198, +126.7554540032313, 35.6083110736722, 52.4326631074923, 70.5984829396934, +114.9328486858554, 123.7327759246029, 40.7173683236900, 83.5475960166881, +109.8546540652656, 124.7524220928328, 102.5881775499266, 26.3053289774364, +23.7604822031038, 115.2167847096998, 103.8149410373601, 32.8017559800305, +58.9034036672224, 90.0879235091097, 101.0914081209765, 58.3491620097073, +98.0200247624982, 124.6008366330531, 39.2558437172584, 7.1744712624580, +67.0616325452280, 122.7115697836092, 11.6646539027172, 15.0963611673081, +56.2640637421348, 47.5763235909754, 100.1657441128817, 113.6655808620460, +108.1460032370621, 55.0195177453661, 83.1846346646476, 24.5984072203740, +22.2073319657740, 95.0788518633129, 50.7522936103643, 123.9020030479422, +58.1422270807169, 4.0619860310396, 91.8312739561458, 25.3404711006863, +125.9953769436085, 81.9027093434253, 119.2787707407394, 67.6462149339012, +99.5446501241739, 56.8987805512262, 43.9906327929304, 92.3701788021113, +98.3428376774969, 69.5646748270675, 53.4996171246747, 83.2464765101888, +50.8298518894379, 37.4044702227248, 64.2762445510720, 65.1642710273919, +61.0403958843278, 107.0939156315727, 84.9807938137002, 36.4419886639537, +36.0674314070807, 41.1863990617853, 34.1134333173341, 40.1654284187432, +110.2061980283848, 58.2747634324593, 8.2652508654936, 84.8657269276985, +39.7427396959359, 40.3484251091017, 62.3367494634989, 100.0965248216393, +17.9856988871404, 37.7381166395443, 122.2511344525270, 53.6155201446337, +121.4882436960415, 117.5303490113143, 94.6368971907706, 38.2417671858528, +85.3007853428371, 91.8310813139338, 59.0950238383818, 20.1365143154452, +31.8132569938028, 8.1306371726704, 1.2355514770539, 123.3712683894538, +126.3817737691020, 92.8536528781306, 115.2245528638477, 86.2163452907541, +106.2037131088803, 34.4492051165780, 6.0400518803112, 21.3379861215772, +114.4018276270487, 88.4099110776605, 92.7239685490373, 14.3053028054094, +80.6762380975654, 26.1445673229846, 0.7583361271575, 27.0607179529316, +33.2512377059326, 98.6619370443103, 63.8826839625289, 123.0094705796845, +50.6560954091400, 26.7394813423694, 88.1922859960200, 30.5195810936948, +14.6585781642509, 7.9568807519772, 118.5705627159078, 19.2873097747971, +78.0224594837159, 46.4718351580537, 16.0875179246476, 119.8061141929618, +24.6500569100725, 76.4042331932132, 11.3254880361843, 3.3120707288906, +31.6708427219050, 2.8537699593481, 110.8534383097912, 17.3655399164956, +102.6381248117602, 18.0726703489538, 91.2636810370086, 75.5774068588286, +87.0314877438506, 55.3143629093256, 44.2172376719384, 92.0220172237707, +10.6195026685575, 120.2827255093878, 25.9762998940313, 108.0999216344673, +5.4558956648483, 61.2755981373021, 19.0222067921526, 114.1685858900512, +1.3988836414175, 20.1144738290992, 69.2324788892793, 9.5927694484558, +88.6320676024221, 79.4213431251335, 66.5863089871529, 85.3199968139268, +95.2773369994375, 113.2821245124946, 27.8255762587421, 77.9117970233372, +86.2564213677572, 126.9481797213425, 116.1358944718427, 10.6790145089286, +43.4215926134128, 60.8945461795174, 17.0208500106916, 79.3995754492467, +41.3380092574926, 2.4530803572634, 116.2089090888430, 61.2380876826300, +0.3537947537162, 51.9575119856547, 122.7358058666511, 14.1852089232696, +23.3507821072595, 5.8096904185646, 113.2331101229569, 13.7580125991991, +11.7855857069537, 24.7496657486771, 25.9241642476638, 54.4655889526315, +42.4222702581539, 100.4176533093758, 104.1710088738105, 92.5104732944213, +14.6755995818766, 9.6996071979867, 85.6997777622658, 3.9965850729479, +25.2352476237506, 100.9320210092384, 8.6477869193292, 73.8356721745039, +86.9067246722555, 68.6568402371634, 33.8265671291512, 25.6686369300208, +36.2206850816592, 0.2447338701434, 71.1099205944268, 22.0354761583896, +79.6037390602770, 36.5744798353754, 52.2022458557981, 65.8457264014733, +91.9009448717818, 102.9545211675365, 42.3841703135447, 37.4353559191503, +32.8188077960251, 103.6865306383402, 127.7041869162136, 68.3083345612084, +107.8717808033674, 75.2410781137837, 76.1041838881114, 103.8751957304194, +107.6396338248810, 122.5473803852440, 84.9406853117704, 33.8039616503771, +119.2571092207251, 4.8748813890269, 95.4794013348778, 93.5884722310996, +23.3414445628139, 78.1638338333759, 73.5317216857950, 1.3059684044244, +82.4873686816950, 59.5621296444731, 78.4085677035193, 16.6416422206171, +40.0461694784677, 34.0911076823674, 96.1366095394532, 2.6108135593174, +78.8291143546016, 3.9471143502496, 9.0456287902992, 10.5207797933932, +112.6250113773276, 111.6479222102314, 107.6336449885898, 8.7498156469082, +89.5417904674736, 92.4967921210904, 58.8890002644104, 55.7378288170965, +109.4181578072804, 69.1814242923546, 87.0441724467297, 15.8296855165761, +55.8295421860318, 100.6752669684008, 74.0563056813815, 54.5235737816075, +36.2296695877936, 79.1709868084504, 50.8391007421720, 19.5880273075719, +3.8584819454041, 118.7170382694886, 10.7331163933189, 1.2476683860867, +117.3905057261654, 43.9046514834765, 24.8081458922513, 106.8697259327721, +42.6035903294587, 68.2196200807670, 47.8517658337260, 33.8537746825506, +83.2232395798076, 27.2286016471817, 51.8675422313938, 27.4854107627112, +126.5862280123803, 44.7650300472812, 119.7253937682721, 110.7565424958042, +5.2931398774000, 108.0043857600560, 113.9464543396358, 78.7695661553971, +79.5907873285891, 61.1226821230364, 80.6796526688522, 60.0027599614126, +4.7664217971109, 115.8204569163828, 12.2936688718822, 3.5187533514196, +1.8965111979733, 8.6249037425150, 106.5374951262667, 23.0267852652011, +37.1994156414640, 119.2870169241387, 52.5295552259914, 3.3456409589134, +127.8667318224286, 79.8030059709228, 59.5066369453010, 100.3813210597175, +94.1307216128943, 83.0899714022362, 107.0316076181045, 111.3741791766948, +49.5265674225644, 92.7169496252746, 127.8550014495174, 98.7570013267719, +45.8042156313566, 54.8197073595690, 72.7213353257260, 113.8014557295486, +28.9197413459978, 125.3950029599457, 115.9423894826054, 25.4009879945782, +23.2628435600842, 33.6861631431087, 113.2154598167238, 0.2360582948830, +95.0985958422993, 25.1593547580574, 42.3110669452283, 91.7529548833859, +67.2219432309372, 4.2980114241587, 16.4463716821961, 94.8406221712197, +59.3271878041919, 67.0886749937612, 84.1010173950815, 75.9530086274971, +33.8896262207486, 25.4579093574816, 22.1786463363928, 63.1326249535813, +7.8351033962495, 83.4161937029176, 118.1748589827562, 22.0336477263056, +88.2971823030604, 53.6393190872107, 10.2359010028820, 62.8961943084822, +126.4143487803705, 117.2169236490582, 51.0343219875518, 126.1782904854875, +0.0027366280568, 21.6771922808500, 22.9030867921668, 36.2497818042756, +32.0547758490102, 95.1013325299608, 46.8365470985121, 65.2141537373951, +11.2359273486007, 99.2767190799474, 99.3993439541195, 63.2829187807082, +118.6329863027823, 70.5631151527926, 38.3653940737086, 55.5003613492010, +82.5776881960117, 24.5226125235309, 96.0210245698788, 60.5440404101014, +21.0920777419079, 90.4127915922612, 107.9388062264485, 86.1958834930304, +116.3529976552133, 109.3892600449683, 16.0521106198673, 118.1747072293305, +103.3362144712993, 114.7673463759792, 98.6061836940265, 67.0864326670237, +58.7234241639839, 103.3389510993562, 8.4445385972245, 121.5092704861934, +118.5640044764448, 90.7782000129941, 70.4402835697123, 55.2810856957366, +97.3399888730329, 1.7999318250455, 62.0549190929415, 41.8396275238319, +32.9643535171469, 87.9729751162105, 72.3630469778381, 100.4203131666502, +126.5799550407473, 115.5420417131586, 112.4955876397414, 40.3840714881122, +82.6091009763112, 19.6720327230506, 77.9548333054198, 92.4343938065853, +33.0933765327061, 70.9620985719199, 1.0612927680189, 94.0069439252871, +93.1767468886342, 8.4295909444008, 57.7294448882944, 99.6674764620454, +121.4550692408602, 23.9001709930134, 111.7685421033616, 66.1739835451236, +96.0484531373011, 112.0190737173050, 114.6783710060075, 54.2088256134693, +21.1536031463899, 65.3884419507293, 113.8190055423505, 48.7332900393444, +98.5661240083008, 54.1179567231415, 25.3614170669398, 58.1820524605839, +102.2913985132665, 97.1460789894434, 41.6599983766954, 9.8570046470766, +85.6217756074023, 56.9004994299731, 116.8181117124940, 119.6148316821153, +89.5468808829537, 118.7151521401085, 127.8625980614976, 117.8794044805129, +123.7660264353110, 54.7236277119832, 127.1447431441139, 57.5920428901874, +37.1221107417355, 117.2210956761712, 78.6237987049966, 110.9132851878709, +114.0354597503485, 5.1705638790366, 101.2401693338715, 65.3021697110041, +17.2412272175966, 7.1890628967383, 70.5590058297659, 87.0591748166174, +105.7774276033870, 115.8073512258974, 61.3070196198798, 95.9204228967058, +94.5818496786905, 80.0688260570489, 84.9534301557361, 102.9670179965752, +63.6509462891384, 52.2036252264882, 8.9693254274173, 73.7715418682301, +66.4239663791023, 25.1978271720921, 42.9187773069920, 8.8319234293103, +24.9768055197675, 62.1899927548086, 79.9214548840753, 42.0635203915013, +95.8474233000760, 62.0989163211076, 51.4110883713752, 30.5452535890719, +111.7104324622594, 81.8828829908198, 67.2694802001442, 24.6512576456420, +105.7489089266159, 0.9516596798560, 89.0719458875581, 9.8284859703055, +125.3459835040131, 83.5263364703983, 116.7590109057534, 22.3789654478333, +19.4839828701150, 91.9278331230990, 35.5951624678425, 73.7124410614895, +53.3964113841748, 83.1349291592533, 16.1314582899825, 44.5644878952599, +101.1137560480804, 119.8203777632771, 108.3327563313454, 59.0502355969745, +90.7994648044926, 126.0905615678479, 54.0103704584811, 60.2542112154207, +2.0727164754983, 58.6468880449640, 60.1894778293508, 105.4214588894609, +9.2874439998006, 113.7831489973623, 12.5297709761792, 127.4589580294951, +123.9806823711752, 115.0363529264165, 114.7348086772183, 101.6017169233420, +49.2062605252519, 121.3266658155837, 70.5626893372101, 103.4938195233670, +22.7223396407079, 68.6902433953668, 85.2544988790781, 106.1578518050526, +32.4361927660351, 76.1187510248827, 23.8251725546202, 101.3859571690606, +64.4121400417817, 5.5499487545108, 67.9391287285551, 4.1579288263609, +99.3709580764971, 27.2116047866696, 3.6405102627541, 121.9494992466408, +63.2889461216000, 101.4436745519953, 85.8584928316337, 63.8299881517095, +71.9899807311548, 72.5763901214005, 87.2268234897530, 98.3882638674175, +49.4554516307336, 67.9706630427254, 59.6127429882124, 73.9616321073666, +108.3332840708705, 98.6617121559855, 61.2973288583091, 2.1754322658179, +119.9377849064478, 3.0556237115784, 39.3519555513523, 18.5518276777825, +67.3350569323334, 24.3739776128782, 79.1743747364610, 63.1771281059725, +13.0630026520523, 3.7471969741151, 29.9239263673890, 19.1135034650161, +97.3944247818526, 112.4339607285494, 30.9588017607847, 33.5644366301431, +87.2055584598359, 32.6833709034526, 85.8776352209400, 116.8172946520230, +119.0660908180597, 31.1955391313860, 105.2597610248531, 45.1044587106930, +39.0479362788833, 40.5215423891887, 99.1662021741114, 36.8725040130655, +51.0153587102030, 19.3812203497538, 11.1832545451742, 32.4635309728158, +113.7123382024990, 42.9531435570461, 22.4368440613322, 50.5352100965265, +120.7247222628094, 53.0473950752278, 67.3271211699243, 101.6112187977932, +2.8154841078517, 5.7877248552571, 56.7945920493429, 97.2510475373133, +76.5706884621506, 100.2099089493090, 118.2216855838064, 87.7533938697322, +121.2037795154395, 35.7762468623818, 4.8932797931569, 76.0993208047465, +19.0255447714708, 112.2698702738946, 66.9717859937678, 110.1530408180100, +70.6015191406950, 58.0734811099588, 24.7914126630832, 38.1379881082745, +86.5098773047840, 121.6168778508980, 77.4547014597127, 35.9746672082574, +73.5027642592335, 72.2222154476783, 36.5700213483395, 99.8915455210449, +73.1481899959725, 66.2274865220429, 125.2696105229061, 103.8971425182638, +13.8175963823765, 75.9636741038243, 72.0152113772999, 54.0642025722490, +10.3362177062483, 90.3882848445271, 48.1735829935286, 62.2368969611064, +35.2199036046955, 3.5399971620832, 126.1645317069090, 53.0668627866855, +103.2743057493466, 54.2454483761664, 115.8098674359777, 65.1363176410721, +48.5759472477138, 45.8758248304370, 112.3189294861252, 12.6012800394563, +33.6651763476735, 7.0858244928931, 39.4927026217304, 61.7736308862332, +51.9598664287291, 107.1679406665116, 79.3080399405714, 76.0627239700699, +2.6418529761219, 125.1080564247016, 45.3954271289499, 76.5776504634775, +51.6475354077516, 16.4594493584984, 73.0717305285259, 117.4106385062498, +46.3121763087400, 61.9837531139998, 106.8477342030256, 121.2453135220545, +42.1485834317974, 81.5320799134355, 65.5237502760830, 105.0122658503299, +65.9348977515171, 17.4228891215394, 7.7775282299973, 53.3336177120607, +53.8700886023557, 114.5108450588355, 63.2987140115810, 120.0964577757271, +50.8541406033813, 87.5352650096339, 121.5966695517286, 102.7914166333114, +21.4823598961729, 102.8140070321104, 66.7032056165408, 72.9047094923000, +101.5092711921359, 24.1242128722948, 99.9220634568120, 112.0986327454907, +38.2391073881831, 25.1568065998875, 40.5836622307932, 44.9937939257332, +124.4436622245441, 84.5512836969231, 87.1405597138873, 19.4313963742142, +77.9979277020311, 38.5922455967368, 38.0833635507540, 24.6643099899703, +37.9573495564784, 15.9328253939435, 56.0151347182762, 45.8608918403559, +94.1052653631686, 91.8274381588341, 2.4436703931744, 119.3138487298572, +68.9450494372030, 16.9594059069452, 51.3627031088633, 124.0403400045076, +102.1645414112902, 90.4274093333759, 119.7734129390555, 118.0659087254041, +8.6892702023914, 75.6738126034261, 114.5516222056708, 91.6954763362629, +46.5666807510735, 46.9283776501791, 100.8306192033135, 27.1352843768593, +84.6354888475665, 43.0103429160129, 3.4796612874976, 59.9711788575962, +87.4239167382121, 34.6334164899930, 81.6025885127497, 41.5630248978562, +0.9315719012784, 125.3812662946904, 50.5662419435411, 9.6177231714212, +49.0502522816184, 95.0368372644469, 89.2087043939199, 53.0099123367155, +2.6373161685827, 117.9953017188214, 111.9962431713921, 12.5714075027832, +67.4651323871059, 104.8018576394775, 80.4227109925927, 103.7696560508430, +94.1096175155182, 76.1544025894973, 52.4756701832990, 66.9743331386588, +85.2774681846041, 12.6762982069870, 123.0827802396765, 25.3062893270079, +40.1254664250302, 41.9129570321706, 55.6866411229999, 126.5624415867787, +18.9069528071708, 127.5493831632423, 76.5463735221635, 9.2892295761449, +52.1225278024201, 19.8385247084492, 124.9306493983281, 127.1126154657046, +98.7107612354265, 101.1727800840385, 114.8753619728961, 86.1393537326433, +74.6412610759219, 101.3480774636139, 91.1680818028599, 98.8716050846836, +110.5651259341115, 14.1063934034232, 78.1499350434867, 43.5907927358480, +27.9318944941889, 76.6747433900250, 90.2607960525252, 2.6256051671810, +83.9060177597711, 113.2093626787930, 89.3510416566166, 85.3435762325970, +26.3269123557615, 124.0314841848013, 27.1223196513589, 17.0376827200119, +102.7813086392271, 45.2338651629323, 123.5808672884390, 103.6686932331271, +78.6508703598058, 26.9038363820425, 65.0723898713814, 120.5115166271625, +22.8193568097518, 49.3616315356277, 0.0766164660811, 51.9477517846728, +6.8354909451844, 97.4606178856737, 22.7097089396369, 91.2446982689410, +103.4852491503047, 117.4006168792958, 111.5670113487016, 100.8596439831237, +31.1713835146145, 3.4171435848890, 66.0753602693208, 73.8278073416221, +44.4640845863447, 115.0774013339902, 116.6265063232866, 27.4264018663328, +119.4175191481679, 70.7909969421062, 111.1088854591869, 15.7488259150408, +99.2012693151838, 94.1988277873950, 116.0248621050384, 106.6897527476259, +105.0450037014880, 49.8521396153849, 121.1026641694376, 53.0972519168152, +84.4239788448550, 127.8643605112398, 99.2137712106173, 121.1792806355186, +94.7831241333779, 91.2594698496440, 97.3249783969135, 121.9234801502542, +26.7197969680279, 70.2683732240779, 80.6600866693352, 80.8919896860104, +46.1618487453842, 57.8911804826423, 73.6855168685715, 18.7354468790514, +78.0608490472943, 90.6259333913335, 44.9685817570279, 62.3120231322535, +6.7672199042361, 69.4783681954622, 33.4169302738350, 28.0774672162148, +74.5390442956886, 105.9684892194199, 35.6771959232526, 21.4417923788735, +21.9591406686041, 51.5840479971767, 27.8206288348048, 28.7798600330855, +120.9578801360717, 106.3831195134591, 51.4484084488118, 127.0344000454221, +101.6653764721311, 87.7410042098449, 69.6425893034984, 20.7733867861207, +41.0381228518850, 0.3851733805543, 30.0093774339228, 22.3026759728336, +38.0069173751431, 87.1999716568738, 58.2763539228013, 103.6948943024943, +3.3224028364394, 116.0677664224374, 49.8259049886027, 103.2449356798292, +104.6846276413112, 10.0896227406755, 57.5461345582950, 83.2428352624377, +122.0031905742377, 51.2236719369999, 116.0581120197000, 93.2233304815475, +14.9131407807177, 15.9623311832372, 102.8077199341765, 15.8787407949002, +47.0295151691090, 7.8710208571847, 122.3454506966963, 26.2561283233837, +86.2907159730283, 20.6948915816354, 95.6120251266342, 63.9880400001947, +101.3162968034466, 127.3288388249133, 21.0800650217943, 125.6214025605570, +54.6013545648201, 11.3232141189851, 86.5288104221825, 79.3564189445956, +91.5975506732229, 57.9237574608641, 127.3909805414225, 8.3547153511805, +22.1604455216604, 68.2821782549294, 68.0133802015397, 56.9371150997175, +71.9502329565353, 16.1636360362934, 119.5058501919293, 56.0714921616351, +120.5696984494895, 86.8633737372530, 32.1259672195306, 94.3135700665012, +90.4594579164216, 39.5992135589939, 94.7343946540423, 26.4714179162269, +59.9678222220241, 48.7501738298452, 60.2941051406293, 62.3464197210718, +32.7305890474145, 33.2841189658661, 48.0790125951539, 81.3741701624236, +14.9625383685169, 87.3319436718393, 44.6073330848512, 6.6078230173363, +100.9354286663865, 106.5600890417397, 17.2557010730988, 43.9983135666690, +13.3405734362735, 123.0958742476515, 46.8422672966692, 85.2690812746385, +4.6616874954950, 85.2908063928088, 11.2595102243403, 38.3481174289939, +69.8568954197024, 125.2313859449846, 44.1541801300618, 43.3854775034755, +73.2349944455712, 32.3163532765193, 36.8305994443738, 10.8885747244994, +50.4988747474267, 5.2028166079907, 81.0665271063645, 97.1247045850031, +7.7533626592501, 83.2294637948412, 38.4869355738568, 1.1455396419137, +127.0925822253770, 22.7159010873716, 42.5614074070758, 83.0942686587080, +17.0861897548131, 100.0280108917635, 1.2759900695067, 59.8171084801746, +86.4663748547744, 30.4267631910866, 95.1238850798103, 48.1182573661759, +21.7688727480214, 91.1280623502694, 115.7175695838954, 106.3833953041506, +42.7603243788520, 91.6257681677238, 88.3594482356494, 31.8717496543525, +94.3147522054216, 115.9953188244232, 123.9421214442431, 125.1900476800231, +78.1541881925213, 16.8136268932436, 121.1981354324138, 77.0086484910029, +114.7793396053739, 85.9075508517714, 100.0430907476894, 31.6850709466660, +74.4216066349398, 113.8719218307510, 108.6234519391430, 14.6044980951606, +30.0176993748256, 91.5077963897529, 85.8999326629098, 109.8994420682543, +31.4072129276615, 116.4840742295999, 121.9345595808395, 53.0238176831155, +13.5238787594828, 53.1760857352876, 79.6121365202647, 109.6521291051303, +37.1616323167280, 56.2842031383348, 16.8018538434067, 39.9715846963094, +89.7526237786527, 3.4763845221495, 44.2795219627579, 12.7439752876498, +69.1627283418377, 39.9068119115694, 20.2900114153931, 37.4776573355671, +6.9376002582431, 55.9420678876071, 125.8143628229454, 120.3331021630825, +88.3372567111334, 81.3592068931829, 41.8139896587534, 106.4378147024837, +52.7377399451741, 118.3549561455636, 44.8670032233312, 127.7139223216632, +20.4536917900917, 84.1449529324402, 106.8390303155589, 38.8015627445660, +98.4227515321331, 33.9775705495745, 9.3210386081231, 58.4511668358236, +38.8668677391796, 7.5843838488610, 90.2617737475139, 26.1228924515298, +44.0189529862343, 0.6194915178323, 11.0607683710106, 6.5412956506672, +23.6838819494862, 113.1816813280721, 40.5263034294016, 31.3507797864037, +16.7784808952261, 30.6214822077292, 41.1237492156791, 38.3406661927424, +82.6516611960957, 105.1157376063595, 111.9806891009122, 82.9377388744325, +67.6492550092047, 7.3894010816651, 95.4706936923185, 28.8476922646387, +4.7608907840964, 88.1029467992964, 91.5343540141053, 74.3097240078774, +126.9782851333629, 103.1836423162295, 122.0805174084755, 100.8553926222284, +90.8835867470520, 37.8451528129378, 110.7680261650905, 84.3422910963848, +25.1795743225047, 6.9025396736816, 38.4646443307701, 121.8287945361011, +117.3316140125187, 48.8634562719909, 120.0842210613583, 78.9909478197763, +116.1457090918653, 6.1100948481402, 79.4849384797201, 33.2079702174328, +92.3133197856663, 70.7973702283564, 111.2258325141044, 63.4656275210276, +25.0062500950909, 31.9625747352664, 78.1867713696262, 78.6965261468182, +14.5765179463553, 29.7671408791873, 120.0655215345628, 41.7211253241269, +70.4883299202138, 13.5548030201135, 4.9507831954168, 114.1460388834337, +109.5476038966084, 33.3719166076611, 51.3999558330513, 115.7188093605073, +40.8555479835978, 6.7271781595085, 40.2744563409474, 89.8646002234261, +65.5666475601339, 30.1871619365118, 55.5906344314994, 32.3586773427011, +70.5412003726425, 53.7123565923946, 36.2972568442567, 7.0755728516148, +98.2196154455746, 34.8545200987042, 124.5097268803556, 19.5230892987564, +116.4176235145040, 123.2258656002702, 66.8170948339706, 74.6964981903771, +45.0286551923625, 2.9941414012546, 24.9930064198528, 58.8826163089288, +17.6625989757770, 115.5169851125763, 16.5489444213682, 29.9437896152697, +29.8135004778455, 127.2102028723854, 20.8889017202374, 67.9489003140241, +93.5220354038859, 70.6690484614433, 5.9373809722892, 61.1633580611848, +68.6035882554034, 31.0886829044152, 100.8562103979551, 61.5280154037885, +28.6765564813635, 11.1447885684412, 84.8010394968097, 9.1534671826071, +28.0072644483332, 126.8961719865427, 45.9993086671453, 81.3107663175607, +43.6990197504400, 16.4248879628372, 122.1220375272082, 112.8164035011159, +49.0588335623307, 88.7276749428025, 19.4190293640918, 19.1150438874564, +103.9168741590888, 66.7214325381077, 76.2446600553788, 35.9679738450646, +30.2969197771963, 5.7303745773297, 65.9316353508884, 97.1335617756162, +5.3970316673615, 123.8189551810822, 76.3994230387730, 71.8690163231776, +58.4091006193352, 74.0006199227649, 26.9076380258927, 49.2556333771235, +65.0194438402632, 87.0856571006988, 85.1454084912061, 111.7086775227025, +115.9611205998627, 93.0267082885963, 85.9818290276368, 3.1447170987468, +99.2189104423015, 31.6601402906981, 109.4515962514335, 80.1038664952404, +36.8385994605900, 20.2777439450276, 120.3878152931052, 0.8706256155254, +37.7660370048909, 12.7554735600741, 86.9991764831353, 68.6324752888793, +96.7998280975967, 68.0629567820872, 18.4858481374038, 24.9308117744191, +16.1409044936955, 102.1968597649582, 63.8819119035648, 94.8852711761767, +74.4982273925553, 74.5500051130308, 48.1974796281184, 90.7895499294575, +8.4876051584667, 11.5176711732138, 33.6356622137295, 5.3428880597199, +71.7213577366068, 124.4487257583294, 104.5443795214148, 119.6174912413664, +86.8666013287691, 42.9402681193036, 28.1088659894228, 85.9959757132437, +89.1291565118028, 123.7052007893590, 63.2180120643312, 20.4966812229234, +47.1480002622809, 126.8951935166936, 8.4606742898285, 22.2171884878619, +121.8317936034090, 15.9478283002730, 66.9581502391762, 26.9465224272322, +93.6296120125938, 9.9726980971045, 118.1446880652312, 2.8400620831363, +43.6850556934648, 40.1278394051491, 84.5227032101353, 38.3421676337450, +109.7758566652312, 52.1726608519315, 51.6455105783630, 118.1583654238649, +114.1858658130215, 53.4972143422334, 48.6213865506562, 28.1898900401731, +97.2269338226071, 73.0524670821859, 96.4374824615370, 76.7302525400791, +53.8726829541254, 58.3560902748052, 68.7576678715449, 31.6554944662636, +104.1648646482103, 101.0206832164064, 57.2512837914989, 77.2183421613734, +127.0494961734160, 97.9966581920146, 116.9685115166793, 124.2094340306751, +17.4553670964462, 92.6791081264052, 107.9693562891192, 107.1131995223058, +54.6504248635147, 61.1404227899110, 4.8069474719497, 64.4920594992545, +84.6423481500905, 36.4262814691413, 113.3130836418425, 56.4524581099173, +110.6647226729732, 70.8282139035073, 89.9234958113746, 33.9344701328941, +90.0164726795705, 79.8916564359756, 15.8806809856932, 58.3609782133070, +33.8566909590069, 15.8891555740913, 10.2477467107809, 84.6383488572381, +63.7084644733502, 10.0215555476125, 116.9098387904977, 67.4990305022798, +84.9915497102735, 62.7579605871616, 108.0182137992318, 105.8783502475723, +24.4796294683961, 102.4469168067197, 27.4370687135668, 87.9875700287463, +88.6964742954338, 79.1300543915155, 35.5873395370261, 32.2440161855165, +54.8348932521580, 45.3388224455243, 115.5563358606567, 20.9004231192639, +7.8408098257337, 37.4996159251312, 116.1670363490316, 77.4798316720314, +88.6860661323583, 97.8572825649089, 117.3912723611068, 4.0477172751202, +67.1380495145629, 122.5427571509698, 113.7464381390002, 127.6390190718877, +80.5346271174655, 2.8465139879130, 4.5643126389777, 102.6562769294978, +72.5700964669558, 37.5261768277391, 65.6044745750746, 112.5825264382095, +125.2855595337625, 97.0497259353519, 11.9730935748541, 93.0415432886414, +68.4608562907487, 85.9820337695917, 48.1797802672627, 47.5604331714848, +113.2159477999508, 123.2957496025114, 3.3208561555114, 35.7361161279195, +123.5356098392678, 121.0567576256845, 32.7953654680380, 119.4878925641477, +21.8256568414279, 84.2216759716262, 90.9140401309887, 22.1866377695401, +51.3167551398821, 88.9637063559907, 78.7644330629913, 76.6604782699889, +67.9112721401785, 3.8513821977430, 91.8102203439037, 83.3287457019690, +122.4562382076197, 12.4813685475296, 41.3775590254821, 29.4146949189784, +100.9110858314257, 119.7417976817776, 109.5310944828815, 53.3506526599408, +65.4469908780637, 41.3719420625698, 77.7238314513694, 29.7108747501443, +72.5325801114238, 50.6629386184099, 36.6676916054765, 81.0446876068808, +91.6496949026592, 68.0681899506916, 43.7196961844897, 69.4630570735145, +83.2942145854673, 113.4753517440871, 24.2898658627131, 6.6337363154784, +58.3830445680688, 6.6109696657448, 74.4390580404732, 103.0542989257045, +67.6639733033553, 126.2943167082473, 10.4623518634878, 38.2492783843769, +105.1905636085153, 62.1202114513704, 10.7756851961723, 51.8399109485745, +22.0176544291981, 78.1016493803364, 53.8620091331480, 120.3067797386585, +84.6305281317935, 87.4646453072618, 119.4735914429061, 3.5858405249127, +97.6043401218971, 29.1631082432173, 10.1275838660670, 28.1412830483826, +60.4810163660352, 61.2540349649517, 97.2312981939089, 53.8472800505568, +96.5754629227219, 15.7752308918979, 46.7293866494342, 121.5211640566220, +31.4177230742843, 26.9585074311860, 22.3862005576427, 121.1684447495120, +84.6884634293096, 99.0816963776395, 25.2528241394334, 32.8485524807351, +28.3352890146595, 61.8790269782203, 33.2019077694052, 36.0285093356057, +90.6497574274660, 50.3529434438576, 11.9806762989520, 87.0639169025532, +31.5955507306361, 47.2802855592595, 9.8175886915147, 3.4542676822535, +73.7924526677432, 1.1998908525332, 76.4433938024768, 19.9451725575818, +39.1958559337984, 6.2734689741738, 62.4539258174849, 45.6746919367810, +102.3517572164311, 7.7713187969156, 22.0486999256763, 109.1833125265237, +77.2834529640542, 5.7694802311107, 34.7298262281017, 44.4349004833190, +96.0111597627453, 33.9719163337592, 104.8511766087502, 59.9826503675350, +97.1170012807087, 124.3464487774048, 95.8509433119795, 10.0530843185508, +111.2858873527897, 59.7667586485700, 46.6993922212624, 107.8316196109316, +76.4621535299635, 14.8814380238212, 107.0470442078295, 56.5169809127771, +101.1651298874827, 22.2546061381021, 16.0813288763544, 55.4904379507017, +59.7185672203631, 12.3609857616764, 28.5280751122758, 78.5352547534440, +95.0116755808758, 34.0703243771895, 20.1323045585921, 50.5767750379521, +114.8447812138334, 44.2951284853253, 39.8398046083002, 54.8621308462984, +26.7440654759966, 82.8559409169741, 78.2670448786891, 16.6909811574458, +25.9496077419955, 123.8610667567053, 79.2023896943789, 46.1179881310640, +54.4187627688138, 9.2354950351806, 55.6278254052754, 125.9017819156413, +90.1653075638066, 2.8809162391726, 24.1169330590018, 34.6748695535003, +118.7335167484048, 63.3304373916846, 25.1355223772747, 40.1982619949608, +104.2403725871073, 50.4520839091633, 75.6914232129657, 53.6635975491552, +22.6858585582515, 71.2520481083784, 84.5224082863528, 95.8237277715577, +13.0531939924942, 9.5306397720848, 115.5471766533084, 124.3622128946531, +111.9322096034569, 39.7972594684908, 92.3865806890589, 65.8142214723929, +41.4907521798698, 9.8818172858478, 35.6583262251962, 43.5889703238332, +125.9610211839718, 95.9095150082882, 19.1173123210284, 91.2861516304715, +83.4325074345956, 88.1263286881737, 98.7904312474609, 43.2342454396348, +49.5895511738907, 74.1660241233958, 23.4567660798583, 123.9259536843402, +66.9719170047771, 25.8299237013934, 124.6181080325591, 99.1481892928240, +77.5027290943557, 89.6577756226332, 97.0819718693765, 81.1405162593073, +22.4433698758685, 90.5559230868499, 99.1884153947180, 84.6291484630802, +107.1639664076101, 6.3755794197207, 2.3531824957361, 63.5749960241723, +1.2976602917992, 20.6547185278752, 16.2573967651731, 38.0115087209323, +78.6089545258363, 127.2586815353756, 116.5642335361635, 35.3747090862015, +83.2806184083599, 34.0414619008272, 87.3850101639447, 87.3546647836243, +81.9899654770223, 4.8701695226460, 108.2074860242230, 110.8417762438030, +57.9661101968801, 20.9618824817994, 30.7000932240393, 104.8255939971775, +84.4112134968914, 7.4688392316312, 110.6196581044326, 127.7820650934158, +17.3830694041136, 106.8545833727599, 98.0247623184811, 81.8080734395460, +10.3894535351496, 124.5470358117237, 113.2301628520853, 100.3779448738219, +36.8622686438552, 11.6871138865534, 17.2017543395989, 1.4875595576538, +93.1206525997821, 115.4712232292961, 10.9457953623244, 5.7659878161577, +81.1725817700720, 48.4012709485373, 21.5126850705187, 98.3308055262690, +106.5457650919192, 35.1625471874897, 53.2714404711832, 1.7201710947418, +83.7535987886384, 36.5118752887993, 56.1244296692891, 83.9715337548272, +120.5521611536630, 40.1648122855298, 43.9807145204305, 38.7440877141171, +114.3834217127335, 9.9352305577766, 19.0193955986851, 14.0054768389116, +5.7371179488195, 124.7728752478831, 6.4822663098957, 4.2495583911657, +29.4500085252570, 42.5993866522794, 8.4599890748318, 23.6840206494946, +117.7365900230299, 122.5706611250391, 30.0706098219709, 19.4057844371562, +53.3034659872313, 70.9091717334973, 42.9719320735763, 51.5832948924896, +52.2149062399822, 31.8492310791506, 106.0717189209870, 96.2433725447596, +72.9402363043932, 7.9685050286206, 68.3611063679499, 34.1961485902761, +126.3472977272921, 65.4923974580562, 48.1333173141504, 112.3418208883804, +71.4022713636059, 112.7307193804210, 75.4276280158328, 67.1527129128355, +105.5939150348277, 77.1393893124254, 109.5035946283041, 81.9098943257285, +9.3693681402921, 7.0439235004801, 119.7387759647047, 117.9635837031359, +73.3926806791651, 127.1059581633219, 1.6145845659145, 21.8093857270709, +12.8298891842504, 126.6961466663965, 70.0151298372145, 44.5865166394909, +82.2829972888729, 65.0447954242326, 30.5453776859424, 48.0868486985969, +83.2483049422727, 27.2232335932661, 73.0133004528532, 98.9064840538923, +60.2993306798392, 81.5956026099602, 92.7156310513223, 121.1466177670036, +122.0531533332789, 3.7016019838404, 66.3263219903811, 40.1432590075504, +37.7935002026118, 99.6470683085020, 80.8409912962657, 47.8299165590806, +94.3891529880414, 47.1628683429038, 106.6909918089821, 72.5797672609704, +24.8920930143875, 39.7818336076019, 46.2688264466211, 108.3055764345012, +36.3708049824325, 37.7219821986379, 38.4779802739983, 116.2839562838357, +39.9298420138330, 118.6538022713055, 102.7667776824752, 69.0233579599407, +40.9266958427274, 123.1781469561058, 17.8770358049669, 47.7800780757238, +22.7359258042350, 101.2260265225666, 76.7737495064613, 110.5926668562892, +62.9299879963184, 16.7890791375139, 104.9276285064070, 15.1000714372378, +2.3483869444339, 100.7234882585348, 116.4361474460159, 57.7686197430681, +75.4327156298946, 96.7375399920799, 19.8863565418340, 95.1271392549980, +54.4391392722908, 100.3248086442821, 8.5193735400771, 66.1551830480598, +116.0207118336208, 90.8099442547233, 10.0467908429200, 46.9973538140754, +32.5936465415143, 27.9505537878492, 81.4637465260288, 112.8135685253952, +81.9334491872850, 73.5203423842417, 23.1287006843503, 99.3407823309958, +115.0025216876541, 104.6693749915200, 46.7463688472036, 99.9024501908116, +81.4426170966786, 49.9325096243678, 121.4584541290339, 23.6739972940059, +77.0217407704432, 83.7910040411125, 22.6559978232980, 109.8946015750498, +108.6975374727964, 24.4544563407332, 52.5285439735877, 42.5423544247366, +108.0452713873448, 35.1366766854826, 124.7792649850153, 61.0479175732694, +119.6396242937258, 96.0659831613609, 125.9466209998106, 6.8260557683306, +50.7511497376259, 24.2332708352400, 124.0165369492101, 79.4103674662348, +119.0476878243721, 4.6845988653063, 97.7536132194817, 19.1452375739558, +40.1739793606913, 106.0502094524215, 109.3539739164309, 16.4999820666853, +84.7070295013054, 121.6165964573699, 27.9827190171847, 102.8124279858602, +93.1810713248239, 33.7287702121440, 77.4076004984824, 50.6387169000873, +62.9840619857349, 73.8786087380157, 58.1832265528772, 1.9361444124655, +61.7885473062231, 43.0293333730797, 109.0152854234983, 54.9624915378925, +58.3722737703343, 53.4281715999489, 11.0953164748360, 106.9619063637042, +26.2570909980019, 109.1234235675649, 77.6614424351889, 7.1118534240461, +63.9150376617513, 17.3047787627693, 113.8080224328712, 47.4150555950660, +69.9744242755577, 104.0890170820472, 123.3549882151908, 95.1619962896975, +73.9764241324628, 26.6814537172585, 97.7056134798125, 23.3377072323755, +49.0493583907603, 39.1574953976821, 60.4102239890072, 47.1132139186902, +45.5559420201722, 112.0334203764952, 113.0361041356978, 118.5934505418844, +73.0132958632956, 107.3444893860000, 27.0627536899702, 94.0513894995914, +45.2699236484570, 3.3855695740253, 32.7726609263442, 38.1580702244109, +29.8491588969944, 71.5270146464589, 112.5089931415902, 110.4341033615331, +65.4790118045541, 93.7641966183503, 88.8317934688329, 98.3170155744613, +107.5244888567945, 7.4534360205072, 69.8532136407929, 84.1867816244190, +86.6720410392955, 53.5009129296527, 34.1348897973704, 39.5588270610007, +85.1385642686573, 7.7213993704512, 92.6584083273348, 94.5451137863775, +43.7459019030192, 2.6945062888295, 119.7548197469464, 77.6945124034279, +56.9756436613275, 116.7591977663148, 110.0389956748295, 18.8175734369166, +}; + diff --git a/babl/babl-sampling.c b/babl/babl-sampling.c new file mode 100644 index 0000000..e671078 --- /dev/null +++ b/babl/babl-sampling.c @@ -0,0 +1,81 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#define HORIZONTAL_MIN 1 +#define HORIZONTAL_MAX 4 +#define VERTICAL_MIN 1 +#define VERTICAL_MAX 4 + +#include "config.h" +#include "babl-internal.h" + +static BablSampling sampling_db[(HORIZONTAL_MAX - HORIZONTAL_MIN + 1) * + (VERTICAL_MAX - VERTICAL_MIN + 1)]; + +const Babl * +babl_sampling (int horizontal, + int vertical) +{ + if (vertical >= 1 && + vertical <= 4 && + horizontal >= 1 && + horizontal <= 4) + return (Babl *) &sampling_db [ (vertical - 1) * 4 + (horizontal - 1)]; + else + babl_log ("babl_samping(%i,%i): arguments out of bounds", + horizontal, vertical); + return NULL; +} + +void +babl_sampling_class_for_each (BablEachFunction each_fun, + void *user_data) +{ + int horizontal; + int vertical; + + for (horizontal = HORIZONTAL_MIN; horizontal <= HORIZONTAL_MAX; horizontal++) + for (vertical = VERTICAL_MIN; vertical <= VERTICAL_MAX; vertical++) + { + int index = (vertical - VERTICAL_MIN) * VERTICAL_MAX + (horizontal - HORIZONTAL_MIN); + if (each_fun (BABL (&sampling_db[index]), user_data)) + return; + } +} + +void +babl_sampling_class_init (void) +{ + int horizontal; + int vertical; + + for (horizontal = HORIZONTAL_MIN; horizontal <= HORIZONTAL_MAX; horizontal++) + for (vertical = VERTICAL_MIN; vertical <= VERTICAL_MAX; vertical++) + { + int index = (vertical - VERTICAL_MIN) * VERTICAL_MAX + (horizontal - HORIZONTAL_MIN); + sampling_db[index].instance.class_type = BABL_SAMPLING; + sampling_db[index].instance.id = 0; + sampling_db[index].horizontal = horizontal; + sampling_db[index].vertical = vertical; + sampling_db[index].instance.name = sampling_db[index].name; + sampling_db[index].name[0] = '0' + horizontal; + sampling_db[index].name[1] = ':'; + sampling_db[index].name[2] = '0' + vertical; + sampling_db[index].name[3] = '\0'; + } +} diff --git a/babl/babl-sampling.h b/babl/babl-sampling.h new file mode 100644 index 0000000..e3aa7ed --- /dev/null +++ b/babl/babl-sampling.h @@ -0,0 +1,35 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005-2008, Øyvind Kolås and others. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#ifndef _BABL_SAMPLING_H +#define _BABL_SAMPLING_H + +BABL_CLASS_DECLARE (sampling); + +typedef struct +{ + BablInstance instance; + int horizontal; + int vertical; + char name[4]; +} BablSampling; + +void +babl_sampling_class_init (void); + +#endif diff --git a/babl/babl-sanity.c b/babl/babl-sanity.c new file mode 100644 index 0000000..3cfce14 --- /dev/null +++ b/babl/babl-sanity.c @@ -0,0 +1,144 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include "babl-internal.h" + +static int OK; + +static int +foo (Babl *babl, + void *user_data) +{ +/* babl_log ("%s", babl->instance.name);*/ + return 0; +} + +static Babl * +babl_conversion_destination (Babl *babl); + +static int +type_sanity (Babl *babl, + void *user_data) +{ + /* ensure that every type has reference conversions to + * and from double */ + int ok, i; + BablList *list; + + ok = 0; + list = babl->type.from_list; + if (list) + { + for (i = 0; i < babl_list_size (list); i++) + { + if (babl_conversion_destination ((Babl *) list->items[i]) == babl_type_from_id (BABL_DOUBLE)) + { + ok = 1; + break; + } + } + } + if (!ok) + { + OK = 0; + babl_log ("lack of sanity! type '%s' has no conversion to double", + babl->instance.name); + } + + return 0; +} + + +static int +model_sanity (Babl *babl, + void *user_data) +{ + /* ensure that every type has reference conversions to + * and from RGBA / cmykA */ + int ok, i; + BablList *list; + + ok = 0; + list = babl->model.from_list; + if (list) + { + for (i = 0; i < babl_list_size (list); i++) + { + if (babl_conversion_destination ((Babl *) list->items[i]) == babl_model_from_id (BABL_RGBA) || + babl_conversion_destination ((Babl *) list->items[i]) == babl_model ("cmykA")) + { + ok = 1; + break; + } + } + } + + if (ok == 0 && babl == babl_model ("cmykA")) + ok = 1; + + if (!ok) + { + OK = 0; + babl_log ("lack of sanity! model '%s' has no conversion to 'RGBA' or 'cmykA'", + babl->instance.name); + } + + return 0; +} + +static int +id_sanity (Babl *babl, + void *user_data) +{ + if (0 && 0 == babl->instance.id && + babl->instance.creator && + !strcmp (BABL (babl->instance.creator)->instance.name, "BablBase")) + { + OK = 0; + babl_log ("%s\t'%s' has id==0", + babl_class_name (babl->class_type), babl->instance.name); + } + return 0; +} + +int +babl_sanity (void) +{ + OK=1; + + babl_type_class_for_each (id_sanity, NULL); + babl_component_class_for_each (id_sanity, NULL); + babl_model_class_for_each (id_sanity, NULL); + babl_format_class_for_each (id_sanity, NULL); + + babl_type_class_for_each (type_sanity, NULL); + babl_sampling_class_for_each (foo, NULL); + babl_component_class_for_each (foo, NULL); + babl_model_class_for_each (model_sanity, NULL); + babl_format_class_for_each (foo, NULL); + babl_conversion_class_for_each (foo, NULL); + + return OK; +} + +static Babl * +babl_conversion_destination (Babl *babl) +{ + return (Babl *)babl->conversion.destination; +} diff --git a/babl/babl-space.c b/babl/babl-space.c new file mode 100644 index 0000000..c662629 --- /dev/null +++ b/babl/babl-space.c @@ -0,0 +1,1456 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2017 Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#define MAX_SPACES 100 + +#include "config.h" +#include "babl-internal.h" +#include "base/util.h" +#include "babl-trc.h" + +static BablSpace space_db[MAX_SPACES]; + +static void babl_chromatic_adaptation_matrix (const double *whitepoint, + const double *target_whitepoint, + double *chad_matrix) +{ + double bradford[9]={ 0.8951000, 0.2664000, -0.1614000, + -0.7502000, 1.7135000, 0.0367000, + 0.0389000, -0.0685000, 1.0296000}; + double bradford_inv[9]={0.9869929,-0.1470543, 0.1599627, + 0.4323053, 0.5183603, 0.0492912, + -0.0085287, 0.0400428, 0.9684867}; + + double vec_a[3]; + double vec_b[3]; + + babl_matrix_mul_vector (bradford, whitepoint, vec_a); + babl_matrix_mul_vector (bradford, target_whitepoint, vec_b); + + memset (chad_matrix, 0, sizeof (double) * 9); + + chad_matrix[0] = vec_b[0] / vec_a[0]; + chad_matrix[4] = vec_b[1] / vec_a[1]; + chad_matrix[8] = vec_b[2] / vec_a[2]; + + babl_matrix_mul_matrix (bradford_inv, chad_matrix, chad_matrix); + babl_matrix_mul_matrix (chad_matrix, bradford, chad_matrix); +} + +#define LAB_EPSILON (216.0f / 24389.0f) +#define LAB_KAPPA (24389.0f / 27.0f) + +#if 1 +#define D50_WHITE_REF_X 0.964202880f +#define D50_WHITE_REF_Y 1.000000000f +#define D50_WHITE_REF_Z 0.824905400f +#else +#define D50_WHITE_REF_X 0.964200000f +#define D50_WHITE_REF_Y 1.000000000f +#define D50_WHITE_REF_Z 0.824900000f +#endif + +static inline void +XYZ_to_LAB (double X, + double Y, + double Z, + double *to_L, + double *to_a, + double *to_b) +{ + double f_x, f_y, f_z; + + double x_r = X / D50_WHITE_REF_X; + double y_r = Y / D50_WHITE_REF_Y; + double z_r = Z / D50_WHITE_REF_Z; + + if (x_r > LAB_EPSILON) f_x = pow(x_r, 1.0 / 3.0); + else ( f_x = ((LAB_KAPPA * x_r) + 16) / 116.0 ); + + if (y_r > LAB_EPSILON) f_y = pow(y_r, 1.0 / 3.0); + else ( f_y = ((LAB_KAPPA * y_r) + 16) / 116.0 ); + + if (z_r > LAB_EPSILON) f_z = pow(z_r, 1.0 / 3.0); + else ( f_z = ((LAB_KAPPA * z_r) + 16) / 116.0 ); + + *to_L = (116.0 * f_y) - 16.0; + *to_a = 500.0 * (f_x - f_y); + *to_b = 200.0 * (f_y - f_z); +} + +/* round all values to s15f16 precision and brute-force + * jitter +/- 1 all entries for best uniform gray axis - this + * also optimizes the accuracy of the matrix for floating point + * computations. + * + * the inverse matrix should be equalized against the original + * matrix looking for the bit-exact inverse of this integer-solution. + * + */ +static void +babl_matrix_equalize (double *in_mat) +{ + double mat[9]; + int j[9]; + int best_j[9]; + double in[12] = {1.0, 1.0, 1.0, // white + 0.0, 0.0, 0.0, // black + 0.5, 0.5, 0.5, // gray + 0.33, 0.33, 0.33}; // grey + double out[12] = {}; + double lab[12] = {}; + double best_error = 1000000.0; + int i; + + for (i = 0; i < 9; i++) + best_j[i] = 0; + + for (j[0] = -1; j[0] <= 1; j[0]++) + for (j[1] = -1; j[1] <= 1; j[1]++) + for (j[2] = -1; j[2] <= 1; j[2]++) + for (j[3] = -1; j[3] <= 1; j[3]++) + for (j[4] = -1; j[4] <= 1; j[4]++) + for (j[5] = -1; j[5] <= 1; j[5]++) + for (j[6] = -1; j[6] <= 1; j[6]++) + for (j[7] = -1; j[7] <= 1; j[7]++) + for (j[8] = -1; j[8] <= 1; j[8]++) + { + double error = 0; + + for (i = 0; i < 9; i++) + { + int32_t val = in_mat[i] * 65536.0 + 0.5f; + mat[i] = val / 65536.0 + j[i] / 65536.0; + } + for (i = 0; i < 4; i++) + { + babl_matrix_mul_vector (mat, &in[i*3], &out[i*3]); + } + for (i = 0; i < 4; i++) + { + XYZ_to_LAB (out[i*3+0], out[i*3+1], out[i*3+2], + &lab[i*3+0], &lab[i*3+1], &lab[i*3+2]); + } +#define square(a) ((a)*(a)) + error += square (lab[0*3+0]-100.0f); // L white = 100.0 + error += square (lab[1*3+0]-0.0f); // L black = 0.0 + + for (i = 0; i < 4; i++) + { + error += square (lab[i*3+1]); // a = 0.0 + error += square (lab[i*3+2]); // b = 0.0 + } +#undef square + if (error <= best_error) + { + best_error = error; + memcpy (&best_j[0], &j[0], sizeof (best_j)); + } + } + for (i = 0; i < 9; i++) + { + int32_t val = in_mat[i] * 65536.0 + 0.5f; + in_mat[i] = val / 65536.0 + best_j[i] / 65536.0; + } +} + +static void +babl_space_compute_matrices (BablSpace *space, + BablSpaceFlags equalize_matrix) +{ +#define _ space-> + /* transform spaces xy(Y) specified data to XYZ */ + double red_XYZ[3] = { _ xr / _ yr, 1.0, ( 1.0 - _ xr - _ yr) / _ yr}; + double green_XYZ[3] = { _ xg / _ yg, 1.0, ( 1.0 - _ xg - _ yg) / _ yg}; + double blue_XYZ[3] = { _ xb / _ yb, 1.0, ( 1.0 - _ xb - _ yb) / _ yb}; + double whitepoint_XYZ[3] = { _ xw / _ yw, 1.0, ( 1.0 - _ xw - _ yw) / _ yw}; + double D50_XYZ[3] = {0.96420288, 1.0, 0.82490540}; +#undef _ + + double mat[9] = {red_XYZ[0], green_XYZ[0], blue_XYZ[0], + red_XYZ[1], green_XYZ[1], blue_XYZ[1], + red_XYZ[2], green_XYZ[2], blue_XYZ[2]}; + double inv_mat[9]; + double S[3]; + double chad[9]; + + babl_matrix_invert (mat, inv_mat); + babl_matrix_mul_vector (inv_mat, whitepoint_XYZ, S); + + mat[0] *= S[0]; mat[1] *= S[1]; mat[2] *= S[2]; + mat[3] *= S[0]; mat[4] *= S[1]; mat[5] *= S[2]; + mat[6] *= S[0]; mat[7] *= S[1]; mat[8] *= S[2]; + + babl_chromatic_adaptation_matrix (whitepoint_XYZ, D50_XYZ, chad); + + babl_matrix_mul_matrix (chad, mat, mat); + + if (equalize_matrix) + babl_matrix_equalize (mat); + + memcpy (space->RGBtoXYZ, mat, sizeof (mat)); + + babl_matrix_invert (mat, inv_mat); + + memcpy (space->XYZtoRGB, inv_mat, sizeof (mat)); + + babl_matrix_to_float (space->RGBtoXYZ, space->RGBtoXYZf); + babl_matrix_to_float (space->XYZtoRGB, space->XYZtoRGBf); +} + +const Babl * +babl_space (const char *name) +{ + int i; + for (i = 0; space_db[i].instance.class_type; i++) + if (!strcmp (space_db[i].instance.name, name)) + return (Babl*)&space_db[i]; + return NULL; +} + +Babl * +_babl_space_for_lcms (const char *icc_data, + int icc_length) +{ + int i=0; + BablSpace space = {0,}; + + + for (i = 0; space_db[i].instance.class_type; i++) + { + if (space_db[i].icc_length == + icc_length && + (memcmp (space_db[i].icc_profile, icc_data, icc_length) == 0)) + { + return (void*)&space_db[i]; + } + } + + memset (&space, 0, sizeof(space)); + space.instance.class_type = BABL_SPACE; + space.instance.id = 0; + space.icc_type = BablICCTypeCMYK; + + if (i >= MAX_SPACES-1) + { + babl_log ("too many BablSpaces"); + return NULL; + } + + /* initialize it with copy of srgb content */ + { + const BablSpace *srgb = &babl_space("sRGB")->space; + memcpy (&space.xw, + &srgb->xw, +((char*)&srgb->icc_profile - +(char*)&srgb->xw)); + } + + space_db[i]=space; + space_db[i].instance.name = space_db[i].name; + snprintf (space_db[i].name, sizeof (space_db[i].name), "space-lcms-%i", i); + + + return (Babl*)&space_db[i]; +} + +const Babl * +babl_space_from_rgbxyz_matrix (const char *name, + double wx, double wy, double wz, + double rx, double gx, double bx, + double ry, double gy, double by, + double rz, double gz, double bz, + const Babl *trc_red, + const Babl *trc_green, + const Babl *trc_blue) +{ + int i=0; + BablSpace space = {0,}; + space.instance.class_type = BABL_SPACE; + space.instance.id = 0; + /* transplant matrixes */ + + space.RGBtoXYZ[0] = rx; + space.RGBtoXYZ[1] = gx; + space.RGBtoXYZ[2] = bx; + space.RGBtoXYZ[3] = ry; + space.RGBtoXYZ[4] = gy; + space.RGBtoXYZ[5] = by; + space.RGBtoXYZ[6] = rz; + space.RGBtoXYZ[7] = gz; + space.RGBtoXYZ[8] = bz; + space.icc_type = BablICCTypeRGB; + + babl_matrix_invert (space.RGBtoXYZ, space.XYZtoRGB); + + babl_matrix_to_float (space.RGBtoXYZ, space.RGBtoXYZf); + babl_matrix_to_float (space.XYZtoRGB, space.XYZtoRGBf); + + /* recover chromaticities from matrix */ + { + double red[3]={1.,.0,.0}; + double xyz[3]={1.,.0,.0}; + _babl_space_to_xyz ((Babl*)&space, &red[0], &xyz[0]); + space.xr = xyz[0] / (xyz[0] + xyz[1] + xyz[2]); + space.yr = xyz[1] / (xyz[0] + xyz[1] + xyz[2]); + } + { + double green[3]={0.,1.0,.0}; + double xyz[3]={0.,1.0,.0}; + _babl_space_to_xyz ((Babl*)&space, &green[0], &xyz[0]); + space.xg = xyz[0] / (xyz[0] + xyz[1] + xyz[2]); + space.yg = xyz[1] / (xyz[0] + xyz[1] + xyz[2]); + } + { + double blue[3]={0.,.0,1.0}; + double xyz[3]={0.,1.0,.0}; + _babl_space_to_xyz ((Babl*)&space, &blue[0], &xyz[0]); + space.xb = xyz[0] / (xyz[0] + xyz[1] + xyz[2]); + space.yb = xyz[1] / (xyz[0] + xyz[1] + xyz[2]); + } + space.xw = wx / (wx+wy+wz); + space.yw = wy / (wx+wy+wz); + + space.whitepoint[0] = wx; + space.whitepoint[1] = wy; + space.whitepoint[2] = wz; + + space.trc[0] = trc_red; + space.trc[1] = trc_green?trc_green:trc_red; + space.trc[2] = trc_blue?trc_blue:trc_red; + + for (i = 0; space_db[i].instance.class_type; i++) + { + int offset = ((char*)&space_db[i].xr) - (char*)(&space_db[i]); + int size = ((char*)&space_db[i].trc) + sizeof(space_db[i].trc) - ((char*)&space_db[i].xr); + + if (memcmp ((char*)(&space_db[i]) + offset, ((char*)&space) + offset, size)==0) + { + return (void*)&space_db[i]; + } + } + if (i >= MAX_SPACES-1) + { + babl_log ("too many BablSpaces"); + return NULL; + } + + space_db[i]=space; + space_db[i].instance.name = space_db[i].name; + if (name) + snprintf (space_db[i].name, sizeof (space_db[i].name), "%s", name); + else + /* XXX: this can get longer than 256bytes ! */ + snprintf (space_db[i].name, sizeof (space_db[i].name), + "space-%.4f,%.4f_%.4f,%.4f_%.4f,%.4f_%.4f,%.4f_%s,%s,%s", + wx,wy,rx,ry,bx,by,gx,gy,babl_get_name (space.trc[0]), + babl_get_name(space.trc[1]), babl_get_name(space.trc[2])); + + babl_space_get_icc ((Babl*)&space_db[i], NULL); + return (Babl*)&space_db[i]; +} + +const Babl * +babl_space_from_chromaticities (const char *name, + double wx, double wy, + double rx, double ry, + double gx, double gy, + double bx, double by, + const Babl *trc_red, + const Babl *trc_green, + const Babl *trc_blue, + BablSpaceFlags flags) +{ + int i=0; + BablSpace space = {0,}; + space.instance.class_type = BABL_SPACE; + space.instance.id = 0; + + space.xr = rx; + space.yr = ry; + space.xg = gx; + space.yg = gy; + space.xb = bx; + space.yb = by; + space.xw = wx; + space.yw = wy; + space.trc[0] = trc_red; + space.trc[1] = trc_green?trc_green:trc_red; + space.trc[2] = trc_blue?trc_blue:trc_red; + + space.whitepoint[0] = wx / wy; + space.whitepoint[1] = 1.0; + space.whitepoint[2] = (1.0 - wx - wy) / wy; + space.icc_type = BablICCTypeRGB; + + for (i = 0; space_db[i].instance.class_type; i++) + { + int offset = ((char*)&space_db[i].xr) - (char*)(&space_db[i]); + int size = ((char*)&space_db[i].trc) + sizeof(space_db[i].trc) - ((char*)&space_db[i].xr); + + if (memcmp ((char*)(&space_db[i]) + offset, ((char*)&space) + offset, size)==0) + { + return (void*)&space_db[i]; + } + } + if (i >= MAX_SPACES-1) + { + babl_log ("too many BablSpaces"); + return NULL; + } + space_db[i]=space; + space_db[i].instance.name = space_db[i].name; + if (name) + snprintf (space_db[i].name, sizeof (space_db[i].name), "%s", name); + else + /* XXX: this can get longer than 256bytes ! */ + snprintf (space_db[i].name, sizeof (space_db[i].name), + "space-%.4f,%.4f_%.4f,%.4f_%.4f,%.4f_%.4f,%.4f_%s,%s,%s", + wx,wy,rx,ry,bx,by,gx,gy,babl_get_name (space.trc[0]), + babl_get_name(space.trc[1]), babl_get_name(space.trc[2])); + + /* compute matrixes */ + babl_space_compute_matrices (&space_db[i], flags); + + babl_space_get_icc ((Babl*)&space_db[i], NULL); + return (Babl*)&space_db[i]; +} + +const Babl * +babl_space_from_gray_trc (const char *name, + const Babl *trc_gray, + BablSpaceFlags flags) +{ + int i=0; + BablSpace space = {0,}; + space.instance.class_type = BABL_SPACE; + space.instance.id = 0; + + space.xw = 0.3127; + space.yw = 0.3290; + + space.xr = 0.639998686; + space.yr = 0.330010138; + space.xg = 0.300003784; + space.yg = 0.600003357; + space.xb = 0.150002046; + space.yb = 0.059997204; + space.trc[0] = trc_gray; + space.trc[1] = trc_gray; + space.trc[2] = trc_gray; + + space.whitepoint[0] = space.xw / space.yw; + space.whitepoint[1] = 1.0; + space.whitepoint[2] = (1.0 - space.xw - space.yw) / space.yw; + space.icc_type = BablICCTypeGray; + + for (i = 0; space_db[i].instance.class_type; i++) + { + int offset = ((char*)&space_db[i].xr) - (char*)(&space_db[i]); + int size = ((char*)&space_db[i].trc) + sizeof(space_db[i].trc) - ((char*)&space_db[i].xr); + + if (memcmp ((char*)(&space_db[i]) + offset, ((char*)&space) + offset, size)==0) + { + return (void*)&space_db[i]; + } + } + if (i >= MAX_SPACES-1) + { + babl_log ("too many BablSpaces"); + return NULL; + } + space_db[i]=space; + space_db[i].instance.name = space_db[i].name; + if (name) + snprintf (space_db[i].name, sizeof (space_db[i].name), "%s", name); + else + /* XXX: this can get longer than 256bytes ! */ + snprintf (space_db[i].name, sizeof (space_db[i].name), + "space-gray-%s", babl_get_name(space.trc[0])); + + /* compute matrixes */ + babl_space_compute_matrices (&space_db[i], 1); + + //babl_space_get_icc ((Babl*)&space_db[i], NULL); + return (Babl*)&space_db[i]; + +} + + +void +babl_space_class_for_each (BablEachFunction each_fun, + void *user_data) +{ + int i=0; + for (i = 0; space_db[i].instance.class_type; i++) + if (each_fun (BABL (&space_db[i]), user_data)) + return; +} + +void +babl_space_class_init (void) +{ +#if 0 + babl_space_from_chromaticities ("sRGB", + 0.3127, 0.3290, /* D65 */ + 0.6400, 0.3300, + 0.3000, 0.6000, + 0.1500, 0.0600, + babl_trc("sRGB"), NULL, NULL, 1); +#else + babl_space_from_chromaticities ("sRGB", + 0.3127, 0.3290, /* D65 */ + 0.639998686, 0.330010138, + 0.300003784, 0.600003357, + 0.150002046, 0.059997204, + babl_trc("sRGB"), NULL, NULL, + 0); + /* hard-coded pre-quantized values - to match exactly what is used in standards see issue #18 */ +#endif + + /* sRGB with linear TRCs is scRGB. + */ + babl_space_from_chromaticities ("scRGB", + 0.3127, 0.3290, /* D65 */ + 0.639998686, 0.330010138, + 0.300003784, 0.600003357, + 0.150002046, 0.059997204, + babl_trc("linear"), NULL, NULL, + 0); + /* hard-coded pre-quantized values - to match exactly what is used in standards see issue #18 */ + + babl_space_from_chromaticities ("Rec2020", + 0.3127, 0.3290, /* D65 */ + 0.708, 0.292, + 0.170, 0.797, + 0.131, 0.046, + // XXX: is using sRGB TRC right? + babl_trc("sRGB"), NULL, NULL, 1); + + babl_space_from_chromaticities ( + "Adobish", /* a space that can be used as a place-holder for a sRGB like +space with displaced green coordinates from a big graphics software vendor that +would rather not it's name be directly used when referring to this color space, +this color space isn't exactly like theirs but close enough with babls own +computations of uniform gray axis */ + 0.3127, 0.3290, /* D65 */ + 0.6400, 0.3300, + 0.2100, 0.7100, + 0.1500, 0.0600, + babl_trc("2.2"), NULL, NULL, 1); + + babl_space_from_chromaticities ( + "ProPhoto", + 0.34567, 0.3585, /* D50 */ + 0.7347, 0.2653, + 0.1596, 0.8404, + 0.0366, 0.0001, + babl_trc("1.8"), NULL, NULL, 1); + + babl_space_from_chromaticities ( + "Apple", + 0.3127, 0.3290, /* D65 */ + 0.6250, 0.3400, + 0.2800, 0.5950, + 0.1550, 0.0700, + babl_trc("1.8"), NULL, NULL, 1); + +#if 0 + babl_space_from_chromaticities ( + "WideGamut", + 0.34567, 0.3585, /* D50 */ + 0.7350, 0.2650, + 0.1150, 0.8260, + 0.1570, 0.0180, + babl_trc("2.2"), NULL, NULL, 1); + + babl_space_from_chromaticities ( + "Best", + 0.34567, 0.3585, /* D50 */ + 0.7347, 0.2653, + 0.2150, 0.7750, + 0.1300, 0.0350, + babl_trc("2.2"), NULL, NULL, 1); + + babl_space_from_chromaticities ( + "Beta", + 0.34567, 0.3585, /* D50 */ + 0.6888, 0.3112, + 0.1986, 0.7551, + 0.1265, 0.0352, + babl_trc("2.2"), NULL, NULL, 1); + + babl_space_from_chromaticities ( + "Bruce", + 0.3127, 0.3290, /* D65 */ + 0.6400, 0.3300, + 0.2800, 0.6500, + 0.1500, 0.0600, + babl_trc("1.8"), NULL, NULL); + + babl_space_from_chromaticities ( + "PAL", + 0.3127, 0.3290, /* D65 */ + 0.6400, 0.3300, + 0.2900, 0.6000, + 0.1500, 0.0600, + babl_trc("2.2"), NULL, NULL, 1); + + babl_space_from_chromaticities ( + "SMPTE-C", + 0.3127, 0.3290, /* D65 */ + 0.6300, 0.3300, + 0.3100, 0.5950, + 0.1550, 0.0700, + babl_trc("2.2"), NULL, NULL, 1); + + babl_space_from_chromaticities ( + "ColorMatch", + 0.34567, 0.3585, /* D50 */ + 0.6300, 0.3400, + 0.2950, 0.6050, + 0.1500, 0.0750, + babl_trc("1.8"), NULL, NULL, 1); + + babl_space_from_chromaticities ( + "Don RGB 4", + 0.34567, 0.3585, /* D50 */ + 0.6960, 0.3000, + 0.2150, 0.7650, + 0.1300, 0.0350, + babl_trc("1.8"), NULL, NULL, 1); +#endif + + babl_space_from_chromaticities ( + "ACEScg", + 0.32168, 0.33767, + 0.713, 0.293, + 0.165, 0.830, + 0.128, 0.044, + babl_trc("linear"), NULL, NULL, 1); + + babl_space_from_chromaticities ( + "ACES2065-1", + 0.32168, 0.33767, + 0.7347, 0.2653, + 0.0000, 1.0000, + 0.0001, -0.0770, + babl_trc("linear"), NULL, NULL, 1); + +} + +void +babl_space_to_xyz (const Babl *space, + const double *rgb, + double *xyz) +{ + _babl_space_to_xyz (space, rgb, xyz); +} + +void +babl_space_from_xyz (const Babl *space, + const double *xyz, + double *rgb) +{ + _babl_space_from_xyz (space, xyz, rgb); +} + +const double * +babl_space_get_rgbtoxyz (const Babl *space) +{ + return space->space.RGBtoXYZ; +} + +/////////////////// + + +static void +prep_conversion (const Babl *babl) +{ + Babl *conversion = (void*) babl; + const Babl *source_space = babl_conversion_get_source_space (conversion); + float *matrixf; + int i; + float *lut_red; + float *lut_green; + float *lut_blue; + + double matrix[9]; + babl_matrix_mul_matrix ( + (conversion->conversion.destination)->format.space->space.XYZtoRGB, + (conversion->conversion.source)->format.space->space.RGBtoXYZ, + matrix); + + matrixf = babl_calloc (sizeof (float), 9 + 256 * 3); // we leak this matrix , which is a singleton + babl_matrix_to_float (matrix, matrixf); + conversion->conversion.data = matrixf; + + lut_red = matrixf + 9; + lut_green = lut_red + 256; + lut_blue = lut_green + 256; + for (i = 0; i < 256; i++) + { + lut_red[i] = babl_trc_to_linear (source_space->space.trc[0], i/255.0); + lut_green[i] = babl_trc_to_linear (source_space->space.trc[1], i/255.0); + lut_blue[i] = babl_trc_to_linear (source_space->space.trc[2], i/255.0); + } +} + +#define TRC_IN(rgba_in, rgba_out) do{ int i;\ + for (i = 0; i < samples; i++) \ + { \ + rgba_out[i*4+3] = rgba_in[i*4+3]; \ + } \ + if ((source_space->space.trc[0] == source_space->space.trc[1]) && \ + (source_space->space.trc[1] == source_space->space.trc[2])) \ + { \ + const Babl *trc = (void*)source_space->space.trc[0]; \ + babl_trc_to_linear_buf(trc, rgba_in, rgba_out, 4, 4, 3, samples); \ + } \ + else \ + { \ + int c; \ + for (c = 0; c < 3; c ++) \ + { \ + const Babl *trc = (void*)source_space->space.trc[c]; \ + babl_trc_to_linear_buf(trc, rgba_in + c, rgba_out + c, 4, 4, 1, samples); \ + } \ + } \ +}while(0) + +#define TRC_OUT(rgba_in, rgba_out) do{\ + { \ + int c; \ + if ((destination_space->space.trc[0] == destination_space->space.trc[1]) && \ + (destination_space->space.trc[1] == destination_space->space.trc[2])) \ + { \ + const Babl *trc = (void*)destination_space->space.trc[0]; \ + babl_trc_from_linear_buf(trc, rgba_in, rgba_out, 4, 4, 3, samples); \ + } \ + else \ + { \ + for (c = 0; c < 3; c ++) \ + { \ + const Babl *trc = (void*)destination_space->space.trc[c]; \ + babl_trc_from_linear_buf(trc, rgba_in + c, rgba_out + c, 4, 4, 1, samples); \ + } \ + } \ + }\ +} while(0) + + + + +static inline void +universal_nonlinear_rgba_converter (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples, + void *data) +{ + const Babl *source_space = babl_conversion_get_source_space (conversion); + const Babl *destination_space = babl_conversion_get_destination_space (conversion); + + float * matrixf = data; + float *rgba_in = (void*)src_char; + float *rgba_out = (void*)dst_char; + + TRC_IN(rgba_in, rgba_out); + + babl_matrix_mul_vectorff_buf4 (matrixf, rgba_out, rgba_out, samples); + + TRC_OUT(rgba_out, rgba_out); +} + +static inline void +universal_nonlinear_rgb_linear_converter (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples, + void *data) +{ + const Babl *source_space = babl_conversion_get_source_space (conversion); + float * matrixf = data; + float *rgba_in = (void*)src_char; + float *rgba_out = (void*)dst_char; + + TRC_IN(rgba_in, rgba_out); + + babl_matrix_mul_vectorff_buf4 (matrixf, rgba_out, rgba_out, samples); +} + +static inline void +universal_linear_rgb_nonlinear_converter (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples, + void *data) +{ + const Babl *destination_space = conversion->conversion.destination->format.space; + float * matrixf = data; + float *rgba_in = (void*)src_char; + float *rgba_out = (void*)dst_char; + + babl_matrix_mul_vectorff_buf4 (matrixf, rgba_in, rgba_out, samples); + + TRC_OUT(rgba_out, rgba_out); +} + +static inline void +universal_nonlinear_rgba_u8_converter (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples, + void *data) +{ + const Babl *destination_space = conversion->conversion.destination->format.space; + + float * matrixf = data; + float * in_trc_lut_red = matrixf + 9; + float * in_trc_lut_green = in_trc_lut_red + 256; + float * in_trc_lut_blue = in_trc_lut_green + 256; + int i; + uint8_t *rgba_in_u8 = (void*)src_char; + uint8_t *rgba_out_u8 = (void*)dst_char; + + float *rgb = babl_malloc (sizeof(float) * 4 * samples); + + for (i = 0; i < samples; i++) + { + rgb[i*4+0]=in_trc_lut_red[rgba_in_u8[i*4+0]]; + rgb[i*4+1]=in_trc_lut_green[rgba_in_u8[i*4+1]]; + rgb[i*4+2]=in_trc_lut_blue[rgba_in_u8[i*4+2]]; + rgba_out_u8[i*4+3] = rgba_in_u8[i*4+3]; + } + + babl_matrix_mul_vectorff_buf4 (matrixf, rgb, rgb, samples); + + { + const Babl *from_trc_red = (void*)destination_space->space.trc[0]; + const Babl *from_trc_green = (void*)destination_space->space.trc[1]; + const Babl *from_trc_blue = (void*)destination_space->space.trc[2]; + for (i = 0; i < samples * 4; i+=4) + { + rgba_out_u8[i+0] = babl_trc_from_linear (from_trc_red, rgb[i+0]) * 255.5f; + rgba_out_u8[i+1] = babl_trc_from_linear (from_trc_green, rgb[i+1]) * 255.5f; + rgba_out_u8[i+2] = babl_trc_from_linear (from_trc_blue, rgb[i+2]) * 255.5f; + } + } + babl_free (rgb); +} + + +static inline void +universal_rgba_converter (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples, + void *data) +{ + float *matrixf = data; + float *rgba_in = (void*)src_char; + float *rgba_out = (void*)dst_char; + + babl_matrix_mul_vectorff_buf4 (matrixf, rgba_in, rgba_out, samples); +} + +static inline void +universal_rgb_converter (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples, + void *data) +{ + float *matrixf = data; + float *rgb_in = (void*)src_char; + float *rgb_out = (void*)dst_char; + + babl_matrix_mul_vectorff_buf3 (matrixf, rgb_in, rgb_out, samples); +} + + +static inline void +universal_ya_converter (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples, + void *data) +{ + memcpy (dst_char, src_char, samples * 4 * 2); +} + +static inline void +universal_y_converter (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples, + void *data) +{ + memcpy (dst_char, src_char, samples * 4); +} + + +static inline void +universal_nonlinear_rgb_u8_converter (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples, + void *data) +{ + const Babl *destination_space = conversion->conversion.destination->format.space; + + float * matrixf = data; + float * in_trc_lut_red = matrixf + 9; + float * in_trc_lut_green = in_trc_lut_red + 256; + float * in_trc_lut_blue = in_trc_lut_green + 256; + int i; + uint8_t *rgb_in_u8 = (void*)src_char; + uint8_t *rgb_out_u8 = (void*)dst_char; + + float *rgba_out = babl_malloc (sizeof(float) * 4 * samples); + + for (i = 0; i < samples; i++) + { + rgba_out[i*4+0]=in_trc_lut_red[rgb_in_u8[i*3+0]]; + rgba_out[i*4+1]=in_trc_lut_green[rgb_in_u8[i*3+1]]; + rgba_out[i*4+2]=in_trc_lut_blue[rgb_in_u8[i*3+2]]; + rgba_out[i*4+3]=rgb_in_u8[i*3+2] * 255.5f; + } + + babl_matrix_mul_vectorff_buf4 (matrixf, rgba_out, rgba_out, samples); + + { + int c; + TRC_OUT(rgba_out, rgba_out); + + for (i = 0; i < samples; i++) + for (c = 0; c < 3; c ++) + rgb_out_u8[i*3+c] = rgba_out[i*4+c] * 255.5f; + } + + babl_free (rgba_out); +} + + +#if defined(USE_SSE2) + +#define m(matr, j, i) matr[j*3+i] + +#include + +static inline void babl_matrix_mul_vectorff_buf4_sse2 (const float *mat, + const float *v_in, + float *v_out, + int samples) +{ + const __v4sf m___0 = {m(mat, 0, 0), m(mat, 1, 0), m(mat, 2, 0), 0}; + const __v4sf m___1 = {m(mat, 0, 1), m(mat, 1, 1), m(mat, 2, 1), 0}; + const __v4sf m___2 = {m(mat, 0, 2), m(mat, 1, 2), m(mat, 2, 2), 1}; + int i; + for (i = 0; i < samples; i ++) + { + __v4sf a, b, c = _mm_load_ps(&v_in[0]); + a = (__v4sf) _mm_shuffle_epi32((__m128i)c, _MM_SHUFFLE(0,0,0,0)); + b = (__v4sf) _mm_shuffle_epi32((__m128i)c, _MM_SHUFFLE(1,1,1,1)); + c = (__v4sf) _mm_shuffle_epi32((__m128i)c, _MM_SHUFFLE(3,2,2,2)); + _mm_store_ps (v_out, m___0 * a + m___1 * b + m___2 * c); + v_out += 4; + v_in += 4; + } + _mm_empty (); +} + +#undef m + + +static inline void +universal_nonlinear_rgba_converter_sse2 (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples, + void *data) +{ + const Babl *source_space = babl_conversion_get_source_space (conversion); + const Babl *destination_space = babl_conversion_get_destination_space (conversion); + float * matrixf = data; + float *rgba_in = (void*)src_char; + float *rgba_out = (void*)dst_char; + + TRC_IN(rgba_in, rgba_out); + + babl_matrix_mul_vectorff_buf4_sse2 (matrixf, rgba_out, rgba_out, samples); + + TRC_OUT(rgba_out, rgba_out); +} + + +static inline void +universal_rgba_converter_sse2 (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples, + void *data) +{ + float *matrixf = data; + float *rgba_in = (void*)src_char; + float *rgba_out = (void*)dst_char; + + babl_matrix_mul_vectorff_buf4_sse2 (matrixf, rgba_in, rgba_out, samples); +} + +static inline void +universal_nonlinear_rgba_u8_converter_sse2 (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples, + void *data) +{ + const Babl *destination_space = conversion->conversion.destination->format.space; + + float * matrixf = data; + float * in_trc_lut_red = matrixf + 9; + float * in_trc_lut_green = in_trc_lut_red + 256; + float * in_trc_lut_blue = in_trc_lut_green + 256; + int i; + uint8_t *rgba_in_u8 = (void*)src_char; + uint8_t *rgba_out_u8 = (void*)dst_char; + + float *rgba_out = babl_malloc (sizeof(float) * 4 * samples); + + for (i = 0; i < samples * 4; i+= 4) + { + rgba_out[i+0]=in_trc_lut_red[rgba_in_u8[i+0]]; + rgba_out[i+1]=in_trc_lut_green[rgba_in_u8[i+1]]; + rgba_out[i+2]=in_trc_lut_blue[rgba_in_u8[i+2]]; + rgba_out_u8[i+3] = rgba_in_u8[i+3]; + } + + babl_matrix_mul_vectorff_buf4_sse2 (matrixf, rgba_out, rgba_out, samples); + + { + int c; + TRC_OUT(rgba_out, rgba_out); + + for (i = 0; i < samples * 4; i+= 4) + for (c = 0; c < 3; c ++) + rgba_out_u8[i+c] = rgba_out[i+c] * 255.5f; + } + + babl_free (rgba_out); +} + +static inline void +universal_nonlinear_rgb_u8_converter_sse2 (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples, + void *data) +{ + const Babl *destination_space = conversion->conversion.destination->format.space; + + float * matrixf = data; + float * in_trc_lut_red = matrixf + 9; + float * in_trc_lut_green = in_trc_lut_red + 256; + float * in_trc_lut_blue = in_trc_lut_green + 256; + int i; + uint8_t *rgb_in_u8 = (void*)src_char; + uint8_t *rgb_out_u8 = (void*)dst_char; + + float *rgba_out = babl_malloc (sizeof(float) * 4 * samples); + + for (i = 0; i < samples; i++) + { + rgba_out[i*4+0]=in_trc_lut_red[rgb_in_u8[i*3+0]]; + rgba_out[i*4+1]=in_trc_lut_green[rgb_in_u8[i*3+1]]; + rgba_out[i*4+2]=in_trc_lut_blue[rgb_in_u8[i*3+2]]; + } + + babl_matrix_mul_vectorff_buf4_sse2 (matrixf, rgba_out, rgba_out, samples); + + { + int c; + TRC_OUT(rgba_out, rgba_out); + + for (i = 0; i < samples; i++) + for (c = 0; c < 3; c ++) + rgb_out_u8[i*3+c] = rgba_out[i*4+c] * 255.5f; + } + + babl_free (rgba_out); +} + + +static inline void +universal_nonlinear_rgb_linear_converter_sse2 (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples, + void *data) +{ + const Babl *source_space = babl_conversion_get_source_space (conversion); + float * matrixf = data; + float *rgba_in = (void*)src_char; + float *rgba_out = (void*)dst_char; + + TRC_IN(rgba_in, rgba_out); + + babl_matrix_mul_vectorff_buf4_sse2 (matrixf, rgba_out, rgba_out, samples); +} + + +static inline void +universal_linear_rgb_nonlinear_converter_sse2 (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples, + void *data) +{ + const Babl *destination_space = conversion->conversion.destination->format.space; + float * matrixf = data; + float *rgba_in = (void*)src_char; + float *rgba_out = (void*)dst_char; + + babl_matrix_mul_vectorff_buf4_sse2 (matrixf, rgba_in, rgba_out, samples); + + TRC_OUT(rgba_out, rgba_out); +} +#endif + + +static int +add_rgb_adapter (Babl *babl, + void *space) +{ + if (babl != space) + { + +#if defined(USE_SSE2) + if ((babl_cpu_accel_get_support () & BABL_CPU_ACCEL_X86_SSE) && + (babl_cpu_accel_get_support () & BABL_CPU_ACCEL_X86_SSE2)) + { + + + prep_conversion(babl_conversion_new( + babl_format_with_space("RGBA float", space), + babl_format_with_space("RGBA float", babl), + "linear", universal_rgba_converter_sse2, + NULL)); + prep_conversion(babl_conversion_new( + babl_format_with_space("RGBA float", babl), + babl_format_with_space("RGBA float", space), + "linear", universal_rgba_converter_sse2, + NULL)); + prep_conversion(babl_conversion_new( + babl_format_with_space("R'G'B'A float", space), + babl_format_with_space("R'G'B'A float", babl), + "linear", universal_nonlinear_rgba_converter_sse2, + NULL)); + prep_conversion(babl_conversion_new( + babl_format_with_space("R'G'B'A float", babl), + babl_format_with_space("R'G'B'A float", space), + "linear", universal_nonlinear_rgba_converter_sse2, + NULL)); + + prep_conversion(babl_conversion_new( + babl_format_with_space("R'G'B'A float", space), + babl_format_with_space("RGBA float", babl), + "linear", universal_nonlinear_rgb_linear_converter_sse2, + NULL)); + prep_conversion(babl_conversion_new( + babl_format_with_space("R'G'B'A float", babl), + babl_format_with_space("RGBA float", space), + "linear", universal_nonlinear_rgb_linear_converter_sse2, + NULL)); + + prep_conversion(babl_conversion_new( + babl_format_with_space("RGBA float", babl), + babl_format_with_space("R'G'B'A float", space), + "linear", universal_linear_rgb_nonlinear_converter_sse2, + NULL)); + prep_conversion(babl_conversion_new( + babl_format_with_space("RGBA float", space), + babl_format_with_space("R'G'B'A float", babl), + "linear", universal_linear_rgb_nonlinear_converter_sse2, + NULL)); + + prep_conversion(babl_conversion_new( + babl_format_with_space("R'G'B'A u8", space), + babl_format_with_space("R'G'B'A u8", babl), + "linear", universal_nonlinear_rgba_u8_converter_sse2, + NULL)); + prep_conversion(babl_conversion_new( + babl_format_with_space("R'G'B'A u8", babl), + babl_format_with_space("R'G'B'A u8", space), + "linear", universal_nonlinear_rgba_u8_converter_sse2, + NULL)); + + prep_conversion(babl_conversion_new( + babl_format_with_space("R'G'B' u8", space), + babl_format_with_space("R'G'B' u8", babl), + "linear", universal_nonlinear_rgb_u8_converter_sse2, + NULL)); + prep_conversion(babl_conversion_new( + babl_format_with_space("R'G'B' u8", babl), + babl_format_with_space("R'G'B' u8", space), + "linear", universal_nonlinear_rgb_u8_converter_sse2, + NULL)); + } + //else +#endif + { + prep_conversion(babl_conversion_new( + babl_format_with_space("RGBA float", space), + babl_format_with_space("RGBA float", babl), + "linear", universal_rgba_converter, + NULL)); + prep_conversion(babl_conversion_new( + babl_format_with_space("RGBA float", babl), + babl_format_with_space("RGBA float", space), + "linear", universal_rgba_converter, + NULL)); + + prep_conversion(babl_conversion_new( + babl_format_with_space("R'G'B'A float", space), + babl_format_with_space("R'G'B'A float", babl), + "linear", universal_nonlinear_rgba_converter, + NULL)); + prep_conversion(babl_conversion_new( + babl_format_with_space("R'G'B'A float", babl), + babl_format_with_space("R'G'B'A float", space), + "linear", universal_nonlinear_rgba_converter, + NULL)); + + prep_conversion(babl_conversion_new( + babl_format_with_space("R'G'B'A float", space), + babl_format_with_space("RGBA float", babl), + "linear", universal_nonlinear_rgb_linear_converter, + NULL)); + prep_conversion(babl_conversion_new( + babl_format_with_space("R'G'B'A float", babl), + babl_format_with_space("RGBA float", space), + "linear", universal_nonlinear_rgb_linear_converter, + NULL)); + + prep_conversion(babl_conversion_new( + babl_format_with_space("R'G'B'A u8", space), + babl_format_with_space("R'G'B'A u8", babl), + "linear", universal_nonlinear_rgba_u8_converter, + NULL)); + prep_conversion(babl_conversion_new( + babl_format_with_space("R'G'B'A u8", babl), + babl_format_with_space("R'G'B'A u8", space), + "linear", universal_nonlinear_rgba_u8_converter, + NULL)); + + prep_conversion(babl_conversion_new( + babl_format_with_space("R'G'B' u8", space), + babl_format_with_space("R'G'B' u8", babl), + "linear", universal_nonlinear_rgb_u8_converter, + NULL)); + prep_conversion(babl_conversion_new( + babl_format_with_space("R'G'B' u8", babl), + babl_format_with_space("R'G'B' u8", space), + "linear", universal_nonlinear_rgb_u8_converter, + NULL)); + + prep_conversion(babl_conversion_new( + babl_format_with_space("RGBA float", babl), + babl_format_with_space("R'G'B'A float", space), + "linear", universal_linear_rgb_nonlinear_converter, + NULL)); + prep_conversion(babl_conversion_new( + babl_format_with_space("RGBA float", space), + babl_format_with_space("R'G'B'A float", babl), + "linear", universal_linear_rgb_nonlinear_converter, + NULL)); + } + + prep_conversion(babl_conversion_new( + babl_format_with_space("RGB float", space), + babl_format_with_space("RGB float", babl), + "linear", universal_rgb_converter, + NULL)); + prep_conversion(babl_conversion_new( + babl_format_with_space("RGB float", babl), + babl_format_with_space("RGB float", space), + "linear", universal_rgb_converter, + NULL)); + + prep_conversion(babl_conversion_new( + babl_format_with_space("Y float", space), + babl_format_with_space("Y float", babl), + "linear", universal_y_converter, + NULL)); + prep_conversion(babl_conversion_new( + babl_format_with_space("YaA float", babl), + babl_format_with_space("YaA float", space), + "linear", universal_ya_converter, + NULL)); + prep_conversion(babl_conversion_new( + babl_format_with_space("YA float", babl), + babl_format_with_space("YA float", space), + "linear", universal_ya_converter, + NULL)); + } + return 0; +} + +/* The first time a new Babl space is used - for creation of a fish, is when + * this function is called, it adds conversions hooks that provides its formats + * with conversions internally as well as for conversions to and from other RGB + * spaces. + */ +void +_babl_space_add_universal_rgb (const Babl *space) +{ + babl_space_class_for_each (add_rgb_adapter, (void*)space); +} + + +const Babl * +babl_space_match_trc_matrix (const Babl *trc_red, + const Babl *trc_green, + const Babl *trc_blue, + float rx, float ry, float rz, + float gx, float gy, float gz, + float bx, float by, float bz) +{ + int i; + double delta = 0.001; + for (i = 0; space_db[i].instance.class_type; i++) + { + BablSpace *space = &space_db[i]; + if (space->icc_type == BablICCTypeRGB && + trc_red == space->trc[0] && + trc_green == space->trc[1] && + trc_blue == space->trc[2] && + fabs(rx - space->RGBtoXYZ[0]) < delta && + fabs(ry - space->RGBtoXYZ[3]) < delta && + fabs(rz - space->RGBtoXYZ[6]) < delta && + fabs(gx - space->RGBtoXYZ[1]) < delta && + fabs(gy - space->RGBtoXYZ[4]) < delta && + fabs(gz - space->RGBtoXYZ[7]) < delta && + fabs(bx - space->RGBtoXYZ[2]) < delta && + fabs(by - space->RGBtoXYZ[5]) < delta && + fabs(bz - space->RGBtoXYZ[8]) < delta) + { + return (void*)&space_db[i]; + } + } + return NULL; +} + +const Babl * +babl_space_with_trc (const Babl *babl, + const Babl *trc) +{ + double xw, yw, xr, yr, xg, yg, xb, yb; + const Babl *red_trc = NULL; + const Babl *green_trc = NULL; + const Babl *blue_trc = NULL; + + babl_space_get (babl, + &xw, &yw, + &xr, &yr, + &xg, &yg, + &xb, &yb, + &red_trc, &green_trc, &blue_trc); + if (red_trc == trc && green_trc == trc && blue_trc == trc) + return babl; + return babl_space_from_chromaticities (NULL, + xw, yw, xr, yr, xg, yg, xb, yb, trc, trc, trc, + BABL_SPACE_FLAG_EQUALIZE); + +} + +void +babl_space_get (const Babl *babl, + double *xw, double *yw, + double *xr, double *yr, + double *xg, double *yg, + double *xb, double *yb, + const Babl **red_trc, + const Babl **green_trc, + const Babl **blue_trc) +{ + const BablSpace *space = &babl->space; + /* XXX: note: for spaces set by matrix should be possible to derive + the chromaticities of r,g,b and thus even then keep this + is canonical data + */ + if(xw)*xw = space->xw; + if(yw)*yw = space->yw; + if(xr)*xr = space->xr; + if(yr)*yr = space->yr; + if(xg)*xg = space->xg; + if(yg)*yg = space->yg; + if(xb)*xb = space->xb; + if(yb)*yb = space->yb; + if(red_trc)*red_trc = space->trc[0]; + if(green_trc)*green_trc = space->trc[1]; + if(blue_trc)*blue_trc = space->trc[2]; +} + +int +babl_space_is_cmyk (const Babl *space) +{ + return space?space->space.icc_type == BablICCTypeCMYK:0; +} + +int +babl_space_is_gray (const Babl *space) +{ + return space?space->space.icc_type == BablICCTypeGray:0; +} + + +/* Trademarks: + * + * International Color Consortium is a registered trademarks of the. + * International Color Consortium. + * Apple is a trademark or registered trademark of Apple Inc in many countries. + * Adobish is meant to concisely convey resemblence/compatibility with Adobe + * RGB- without actualy being it, Adobe is a trademark or registered trademark + * of Adobe Systems Incorporated in many countires. + */ + +void +babl_space_get_rgb_luminance (const Babl *space, + double *red_luminance, + double *green_luminance, + double *blue_luminance) +{ + if (!space) + space = babl_space ("sRGB"); + if (red_luminance) + *red_luminance = space->space.RGBtoXYZ[3]; + if (green_luminance) + *green_luminance = space->space.RGBtoXYZ[4]; + if (blue_luminance) + *blue_luminance = space->space.RGBtoXYZ[5]; +} + +double +babl_space_get_gamma (const Babl *space) +{ + if (space->space.trc[0] != space->space.trc[1] || + space->space.trc[1] != space->space.trc[2] || + space->space.trc[0]->trc.type != BABL_TRC_FORMULA_GAMMA) + return 0.0; + return space->space.trc[0]->trc.gamma; +} diff --git a/babl/babl-space.h b/babl/babl-space.h new file mode 100644 index 0000000..86692e9 --- /dev/null +++ b/babl/babl-space.h @@ -0,0 +1,175 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2017, Øyvind Kolås and others. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#ifndef _BABL_SPACE_H +#define _BABL_SPACE_H + +#include "config.h" +#include +#include +#include "base/util.h" +#include "babl-matrix.h" + +#ifdef HAVE_LCMS +#include +#endif + +BABL_CLASS_DECLARE (space); + +typedef struct +{ + //int is_cmyk; +#ifdef HAVE_LCMS + cmsHPROFILE lcms_profile; + cmsHTRANSFORM lcms_to_rgba; + cmsHTRANSFORM lcms_from_rgba; +#endif + int filler; +} BablCMYK; + +#if 0 // draft datastructures for spectral spaces +typedef struct _BablSpectrumType BablSpectrumType; + +struct _BablSpectrumType { + double nm_start; + double nm_gap; + double nm_end; /* last band, computed */ + int bands; +}; + +typedef struct +{ + BablSpectrumType spectrum_type; + int is_spectral; + float *observer_x; + float *observer_y; + float *observer_z; + float *illuminant; + float rev_y_scale; +} BablSpectralSpace; + +typedef struct +{ + BablSpectralSpace *spectral_space; + int inks; + float *on_white; + float *on_black; + float *opaqueness; + float scale; + float trc_gamma; + float *illuminant; +} BablCoat; + +#define BABL_MAX_COATS 16 + +typedef struct +{ + BablSpectralSpace *spectral_space; + BablCoat coat_def[BABL_MAX_COATS]; + int coats; + float *substrate; + + int stochastic_iterations; + float stochastic_diffusion0; + float stochastic_diffusion1; +} BablProcessSpace; +#endif + +typedef enum { + BablICCTypeRGB = 0, + BablICCTypeGray = 2, + BablICCTypeCMYK = 3, +} BablICCType; + +typedef struct +{ + BablInstance instance; + double xw; // white-point chromaticity + double yw; + + double xr; // red primary chromaticity + double yr; + + double xg; // green primary chromaticity + double yg; + + double xb; // blue primary chromaticity + double yb; + + BablICCType icc_type; /* taken into account when looking for duplicate spaces*/ + double whitepoint[3]; /* CIE XYZ whitepoint */ + const Babl *trc[3]; + + /* ------------- end of dedup zone -------------- */ + + char name[512]; // XXX: allocate this dynamically instead - + // or use iccv4 style hashes for name. + + double RGBtoXYZ[9]; /* matrices for conversions */ + double XYZtoRGB[9]; + float RGBtoXYZf[9]; /* matrices for conversions */ + float XYZtoRGBf[9]; + + /* the space should contain matrix to/from XYZ */ + /* and before converting a span, all that needs to be + rigged is merging matrices */ + + /* we should here also add more things read from ICC profile, + * making it possible to round-trip data. Unless it is sRGB, when + * standard should win. + */ + char *icc_profile; + int icc_length; + BablCMYK cmyk; +} BablSpace; + + +static inline void babl_space_to_xyzf (const Babl *space, const float *rgb, float *xyz) +{ + BablSpace *space_ = (void*)space; + babl_matrix_mul_vectorff (space_->RGBtoXYZf, rgb, xyz); +} + +static inline void babl_space_from_xyzf (const Babl *space, const float *xyz, float *rgb) +{ + BablSpace *space_ = (void*)space; + babl_matrix_mul_vectorff (space_->XYZtoRGBf, xyz, rgb); +} + +static inline void _babl_space_to_xyz (const Babl *space, const double *rgb, double *xyz) +{ + BablSpace *space_ = (void*)space; + babl_matrix_mul_vector (space_->RGBtoXYZ, rgb, xyz); +} + +static inline void _babl_space_from_xyz (const Babl *space, const double *xyz, double *rgb) +{ + BablSpace *space_ = (void*)space; + babl_matrix_mul_vector (space_->XYZtoRGB, xyz, rgb); +} + +void +babl_space_class_init (void); + +const Babl * +babl_space_from_gray_trc (const char *name, + const Babl *trc_gray, + BablSpaceFlags flags); + + +#endif diff --git a/babl/babl-trc.c b/babl/babl-trc.c new file mode 100644 index 0000000..d8a69dd --- /dev/null +++ b/babl/babl-trc.c @@ -0,0 +1,708 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2017 Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#define MAX_TRCS 100 + +/* FIXME: choose parameters more intelligently */ +#define POLY_GAMMA_X0 ( 0.5 / 255.0) +#define POLY_GAMMA_X1 (254.5 / 255.0) +#define POLY_GAMMA_DEGREE 6 +#define POLY_GAMMA_SCALE 2 + +#include "config.h" +#include "babl-internal.h" +#include "base/util.h" + +static BablTRC trc_db[MAX_TRCS]; + +static inline float +_babl_trc_linear (const Babl *trc_, + float value) +{ + return value; +} + +static inline float +babl_trc_lut_from_linear (const Babl *trc_, + float x) +{ + BablTRC *trc = (void*)trc_; + int entry; + float ret, diff; + + entry = x * (trc->lut_size-1); + diff = ( (x * (trc->lut_size-1)) - entry); + + if (entry >= trc->lut_size -1) + { + entry = trc->lut_size - 1; + diff = 0.0; + } + else if (entry < 0) entry = 0; + + if (diff > 0.0) + { + ret = trc->inv_lut[entry] * (1.0 - diff) + trc->inv_lut[entry+1] * diff; + } + else + { + ret = trc->inv_lut[entry]; + } + return ret; +} + +static inline float +babl_trc_lut_to_linear (const Babl *trc_, + float x) +{ + BablTRC *trc = (void*)trc_; + int entry; + float ret, diff; + + entry = x * (trc->lut_size-1); + diff = ( (x * (trc->lut_size-1)) - entry); + + if (entry >= trc->lut_size) entry = trc->lut_size - 1; + else if (entry < 0) entry = 0; + + if (diff > 0.0 && entry < trc->lut_size - 1) + { + ret = trc->lut[entry] * (1.0 - diff) + trc->lut[entry+1] * diff; + } + else + { + ret = trc->lut[entry]; + } + return ret; +} + +static inline float +_babl_trc_gamma_to_linear (const Babl *trc_, + float value) +{ + BablTRC *trc = (void*)trc_; + if (value >= trc->poly_gamma_to_linear_x0 && + value <= trc->poly_gamma_to_linear_x1) + { + return babl_polynomial_eval (&trc->poly_gamma_to_linear, value); + } + else if (value > 0.0f) + { + return powf (value, trc->gamma); + } + return 0.0f; +} + +static inline float +_babl_trc_gamma_from_linear (const Babl *trc_, + float value) +{ + BablTRC *trc = (void*)trc_; + if (value >= trc->poly_gamma_from_linear_x0 && + value <= trc->poly_gamma_from_linear_x1) + { + return babl_polynomial_eval (&trc->poly_gamma_from_linear, value); + } + else if (value > 0.0f) + { + return powf (value, trc->rgamma); + } + return 0.0f; +} + +static inline void +_babl_trc_gamma_to_linear_buf (const Babl *trc_, + const float *in, + float *out, + int in_gap, + int out_gap, + int components, + int count) +{ + int i, c; + for (i = 0; i < count; i ++) + for (c = 0; c < components; c ++) + out[out_gap * i + c] = _babl_trc_gamma_to_linear (trc_, in[in_gap *i + c]); +} + +static inline void +_babl_trc_gamma_from_linear_buf (const Babl *trc_, + const float *in, + float *out, + int in_gap, + int out_gap, + int components, + int count) +{ + int i, c; + for (i = 0; i < count; i ++) + for (c = 0; c < components; c ++) + out[out_gap * i + c] = _babl_trc_gamma_from_linear (trc_, in[in_gap *i + c]); +} + +static inline float +_babl_trc_formula_srgb_from_linear (const Babl *trc_, + float value) +{ + BablTRC *trc = (void*)trc_; + float x= value; + float a = trc->lut[1]; + float b = trc->lut[2]; + float c = trc->lut[3]; + float d = trc->lut[4]; + float e = trc->lut[5]; + float f = trc->lut[6]; + + if (x - f > c * d) // XXX: verify that this math is the correct inverse + { + float v = _babl_trc_gamma_from_linear ((Babl *) trc, x - f); + v = (v-b)/a; + if (v < 0.0 || v >= 0.0) + return v; + return 0.0; + } + if (c > 0.0) + return (x - e) / c; + return 0.0; +} + +static inline float +_babl_trc_formula_srgb_to_linear (const Babl *trc_, + float value) +{ + BablTRC *trc = (void*)trc_; + float x= value; + float a = trc->lut[1]; + float b = trc->lut[2]; + float c = trc->lut[3]; + float d = trc->lut[4]; + float e = trc->lut[5]; + float f = trc->lut[6]; + + if (x >= d) + { + return _babl_trc_gamma_to_linear ((Babl *) trc, a * x + b) + e; + } + return c * x + f; +} +static inline float +_babl_trc_formula_cie_from_linear (const Babl *trc_, + float value) +{ + BablTRC *trc = (void*)trc_; + float x= value; + float a = trc->lut[1]; + float b = trc->lut[2]; + float c = trc->lut[3]; + + if (x > c) + { + float v = _babl_trc_gamma_from_linear ((Babl *) trc, x - c); + v = (v-b)/a; + if (v < 0.0 || v >= 0.0) + return v; + } + return 0.0; +} + +static inline float +_babl_trc_formula_cie_to_linear (const Babl *trc_, + float value) +{ + BablTRC *trc = (void*)trc_; + float x= value; + float a = trc->lut[1]; + float b = trc->lut[2]; + float c = trc->lut[3]; + + if (x >= -b / a) + { + return _babl_trc_gamma_to_linear ((Babl *) trc, a * x + b) + c; + } + return c; +} + + + +static inline float +_babl_trc_srgb_to_linear (const Babl *trc_, + float value) +{ + return babl_gamma_2_2_to_linearf (value); +} + +static inline float +_babl_trc_srgb_from_linear (const Babl *trc_, + float value) +{ + return babl_linear_to_gamma_2_2f (value); +} + +static inline void +_babl_trc_srgb_to_linear_buf (const Babl *trc_, + const float *in, + float *out, + int in_gap, + int out_gap, + int components, + int count) +{ + int i, c; + for (i = 0; i < count; i ++) + for (c = 0; c < components; c++) + out[out_gap * i + c] = babl_gamma_2_2_to_linearf (in[in_gap * i + c]); +} + +static inline void +_babl_trc_srgb_from_linear_buf (const Babl *trc_, + const float *in, + float *out, + int in_gap, + int out_gap, + int components, + int count) +{ + int i, c; + for (i = 0; i < count; i ++) + for (c = 0; c < components; c++) + out[out_gap * i + c] = babl_linear_to_gamma_2_2f (in[in_gap * i + c]); +} + +static inline void +_babl_trc_to_linear_buf_generic (const Babl *trc_, + const float *in, + float *out, + int in_gap, + int out_gap, + int components, + int count) +{ + int i, c; + BablTRC *trc = (void*)trc_; + for (i = 0; i < count; i ++) + for (c = 0; c < components; c ++) + out[out_gap * i + c] = trc->fun_to_linear (trc_, in[in_gap * i + c]); +} + +static inline void +_babl_trc_from_linear_buf_generic (const Babl *trc_, + const float *in, + float *out, + int in_gap, + int out_gap, + int components, + int count) +{ + int i, c; + BablTRC *trc = (void*)trc_; + for (i = 0; i < count; i ++) + for (c = 0; c < components; c ++) + out[out_gap * i + c] = trc->fun_from_linear (trc_, in[in_gap * i + c]); +} + +static inline void _babl_trc_linear_buf (const Babl *trc_, + const float *in, + float *out, + int in_gap, + int out_gap, + int components, + int count) +{ + int i, c; + for (i = 0; i < count; i ++) + for (c = 0; c < components; c ++) + out[i * out_gap + c] = in[i * in_gap + c]; +} + + +const Babl * +babl_trc (const char *name) +{ + int i; + for (i = 0; trc_db[i].instance.class_type; i++) + if (!strcmp (trc_db[i].instance.name, name)) + { + return (Babl*)&trc_db[i]; + } + babl_log("failed to find trc '%s'\n", name); + return NULL; +} + +const Babl * +babl_trc_new (const char *name, + BablTRCType type, + double gamma, + int n_lut, + float *lut) +{ + int i=0; + static BablTRC trc; + trc.instance.class_type = BABL_TRC; + trc.instance.id = 0; + trc.type = type; + trc.gamma = gamma > 0.0 ? gamma : 0.0; + trc.rgamma = gamma > 0.0001 ? 1.0 / gamma : 0.0; + + if (n_lut ) + { + for (i = 0; trc_db[i].instance.class_type; i++) + { + if ( trc_db[i].lut_size == n_lut && + (memcmp (trc_db[i].lut, lut, sizeof (float) * n_lut)==0) + ) + { + return (void*)&trc_db[i]; + } + } + } + else + for (i = 0; trc_db[i].instance.class_type; i++) + { + int offset = ((char*)&trc_db[i].type) - (char*)(&trc_db[i]); + int size = ((char*)&trc_db[i].gamma + sizeof(double)) - ((char*)&trc_db[i].type); + + if (memcmp ((char*)(&trc_db[i]) + offset, ((char*)&trc) + offset, size)==0) + { + return (void*)&trc_db[i]; + } + } + if (i >= MAX_TRCS-1) + { + babl_log ("too many BablTRCs"); + return NULL; + } + trc_db[i]=trc; + trc_db[i].instance.name = trc_db[i].name; + if (name) + snprintf (trc_db[i].name, sizeof (trc_db[i].name), "%s", name); + else if (n_lut) + snprintf (trc_db[i].name, sizeof (trc_db[i].name), "lut-trc"); + else + snprintf (trc_db[i].name, sizeof (trc_db[i].name), "trc-%i-%f", type, gamma); + + if (n_lut) + { + int j; + trc_db[i].lut_size = n_lut; + trc_db[i].lut = babl_calloc (sizeof (float), n_lut); + memcpy (trc_db[i].lut, lut, sizeof (float) * n_lut); + trc_db[i].inv_lut = babl_calloc (sizeof (float), n_lut); + + for (j = 0; j < n_lut; j++) + { + int k; + double min = 0.0; + double max = 1.0; + for (k = 0; k < 16; k++) + { + double guess = (min + max) / 2; + float reversed_index = babl_trc_lut_to_linear (BABL(&trc_db[i]), guess) * (n_lut-1.0); + + if (reversed_index < j) + { + min = guess; + } + else if (reversed_index > j) + { + max = guess; + } + } + trc_db[i].inv_lut[j] = (min + max) / 2; + } + } + + trc_db[i].fun_to_linear_buf = _babl_trc_to_linear_buf_generic; + trc_db[i].fun_from_linear_buf = _babl_trc_from_linear_buf_generic; + + switch (trc_db[i].type) + { + case BABL_TRC_LINEAR: + trc_db[i].fun_to_linear = _babl_trc_linear; + trc_db[i].fun_from_linear = _babl_trc_linear; + trc_db[i].fun_from_linear_buf = _babl_trc_linear_buf; + trc_db[i].fun_to_linear_buf = _babl_trc_linear_buf; + break; + case BABL_TRC_FORMULA_GAMMA: + trc_db[i].fun_to_linear = _babl_trc_gamma_to_linear; + trc_db[i].fun_from_linear = _babl_trc_gamma_from_linear; + trc_db[i].fun_to_linear_buf = _babl_trc_gamma_to_linear_buf; + trc_db[i].fun_from_linear_buf = _babl_trc_gamma_from_linear_buf; + + trc_db[i].poly_gamma_to_linear_x0 = POLY_GAMMA_X0; + trc_db[i].poly_gamma_to_linear_x1 = POLY_GAMMA_X1; + babl_polynomial_approximate_gamma (&trc_db[i].poly_gamma_to_linear, + trc_db[i].gamma, + trc_db[i].poly_gamma_to_linear_x0, + trc_db[i].poly_gamma_to_linear_x1, + POLY_GAMMA_DEGREE, POLY_GAMMA_SCALE); + + trc_db[i].poly_gamma_from_linear_x0 = POLY_GAMMA_X0; + trc_db[i].poly_gamma_from_linear_x1 = POLY_GAMMA_X1; + babl_polynomial_approximate_gamma (&trc_db[i].poly_gamma_from_linear, + trc_db[i].rgamma, + trc_db[i].poly_gamma_from_linear_x0, + trc_db[i].poly_gamma_from_linear_x1, + POLY_GAMMA_DEGREE, POLY_GAMMA_SCALE); + break; + case BABL_TRC_FORMULA_CIE: + trc_db[i].lut = babl_calloc (sizeof (float), 4); + { + int j; + for (j = 0; j < 4; j++) + trc_db[i].lut[j] = lut[j]; + } + trc_db[i].fun_to_linear = _babl_trc_formula_cie_to_linear; + trc_db[i].fun_from_linear = _babl_trc_formula_cie_from_linear; + + trc_db[i].poly_gamma_to_linear_x0 = lut[4]; + trc_db[i].poly_gamma_to_linear_x1 = POLY_GAMMA_X1; + babl_polynomial_approximate_gamma (&trc_db[i].poly_gamma_to_linear, + trc_db[i].gamma, + trc_db[i].poly_gamma_to_linear_x0, + trc_db[i].poly_gamma_to_linear_x1, + POLY_GAMMA_DEGREE, POLY_GAMMA_SCALE); + + trc_db[i].poly_gamma_from_linear_x0 = lut[3] * lut[4]; + trc_db[i].poly_gamma_from_linear_x1 = POLY_GAMMA_X1; + babl_polynomial_approximate_gamma (&trc_db[i].poly_gamma_from_linear, + trc_db[i].rgamma, + trc_db[i].poly_gamma_from_linear_x0, + trc_db[i].poly_gamma_from_linear_x1, + POLY_GAMMA_DEGREE, POLY_GAMMA_SCALE); + break; + + case BABL_TRC_FORMULA_SRGB: + trc_db[i].lut = babl_calloc (sizeof (float), 7); + { + int j; + for (j = 0; j < 7; j++) + trc_db[i].lut[j] = lut[j]; + } + trc_db[i].fun_to_linear = _babl_trc_formula_srgb_to_linear; + trc_db[i].fun_from_linear = _babl_trc_formula_srgb_from_linear; + + trc_db[i].poly_gamma_to_linear_x0 = lut[4]; + trc_db[i].poly_gamma_to_linear_x1 = POLY_GAMMA_X1; + babl_polynomial_approximate_gamma (&trc_db[i].poly_gamma_to_linear, + trc_db[i].gamma, + trc_db[i].poly_gamma_to_linear_x0, + trc_db[i].poly_gamma_to_linear_x1, + POLY_GAMMA_DEGREE, POLY_GAMMA_SCALE); + + trc_db[i].poly_gamma_from_linear_x0 = lut[3] * lut[4]; + trc_db[i].poly_gamma_from_linear_x1 = POLY_GAMMA_X1; + babl_polynomial_approximate_gamma (&trc_db[i].poly_gamma_from_linear, + trc_db[i].rgamma, + trc_db[i].poly_gamma_from_linear_x0, + trc_db[i].poly_gamma_from_linear_x1, + POLY_GAMMA_DEGREE, POLY_GAMMA_SCALE); + break; + case BABL_TRC_SRGB: + trc_db[i].fun_to_linear = _babl_trc_srgb_to_linear; + trc_db[i].fun_from_linear = _babl_trc_srgb_from_linear; + trc_db[i].fun_from_linear_buf = _babl_trc_srgb_from_linear_buf; + trc_db[i].fun_to_linear_buf = _babl_trc_srgb_to_linear_buf; + break; + case BABL_TRC_LUT: + trc_db[i].fun_to_linear = babl_trc_lut_to_linear; + trc_db[i].fun_from_linear = babl_trc_lut_from_linear; + break; + } + return (Babl*)&trc_db[i]; +} + +const Babl * +babl_trc_lut (const char *name, + int n, + float *entries) +{ + return babl_trc_new (name, BABL_TRC_LUT, 0, n, entries); +} + +void +babl_trc_class_for_each (BablEachFunction each_fun, + void *user_data) +{ + int i=0; + for (i = 0; trc_db[i].instance.class_type; i++) + if (each_fun (BABL (&trc_db[i]), user_data)) + return; +} + +const Babl * +babl_trc_formula_srgb (double g, + double a, + double b, + double c, + double d, + double e, + double f) +{ + char name[128]; + int i; + float params[7]={g, a, b, c, d, e, f}; + + if (fabs (g - 2.400) < 0.01 && + fabs (a - 0.947) < 0.01 && + fabs (b - 0.052) < 0.01 && + fabs (c - 0.077) < 0.01 && + fabs (d - 0.040) < 0.01 && + fabs (e - 0.000) < 0.01 && + fabs (f - 0.000) < 0.01 + ) + return babl_trc ("sRGB"); + + snprintf (name, sizeof (name), "%.6f %.6f %.4f %.4f %.4f %.4f %.4f", g, a, b, c, d, e, f); + for (i = 0; name[i]; i++) + if (name[i] == ',') name[i] = '.'; + while (name[strlen(name)-1]=='0') + name[strlen(name)-1]='\0'; + return babl_trc_new (name, BABL_TRC_FORMULA_SRGB, g, 0, params); +} + +const Babl * +babl_trc_formula_cie (double g, + double a, + double b, + double c) +{ + char name[128]; + int i; + float params[4]={g, a, b, c}; + + snprintf (name, sizeof (name), "%.6f %.6f %.4f %.4f", g, a, b, c); + for (i = 0; name[i]; i++) + if (name[i] == ',') name[i] = '.'; + while (name[strlen(name)-1]=='0') + name[strlen(name)-1]='\0'; + return babl_trc_new (name, BABL_TRC_FORMULA_CIE, g, 0, params); +} + + +const Babl * +babl_trc_gamma (double gamma) +{ + char name[32]; + int i; + if (fabs (gamma - 1.0) < 0.01) + return babl_trc_new ("linear", BABL_TRC_LINEAR, 1.0, 0, NULL); + + snprintf (name, sizeof (name), "%.6f", gamma); + for (i = 0; name[i]; i++) + if (name[i] == ',') name[i] = '.'; + while (name[strlen(name)-1]=='0') + name[strlen(name)-1]='\0'; + return babl_trc_new (name, BABL_TRC_FORMULA_GAMMA, gamma, 0, NULL); +} + +void +babl_trc_class_init (void) +{ + babl_trc_new ("sRGB", BABL_TRC_SRGB, 2.2, 0, NULL); + babl_trc_gamma (2.2); + babl_trc_gamma (1.8); + babl_trc_gamma (1.0); + babl_trc_new ("linear", BABL_TRC_LINEAR, 1.0, 0, NULL); +} + +#if 0 +float +babl_trc_from_linear (const Babl *trc_, + float value) +{ + return babl_trc_from_linear (trc_, value); +} + +float +babl_trc_to_linear (const Babl *trc_, + float value) +{ + return babl_trc_to_linear (trc_, value); +} +#endif + +static int +babl_lut_match_gamma (float *lut, + int lut_size, + float gamma) +{ + int match = 1; + int i; + if (lut_size > 1024) + { + for (i = 0; match && i < lut_size; i++) + { + if (fabs (lut[i] - pow ((i / (lut_size-1.0)), gamma)) > 0.0001) + match = 0; + } + } + else + { + for (i = 0; match && i < lut_size; i++) + { + if (fabs (lut[i] - pow ((i / (lut_size-1.0)), gamma)) > 0.001) + match = 0; + } + } + return match; +} + +const Babl * +babl_trc_lut_find (float *lut, + int lut_size) +{ + int i; + int match = 1; + + /* look for linear match */ + for (i = 0; match && i < lut_size; i++) + if (fabs (lut[i] - i / (lut_size-1.0)) > 0.015) + match = 0; + if (match) + return babl_trc_gamma (1.0); + + /* look for sRGB match: */ + match = 1; + if (lut_size > 1024) + { + for (i = 0; match && i < lut_size; i++) + { + if (fabs (lut[i] - gamma_2_2_to_linear (i / (lut_size-1.0))) > 0.0001) + match = 0; + } + } + else + { + for (i = 0; match && i < lut_size; i++) + { + if (fabs (lut[i] - gamma_2_2_to_linear (i / (lut_size-1.0))) > 0.001) + match = 0; + } + } + if (match) + return babl_trc ("sRGB"); + + if (babl_lut_match_gamma (lut, lut_size, 2.2)) + return babl_trc_gamma(2.2); + + if (babl_lut_match_gamma (lut, lut_size, 1.8)) + return babl_trc_gamma(1.8); + + return NULL; +} + diff --git a/babl/babl-trc.h b/babl/babl-trc.h new file mode 100644 index 0000000..cfe742c --- /dev/null +++ b/babl/babl-trc.h @@ -0,0 +1,107 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2017, Øyvind Kolås and others. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#ifndef _BABL_TRC_H +#define _BABL_TRC_H + +#include +#include +#include "base/util.h" +#include "babl-polynomial.h" + +BABL_CLASS_DECLARE (trc); + +typedef enum {BABL_TRC_LINEAR, + BABL_TRC_FORMULA_GAMMA, + BABL_TRC_SRGB, + BABL_TRC_FORMULA_SRGB, + BABL_TRC_LUT, + BABL_TRC_FORMULA_CIE} +BablTRCType; + +typedef struct +{ + BablInstance instance; + BablTRCType type; + int lut_size; + double gamma; + float rgamma; + float (*fun_to_linear)(const Babl *trc, float val); + float (*fun_from_linear)(const Babl *trc, float val); + + void (*fun_to_linear_buf)(const Babl *trc, + const float *in, + float *out, + int in_gap, + int out_gap, + int components, + int count); + void (*fun_from_linear_buf)(const Babl *trc, + const float *in, + float *out, + int in_gap, + int out_gap, + int components, + int count); + BablPolynomial poly_gamma_to_linear; + float poly_gamma_to_linear_x0; + float poly_gamma_to_linear_x1; + BablPolynomial poly_gamma_from_linear; + float poly_gamma_from_linear_x0; + float poly_gamma_from_linear_x1; + float *lut; + float *inv_lut; + char name[128]; +} BablTRC; + +static inline void babl_trc_from_linear_buf (const Babl *trc_, + const float *in, float *out, + int in_gap, int out_gap, + int components, + int count) +{ + BablTRC *trc = (void*)trc_; + trc->fun_from_linear_buf (trc_, in, out, in_gap, out_gap, components, count); +} + +static inline void babl_trc_to_linear_buf (const Babl *trc_, + const float *in, float *out, + int in_gap, int out_gap, + int components, + int count) +{ + BablTRC *trc = (void*)trc_; + trc->fun_to_linear_buf (trc_, in, out, in_gap, out_gap, components, count); +} + +static inline float babl_trc_from_linear (const Babl *trc_, float value) +{ + BablTRC *trc = (void*)trc_; + return trc->fun_from_linear (trc_, value); +} + +static inline float babl_trc_to_linear (const Babl *trc_, float value) +{ + BablTRC *trc = (void*)trc_; + return trc->fun_to_linear (trc_, value); +} + +void +babl_trc_class_init (void); + +#endif diff --git a/babl/babl-type.c b/babl/babl-type.c new file mode 100644 index 0000000..c079828 --- /dev/null +++ b/babl/babl-type.c @@ -0,0 +1,248 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include +#include +#include + +#define NEEDS_BABL_DB +#include "babl-internal.h" +#include "babl-db.h" +#include "babl-ref-pixels.h" + +static int +babl_type_destroy (void *data) +{ + Babl *babl = data; + if (babl->type.from_list) + babl_free (babl->type.from_list); + return 0; +} + +static Babl * +type_new (const char *name, + int id, + int bits, + const char *doc) +{ + Babl *babl; + + babl_assert (bits != 0); + babl_assert (bits % 8 == 0); + + babl = babl_malloc (sizeof (BablType) + strlen (name) + 1); + babl_set_destructor (babl, babl_type_destroy); + babl->instance.name = (void *) ((char *) babl + sizeof (BablType)); + babl->class_type = BABL_TYPE; + babl->instance.id = id; + babl->instance.doc = doc; + strcpy (babl->instance.name, name); + babl->type.bits = bits; + babl->type.from_list = NULL; + + return babl; +} + +static int +is_type_duplicate (Babl *babl, + int bits) +{ + if (babl->type.bits != bits) + return 0; + + return 1; +} + +const Babl * +babl_type_new (void *first_arg, + ...) +{ + va_list varg; + Babl *babl; + int id = 0; + int bits = 0; + const char *name = first_arg; + const char *arg; + const char *doc = NULL; + + va_start (varg, first_arg); + + while (1) + { + arg = va_arg (varg, char *); + if (!arg) + break; + + /* first, we assume arguments to be strings */ + else if (!strcmp (arg, "id")) + { + id = va_arg (varg, int); + } + + else if (!strcmp (arg, "bits")) + { + bits = va_arg (varg, int); + } + else if (!strcmp (arg, "integer")) + { + (void) va_arg (varg, int); + } + else if (!strcmp (arg, "min")) + { + (void) va_arg (varg, long); + } + else if (!strcmp (arg, "doc")) + { + doc = va_arg (varg, const char*); + } + else if (!strcmp (arg, "max")) + { + (void) va_arg (varg, long); + } + else if (!strcmp (arg, "min_val")) + { + (void) va_arg (varg, double); + } + else if (!strcmp (arg, "max_val")) + { + (void) va_arg (varg, double); + } + + /* if we didn't point to a known string, we assume argument to be babl */ + else if (BABL_IS_BABL (arg)) + { +#ifdef BABL_LOG + Babl *babl = (Babl *) arg; + + babl_log ("%s unexpected", babl_class_name (babl->class_type)); +#endif + } + else + { + babl_fatal ("unhandled argument '%s' for format '%s'", arg, name); + } + } + + va_end (varg); + + babl = babl_db_exist (db, id, name); + if (id && !babl && babl_db_exist (db, 0, name)) + babl_fatal ("Trying to reregister BablType '%s' with different id!", name); + + if (babl) + { + /* There is an instance already registered by the required id/name, + * returning the preexistent one instead if it doesn't differ. + */ + if (!is_type_duplicate (babl, bits)) + babl_fatal ("BablType '%s' already registered " + "as different type!", name); + + return babl; + } + + babl = type_new (name, id, bits, doc); + + /* Since there is not an already registered instance by the required + * id/name, inserting newly created class into database. + */ + babl_db_insert (db, babl); + return babl; +} + + +#define TOLERANCE 0.000000001 + +static const Babl * +double_vector_format (void) +{ + static const Babl *self = NULL; + + if (!self) + self = babl_format_new ( + babl_model ("Y"), + babl_type ("double"), + babl_component ("Y"), + NULL); + return self; +} + +int +babl_type_is_symmetric (const Babl *babl) +{ + int is_symmetrical = 1; + void *original; + double *clipped; + void *destination; + double *transformed; + + const Babl *ref_fmt; + const Babl *fmt; + Babl *fish_to; + Babl *fish_from; + + const int samples = babl_get_num_type_test_pixels (); + const double *test_pixels = babl_get_type_test_pixels (); + + ref_fmt = double_vector_format (); + fmt = babl_format_new (babl_model ("Y"), + babl, + babl_component ("Y"), + NULL); + fish_to = babl_fish_reference (ref_fmt, fmt); + fish_from = babl_fish_reference (fmt, ref_fmt); + + original = babl_calloc (1, babl->type.bits / 8 * samples); + clipped = babl_calloc (1, 64 / 8 * samples); + destination = babl_calloc (1, babl->type.bits / 8 * samples); + transformed = babl_calloc (1, 64 / 8 * samples); + + babl_process (fish_to, test_pixels, original, samples); + babl_process (fish_from, original, clipped, samples); + babl_process (fish_to, clipped, destination, samples); + babl_process (fish_from, destination, transformed, samples); + + fish_from->fish.pixels -= samples * 2; + fish_to->fish.pixels -= samples * 2; + + { + int cnt = 0; + int i; + for (i = 0; i < samples; i++) + { + if (fabs (clipped[i] - transformed[i]) > TOLERANCE) + { + if (cnt++ < 4) + babl_log ("%s: %f %f %f)", + babl->instance.name, test_pixels[i], clipped[i], transformed[i] + ); + is_symmetrical = 0; + } + } + } + + babl_free (original); + babl_free (clipped); + babl_free (destination); + babl_free (transformed); + + return is_symmetrical; +} + +BABL_CLASS_IMPLEMENT (type) diff --git a/babl/babl-type.h b/babl/babl-type.h new file mode 100644 index 0000000..fb451c5 --- /dev/null +++ b/babl/babl-type.h @@ -0,0 +1,50 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005-2008, Øyvind Kolås and others. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#ifndef _BABL_TYPE_H +#define _BABL_TYPE_H + +BABL_CLASS_DECLARE (type); + +typedef struct +{ + BablInstance instance; + BablList *from_list; + int bits; /*< number of bits used to represent the data type + (initially restricted to a multiple of 8) */ + double min_val; + double max_val; +} BablType; + +typedef struct +{ + BablType type; + int is_signed; + long max; + long min; +} BablTypeInteger; + +typedef struct +{ + BablType type; + /* sign + * biased_exponent + * mantissa */ +} BablTypeFloat; + +#endif diff --git a/babl/babl-types.h b/babl/babl-types.h new file mode 100644 index 0000000..4fc1b1a --- /dev/null +++ b/babl/babl-types.h @@ -0,0 +1,55 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005-2008, Øyvind Kolås and others. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#ifndef _BABL_TYPES_H +#define _BABL_TYPES_H + +#if !defined(BABL_INSIDE_BABL_H) && !defined(BABL_IS_BEING_COMPILED) +#error "babl-types.h must not be included directly, include babl.h instead." +#endif + +/** + * Babl: + * + * The babl API is based around polymorphism and almost everything is + * a Babl object. + **/ +typedef union _Babl Babl; + + +/* Conversion function between linear data of a either a data types or + * color formats. + */ +typedef void (*BablFuncLinear) (const Babl *conversion, + const char *src, + char *dst, + long n, + void *user_data); + +/* TypePlanar,ModelPlanar and FormatPlanar */ +typedef void (*BablFuncPlanar) (const Babl *conversion, + int src_bands, + const char *src[], + int src_pitch[], + int dst_bands, + char *dst[], + int dst_pitch[], + long n, + void *user_data); + +#endif diff --git a/babl/babl-util.c b/babl/babl-util.c new file mode 100644 index 0000000..cab9ab1 --- /dev/null +++ b/babl/babl-util.c @@ -0,0 +1,150 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include +#include "babl-internal.h" + +#ifdef __WIN32__ +#include +#else +#include +#include +#endif + +#ifdef __WIN32__ +static LARGE_INTEGER start_time; +static LARGE_INTEGER timer_freq; + +static void +init_ticks (void) +{ + static int done = 0; + + if (done) + return; + done = 1; + + QueryPerformanceCounter(&start_time); + QueryPerformanceFrequency(&timer_freq); +} + +long +babl_ticks (void) +{ + LARGE_INTEGER end_time; + + init_ticks (); + + QueryPerformanceCounter(&end_time); + return (end_time.QuadPart - start_time.QuadPart) * (1000000.0 / timer_freq.QuadPart); +} +#else +static struct timeval start_time; + +#define usecs(time) ((time.tv_sec - start_time.tv_sec) * 1000000 + time.tv_usec) + +static void +init_ticks (void) +{ + static int done = 0; + + if (done) + return; + done = 1; + gettimeofday (&start_time, NULL); +} + +long +babl_ticks (void) +{ + struct timeval measure_time; + init_ticks (); + gettimeofday (&measure_time, NULL); + return usecs (measure_time) - usecs (start_time); +} +#endif + +double +babl_rel_avg_error (const double *imgA, + const double *imgB, + long samples) +{ + double error = 0.0; + long i; + + for (i = 0; i < samples; i++) + error += fabs (imgA[i] - imgB[i]); + + if (error >= 0.0000001) + error /= samples; + else if (error <= 0.0) + error = 0.0; + else + error = M_PI; + + return error; +} + +int +_babl_file_get_contents (const char *path, + char **contents, + long *length, + void *error) +{ + FILE *file; + long size; + char *buffer; + + file = fopen (path,"rb"); + + if (!file) + return -1; + + if (fseek (file, 0, SEEK_END) == -1 || (size = ftell (file)) == -1) + { + fclose (file); + return -1; + } + if (length) *length = size; + rewind (file); + if ((size_t) size > SIZE_MAX - 8) + { + fclose (file); + return -1; + } + buffer = calloc(size + 8, 1); + + if (!buffer) + { + fclose(file); + return -1; + } + + size -= fread (buffer, 1, size, file); + if (size) + { + fclose (file); + free (buffer); + return -1; + } + fclose (file); + *contents = buffer; + return 0; +} + diff --git a/babl/babl-util.h b/babl/babl-util.h new file mode 100644 index 0000000..9caec36 --- /dev/null +++ b/babl/babl-util.h @@ -0,0 +1,29 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#ifndef _BABL_UTIL_H +#define _BABL_UTIL_H + +long +babl_ticks (void); + +double +babl_rel_avg_error (const double *imgA, + const double *imgB, + long samples); +#endif diff --git a/babl/babl-version.c b/babl/babl-version.c new file mode 100644 index 0000000..9c757b5 --- /dev/null +++ b/babl/babl-version.c @@ -0,0 +1,36 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005-2008, Øyvind Kolås and others. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include "babl-internal.h" + + +void +babl_get_version (int *major, + int *minor, + int *micro) +{ + if (major != NULL) + *major = BABL_MAJOR_VERSION; + + if (minor != NULL) + *minor = BABL_MINOR_VERSION; + + if (micro != NULL) + *micro = BABL_MICRO_VERSION; +} diff --git a/babl/babl-version.h.in b/babl/babl-version.h.in new file mode 100644 index 0000000..305ac06 --- /dev/null +++ b/babl/babl-version.h.in @@ -0,0 +1,51 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005-2008, Øyvind Kolås and others. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#ifndef _BABL_VERSION_H +#define _BABL_VERSION_H + +#if !defined(BABL_INSIDE_BABL_H) && !defined(BABL_IS_BEING_COMPILED) +#error "babl-version.h must not be included directly, include babl.h instead." +#endif + + +/*** + * babl version information + * + * These macros tell the version of babl you are compiling against. + * babl's version number consists of three parts: major, minor and + * micro. + */ + +#define BABL_MAJOR_VERSION @BABL_MAJOR_VERSION@ +#define BABL_MINOR_VERSION @BABL_MINOR_VERSION@ +#define BABL_MICRO_VERSION @BABL_MICRO_VERSION@ + +/** + * babl_get_version: + * @major: (out): The major version number + * @minor: (out): The minor version number + * @micro: (out): The micro version number + * + * Get the version information on the babl library + */ +void babl_get_version (int *major, + int *minor, + int *micro); + +#endif diff --git a/babl/babl.c b/babl/babl.c new file mode 100644 index 0000000..fd90323 --- /dev/null +++ b/babl/babl.c @@ -0,0 +1,192 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include "babl-internal.h" + +static int ref_count = 0; + +#ifdef _WIN32 +static HMODULE libbabl_dll = NULL; + +/* Minimal DllMain that just stores the handle to this DLL */ + +/* Avoid silly "no previous prototype" gcc warning */ +BOOL WINAPI +DllMain (HINSTANCE hinstDLL, + DWORD fdwReason, + LPVOID lpvReserved); + +BOOL WINAPI +DllMain (HINSTANCE hinstDLL, + DWORD fdwReason, + LPVOID lpvReserved) +{ + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + libbabl_dll = hinstDLL; + break; + } + + return TRUE; +} + +#else +#define BABL_PATH LIBDIR BABL_DIR_SEPARATOR BABL_LIBRARY +#endif /* _WIN32 */ + +/* + * Returns a list of directories if the environment variable $BABL_PATH + * is set, or the installation library directory by default. + * This directory will be based on the compilation-time prefix for UNIX + * and an actual DLL path for Windows. + * + * Returns: a string which must be freed after usage. + */ +static char * +babl_dir_list (void) +{ + char *ret; + + ret = getenv ("BABL_PATH"); + if (!ret) + { +#ifdef _WIN32 + /* Figure it out from the location of this DLL */ + char *filename; + int filename_size; + char *sep1, *sep2; + + wchar_t w_filename[MAX_PATH]; + DWORD nSize = sizeof (w_filename) / sizeof ((w_filename)[0]); + + if (GetModuleFileNameW (libbabl_dll, w_filename, nSize) == 0) + babl_fatal ("GetModuleFilenameW failed"); + + filename_size = WideCharToMultiByte (CP_UTF8, 0, w_filename, -1, NULL, 0, + NULL, NULL); + filename = babl_malloc (sizeof (char) * filename_size); + if (!WideCharToMultiByte (CP_UTF8, 0, w_filename, -1, + filename, filename_size, NULL, NULL)) + babl_fatal ("Converting module filename to UTF-8 failed"); + + /* If the DLL file name is of the format + * \bin\*.dll, use \lib\{BABL_LIBRARY}. + * Otherwise, use the directory where the DLL is. + */ + + sep1 = strrchr (filename, BABL_DIR_SEPARATOR[0]); + *sep1 = '\0'; + + sep2 = strrchr (filename, BABL_DIR_SEPARATOR[0]); + if (sep2 != NULL) + { + if (strcasecmp (sep2 + 1, "bin") == 0) + { + char* filename_tmp; + *(++sep2) = '\0'; + filename_tmp = babl_malloc (sizeof (char) * (strlen (filename) + + strlen (BABL_DIR_SEPARATOR BABL_LIBRARY) + 4)); + strcpy (filename_tmp, filename); + babl_free (filename); + strcat (filename_tmp, "lib" BABL_DIR_SEPARATOR BABL_LIBRARY); + filename = filename_tmp; + } + } + + ret = filename; +#else + ret = babl_malloc (sizeof (char) * (strlen (BABL_PATH) + 1)); + strcpy (ret, BABL_PATH); +#endif + } + else + { + char* ret_tmp = babl_malloc (sizeof (char) * (strlen (ret) + 1)); + strcpy (ret_tmp, ret); + ret = ret_tmp; + } + return ret; +} + +void +babl_init (void) +{ + babl_cpu_accel_set_use (1); + + if (ref_count++ == 0) + { + char * dir_list; + + babl_internal_init (); + babl_sampling_class_init (); + babl_type_db (); + babl_trc_class_init (); + babl_space_class_init (); + babl_component_db (); + babl_model_db (); + babl_format_db (); + babl_conversion_db (); + babl_extension_db (); + babl_fish_db (); + babl_core_init (); + babl_sanity (); + babl_extension_base (); + babl_sanity (); + + dir_list = babl_dir_list (); + babl_extension_load_dir_list (dir_list); + babl_free (dir_list); + + babl_init_db (); + } +} + +void +babl_exit (void) +{ + if (!-- ref_count) + { + babl_store_db (); + + babl_extension_deinit (); + babl_free (babl_extension_db ());; + babl_free (babl_fish_db ());; + babl_free (babl_conversion_db ());; + babl_free (babl_format_db ());; + babl_free (babl_model_db ());; + babl_free (babl_component_db ());; + babl_free (babl_type_db ());; + + babl_internal_destroy (); +#if BABL_DEBUG_MEM + babl_memory_sanity (); +#endif + } +} + +#undef babl_model_is + +int +babl_model_is (const Babl *babl, + const char *model) +{ + return babl && ((babl)==babl_model_with_space(model, babl)); +} + diff --git a/babl/babl.h b/babl/babl.h new file mode 100644 index 0000000..4032faa --- /dev/null +++ b/babl/babl.h @@ -0,0 +1,737 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005-2008, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#ifndef _BABL_H +#define _BABL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define BABL_INSIDE_BABL_H +#include +#include +#include +#undef BABL_INSIDE_BABL_H + + +/** + * babl_init: + * + * Initializes the babl library. + */ +void babl_init (void); + +/** + * babl_exit: + * + * Deinitializes the babl library and frees any resources used when + * matched with the number of calls to babl_init(). + */ +void babl_exit (void); + +/** + * babl_type: + * + * Returns the babl object representing the data type given by @name + * such as for example "u8", "u16" or "float". + */ +const Babl * babl_type (const char *name); + +/** + * babl_sampling: + * + * Returns the babl object representing the @horizontal and @vertical + * sampling such as for example 2, 2 for the chroma components in + * YCbCr. + */ +const Babl * babl_sampling (int horizontal, + int vertical); + + +/** + * babl_component: + * + * Returns the babl object representing the color component given by + * @name such as for example "R", "cyan" or "CIE L". + */ +const Babl * babl_component (const char *name); + +/** + * babl_model: + * + * Returns the babl object representing the color model given by @name + * such as for example "RGB", "CMYK" or "CIE Lab". + */ +const Babl * babl_model (const char *name); + +/** + * babl_model_with_space: + * + * The models for formats also have a space in babl, try to avoid code + * needing to use this. + */ +const Babl * +babl_model_with_space (const char *name, const Babl *space); + + +/** + * babl_space: + * + * Returns the babl object representing the specific RGB matrix color + * working space referred to by name. Babl knows of: + * sRGB, Rec2020, Adobish, Apple and ProPhoto + * + */ +const Babl * babl_space (const char *name); + +typedef enum { + BABL_ICC_INTENT_PERCEPTUAL = 0, + BABL_ICC_INTENT_RELATIVE_COLORIMETRIC = 1, + BABL_ICC_INTENT_SATURATION = 2, + BABL_ICC_INTENT_ABSOLUTE_COLORIMETRIC = 3, + BABL_ICC_INTENT_PERFORMANCE = 32 + // black-point compensation toggle will be added if/when support exist in babl +} BablIccIntent; + +/** + * babl_space_from_icc: + * @icc_data: pointer to icc profile in memory + * @icc_length: length of icc profile in bytes + * @intent: the intent from the ICC profile to use. + * @error: (out): pointer to a string where decoding errors can be stored, + * if an error occurs, NULL is returned and an error message + * is provided in error. + * + * Create a babl space from an in memory ICC profile, the profile does no + * longer need to be loaded for the space to work, multiple calls with the same + * icc profile and same intent will result in the same babl space. + * + * On a profile that doesn't contain A2B0 and B2A0 CLUTs perceptual and + * relative-colorimetric intents are treated the same. + * + * If a BablSpace cannot be created from the profile NULL is returned and a + * static string is set on the const char *value pointed at with &value + * containing a message describing why the provided data does not yield a babl + * space. + */ +const Babl *babl_space_from_icc (const char *icc_data, + int icc_length, + BablIccIntent intent, + const char **error); +/* babl_space_get_gamma: + * @space: a babl space + * + * Returns the gamma of the TRCs of the space, iff they are all equal + * and a simple gamma number, otherwise 0.0 is returned. + */ +double +babl_space_get_gamma (const Babl *space); + +// XXX : deprecated +const Babl *babl_icc_make_space (const char *icc_data, + int icc_length, + BablIccIntent intent, + const char **error); + + +/* babl_icc_get_key: + * + * @icc_data: pointer to in-memory icc profile + * @icc_length: length of icc profile in bytes + * @key: the key we want to quey, see below for some supported values + * @language: 2 char code for language to extract or NULL + * @country: 2 char country code or NULL + * + * Returns: (transfer full) (nullable): %NULL if key not found or a newly + * allocated utf8 string of the key when found, free with free() when done. + * Supported keys: "description", "copyright", "manufacturer", "device", + * "profile-class", "color-space" and "pcs". + */ + +char *babl_icc_get_key (const char *icc_data, + int icc_length, + const char *key, + const char *language, + const char *country); + + +/** + * babl_format: + * + * Returns the babl object representing the color format given by + * @name such as for example "RGB u8", "CMYK float" or "CIE Lab u16", + * creates a format using the sRGB space, to also specify the color space + * and TRCs for a format, see babl_format_with_space. + */ +const Babl * babl_format (const char *encoding); + +/** + * babl_format_with_space: + * + * Returns the babl object representing the color format given by + * @name such as for example "RGB u8", "R'G'B'A float", "Y float" with + * a specific RGB working space used as the space, the resulting format + * has -space suffixed to it, unless the space requested is sRGB then + * the unsuffixed version is used. If a format is passed in as space + * the space of the format is used. + */ +const Babl * babl_format_with_space (const char *encoding, const Babl *space); + +/** + * babl_format_exists: + * + * Returns 1 if the provided format name is known by babl or 0 if it is + * not. Can also be used to verify that specific extension formats are + * available (though this can also be inferred from the version of babl). + */ +int babl_format_exists (const char *name); + +/* + * babl_format_get_space: + * + * Retrieve the RGB color space used for a pixel format. + */ +const Babl * babl_format_get_space (const Babl *format); + + +/** + * babl_fish: + * + * Create a babl fish capable of converting from source_format to + * destination_format, source and destination can be either strings + * with the names of the formats or Babl-format objects. + */ +const Babl * babl_fish (const void *source_format, + const void *destination_format); + + +/** + * babl_fast_fish: + * + * Create a faster than normal fish with specified performance (and thus + * corresponding precision tradeoff), values tolerance can hold: NULL and + * "default", means do same as babl_fish(), other values understood in + * increasing order of speed gain are: + * "exact" "precise" "fast" "glitch" + * + * Fast fishes should be cached, since they are not internally kept track + * of/made into singletons by babl and many creations of fast fishes will + * otherwise be a leak. + * + */ +const Babl * babl_fast_fish (const void *source_format, + const void *destination_format, + const char *performance); + +/** + * babl_process: + * + * Process n pixels from source to destination using babl_fish, + * returns number of pixels converted. + */ +long babl_process (const Babl *babl_fish, + const void *source, + void *destination, + long n); + + +long babl_process_rows (const Babl *babl_fish, + const void *source, + int source_stride, + void *dest, + int dest_stride, + long n, + int rows); + + +/** + * babl_get_name: + * + * Returns a string describing a Babl object. + */ +const char * babl_get_name (const Babl *babl); + +/** + * babl_format_has_alpha: + * + * Returns whether the @format has an alpha channel. + */ +int babl_format_has_alpha (const Babl *format); + +/** + * babl_format_get_bytes_per_pixel: + * + * Returns the bytes per pixel for a babl color format. + */ +int babl_format_get_bytes_per_pixel (const Babl *format); + +/** + * babl_format_get_model: + * + * Return the model used for constructing the format. + */ +const Babl * babl_format_get_model (const Babl *format); + + + +/** + * BablModelFlag + * @BABL_MODEL_FLAG_ALPHA: the model encodes alpha. + * @BABL_MODEL_FLAG_ASSOCIATED: the alpha is associated alpha. + * @BABL_MODEL_FLAG_INVERTED: the components are inverted (used for getting the additive complement space of CMYK). + * @BABL_MODEL_FLAG_LINEAR: the data has no TRC, i.e. is linear + * @BABL_MODEL_FLAG_NONLINEAR: the data has a TRC - the TRC from the configured space + * @BABL_MODEL_FLAG_PERCEPTUAL: the data has a TRC - a perceptual TRC where 50% gray is 0.5 + * @BABL_MODEL_FLAG_GRAY: this is a gray component model + * @BABL_MODEL_FLAG_RGB: this is an RGB based component model, the space associated is expected to contain an RGB matrix profile. + * @BABL_MODEL_FLAG_CIE: this model is part of the CIE family of spaces + * @BABL_MODEL_FLAG_CMYK: the encodings described are CMYK encodings, the space associated is expected to contain an CMYK ICC profile. + * + */ +typedef enum +{ + BABL_MODEL_FLAG_ALPHA = 1<<1, + BABL_MODEL_FLAG_ASSOCIATED = 1<<2, + BABL_MODEL_FLAG_INVERTED = 1<<3, + + BABL_MODEL_FLAG_LINEAR = 1<<10, + BABL_MODEL_FLAG_NONLINEAR = 1<<11, + BABL_MODEL_FLAG_PERCEPTUAL = 1<<12, + + BABL_MODEL_FLAG_GRAY = 1<<20, + BABL_MODEL_FLAG_RGB = 1<<21, + /* BABL_MODEL_FLAG_SPECTRAL = 1<<22, NYI */ + BABL_MODEL_FLAG_CIE = 1<<23, + BABL_MODEL_FLAG_CMYK = 1<<24, + /* BABL_MODEL_FLAG_LUZ = 1<<25, NYI */ +} BablModelFlag; + +// XXX : should warn when used +#define BABL_MODEL_FLAG_PREMULTIPLIED BABL_MODEL_FLAG_ASSOCIATED + +/* linear, nonlinear and perceptual could occupy two bits with a decidated 0, + * but we do not have a lack of bits in this bit pattern so leave it be. + */ + +BablModelFlag babl_get_model_flags (const Babl *model); + +/** + * babl_format_get_n_components: + * + * Returns the number of components for the given @format. + */ +int babl_format_get_n_components (const Babl *format); + +/** + * babl_format_get_type: + * + * Returns the type in the given @format for the given + * @component_index. + */ +const Babl * babl_format_get_type (const Babl *format, + int component_index); + + +/** + * babl_type_new: + * + * Defines a new data type in babl. A data type that babl can have in + * its buffers requires conversions to and from "double" to be + * registered before passing sanity. + * + * babl_type_new (const char *name, + * "bits", int bits, + * ["min_val", double min_val,] + * ["max_val", double max_val,] + * NULL); + */ +const Babl * babl_type_new (void *first_arg, + ...) BABL_ARG_NULL_TERMINATED; + +/** + * babl_component_new: + * + * Defines a new color component with babl. + * + * babl_component_new (const char *name, + * NULL); + */ +const Babl * babl_component_new (void *first_arg, + ...) BABL_ARG_NULL_TERMINATED; + +/** + * babl_model_new: + * + * Defines a new color model in babl. If no name is provided a name is + * generated by concatenating the name of all the involved components. + * + * babl_model_new (["name", const char *name,] + * BablComponent *component1, + * [BablComponent *componentN, ...] + * NULL); + */ +const Babl * babl_model_new (void *first_arg, + ...) BABL_ARG_NULL_TERMINATED; + +/** + * babl_format_new: + * + * Defines a new pixel format in babl. Provided BablType and|or + * BablSampling is valid for the following components as well. If no + * name is provided a (long) descriptive name is used. + * + * babl_format_new (["name", const char *name,] + * BablModel *model, + * [BablType *type,] + * [BablSampling, *sampling,] + * BablComponent *component1, + * [[BablType *type,] + * [BablSampling *sampling,] + * BablComponent *componentN, + * ...] + * ["planar",] + * NULL); + */ +const Babl * babl_format_new (const void *first_arg, + ...) BABL_ARG_NULL_TERMINATED; + +/* + * babl_format_n: + * + * Defines a new pixel format in babl. With the specified data storage + * type and the given number of components. At the moment behavior of + * conversions are only well defined to other babl_format_n derived formats + * with the same number of components. + */ +const Babl * +babl_format_n (const Babl *type, + int components); + +/** + * babl_format_is_format_n: + * + * Returns whether the @format is a format_n type. + */ +int babl_format_is_format_n (const Babl *format); + +/** + * babl_conversion_new: + * + * Defines a new conversion between either two formats, two models or + * two types in babl. + * + * babl_conversion_new (, + * <"linear"|"planar">, conv_func, + * NULL); + */ +const Babl * babl_conversion_new (const void *first_arg, + ...) BABL_ARG_NULL_TERMINATED; + +/** + * babl_conversion_get_source_space: + * + * Returns the RGB space defined for the source of conversion. + */ +const Babl *babl_conversion_get_source_space (const Babl *conversion); + +/** + * babl_conversion_get_destination_space: + * + * Returns the RGB space defined for the destination of conversion. + */ +const Babl *babl_conversion_get_destination_space (const Babl *conversion); + +/** + * babl_new_palette: + * + * create a new palette based format, name is optional pass in NULL to get + * an anonymous format. If you pass in with_alpha the format also gets + * an 8bit alpha channel. Returns the BablModel of the color model. If + * you pass in the same name the previous formats will be provided + * again. + */ +const Babl *babl_new_palette (const char *name, + const Babl **format_u8, + const Babl **format_u8_with_alpha); + +/** + * babl_new_palette_with_space: + * + * create a new palette based format, name is optional pass in NULL to get + * an anonymous format. If you pass in with_alpha the format also gets + * an 8bit alpha channel. Returns the BablModel of the color model. If + * you pass in the same name the previous formats will be provided + * again. + */ +const Babl *babl_new_palette_with_space (const char *name, + const Babl *space, + const Babl **format_u8, + const Babl **format_u8_with_alpha); + +/** + * babl_format_is_palette: + * + * check whether a format is a palette backed format. + */ +int babl_format_is_palette (const Babl *format); + +/** + * babl_palette_set_palette: + * @babl: a #Babl + * @format: The pixel format + * @data: (array) (element-type guint8): The pixel data + * @count: The number of pixels in @data + * + * Assign a palette to a palette format, the data is a single span of pixels + * representing the colors of the palette. + */ +void babl_palette_set_palette (const Babl *babl, + const Babl *format, + void *data, + int count); + +/** + * babl_palette_reset: + * + * reset a palette to initial state, frees up some caches that optimize + * conversions. + */ +void babl_palette_reset (const Babl *babl); + + +/** + * babl_set_user_data: (skip) + * + * associate a data pointer with a format/model, this data can be accessed and + * used from the conversion functions, encoding color profiles, palettes or + * similar with the data, perhaps this should be made internal API, not + * accesible at all from + */ +void babl_set_user_data (const Babl *babl, void *data); + +/** + * babl_get_user_data: (skip) + * + * Get data set with babl_set_user_data + */ +void * babl_get_user_data (const Babl *babl); + +typedef enum { + BABL_SPACE_FLAG_NONE = 0, + BABL_SPACE_FLAG_EQUALIZE = 1 +} BablSpaceFlags; + +/** + * babl_space_from_chromaticities: + * @name: (nullable): The name for the color space + * @wx: The X-coordinate of the color space's white point + * @wy: The Y-coordinate of the color space's white point + * @rx: The X-coordinate of the red primary + * @ry: The Y-coordinate of the red primary + * @gx: The X-coordinate of the green primary + * @gy: The Y-coordinate of the green primary + * @bx: The X-coordinate of the blue primary + * @by: The Y-coordinate of the blue primary + * @trc_red: The red component of the TRC. + * @trc_green: (nullable): The green component of the TRC (can be %NULL if it's + * the same as @trc_red). + * @trc_blue: (nullable): The blue component of the TRC (can be %NULL if it's + * the same as @trc_red). + * @flags: The #BablSpaceFlags + * + * Creates a new babl-space/ RGB matrix color space definition with the + * specified CIE xy(Y) values for white point: wx, wy and primary + * chromaticities: rx,ry,gx,gy,bx,by and TRCs to be used. After registering a + * new babl-space it can be used with babl_space() passing its name; + * + * Internally this does the math to derive the RGBXYZ matrix as used in an ICC + * profile. + */ +const Babl * babl_space_from_chromaticities (const char *name, + double wx, double wy, + double rx, double ry, + double gx, double gy, + double bx, double by, + const Babl *trc_red, + const Babl *trc_green, + const Babl *trc_blue, + BablSpaceFlags flags); + + +/** + * babl_trc_gamma: + * + * Creates a Babl TRC for a specific gamma value, it will be given + * a name that is a short string representation of the value. + */ +const Babl * babl_trc_gamma (double gamma); + +/** + * babl_trc: + * + * Look up a TRC by name, "sRGB" and "linear" are recognized + * strings in a stock babl configuration. + */ +const Babl * babl_trc (const char *name); + +/** + * babl_space_with_trc: + * + * Creates a variant of an existing space with different trc. + */ +const Babl *babl_space_with_trc (const Babl *space, const Babl *trc); + +/** + * babl_space_get: + * @space: A #Babl instance + * @xw: (out) (optional): The X-coordinate of the color space's white point + * @yw: (out) (optional): The Y-coordinate of the color space's white point + * @xr: (out) (optional): The X-coordinate of the red primary + * @yr: (out) (optional): The Y-coordinate of the red primary + * @xg: (out) (optional): The X-coordinate of the blue primary + * @yg: (out) (optional): The Y-coordinate of the green primary + * @xb: (out) (optional): The X-coordinate of the blue primary + * @yb: (out) (optional): The Y-coordinate of the blue primary + * @red_trc: (out) (optional): The red component of the TRC. + * @green_trc: (out) (optional): The green component of the TRC (can be %NULL + * if it's the same as @red_trc). + * @blue_trc: (out) (optional): The blue component of the TRC (can be %NULL if + * it's the same as @red_trc). + * + * query the chromaticities of white point and primaries as well as trcs + * used for r g a nd b, all arguments are optional (can be %NULL). + */ +void babl_space_get (const Babl *space, + double *xw, double *yw, + double *xr, double *yr, + double *xg, double *yg, + double *xb, double *yb, + const Babl **red_trc, + const Babl **green_trc, + const Babl **blue_trc); + +/** + * babl_space_get_rgb_luminance: + * @space: a BablSpace + * @red_luminance: (out) (optional): Location for the red luminance factor. + * @green_luminance: (out) (optional): Location for the green luminance factor. + * @blue_luminance: (out) (optional): Location for the blue luminance factor. + * + * Retrieve the relevant RGB luminance constants for a babl space. + */ +void +babl_space_get_rgb_luminance (const Babl *space, + double *red_luminance, + double *green_luminance, + double *blue_luminance); + +/** + * babl_model_is: + * + * Returns: 0 if the name of the model in babl does not correspond to the + * provided model name. + */ +int babl_model_is (const Babl *babl, const char *model_name); + +#define babl_model_is(babl,model) (babl&&(babl)==babl_model_with_space(model,babl)) + + +/** + * babl_space_get_icc: + * @babl: a #Babl + * @length: (out) (optional): Length of the profile in bytes. + * + * Return pointer to ICC profile for space note that this is + * the ICC profile for R'G'B', though in formats only supporting linear + * like EXR GEGL chooses to load this lienar data as RGB and use the sRGB + * TRC. + * + * Returns: pointer to ICC profile data. + */ +const char *babl_space_get_icc (const Babl *babl, int *length); + +/** + * babl_space_from_rgbxyz_matrix: + * @name: (nullable): The name for the color space + * @wx: The X-coordinate of the color space's white point + * @wy: The Y-coordinate of the color space's white point + * @wz: The Z-coordinate of the color space's white point + * @rx: The X-coordinate of the red primary + * @ry: The Y-coordinate of the red primary + * @rz: The Z-coordinate of the red primary + * @gx: The X-coordinate of the green primary + * @gy: The Y-coordinate of the green primary + * @gz: The Z-coordinate of the green primary + * @bx: The X-coordinate of the blue primary + * @by: The Y-coordinate of the blue primary + * @bz: The Z-coordinate of the blue primary + * @trc_red: The red component of the TRC. + * @trc_green: (nullable): The green component of the TRC (can be %NULL if it's + * the same as @trc_red). + * @trc_blue: (nullable): The blue component of the TRC (can be %NULL if it's + * the same as @trc_red). + * + * Creates a new RGB matrix color space definition using a precomputed D50 + * adapted 3x3 matrix and associated CIE XYZ whitepoint, as possibly read from + * an ICC profile. + */ +const Babl * +babl_space_from_rgbxyz_matrix (const char *name, + double wx, double wy, double wz, + double rx, double gx, double bx, + double ry, double gy, double by, + double rz, double gz, double bz, + const Babl *trc_red, + const Babl *trc_green, + const Babl *trc_blue); + +/** + * babl_format_get_encoding: + * + * Returns the components and data type, without space suffix. + */ +const char * babl_format_get_encoding (const Babl *babl); + +int babl_space_is_cmyk (const Babl *space); +int babl_space_is_gray (const Babl *space); + +/* values below this are stored associated with this value, it should also be + * used as a generic alpha zero epsilon in GEGL to keep the threshold effects + * on one known value. + */ +#define BABL_ALPHA_FLOOR (1/65536.0) +#define BABL_ALPHA_FLOOR_F (1/65536.0f) + +#ifdef __cplusplus +} +#endif + +#endif + +/* Trademarks: + * + * International Color Consortium is a registered trademarks of the. + * International Color Consortium. + * Apple is a trademark or registered trademark of Apple Inc in many countries. + * Adobish is meant to concisely convey resemblence/compatibility with Adobe + * RGB- without actualy being it, Adobe is a trademark or registered trademark + * of Adobe Systems Incorporated in many countires. + */ diff --git a/babl/base/babl-base.c b/babl/base/babl-base.c new file mode 100644 index 0000000..1d93341 --- /dev/null +++ b/babl/base/babl-base.c @@ -0,0 +1,75 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include "babl-base.h" + +extern int babl_hmpf_on_name_lookups; + +static void types (void); +static void models (void); + +void +babl_base_init (void) +{ + babl_hmpf_on_name_lookups++; + + types (); + models (); + babl_formats_init (); + + babl_hmpf_on_name_lookups--; +} + +void +babl_base_destroy (void) +{ + /* done by the destruction of the elemental babl clases */ +} + +/* + * types + */ + + +static void +types (void) +{ + babl_base_type_float (); + babl_base_type_u15 (); + babl_base_type_half (); + babl_base_type_u8 (); + babl_base_type_u16 (); + babl_base_type_u32 (); +} + +/* + * models + */ + + +static void +models (void) +{ + babl_hmpf_on_name_lookups--; + babl_base_model_rgb (); + babl_base_model_gray (); + babl_base_model_cmyk (); + babl_hmpf_on_name_lookups++; + babl_base_model_ycbcr (); +} diff --git a/babl/base/babl-base.h b/babl/base/babl-base.h new file mode 100644 index 0000000..64f1667 --- /dev/null +++ b/babl/base/babl-base.h @@ -0,0 +1,40 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#ifndef _BABL_BASE_H +#define _BABL_BASE_H + + +void babl_base_init (void); +void babl_base_destroy (void); +void babl_formats_init (void); + +void babl_base_type_half (void); +void babl_base_type_float (void); +void babl_base_type_u8 (void); +void babl_base_type_u16 (void); +void babl_base_type_u15 (void); +void babl_base_type_u32 (void); + +void babl_base_model_pal (void); +void babl_base_model_rgb (void); +void babl_base_model_cmyk (void); +void babl_base_model_gray (void); +void babl_base_model_ycbcr (void); + +#endif diff --git a/babl/base/formats.c b/babl/base/formats.c new file mode 100644 index 0000000..bad9d14 --- /dev/null +++ b/babl/base/formats.c @@ -0,0 +1,228 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2006, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include + +#include "babl-classes.h" +#include "babl.h" +#include "babl-ids.h" +#include "babl-base.h" + +void +babl_formats_init (void) +{ + const Babl *types[]={ + babl_type_from_id (BABL_DOUBLE), + babl_type_from_id (BABL_FLOAT), + babl_type_from_id (BABL_HALF), + babl_type_from_id (BABL_U8), + babl_type_from_id (BABL_U16), + babl_type_from_id (BABL_U32) + }; + for (int i = 0; i < sizeof (types)/sizeof(types[0]);i++) + { + const Babl *type = types[i]; + + babl_format_new ( + babl_model_from_id (BABL_RGBA_NONLINEAR_PREMULTIPLIED), + type, + babl_component_from_id (BABL_RED_NONLINEAR_MUL_ALPHA), + babl_component_from_id (BABL_GREEN_NONLINEAR_MUL_ALPHA), + babl_component_from_id (BABL_BLUE_NONLINEAR_MUL_ALPHA), + babl_component_from_id (BABL_ALPHA), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_RGBA_PERCEPTUAL_PREMULTIPLIED), + type, + babl_component_from_id (BABL_RED_PERCEPTUAL_MUL_ALPHA), + babl_component_from_id (BABL_GREEN_PERCEPTUAL_MUL_ALPHA), + babl_component_from_id (BABL_BLUE_PERCEPTUAL_MUL_ALPHA), + babl_component_from_id (BABL_ALPHA), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_RGBA_NONLINEAR), + type, + babl_component_from_id (BABL_RED_NONLINEAR), + babl_component_from_id (BABL_GREEN_NONLINEAR), + babl_component_from_id (BABL_BLUE_NONLINEAR), + babl_component_from_id (BABL_ALPHA), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_RGBA_PERCEPTUAL), + type, + babl_component_from_id (BABL_RED_PERCEPTUAL), + babl_component_from_id (BABL_GREEN_PERCEPTUAL), + babl_component_from_id (BABL_BLUE_PERCEPTUAL), + babl_component_from_id (BABL_ALPHA), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_RGB_NONLINEAR), + type, + babl_component_from_id (BABL_RED_NONLINEAR), + babl_component_from_id (BABL_GREEN_NONLINEAR), + babl_component_from_id (BABL_BLUE_NONLINEAR), + NULL); + babl_format_new ( + babl_model_from_id (BABL_RGB_NONLINEAR), + type, + babl_component_from_id (BABL_RED_NONLINEAR), + babl_component_from_id (BABL_GREEN_NONLINEAR), + babl_component_from_id (BABL_BLUE_NONLINEAR), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_RGB_PERCEPTUAL), + type, + babl_component_from_id (BABL_RED_PERCEPTUAL), + babl_component_from_id (BABL_GREEN_PERCEPTUAL), + babl_component_from_id (BABL_BLUE_PERCEPTUAL), + NULL); + babl_format_new ( + babl_model_from_id (BABL_RGB_PERCEPTUAL), + type, + babl_component_from_id (BABL_RED_PERCEPTUAL), + babl_component_from_id (BABL_GREEN_PERCEPTUAL), + babl_component_from_id (BABL_BLUE_PERCEPTUAL), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_MODEL_GRAY_NONLINEAR), + type, + babl_component_from_id (BABL_GRAY_NONLINEAR), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_MODEL_GRAY_PERCEPTUAL), + type, + babl_component_from_id (BABL_GRAY_PERCEPTUAL), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_MODEL_GRAY_NONLINEAR_ALPHA), + type, + babl_component_from_id (BABL_GRAY_NONLINEAR), + babl_component_from_id (BABL_ALPHA), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_MODEL_GRAY_PERCEPTUAL_ALPHA), + type, + babl_component_from_id (BABL_GRAY_PERCEPTUAL), + babl_component_from_id (BABL_ALPHA), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_MODEL_GRAY_PERCEPTUAL_ALPHA_PREMULTIPLIED), + type, + babl_component_from_id (BABL_GRAY_PERCEPTUAL_MUL_ALPHA), + babl_component_from_id (BABL_ALPHA), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_MODEL_GRAY_NONLINEAR_ALPHA_PREMULTIPLIED), + type, + babl_component_from_id (BABL_GRAY_NONLINEAR_MUL_ALPHA), + babl_component_from_id (BABL_ALPHA), + NULL); + + + babl_format_new ( + babl_model_from_id (BABL_RGBA), + type, + babl_component_from_id (BABL_RED), + babl_component_from_id (BABL_GREEN), + babl_component_from_id (BABL_BLUE), + babl_component_from_id (BABL_ALPHA), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_RGB), + type, + babl_component_from_id (BABL_RED), + babl_component_from_id (BABL_GREEN), + babl_component_from_id (BABL_BLUE), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_RGBA_PREMULTIPLIED), + type, + babl_component_from_id (BABL_RED_MUL_ALPHA), + babl_component_from_id (BABL_GREEN_MUL_ALPHA), + babl_component_from_id (BABL_BLUE_MUL_ALPHA), + babl_component_from_id (BABL_ALPHA), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_GRAY_ALPHA), + type, + babl_component_from_id (BABL_GRAY_LINEAR), + babl_component_from_id (BABL_ALPHA), + NULL); + babl_format_new ( + babl_model_from_id (BABL_GRAY_ALPHA_PREMULTIPLIED), + type, + babl_component_from_id (BABL_GRAY_LINEAR_MUL_ALPHA), + babl_component_from_id (BABL_ALPHA), + NULL); + babl_format_new ( + babl_model_from_id (BABL_GRAY), + type, + babl_component_from_id (BABL_GRAY_LINEAR), + NULL); + + } + + /* overriding name, since the generated name would be wrong due + * to differing types + */ + babl_format_new ( + "name", "Y'CbCr u8", + "planar", + babl_model_from_id (BABL_YCBCR), + babl_type_from_id (BABL_U8_LUMA), + babl_sampling (1, 1), + babl_component_from_id (BABL_GRAY_NONLINEAR), + babl_type_from_id (BABL_U8_CHROMA), + babl_sampling (2, 2), + babl_component_from_id (BABL_CB), + babl_sampling (2, 2), + babl_component_from_id (BABL_CR), + NULL); + babl_format_new ( + babl_model_from_id (BABL_YCBCR), + babl_type_from_id (BABL_FLOAT), + babl_component_from_id (BABL_GRAY_NONLINEAR), + babl_type_from_id (BABL_FLOAT), + babl_component_from_id (BABL_CB), + babl_component_from_id (BABL_CR), + NULL); + babl_format_new ( + babl_model_from_id (BABL_YCBCR_ALPHA), + babl_type_from_id (BABL_FLOAT), + babl_component_from_id (BABL_GRAY_NONLINEAR), + babl_type_from_id (BABL_FLOAT), + babl_component_from_id (BABL_CB), + babl_component_from_id (BABL_CR), + babl_component_from_id (BABL_ALPHA), + NULL); +} diff --git a/babl/base/meson.build b/babl/base/meson.build new file mode 100644 index 0000000..a78fd84 --- /dev/null +++ b/babl/base/meson.build @@ -0,0 +1,23 @@ +bablBaseInclude = include_directories('.') + +babl_base_sources = [ + 'babl-base.c', + 'formats.c', + 'model-cmyk.c', + 'model-gray.c', + 'model-rgb.c', + 'model-ycbcr.c', + 'pow-24.c', + 'type-float.c', + 'type-half.c', + 'type-u15.c', + 'type-u16.c', + 'type-u32.c', + 'type-u8.c', +] + +babl_base = static_library('babl_base', + babl_base_sources, + include_directories: [rootInclude, bablInclude], + dependencies: [math, lcms], +) diff --git a/babl/base/model-cmyk.c b/babl/base/model-cmyk.c new file mode 100644 index 0000000..13fdedf --- /dev/null +++ b/babl/base/model-cmyk.c @@ -0,0 +1,1183 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, 2018 Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +/* This file define the "cmy" and "cmyk" models and related formats these + * are CMYK formats withthe components stored so that 0 means full coverage + * and 1.0 means no coverage which makes additive compositing/blending work + * like as if it was RGB + + * conversions should be made with reference to the icc profile in the space + * using lcms2 for handling. + */ + +#include "config.h" + +#include +#include + +#include "babl-internal.h" +#include "babl-base.h" +#include "base/util.h" + + +static void +cmyka_to_cmykA (const Babl *conversion, + char *src, + char *dst, + long n) +{ + while (n--) + { + double cyan = ((double *) src)[0]; + double magenta = ((double *) src)[1]; + double yellow = ((double *) src)[2]; + double key = ((double *) src)[3]; + double alpha = ((double *) src)[4]; + double used_alpha = babl_epsilon_for_zero (alpha); + + ((double *) dst)[0] = (cyan) * used_alpha; + ((double *) dst)[1] = (magenta) * used_alpha; + ((double *) dst)[2] = (yellow) * used_alpha; + ((double *) dst)[3] = (key) * used_alpha; + ((double *) dst)[4] = alpha; + + src += 5 * sizeof (double); + dst += 5 * sizeof (double); + } +} + +static void +cmykA_to_cmyka (const Babl *conversion, + char *src, + char *dst, + long n) +{ + while (n--) + { + double alpha = ((double *) src)[4]; + double used_alpha = babl_epsilon_for_zero (alpha); + double ralpha = 1.0/used_alpha; + double cyan = ((double *) src)[0] * ralpha; + double magenta = ((double *) src)[1] * ralpha; + double yellow = ((double *) src)[2] * ralpha; + double key = ((double *) src)[3] * ralpha; + + ((double *) dst)[0] = cyan; + ((double *) dst)[1] = magenta; + ((double *) dst)[2] = yellow; + ((double *) dst)[3] = key; + ((double *) dst)[4] = alpha; + + src += 5 * sizeof (double); + dst += 5 * sizeof (double); + } +} + +static void +cmyk_to_cmyka (const Babl *conversion, + char *src, + char *dst, + long n) +{ + while (n--) + { + double cyan = ((double *) src)[0]; + double magenta = ((double *) src)[1]; + double yellow = ((double *) src)[2]; + double key = ((double *) src)[3]; + + ((double *) dst)[0] = cyan; + ((double *) dst)[1] = magenta; + ((double *) dst)[2] = yellow; + ((double *) dst)[3] = key; + ((double *) dst)[4] = 1.0; + + src += 4 * sizeof (double); + dst += 5 * sizeof (double); + } +} + +static void +cmyka_to_cmyk (const Babl *conversion, + char *src, + char *dst, + long n) +{ + while (n--) + { + double cyan = ((double *) src)[0]; + double magenta = ((double *) src)[1]; + double yellow = ((double *) src)[2]; + double key = ((double *) src)[3]; + + ((double *) dst)[0] = cyan; + ((double *) dst)[1] = magenta; + ((double *) dst)[2] = yellow; + ((double *) dst)[3] = key; + + src += 5 * sizeof (double); + dst += 4 * sizeof (double); + } +} + +///////////////////// +static void +cmyka_to_CMYKA (const Babl *conversion, + char *src, + char *dst, + long n) +{ + while (n--) + { + double cyan = ((double *) src)[0]; + double magenta = ((double *) src)[1]; + double yellow = ((double *) src)[2]; + double key = ((double *) src)[3]; + double alpha = ((double *) src)[4]; + double used_alpha = babl_epsilon_for_zero (alpha); + + ((double *) dst)[0] = (1.0-cyan) * used_alpha; + ((double *) dst)[1] = (1.0-magenta) * used_alpha; + ((double *) dst)[2] = (1.0-yellow) * used_alpha; + ((double *) dst)[3] = (1.0-key) * used_alpha; + ((double *) dst)[4] = alpha; + + src += 5 * sizeof (double); + dst += 5 * sizeof (double); + } +} + +static void +CMYKA_to_cmyka (const Babl *conversion, + char *src, + char *dst, + long n) +{ + while (n--) + { + double alpha = ((double *) src)[4]; + double used_alpha = babl_epsilon_for_zero (alpha); + double ralpha = 1.0 / used_alpha; + double cyan = ((double *) src)[0] * ralpha; + double magenta = ((double *) src)[1] * ralpha; + double yellow = ((double *) src)[2] * ralpha; + double key = ((double *) src)[3] * ralpha; + + ((double *) dst)[0] = 1.0-cyan; + ((double *) dst)[1] = 1.0-magenta; + ((double *) dst)[2] = 1.0-yellow; + ((double *) dst)[3] = 1.0-key; + ((double *) dst)[4] = alpha; + + src += 5 * sizeof (double); + dst += 5 * sizeof (double); + } +} + + + +static void +CMYK_to_cmyka (const Babl *conversion, + char *src, + char *dst, + long n) +{ + while (n--) + { + double cyan = ((double *) src)[0]; + double magenta = ((double *) src)[1]; + double yellow = ((double *) src)[2]; + double key = ((double *) src)[3]; + + ((double *) dst)[0] = 1.0-cyan; + ((double *) dst)[1] = 1.0-magenta; + ((double *) dst)[2] = 1.0-yellow; + ((double *) dst)[3] = 1.0-key; + ((double *) dst)[4] = 1.0; + + src += 4 * sizeof (double); + dst += 5 * sizeof (double); + } +} + +static void +cmyka_to_CMYK (const Babl *conversion, + char *src, + char *dst, + long n) +{ + while (n--) + { + double cyan = ((double *) src)[0]; + double magenta = ((double *) src)[1]; + double yellow = ((double *) src)[2]; + double key = ((double *) src)[3]; + + ((double *) dst)[0] = 1.0-cyan; + ((double *) dst)[1] = 1.0-magenta; + ((double *) dst)[2] = 1.0-yellow; + ((double *) dst)[3] = 1.0-key; + + src += 5 * sizeof (double); + dst += 4 * sizeof (double); + } +} + +static void +cmyka_to_CMYKa (const Babl *conversion, + char *src, + char *dst, + long n) +{ + while (n--) + { + double cyan = ((double *) src)[0]; + double magenta = ((double *) src)[1]; + double yellow = ((double *) src)[2]; + double key = ((double *) src)[3]; + double alpha = ((double *) src)[4]; + + ((double *) dst)[0] = 1.0-cyan; + ((double *) dst)[1] = 1.0-magenta; + ((double *) dst)[2] = 1.0-yellow; + ((double *) dst)[3] = 1.0-key; + ((double *) dst)[4] = alpha; + + src += 5 * sizeof (double); + dst += 5 * sizeof (double); + } +} + + + + + + + +#if 0 +static void +rgba_to_cmykA (const Babl *conversion, + char *src, + char *dst, + long n) +{ + while (n--) + { + double red = (((double *) src)[0]); + double green = (((double *) src)[1]); + double blue = (((double *) src)[2]); + double alpha = ((double *) src)[3]; + double used_alpha = babl_epsilon_for_zero (alpha); + + double cyan, magenta, yellow, key; + + double pullout = 1.0; + + cyan = 1.0 - red; + magenta = 1.0 - green; + yellow = 1.0 - blue; + + key = 1.0; + if (cyan < key) key = cyan; + if (magenta < key) key = magenta; + if (yellow < key) key = yellow; + + key *= pullout; + + if (key < 1.0) + { + cyan = (cyan - key) / (1.0 - key); + magenta = (magenta - key) / (1.0 - key); + yellow = (yellow - key) / (1.0 - key); + } + else + { + cyan = 0.0; + magenta = 0.0; + yellow = 0.0; + } + + ((double *) dst)[0] = (1.0-cyan) * used_alpha; + ((double *) dst)[1] = (1.0-magenta) * used_alpha; + ((double *) dst)[2] = (1.0-yellow) * used_alpha; + ((double *) dst)[3] = (1.0-key) * used_alpha; + ((double *) dst)[4] = alpha; + + src += 4 * sizeof (double); + dst += 5 * sizeof (double); + } +} + +static void +cmykA_to_rgba (const Babl *conversion, + char *src, + char *dst, + long n) +{ + while (n--) + { + double alpha = ((double *) src)[4]; + double used_alpha = babl_epsilon_for_zero (alpha); + double ralpha = 1.0 / used_alpha; + double cyanI = ((double *) src)[0] * ralpha; + double magentaI= ((double *) src)[1] * ralpha; + double yellowI = ((double *) src)[2] * ralpha; + double keyI = ((double *) src)[3] * ralpha; + + double cyan = 1.0-cyanI; + double magenta = 1.0-magentaI; + double yellow = 1.0-yellowI; + double key = 1.0-keyI; + + double red, green, blue; + + if (key < 1.0) + { + cyan = cyan * (1.0 - key) + key; + magenta = magenta * (1.0 - key) + key; + yellow = yellow * (1.0 - key) + key; + } + else + { + cyan = magenta = yellow = 1.0; + } + + red = 1.0 - cyan; + green = 1.0 - magenta; + blue = 1.0 - yellow; + + ((double *) dst)[0] = (red); + ((double *) dst)[1] = (green); + ((double *) dst)[2] = (blue); + ((double *) dst)[3] = alpha; + + src += 5 * sizeof (double); + dst += 4 * sizeof (double); + } +} + +static void +rgba_to_cmyka (const Babl *conversion, + char *src, + char *dst, + long n) +{ + while (n--) + { + double red = (((double *) src)[0]); + double green = (((double *) src)[1]); + double blue = (((double *) src)[2]); + double alpha = ((double *) src)[3]; + + double cyan, magenta, yellow, key; + + double pullout = 1.0; + + cyan = 1.0 - red; + magenta = 1.0 - green; + yellow = 1.0 - blue; + + key = 1.0; + if (cyan < key) key = cyan; + if (magenta < key) key = magenta; + if (yellow < key) key = yellow; + + key *= pullout; + + if (key < 1.0) + { + cyan = (cyan - key) / (1.0 - key); + magenta = (magenta - key) / (1.0 - key); + yellow = (yellow - key) / (1.0 - key); + } + else + { + cyan = 0.0; + magenta = 0.0; + yellow = 0.0; + } + + ((double *) dst)[0] = 1.0-cyan; + ((double *) dst)[1] = 1.0-magenta; + ((double *) dst)[2] = 1.0-yellow; + ((double *) dst)[3] = 1.0-key; + ((double *) dst)[4] = alpha; + + src += 4 * sizeof (double); + dst += 5 * sizeof (double); + } +} + +static void +cmyka_to_rgba (const Babl *conversion, + char *src, + char *dst, + long n) +{ + while (n--) + { + double cyan = 1.0-((double *) src)[0]; + double magenta = 1.0-((double *) src)[1]; + double yellow = 1.0-((double *) src)[2]; + double key = 1.0-((double *) src)[3]; + double alpha = ((double *) src)[4]; + + double red, green, blue; + + if (key < 1.0) + { + cyan = cyan * (1.0 - key) + key; + magenta = magenta * (1.0 - key) + key; + yellow = yellow * (1.0 - key) + key; + } + else + { + cyan = magenta = yellow = 1.0; + } + + red = 1.0 - cyan; + green = 1.0 - magenta; + blue = 1.0 - yellow; + + ((double *) dst)[0] = (red); + ((double *) dst)[1] = (green); + ((double *) dst)[2] = (blue); + ((double *) dst)[3] = alpha; + + src += 5 * sizeof (double); + dst += 4 * sizeof (double); + } +} + +static void +rgba_to_cmyk (const Babl *conversion, + char *src, + char *dst, + long n) +{ + while (n--) + { + double red = (((double *) src)[0]); + double green = (((double *) src)[1]); + double blue = (((double *) src)[2]); + + double cyan, magenta, yellow, key; + + double pullout = 1.0; + + cyan = 1.0 - red; + magenta = 1.0 - green; + yellow = 1.0 - blue; + + key = 1.0; + if (cyan < key) key = cyan; + if (magenta < key) key = magenta; + if (yellow < key) key = yellow; + + key *= pullout; + + if (key < 1.0) + { + cyan = (cyan - key) / (1.0 - key); + magenta = (magenta - key) / (1.0 - key); + yellow = (yellow - key) / (1.0 - key); + } + else + { + cyan = 0.0; + magenta = 0.0; + yellow = 0.0; + } + + ((double *) dst)[0] = 1.0-cyan; + ((double *) dst)[1] = 1.0-magenta; + ((double *) dst)[2] = 1.0-yellow; + ((double *) dst)[3] = 1.0-key; + + src += 4 * sizeof (double); + dst += 4 * sizeof (double); + } +} + +static void +cmyk_to_rgba (const Babl *conversion, + char *src, + char *dst, + long n) +{ + while (n--) + { + double cyan = 1.0-((double *) src)[0]; + double magenta = 1.0-((double *) src)[1]; + double yellow = 1.0-((double *) src)[2]; + double key = 1.0-((double *) src)[3]; + + double red, green, blue; + + if (key < 1.0) + { + cyan = cyan * (1.0 - key) + key; + magenta = magenta * (1.0 - key) + key; + yellow = yellow * (1.0 - key) + key; + } + else + { + cyan = magenta = yellow = 1.0; + } + + red = 1.0 - cyan; + green = 1.0 - magenta; + blue = 1.0 - yellow; + + ((double *) dst)[0] = (red); + ((double *) dst)[1] = (green); + ((double *) dst)[2] = (blue); + + ((double *) dst)[3] = 1.0; + + src += 4 * sizeof (double); + dst += 4 * sizeof (double); + } +} + +static void +rgba_to_cmy (const Babl *conversion, + char *src, + char *dst, + long n) +{ + while (n--) + { + double red = (((double *) src)[0]); + double green = (((double *) src)[1]); + double blue = (((double *) src)[2]); + + double cyan, magenta, yellow; + + cyan = 1.0 - red; + magenta = 1.0 - green; + yellow = 1.0 - blue; + + ((double *) dst)[0] = 1.0-cyan; + ((double *) dst)[1] = 1.0-magenta; + ((double *) dst)[2] = 1.0-yellow; + + src += 4 * sizeof (double); + dst += 3 * sizeof (double); + } +} + +static void +cmy_to_rgba (const Babl *conversion, + char *src, + char *dst, + long n) +{ + while (n--) + { + double cyan = 1.0-((double *) src)[0]; + double magenta = 1.0-((double *) src)[1]; + double yellow = 1.0-((double *) src)[2]; + + double red, green, blue; + + red = 1.0 - cyan; + green = 1.0 - magenta; + blue = 1.0 - yellow; + + ((double *) dst)[0] = (red); + ((double *) dst)[1] = (green); + ((double *) dst)[2] = (blue); + + ((double *) dst)[3] = 1.0; + + src += 3 * sizeof (double); + dst += 4 * sizeof (double); + } +} +#endif + +void +babl_base_model_cmyk (void) +{ + babl_component_new ("cyan", NULL); + babl_component_new ("yellow", NULL); + babl_component_new ("magenta", NULL); + babl_component_new ("key", NULL); + + + babl_component_new ("ca", NULL); + babl_component_new ("ma", NULL); + babl_component_new ("ya", NULL); + babl_component_new ("ka", NULL); + + + babl_component_new ("Cyan", NULL); + babl_component_new ("Yellow", NULL); + babl_component_new ("Magenta", NULL); + babl_component_new ("Key", NULL); + + + babl_component_new ("Ca", NULL); + babl_component_new ("Ma", NULL); + babl_component_new ("Yea", NULL); + babl_component_new ("Ka", NULL); + + babl_model_new ( + "name", "camayakaA", + babl_component ("ca"), + babl_component ("ma"), + babl_component ("ya"), + babl_component ("ka"), + babl_component ("A"), + "cmyk", + "inverted", + "alpha", + "associated", + NULL + ); + + babl_model_new ( + "name", "cmykA", + babl_component ("cyan"), + babl_component ("magenta"), + babl_component ("yellow"), + babl_component ("key"), + babl_component ("A"), + "cmyk", + "inverted", + "alpha", + NULL + ); + babl_model_new ( + "name", "cmyk", + babl_component ("cyan"), + babl_component ("magenta"), + babl_component ("yellow"), + babl_component ("key"), + "cmyk", + "inverted", + NULL + ); + + babl_model_new ( + "name", "CaMaYaKaA", + babl_component ("Ca"), + babl_component ("Ma"), + babl_component ("Yea"), + babl_component ("Ka"), + babl_component ("A"), + "cmyk", + "alpha", + "associated", + NULL + ); + + babl_model_new ( + "name", "CMYKA", + babl_component ("Cyan"), + babl_component ("Magenta"), + babl_component ("Yellow"), + babl_component ("Key"), + babl_component ("A"), + "cmyk", + "alpha", + NULL + ); + babl_model_new ( + "name", "CMYK", + babl_component ("Cyan"), + babl_component ("Magenta"), + babl_component ("Yellow"), + babl_component ("Key"), + "cmyk", + NULL + ); + + babl_conversion_new ( + babl_model ("cmykA"), + babl_model ("cmyk"), + "linear", cmyka_to_cmyk, + NULL + ); + babl_conversion_new ( + babl_model ("cmyk"), + babl_model ("cmykA"), + "linear", cmyk_to_cmyka, + NULL + ); + babl_conversion_new ( + babl_model ("cmykA"), + babl_model ("camayakaA"), + "linear", cmyka_to_cmykA, + NULL + ); + babl_conversion_new ( + babl_model ("camayakaA"), + babl_model ("cmykA"), + "linear", cmykA_to_cmyka, + NULL + ); + + babl_conversion_new ( + babl_model ("cmykA"), + babl_model ("CMYKA"), + "linear", cmyka_to_CMYKa, + NULL + ); + babl_conversion_new ( + babl_model ("CMYKA"), + babl_model ("cmykA"), + "linear", cmyka_to_CMYKa, // does the same job + NULL + ); + + + babl_conversion_new ( + babl_model ("cmykA"), + babl_model ("CMYK"), + "linear", cmyka_to_CMYK, + NULL + ); + babl_conversion_new ( + babl_model ("CMYK"), + babl_model ("cmykA"), + "linear", CMYK_to_cmyka, + NULL + ); + babl_conversion_new ( + babl_model ("cmykA"), + babl_model ("CaMaYaKaA"), + "linear", cmyka_to_CMYKA, + NULL + ); + babl_conversion_new ( + babl_model ("CaMaYaKaA"), + babl_model ("cmykA"), + "linear", CMYKA_to_cmyka, + NULL + ); + + + +#if 0 + + babl_conversion_new ( + babl_model ("RGBA"), + babl_model ("camayakaA"), + "linear", rgba_to_cmykA, + NULL + ); + babl_conversion_new ( + babl_model ("camayakaA"), + babl_model ("RGBA"), + "linear", cmykA_to_rgba, + NULL + ); + + babl_conversion_new ( + babl_model ("RGBA"), + babl_model ("cmykA"), + "linear", rgba_to_cmyka, + NULL + ); + babl_conversion_new ( + babl_model ("cmykA"), + babl_model ("RGBA"), + "linear", cmyka_to_rgba, + NULL + ); + babl_conversion_new ( + babl_model ("RGBA"), + babl_model ("cmyk"), + "linear", rgba_to_cmyk, + NULL + ); + babl_conversion_new ( + babl_model ("cmyk"), + babl_model ("RGBA"), + "linear", cmyk_to_rgba, + NULL + ); + babl_conversion_new ( + babl_model ("RGBA"), + babl_model ("cmy"), + "linear", rgba_to_cmy, + NULL + ); + babl_conversion_new ( + babl_model ("cmy"), + babl_model ("RGBA"), + "linear", cmy_to_rgba, + NULL + ); +#endif + + babl_format_new ( + "name", "camayakaA float", + babl_model ("camayakaA"), + babl_type ("float"), + babl_component ("ca"), + babl_component ("ma"), + babl_component ("ya"), + babl_component ("ka"), + babl_component ("A"), + NULL + ); + babl_format_new ( + "name", "cmykA float", + babl_model ("cmykA"), + babl_type ("float"), + babl_component ("cyan"), + babl_component ("magenta"), + babl_component ("yellow"), + babl_component ("key"), + babl_component ("A"), + NULL + ); + babl_format_new ( + "name", "cmyk float", + babl_model ("cmyk"), + babl_type ("float"), + babl_component ("cyan"), + babl_component ("magenta"), + babl_component ("yellow"), + babl_component ("key"), + NULL + ); + + babl_format_new ( + "name", "cmyk u8", + babl_model ("cmyk"), + babl_type ("u8"), + babl_component ("cyan"), + babl_component ("magenta"), + babl_component ("yellow"), + babl_component ("key"), + NULL + ); + babl_format_new ( + "name", "cmykA u8", + babl_model ("cmykA"), + babl_type ("u8"), + babl_component ("cyan"), + babl_component ("magenta"), + babl_component ("yellow"), + babl_component ("key"), + babl_component ("A"), + NULL + ); + + babl_format_new ( + "name", "cmyk u16", + babl_model ("cmyk"), + babl_type ("u16"), + babl_component ("cyan"), + babl_component ("magenta"), + babl_component ("yellow"), + babl_component ("key"), + NULL + ); + babl_format_new ( + "name", "cmykA u16", + babl_model ("cmykA"), + babl_type ("u16"), + babl_component ("cyan"), + babl_component ("magenta"), + babl_component ("yellow"), + babl_component ("key"), + babl_component ("A"), + NULL + ); + babl_format_new ( + "name", "cmyk u32", + babl_model ("cmyk"), + babl_type ("u32"), + babl_component ("cyan"), + babl_component ("magenta"), + babl_component ("yellow"), + babl_component ("key"), + NULL + ); + babl_format_new ( + "name", "cmykA u32", + babl_model ("cmykA"), + babl_type ("u32"), + babl_component ("cyan"), + babl_component ("magenta"), + babl_component ("yellow"), + babl_component ("key"), + babl_component ("A"), + NULL + ); + + babl_format_new ( + "name", "cmyk float", + babl_model ("cmyk"), + babl_type ("float"), + babl_component ("cyan"), + babl_component ("magenta"), + babl_component ("yellow"), + babl_component ("key"), + NULL + ); + babl_format_new ( + "name", "cmykA float", + babl_model ("cmykA"), + babl_type ("float"), + babl_component ("cyan"), + babl_component ("magenta"), + babl_component ("yellow"), + babl_component ("key"), + babl_component ("A"), + NULL + ); + + babl_format_new ( + "name", "cmyk half", + babl_model ("cmyk"), + babl_type ("half"), + babl_component ("cyan"), + babl_component ("magenta"), + babl_component ("yellow"), + babl_component ("key"), + NULL + ); + babl_format_new ( + "name", "cmykA half", + babl_model ("cmykA"), + babl_type ("half"), + babl_component ("cyan"), + babl_component ("magenta"), + babl_component ("yellow"), + babl_component ("key"), + babl_component ("A"), + NULL + ); + babl_format_new ( + "name", "camayakaA u16", + babl_model ("camayakaA"), + babl_type ("u16"), + babl_component ("ca"), + babl_component ("ma"), + babl_component ("ya"), + babl_component ("ka"), + babl_component ("A"), + NULL + ); + babl_format_new ( + "name", "camayakaA u8", + babl_model ("camayakaA"), + babl_type ("u8"), + babl_component ("ca"), + babl_component ("ma"), + babl_component ("ya"), + babl_component ("ka"), + babl_component ("A"), + NULL + ); + + babl_format_new ( + "name", "camayakaA half", + babl_model ("camayakaA"), + babl_type ("half"), + babl_component ("ca"), + babl_component ("ma"), + babl_component ("ya"), + babl_component ("ka"), + babl_component ("A"), + NULL + ); + + /********************************/ + babl_format_new ( + "name", "CaMaYaKaA float", + babl_model ("CaMaYaKaA"), + babl_type ("float"), + babl_component ("Ca"), + babl_component ("Ma"), + babl_component ("Ya"), + babl_component ("Ka"), + babl_component ("A"), + NULL + ); + babl_format_new ( + "name", "CMYKA float", + babl_model ("CMYKA"), + babl_type ("float"), + babl_component ("Cyan"), + babl_component ("Magenta"), + babl_component ("Yellow"), + babl_component ("Key"), + babl_component ("A"), + NULL + ); + babl_format_new ( + "name", "CMYK float", + babl_model ("CMYK"), + babl_type ("float"), + babl_component ("Cyan"), + babl_component ("Magenta"), + babl_component ("Yellow"), + babl_component ("Key"), + NULL + ); + babl_format_new ( + "name", "CMYKA half", + babl_model ("CMYKA"), + babl_type ("half"), + babl_component ("Cyan"), + babl_component ("Magenta"), + babl_component ("Yellow"), + babl_component ("Key"), + babl_component ("A"), + NULL + ); + babl_format_new ( + "name", "CMYK half", + babl_model ("CMYK"), + babl_type ("half"), + babl_component ("Cyan"), + babl_component ("Magenta"), + babl_component ("Yellow"), + babl_component ("Key"), + NULL + ); + + babl_format_new ( + "name", "CMYK u8", + babl_model ("CMYK"), + babl_type ("u8"), + babl_component ("Cyan"), + babl_component ("Magenta"), + babl_component ("Yellow"), + babl_component ("Key"), + NULL + ); + babl_format_new ( + "name", "CMYKA u8", + babl_model ("CMYKA"), + babl_type ("u8"), + babl_component ("Cyan"), + babl_component ("Magenta"), + babl_component ("Yellow"), + babl_component ("Key"), + babl_component ("A"), + NULL + ); + + babl_format_new ( + "name", "CMYK u16", + babl_model ("CMYK"), + babl_type ("u16"), + babl_component ("Cyan"), + babl_component ("Magenta"), + babl_component ("Yellow"), + babl_component ("Key"), + NULL + ); + babl_format_new ( + "name", "CMYKA u16", + babl_model ("CMYKA"), + babl_type ("u16"), + babl_component ("Cyan"), + babl_component ("Magenta"), + babl_component ("Yellow"), + babl_component ("Key"), + babl_component ("A"), + NULL + ); + babl_format_new ( + "name", "CMYK u32", + babl_model ("CMYK"), + babl_type ("u32"), + babl_component ("Cyan"), + babl_component ("Magenta"), + babl_component ("Yellow"), + babl_component ("Key"), + NULL + ); + babl_format_new ( + "name", "CMYKA u32", + babl_model ("CMYKA"), + babl_type ("u32"), + babl_component ("Cyan"), + babl_component ("Magenta"), + babl_component ("Yellow"), + babl_component ("Key"), + babl_component ("A"), + NULL + ); + + babl_format_new ( + "name", "CMYK float", + babl_model ("CMYK"), + babl_type ("float"), + babl_component ("Cyan"), + babl_component ("Magenta"), + babl_component ("Yellow"), + babl_component ("Key"), + NULL + ); + babl_format_new ( + "name", "CMYKA float", + babl_model ("CMYKA"), + babl_type ("float"), + babl_component ("Cyan"), + babl_component ("Magenta"), + babl_component ("Yellow"), + babl_component ("Key"), + babl_component ("A"), + NULL + ); + babl_format_new ( + "name", "CaMaYaKaA u8", + babl_model ("CaMaYaKaA"), + babl_type ("u8"), + babl_component ("Ca"), + babl_component ("Ma"), + babl_component ("Yea"), + babl_component ("Ka"), + babl_component ("A"), + NULL + ); + + babl_format_new ( + "name", "CaMaYaKaA u16", + babl_model ("CaMaYaKaA"), + babl_type ("u16"), + babl_component ("Ca"), + babl_component ("Ma"), + babl_component ("Yea"), + babl_component ("Ka"), + babl_component ("A"), + NULL + ); + babl_format_new ( + "name", "CaMaYaKaA half", + babl_model ("CaMaYaKaA"), + babl_type ("half"), + babl_component ("Ca"), + babl_component ("Ma"), + babl_component ("Yea"), + babl_component ("Ka"), + babl_component ("A"), + NULL + ); +} + diff --git a/babl/base/model-gray.c b/babl/base/model-gray.c new file mode 100644 index 0000000..3862400 --- /dev/null +++ b/babl/base/model-gray.c @@ -0,0 +1,1741 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include + +#include "babl-internal.h" +#include "babl-ids.h" +#include "math.h" +#include "babl-base.h" + +static void components (void); +static void models (void); +static void conversions (void); +static void formats (void); +static void init_single_precision (void); + +void +babl_base_model_gray (void) +{ + components (); + models (); + conversions (); + formats (); + init_single_precision (); +} + +static void +components (void) +{ + babl_component_new ( + "Y", + "id", BABL_GRAY_LINEAR, + "luma", + NULL); + + babl_component_new ( + "Ya", + "id", BABL_GRAY_LINEAR_MUL_ALPHA, + "luma", + NULL); + + babl_component_new ( + "Y'", + "id", BABL_GRAY_NONLINEAR, + "luma", + NULL); + + babl_component_new ( + "Y'a", + "id", BABL_GRAY_NONLINEAR_MUL_ALPHA, + "luma", + NULL); + + babl_component_new ( + "Y~", + "id", BABL_GRAY_PERCEPTUAL, + "luma", + NULL); + + babl_component_new ( + "Y~a", + "id", BABL_GRAY_PERCEPTUAL_MUL_ALPHA, + "luma", + NULL); +} + +static void +models (void) +{ + babl_model_new ( + "id", BABL_GRAY, + babl_component_from_id (BABL_GRAY_LINEAR), + "gray", + "linear", + NULL); + + + babl_model_new ( + "id", BABL_GRAY_ALPHA, + babl_component_from_id (BABL_GRAY_LINEAR), + babl_component_from_id (BABL_ALPHA), + "gray", + "linear", + "alpha", + NULL); + + babl_model_new ( + "id", BABL_GRAY_ALPHA_PREMULTIPLIED, + babl_component_from_id (BABL_GRAY_LINEAR_MUL_ALPHA), + babl_component_from_id (BABL_ALPHA), + "gray", + "linear", + "associated", + "alpha", + NULL); + + babl_model_new ( + "id", BABL_MODEL_GRAY_NONLINEAR, + babl_component_from_id (BABL_GRAY_NONLINEAR), + "gray", + "nonlinear", + NULL); + + babl_model_new ( + "id", BABL_MODEL_GRAY_NONLINEAR_ALPHA, + babl_component_from_id (BABL_GRAY_NONLINEAR), + babl_component_from_id (BABL_ALPHA), + "gray", + "nonlinear", + "alpha", + NULL); + + babl_model_new ( + "id", BABL_MODEL_GRAY_NONLINEAR_ALPHA_PREMULTIPLIED, + babl_component_from_id (BABL_GRAY_NONLINEAR_MUL_ALPHA), + babl_component_from_id (BABL_ALPHA), + "gray", + "nonlinear", + "associated", + "alpha", + NULL); + + babl_model_new ( + "id", BABL_MODEL_GRAY_PERCEPTUAL, + babl_component_from_id (BABL_GRAY_PERCEPTUAL), + "gray", + "perceptual", + NULL); + + babl_model_new ( + "id", BABL_MODEL_GRAY_PERCEPTUAL_ALPHA, + babl_component_from_id (BABL_GRAY_PERCEPTUAL), + babl_component_from_id (BABL_ALPHA), + "gray", + "perceptual", + "alpha", + NULL); + + babl_model_new ( + "id", BABL_MODEL_GRAY_PERCEPTUAL_ALPHA_PREMULTIPLIED, + babl_component_from_id (BABL_GRAY_PERCEPTUAL_MUL_ALPHA), + babl_component_from_id (BABL_ALPHA), + "gray", + "perceptual", + "associated", + "alpha", + NULL); + +} + +static void +rgba_to_graya (Babl *conversion, + char *src, + char *dst, + long n) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + double RGB_LUMINANCE_RED = space->space.RGBtoXYZ[3]; + double RGB_LUMINANCE_GREEN = space->space.RGBtoXYZ[4]; + double RGB_LUMINANCE_BLUE = space->space.RGBtoXYZ[5]; + + while (n--) + { + double red, green, blue; + double luminance, alpha; + + red = ((double *) src)[0]; + green = ((double *) src)[1]; + blue = ((double *) src)[2]; + alpha = ((double *) src)[3]; + + luminance = red * RGB_LUMINANCE_RED + + green * RGB_LUMINANCE_GREEN + + blue * RGB_LUMINANCE_BLUE; + + ((double *) dst)[0] = luminance; + ((double *) dst)[1] = alpha; + + src += sizeof (double) * 4; + dst += sizeof (double) * 2; + } +} + +static void +rgba_to_gray (Babl *conversion, + char *src, + char *dst, + long n) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + double RGB_LUMINANCE_RED = space->space.RGBtoXYZ[3]; + double RGB_LUMINANCE_GREEN = space->space.RGBtoXYZ[4]; + double RGB_LUMINANCE_BLUE = space->space.RGBtoXYZ[5]; + + while (n--) + { + double red, green, blue; + double luminance; + + red = ((double *) src)[0]; + green = ((double *) src)[1]; + blue = ((double *) src)[2]; + + luminance = red * RGB_LUMINANCE_RED + + green * RGB_LUMINANCE_GREEN + + blue * RGB_LUMINANCE_BLUE; + + ((double *) dst)[0] = luminance; + + src += sizeof (double) * 4; + dst += sizeof (double) * 1; + } +} + +static const Babl *perceptual_trc = NULL; + +static void +rgb_to_gray_nonlinear (Babl *conversion, + int src_bands, + char **src, + int *src_pitch, + int dst_bands, + char **dst, + int *dst_pitch, + long n) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + const Babl *trc = space->space.trc[0]; + double RGB_LUMINANCE_RED = space->space.RGBtoXYZ[3]; + double RGB_LUMINANCE_GREEN = space->space.RGBtoXYZ[4]; + double RGB_LUMINANCE_BLUE = space->space.RGBtoXYZ[5]; + + BABL_PLANAR_SANITY + while (n--) + { + double red, green, blue; + double luminance, alpha; + + red = *(double *) src[0]; + green = *(double *) src[1]; + blue = *(double *) src[2]; + if (src_bands > 3) + alpha = *(double *) src[3]; + else + alpha = 1.0; + + luminance = red * RGB_LUMINANCE_RED + + green * RGB_LUMINANCE_GREEN + + blue * RGB_LUMINANCE_BLUE; + *(double *) dst[0] = babl_trc_from_linear (trc, luminance); + + if (dst_bands == 2) + *(double *) dst[1] = alpha; + + BABL_PLANAR_STEP + } +} + + +static void +gray_nonlinear_to_rgb (Babl *conversion, + int src_bands, + char **src, + int *src_pitch, + int dst_bands, + char **dst, + int *dst_pitch, + long n) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + const Babl *trc = space->space.trc[0]; + + BABL_PLANAR_SANITY + while (n--) + { + double luminance; + double red, green, blue; + double alpha; + + luminance = babl_trc_to_linear (trc, *(double *) src[0]); + red = luminance; + green = luminance; + blue = luminance; + if (src_bands > 1) + alpha = *(double *) src[1]; + else + alpha = 1.0; + + *(double *) dst[0] = red; + *(double *) dst[1] = green; + *(double *) dst[2] = blue; + + if (dst_bands > 3) + *(double *) dst[3] = alpha; + + BABL_PLANAR_STEP + } +} + +static void +rgb_to_gray_perceptual (Babl *conversion, + int src_bands, + char **src, + int *src_pitch, + int dst_bands, + char **dst, + int *dst_pitch, + long n) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + const Babl *trc = perceptual_trc; + double RGB_LUMINANCE_RED = space->space.RGBtoXYZ[3]; + double RGB_LUMINANCE_GREEN = space->space.RGBtoXYZ[4]; + double RGB_LUMINANCE_BLUE = space->space.RGBtoXYZ[5]; + + BABL_PLANAR_SANITY + while (n--) + { + double red, green, blue; + double luminance, alpha; + + red = *(double *) src[0]; + green = *(double *) src[1]; + blue = *(double *) src[2]; + if (src_bands > 3) + alpha = *(double *) src[3]; + else + alpha = 1.0; + + luminance = red * RGB_LUMINANCE_RED + + green * RGB_LUMINANCE_GREEN + + blue * RGB_LUMINANCE_BLUE; + *(double *) dst[0] = babl_trc_from_linear (trc, luminance); + + if (dst_bands == 2) + *(double *) dst[1] = alpha; + + BABL_PLANAR_STEP + } +} + +static void +gray_perceptual_to_rgb (Babl *conversion, + int src_bands, + char **src, + int *src_pitch, + int dst_bands, + char **dst, + int *dst_pitch, + long n) +{ + const Babl *trc = perceptual_trc; + + BABL_PLANAR_SANITY + while (n--) + { + double luminance; + double red, green, blue; + double alpha; + + luminance = babl_trc_to_linear (trc, *(double *) src[0]); + red = luminance; + green = luminance; + blue = luminance; + if (src_bands > 1) + alpha = *(double *) src[1]; + else + alpha = 1.0; + + *(double *) dst[0] = red; + *(double *) dst[1] = green; + *(double *) dst[2] = blue; + + if (dst_bands > 3) + *(double *) dst[3] = alpha; + + BABL_PLANAR_STEP + } +} + + +static void +graya_to_rgba (Babl *conversion, + char *src, + char *dst, + long n) +{ + while (n--) + { + double luminance; + double red, green, blue; + double alpha; + + luminance = ((double *) src)[0]; + alpha = ((double *) src)[1]; + red = luminance; + green = luminance; + blue = luminance; + + ((double *) dst)[0] = red; + ((double *) dst)[1] = green; + ((double *) dst)[2] = blue; + ((double *) dst)[3] = alpha; + + src += sizeof (double) * 2; + dst += sizeof (double) * 4; + } +} + + +static void +gray_to_rgba (Babl *conversion, + char *src, + char *dst, + long n) +{ + while (n--) + { + double luminance; + double red, green, blue; + + luminance = ((double *) src)[0]; + red = luminance; + green = luminance; + blue = luminance; + + ((double *) dst)[0] = red; + ((double *) dst)[1] = green; + ((double *) dst)[2] = blue; + ((double *) dst)[3] = 1.0; + + src += sizeof (double) * 1; + dst += sizeof (double) * 4; + } +} + +static void +gray_alpha_associated_alpha_to_rgba (Babl *conversion, + int src_bands, + char **src, + int *src_pitch, + int dst_bands, + char **dst, + int *dst_pitch, + long n) +{ + BABL_PLANAR_SANITY + assert (src_bands == 2); + assert (dst_bands == 4); + + while (n--) + { + double luminance = *(double *) src[0]; + double alpha = *(double *) src[1]; + double used_alpha = babl_epsilon_for_zero (alpha); + luminance = luminance / used_alpha; + + *(double *) dst[0] = luminance; + *(double *) dst[1] = luminance; + *(double *) dst[2] = luminance; + *(double *) dst[3] = alpha; + BABL_PLANAR_STEP + } +} + + +static void +rgba_to_gray_alpha_associated_alpha (Babl *conversion, + int src_bands, + char **src, + int *src_pitch, + int dst_bands, + char **dst, + int *dst_pitch, + long n) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + double RGB_LUMINANCE_RED = space->space.RGBtoXYZ[3]; + double RGB_LUMINANCE_GREEN = space->space.RGBtoXYZ[4]; + double RGB_LUMINANCE_BLUE = space->space.RGBtoXYZ[5]; + + BABL_PLANAR_SANITY; + assert (src_bands == 4); + assert (dst_bands == 2); + + while (n--) + { + double red = *(double *) src[0]; + double green = *(double *) src[1]; + double blue = *(double *) src[2]; + double luminance; + double alpha = *(double *) src[3]; + double used_alpha = babl_epsilon_for_zero (alpha); + + luminance = red * RGB_LUMINANCE_RED + + green * RGB_LUMINANCE_GREEN + + blue * RGB_LUMINANCE_BLUE; + + luminance *= used_alpha; + + *(double *) dst[0] = luminance; + *(double *) dst[1] = alpha; + BABL_PLANAR_STEP + } +} + +static void +separate_alpha_to_associated_alpha (Babl *conversion, + int src_bands, + char **src, + int *src_pitch, + int dst_bands, + char **dst, + int *dst_pitch, + long n) +{ + BABL_PLANAR_SANITY + + while (n--) + { + int band; + double alpha = *(double *) src[src_bands-1]; + double used_alpha = babl_epsilon_for_zero (alpha); + + for (band = 0; band < src_bands - 1; band++) + { + *(double *) dst[band] = *(double *) src[band] * used_alpha; + } + *(double *) dst[dst_bands - 1] = alpha; + + BABL_PLANAR_STEP + } +} + +static void +associated_alpha_to_separate_alpha (Babl *conversion, + int src_bands, + char **src, + int *src_pitch, + int dst_bands, + char **dst, + int *dst_pitch, + long n) +{ + BABL_PLANAR_SANITY + + while (n--) + { + int band; + double alpha = *(double *) src[src_bands-1]; + double used_alpha = babl_epsilon_for_zero (alpha); + double recip_alpha = 1.0 / used_alpha; + + for (band = 0; band < src_bands - 1; band++) + { + *(double *) dst[band] = *(double *) src[band] * recip_alpha; + } + *(double *) dst[dst_bands - 1] = alpha; + + BABL_PLANAR_STEP + } +} + + + +static void +rgba2gray_perceptual_associated_alpha (Babl *conversion, + char *src, + char *dst, + long n) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + const Babl *trc = perceptual_trc; + double RGB_LUMINANCE_RED = space->space.RGBtoXYZ[3]; + double RGB_LUMINANCE_GREEN = space->space.RGBtoXYZ[4]; + double RGB_LUMINANCE_BLUE = space->space.RGBtoXYZ[5]; + + while (n--) + { + double red = ((double *) src)[0]; + double green = ((double *) src)[1]; + double blue = ((double *) src)[2]; + double luminance; + double luma; + double alpha = ((double *) src)[3]; + double used_alpha = babl_epsilon_for_zero (alpha); + + luminance = red * RGB_LUMINANCE_RED + + green * RGB_LUMINANCE_GREEN + + blue * RGB_LUMINANCE_BLUE; + luma = babl_trc_from_linear (trc, luminance); + + ((double *) dst)[0] = luma * used_alpha; + ((double *) dst)[1] = alpha; + + src += 4 * sizeof (double); + dst += 2 * sizeof (double); + } +} + +static void +rgba2gray_nonlinear_associated_alpha (Babl *conversion, + char *src, + char *dst, + long n) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + const Babl *trc = space->space.trc[0]; + double RGB_LUMINANCE_RED = space->space.RGBtoXYZ[3]; + double RGB_LUMINANCE_GREEN = space->space.RGBtoXYZ[4]; + double RGB_LUMINANCE_BLUE = space->space.RGBtoXYZ[5]; + + while (n--) + { + double red = ((double *) src)[0]; + double green = ((double *) src)[1]; + double blue = ((double *) src)[2]; + double luminance; + double luma; + double alpha = ((double *) src)[3]; + double used_alpha = babl_epsilon_for_zero (alpha); + + luminance = red * RGB_LUMINANCE_RED + + green * RGB_LUMINANCE_GREEN + + blue * RGB_LUMINANCE_BLUE; + luma = babl_trc_from_linear (trc, luminance); + + ((double *) dst)[0] = luma * used_alpha; + ((double *) dst)[1] = alpha; + + src += 4 * sizeof (double); + dst += 2 * sizeof (double); + } +} + + +static void +gray_perceptual_associated_alpha2rgba (Babl *conversion, + char *src, + char *dst, + long n) +{ + const Babl *trc = perceptual_trc; + + while (n--) + { + double luma = ((double *) src)[0]; + double luminance; + double alpha = ((double *) src)[1]; + double used_alpha = babl_epsilon_for_zero (alpha); + luma = luma / used_alpha; + + luminance = babl_trc_to_linear (trc, luma); + + ((double *) dst)[0] = luminance; + ((double *) dst)[1] = luminance; + ((double *) dst)[2] = luminance; + ((double *) dst)[3] = alpha; + + src += 2 * sizeof (double); + dst += 4 * sizeof (double); + } +} + +static void +gray_nonlinear_associated_alpha2rgba (Babl *conversion, + char *src, + char *dst, + long n) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + const Babl *trc = space->space.trc[0]; + + while (n--) + { + double luma = ((double *) src)[0]; + double luminance; + double alpha = ((double *) src)[1]; + double used_alpha = babl_epsilon_for_zero (alpha); + luma = luma / used_alpha; + luminance = babl_trc_to_linear (trc, luma); + + ((double *) dst)[0] = luminance; + ((double *) dst)[1] = luminance; + ((double *) dst)[2] = luminance; + ((double *) dst)[3] = alpha; + + src += 2 * sizeof (double); + dst += 4 * sizeof (double); + } +} + +static void +conversions (void) +{ + perceptual_trc = babl_trc ("sRGB"); + babl_conversion_new ( + babl_model_from_id (BABL_MODEL_GRAY_NONLINEAR), + babl_model_from_id (BABL_RGBA), + "planar", gray_nonlinear_to_rgb, + NULL + ); + + babl_conversion_new ( + babl_model_from_id (BABL_RGBA), + babl_model_from_id (BABL_MODEL_GRAY_NONLINEAR), + "planar", rgb_to_gray_nonlinear, + NULL + ); + + babl_conversion_new ( + babl_model_from_id (BABL_MODEL_GRAY_NONLINEAR_ALPHA), + babl_model_from_id (BABL_RGBA), + "planar", gray_nonlinear_to_rgb, + NULL + ); + + babl_conversion_new ( + babl_model_from_id (BABL_RGBA), + babl_model_from_id (BABL_MODEL_GRAY_NONLINEAR_ALPHA), + "planar", rgb_to_gray_nonlinear, + NULL + ); + + + babl_conversion_new ( + babl_model_from_id (BABL_MODEL_GRAY_NONLINEAR_ALPHA_PREMULTIPLIED), + babl_model_from_id (BABL_RGBA), + "linear", gray_nonlinear_associated_alpha2rgba, + NULL + ); + + babl_conversion_new ( + babl_model_from_id (BABL_MODEL_GRAY_PERCEPTUAL_ALPHA_PREMULTIPLIED), + babl_model_from_id (BABL_RGBA), + "linear", gray_perceptual_associated_alpha2rgba, + NULL + ); + + babl_conversion_new ( + babl_model_from_id (BABL_RGBA), + babl_model_from_id (BABL_MODEL_GRAY_NONLINEAR_ALPHA_PREMULTIPLIED), + "linear", rgba2gray_nonlinear_associated_alpha, + NULL + ); + + babl_conversion_new ( + babl_model_from_id (BABL_RGBA), + babl_model_from_id (BABL_MODEL_GRAY_PERCEPTUAL_ALPHA_PREMULTIPLIED), + "linear", rgba2gray_perceptual_associated_alpha, + NULL + ); + + babl_conversion_new ( + babl_model_from_id (BABL_MODEL_GRAY_PERCEPTUAL), + babl_model_from_id (BABL_RGBA), + "planar", gray_perceptual_to_rgb, + NULL + ); + + babl_conversion_new ( + babl_model_from_id (BABL_RGBA), + babl_model_from_id (BABL_MODEL_GRAY_PERCEPTUAL), + "planar", rgb_to_gray_perceptual, + NULL + ); + + babl_conversion_new ( + babl_model_from_id (BABL_MODEL_GRAY_PERCEPTUAL_ALPHA), + babl_model_from_id (BABL_RGBA), + "planar", gray_perceptual_to_rgb, + NULL + ); + + babl_conversion_new ( + babl_model_from_id (BABL_RGBA), + babl_model_from_id (BABL_MODEL_GRAY_PERCEPTUAL_ALPHA), + "planar", rgb_to_gray_perceptual, + NULL + ); + + + babl_conversion_new ( + babl_model_from_id (BABL_GRAY), + babl_model_from_id (BABL_RGBA), + "linear", gray_to_rgba, + NULL + ); + + babl_conversion_new ( + babl_model_from_id (BABL_GRAY_ALPHA), + babl_model_from_id (BABL_RGBA), + "linear", graya_to_rgba, + NULL + ); + + babl_conversion_new ( + babl_model_from_id (BABL_RGBA), + babl_model_from_id (BABL_GRAY_ALPHA), + "linear", rgba_to_graya, + NULL + ); + + babl_conversion_new ( + babl_model_from_id (BABL_RGBA), + babl_model_from_id (BABL_GRAY), + "linear", rgba_to_gray, + NULL + ); + + babl_conversion_new ( + babl_model_from_id (BABL_GRAY_ALPHA), + babl_model_from_id (BABL_GRAY_ALPHA_PREMULTIPLIED), + "planar", separate_alpha_to_associated_alpha, + NULL + ); + + babl_conversion_new ( + babl_model_from_id (BABL_GRAY_ALPHA_PREMULTIPLIED), + babl_model_from_id (BABL_GRAY_ALPHA), + "planar", associated_alpha_to_separate_alpha, + NULL + ); + + babl_conversion_new ( + babl_model_from_id (BABL_GRAY_ALPHA_PREMULTIPLIED), + babl_model_from_id (BABL_RGBA), + "planar", gray_alpha_associated_alpha_to_rgba, + NULL + ); + + babl_conversion_new ( + babl_model_from_id (BABL_RGBA), + babl_model_from_id (BABL_GRAY_ALPHA_PREMULTIPLIED), + "planar", rgba_to_gray_alpha_associated_alpha, + NULL + ); +} + +static void +formats (void) +{ + babl_format_new ( + babl_model_from_id (BABL_GRAY_ALPHA), + babl_type_from_id (BABL_HALF), + babl_component_from_id (BABL_GRAY_LINEAR), + babl_component_from_id (BABL_ALPHA), + NULL); + babl_format_new ( + babl_model_from_id (BABL_GRAY_ALPHA_PREMULTIPLIED), + babl_type_from_id (BABL_HALF), + babl_component_from_id (BABL_GRAY_LINEAR_MUL_ALPHA), + babl_component_from_id (BABL_ALPHA), + NULL); + babl_format_new ( + babl_model_from_id (BABL_GRAY), + babl_type_from_id (BABL_HALF), + babl_component_from_id (BABL_GRAY_LINEAR), + NULL); + babl_format_new ( + babl_model_from_id (BABL_MODEL_GRAY_NONLINEAR_ALPHA), + babl_type_from_id (BABL_HALF), + babl_component_from_id (BABL_GRAY_NONLINEAR), + babl_component_from_id (BABL_ALPHA), + NULL); + babl_format_new ( + babl_model_from_id (BABL_MODEL_GRAY_NONLINEAR_ALPHA_PREMULTIPLIED), + babl_type_from_id (BABL_HALF), + babl_component_from_id (BABL_GRAY_NONLINEAR_MUL_ALPHA), + babl_component_from_id (BABL_ALPHA), + NULL); + babl_format_new ( + babl_model_from_id (BABL_MODEL_GRAY_NONLINEAR), + babl_type_from_id (BABL_HALF), + babl_component_from_id (BABL_GRAY_NONLINEAR), + NULL); + babl_format_new ( + babl_model_from_id (BABL_MODEL_GRAY_PERCEPTUAL), + babl_type_from_id (BABL_HALF), + babl_component_from_id (BABL_GRAY_PERCEPTUAL), + NULL); + babl_format_new ( + babl_model_from_id (BABL_MODEL_GRAY_PERCEPTUAL_ALPHA), + babl_type_from_id (BABL_HALF), + babl_component_from_id (BABL_GRAY_PERCEPTUAL), + babl_component_from_id (BABL_ALPHA), + NULL); + babl_format_new ( + babl_model_from_id (BABL_MODEL_GRAY_PERCEPTUAL_ALPHA_PREMULTIPLIED), + babl_type_from_id (BABL_HALF), + babl_component_from_id (BABL_GRAY_PERCEPTUAL_MUL_ALPHA), + babl_component_from_id (BABL_ALPHA), + NULL); + /***********/ + + babl_format_new ( + babl_model_from_id (BABL_GRAY_ALPHA), + babl_type ("u15"), + babl_component_from_id (BABL_GRAY_LINEAR), + babl_component_from_id (BABL_ALPHA), + NULL); + babl_format_new ( + babl_model_from_id (BABL_GRAY_ALPHA_PREMULTIPLIED), + babl_type ("u15"), + babl_component_from_id (BABL_GRAY_LINEAR_MUL_ALPHA), + babl_component_from_id (BABL_ALPHA), + NULL); + babl_format_new ( + babl_model_from_id (BABL_GRAY), + babl_type ("u15"), + babl_component_from_id (BABL_GRAY_LINEAR), + NULL); + babl_format_new ( + babl_model_from_id (BABL_MODEL_GRAY_NONLINEAR_ALPHA), + babl_type ("u15"), + babl_component_from_id (BABL_GRAY_NONLINEAR), + babl_component_from_id (BABL_ALPHA), + NULL); + babl_format_new ( + babl_model_from_id (BABL_MODEL_GRAY_NONLINEAR_ALPHA_PREMULTIPLIED), + babl_type ("u15"), + babl_component_from_id (BABL_GRAY_NONLINEAR_MUL_ALPHA), + babl_component_from_id (BABL_ALPHA), + NULL); + babl_format_new ( + babl_model_from_id (BABL_MODEL_GRAY_NONLINEAR), + babl_type ("u15"), + babl_component_from_id (BABL_GRAY_NONLINEAR), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_GRAY_ALPHA), + babl_type_from_id (BABL_U32), + babl_component_from_id (BABL_GRAY_LINEAR), + babl_component_from_id (BABL_ALPHA), + NULL); + babl_format_new ( + babl_model_from_id (BABL_GRAY_ALPHA_PREMULTIPLIED), + babl_type_from_id (BABL_U32), + babl_component_from_id (BABL_GRAY_LINEAR_MUL_ALPHA), + babl_component_from_id (BABL_ALPHA), + NULL); + babl_format_new ( + babl_model_from_id (BABL_GRAY), + babl_type_from_id (BABL_U32), + babl_component_from_id (BABL_GRAY_LINEAR), + NULL); + babl_format_new ( + babl_model_from_id (BABL_MODEL_GRAY_NONLINEAR_ALPHA), + babl_type_from_id (BABL_U32), + babl_component_from_id (BABL_GRAY_NONLINEAR), + babl_component_from_id (BABL_ALPHA), + NULL); + babl_format_new ( + babl_model_from_id (BABL_MODEL_GRAY_NONLINEAR_ALPHA_PREMULTIPLIED), + babl_type_from_id (BABL_U32), + babl_component_from_id (BABL_GRAY_NONLINEAR_MUL_ALPHA), + babl_component_from_id (BABL_ALPHA), + NULL); + babl_format_new ( + babl_model_from_id (BABL_MODEL_GRAY_NONLINEAR), + babl_type_from_id (BABL_U32), + babl_component_from_id (BABL_GRAY_NONLINEAR), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_MODEL_GRAY_PERCEPTUAL), + babl_type_from_id (BABL_U32), + babl_component_from_id (BABL_GRAY_PERCEPTUAL), + NULL); + babl_format_new ( + babl_model_from_id (BABL_MODEL_GRAY_PERCEPTUAL_ALPHA), + babl_type_from_id (BABL_U32), + babl_component_from_id (BABL_GRAY_PERCEPTUAL), + babl_component_from_id (BABL_ALPHA), + NULL); + babl_format_new ( + babl_model_from_id (BABL_MODEL_GRAY_PERCEPTUAL_ALPHA_PREMULTIPLIED), + babl_type_from_id (BABL_U32), + babl_component_from_id (BABL_GRAY_PERCEPTUAL_MUL_ALPHA), + babl_component_from_id (BABL_ALPHA), + NULL); +} + +/********** float versions ***********/ + +static void +rgba_to_graya_float (Babl *conversion, + char *src, + char *dst, + long n) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + float RGB_LUMINANCE_RED = space->space.RGBtoXYZf[3]; + float RGB_LUMINANCE_GREEN = space->space.RGBtoXYZf[4]; + float RGB_LUMINANCE_BLUE = space->space.RGBtoXYZf[5]; + + while (n--) + { + float red, green, blue; + float luminance, alpha; + + red = ((float *) src)[0]; + green = ((float *) src)[1]; + blue = ((float *) src)[2]; + alpha = ((float *) src)[3]; + + luminance = red * RGB_LUMINANCE_RED + + green * RGB_LUMINANCE_GREEN + + blue * RGB_LUMINANCE_BLUE; + + ((float *) dst)[0] = luminance; + ((float *) dst)[1] = alpha; + + src += sizeof (float) * 4; + dst += sizeof (float) * 2; + } +} + +static void +rgba_to_gray_float (Babl *conversion, + char *src, + char *dst, + long n) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + float RGB_LUMINANCE_RED = space->space.RGBtoXYZf[3]; + float RGB_LUMINANCE_GREEN = space->space.RGBtoXYZf[4]; + float RGB_LUMINANCE_BLUE = space->space.RGBtoXYZf[5]; + + while (n--) + { + float red, green, blue; + float luminance; + + red = ((float *) src)[0]; + green = ((float *) src)[1]; + blue = ((float *) src)[2]; + + luminance = red * RGB_LUMINANCE_RED + + green * RGB_LUMINANCE_GREEN + + blue * RGB_LUMINANCE_BLUE; + + ((float *) dst)[0] = luminance; + + src += sizeof (float) * 4; + dst += sizeof (float) * 1; + } +} + +static void +rgb_to_gray_nonlinear_float (Babl *conversion, + int src_bands, + char **src, + int *src_pitch, + int dst_bands, + char **dst, + int *dst_pitch, + long n) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + const Babl *trc = space->space.trc[0]; + float RGB_LUMINANCE_RED = space->space.RGBtoXYZf[3]; + float RGB_LUMINANCE_GREEN = space->space.RGBtoXYZf[4]; + float RGB_LUMINANCE_BLUE = space->space.RGBtoXYZf[5]; + + BABL_PLANAR_SANITY + while (n--) + { + float red, green, blue; + float luminance, alpha; + + red = *(float *) src[0]; + green = *(float *) src[1]; + blue = *(float *) src[2]; + if (src_bands > 3) + alpha = *(float *) src[3]; + else + alpha = 1.0f; + + luminance = red * RGB_LUMINANCE_RED + + green * RGB_LUMINANCE_GREEN + + blue * RGB_LUMINANCE_BLUE; + *(float *) dst[0] = babl_trc_from_linear (trc, luminance); + + if (dst_bands == 2) + *(float *) dst[1] = alpha; + + BABL_PLANAR_STEP + } +} + + +static void +gray_nonlinear_to_rgb_float (Babl *conversion, + int src_bands, + char **src, + int *src_pitch, + int dst_bands, + char **dst, + int *dst_pitch, + long n) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + const Babl *trc = space->space.trc[0]; + + BABL_PLANAR_SANITY + while (n--) + { + float luminance; + float red, green, blue; + float alpha; + + luminance = babl_trc_to_linear (trc, *(float *) src[0]); + red = luminance; + green = luminance; + blue = luminance; + if (src_bands > 1) + alpha = *(float *) src[1]; + else + alpha = 1.0f; + + *(float *) dst[0] = red; + *(float *) dst[1] = green; + *(float *) dst[2] = blue; + + if (dst_bands > 3) + *(float *) dst[3] = alpha; + + BABL_PLANAR_STEP + } +} + +static void +rgb_to_gray_perceptual_float (Babl *conversion, + int src_bands, + char **src, + int *src_pitch, + int dst_bands, + char **dst, + int *dst_pitch, + long n) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + const Babl *trc = perceptual_trc; + float RGB_LUMINANCE_RED = space->space.RGBtoXYZf[3]; + float RGB_LUMINANCE_GREEN = space->space.RGBtoXYZf[4]; + float RGB_LUMINANCE_BLUE = space->space.RGBtoXYZf[5]; + + BABL_PLANAR_SANITY + while (n--) + { + float red, green, blue; + float luminance, alpha; + + red = *(float *) src[0]; + green = *(float *) src[1]; + blue = *(float *) src[2]; + if (src_bands > 3) + alpha = *(float *) src[3]; + else + alpha = 1.0f; + + luminance = red * RGB_LUMINANCE_RED + + green * RGB_LUMINANCE_GREEN + + blue * RGB_LUMINANCE_BLUE; + *(float *) dst[0] = babl_trc_from_linear (trc, luminance); + + if (dst_bands == 2) + *(float *) dst[1] = alpha; + + BABL_PLANAR_STEP + } +} + +static void +gray_perceptual_to_rgb_float (Babl *conversion, + int src_bands, + char **src, + int *src_pitch, + int dst_bands, + char **dst, + int *dst_pitch, + long n) +{ + const Babl *trc = perceptual_trc; + + BABL_PLANAR_SANITY + while (n--) + { + float luminance; + float red, green, blue; + float alpha; + + luminance = babl_trc_to_linear (trc, *(float *) src[0]); + red = luminance; + green = luminance; + blue = luminance; + if (src_bands > 1) + alpha = *(float *) src[1]; + else + alpha = 1.0f; + + *(float *) dst[0] = red; + *(float *) dst[1] = green; + *(float *) dst[2] = blue; + + if (dst_bands > 3) + *(float *) dst[3] = alpha; + + BABL_PLANAR_STEP + } +} + + +static void +graya_to_rgba_float (Babl *conversion, + char *src, + char *dst, + long n) +{ + while (n--) + { + float luminance; + float red, green, blue; + float alpha; + + luminance = ((float *) src)[0]; + alpha = ((float *) src)[1]; + red = luminance; + green = luminance; + blue = luminance; + + ((float *) dst)[0] = red; + ((float *) dst)[1] = green; + ((float *) dst)[2] = blue; + ((float *) dst)[3] = alpha; + + src += sizeof (float) * 2; + dst += sizeof (float) * 4; + } +} + + +static void +gray_to_rgba_float (Babl *conversion, + char *src, + char *dst, + long n) +{ + while (n--) + { + float luminance; + float red, green, blue; + + luminance = ((float *) src)[0]; + red = luminance; + green = luminance; + blue = luminance; + + ((float *) dst)[0] = red; + ((float *) dst)[1] = green; + ((float *) dst)[2] = blue; + ((float *) dst)[3] = 1.0; + + src += sizeof (float) * 1; + dst += sizeof (float) * 4; + } +} + +static void +gray_alpha_associated_alpha_to_rgba_float (Babl *conversion, + int src_bands, + char **src, + int *src_pitch, + int dst_bands, + char **dst, + int *dst_pitch, + long n) +{ + BABL_PLANAR_SANITY + assert (src_bands == 2); + assert (dst_bands == 4); + + while (n--) + { + float luminance = *(float *) src[0]; + float alpha = *(float *) src[1]; + float used_alpha = babl_epsilon_for_zero_float (alpha); + luminance = luminance / used_alpha; + + *(float *) dst[0] = luminance; + *(float *) dst[1] = luminance; + *(float *) dst[2] = luminance; + *(float *) dst[3] = alpha; + BABL_PLANAR_STEP + } +} + + +static void +rgba_to_gray_alpha_associated_alpha_float (Babl *conversion, + int src_bands, + char **src, + int *src_pitch, + int dst_bands, + char **dst, + int *dst_pitch, + long n) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + float RGB_LUMINANCE_RED = space->space.RGBtoXYZf[3]; + float RGB_LUMINANCE_GREEN = space->space.RGBtoXYZf[4]; + float RGB_LUMINANCE_BLUE = space->space.RGBtoXYZf[5]; + + BABL_PLANAR_SANITY; + assert (src_bands == 4); + assert (dst_bands == 2); + + while (n--) + { + float red = *(float *) src[0]; + float green = *(float *) src[1]; + float blue = *(float *) src[2]; + float luminance; + float alpha = *(float *) src[3]; + float used_alpha = babl_epsilon_for_zero_float (alpha); + + luminance = red * RGB_LUMINANCE_RED + + green * RGB_LUMINANCE_GREEN + + blue * RGB_LUMINANCE_BLUE; + + luminance *= used_alpha; + + *(float *) dst[0] = luminance; + *(float *) dst[1] = alpha; + BABL_PLANAR_STEP + } +} + +static void +separate_alpha_to_associated_alpha_float (Babl *conversion, + int src_bands, + char **src, + int *src_pitch, + int dst_bands, + char **dst, + int *dst_pitch, + long n) +{ + BABL_PLANAR_SANITY + + while (n--) + { + int band; + float alpha = *(float *) src[src_bands-1]; + float used_alpha = babl_epsilon_for_zero_float (alpha); + + for (band = 0; band < src_bands - 1; band++) + { + *(float *) dst[band] = *(float *) src[band] * used_alpha; + } + *(float *) dst[dst_bands - 1] = alpha; + + BABL_PLANAR_STEP + } +} + +static void +associated_alpha_to_separate_alpha_float (Babl *conversion, + int src_bands, + char **src, + int *src_pitch, + int dst_bands, + char **dst, + int *dst_pitch, + long n) +{ + BABL_PLANAR_SANITY + + while (n--) + { + int band; + float alpha = *(float *) src[src_bands-1]; + float used_alpha = babl_epsilon_for_zero_float (alpha); + float recip_alpha = 1.0f / used_alpha; + + for (band = 0; band < src_bands - 1; band++) + { + *(float *) dst[band] = *(float *) src[band] * recip_alpha; + } + *(float *) dst[dst_bands - 1] = alpha; + + BABL_PLANAR_STEP + } +} + +static void +rgba2gray_nonlinear_associated_alpha_float (Babl *conversion, + char *src, + char *dst, + long n) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + const Babl *trc = space->space.trc[0]; + float RGB_LUMINANCE_RED = space->space.RGBtoXYZf[3]; + float RGB_LUMINANCE_GREEN = space->space.RGBtoXYZf[4]; + float RGB_LUMINANCE_BLUE = space->space.RGBtoXYZf[5]; + + while (n--) + { + float red = ((float *) src)[0]; + float green = ((float *) src)[1]; + float blue = ((float *) src)[2]; + float luminance; + float luma; + float alpha = ((float *) src)[3]; + float used_alpha = babl_epsilon_for_zero_float (alpha); + + luminance = red * RGB_LUMINANCE_RED + + green * RGB_LUMINANCE_GREEN + + blue * RGB_LUMINANCE_BLUE; + luma = babl_trc_from_linear (trc, luminance); + + ((float *) dst)[0] = luma * used_alpha; + ((float *) dst)[1] = alpha; + + src += 4 * sizeof (float); + dst += 2 * sizeof (float); + } +} + +static void +gray_nonlinear_associated_alpha2rgba_float (Babl *conversion, + char *src, + char *dst, + long n) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + const Babl *trc = space->space.trc[0]; + + while (n--) + { + float luma = ((float *) src)[0]; + float luminance; + float alpha = ((float *) src)[1]; + float used_alpha = babl_epsilon_for_zero_float (alpha); + + luma = luma / used_alpha; + luminance = babl_trc_to_linear (trc, luma); + + ((float *) dst)[0] = luminance; + ((float *) dst)[1] = luminance; + ((float *) dst)[2] = luminance; + ((float *) dst)[3] = alpha; + + src += 2 * sizeof (float); + dst += 4 * sizeof (float); + } +} + +static void +rgba2gray_perceptual_associated_alpha_float (Babl *conversion, + char *src, + char *dst, + long n) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + const Babl *trc = perceptual_trc; + float RGB_LUMINANCE_RED = space->space.RGBtoXYZf[3]; + float RGB_LUMINANCE_GREEN = space->space.RGBtoXYZf[4]; + float RGB_LUMINANCE_BLUE = space->space.RGBtoXYZf[5]; + + while (n--) + { + float red = ((float *) src)[0]; + float green = ((float *) src)[1]; + float blue = ((float *) src)[2]; + float luminance; + float luma; + float alpha = ((float *) src)[3]; + float used_alpha = babl_epsilon_for_zero_float (alpha); + + luminance = red * RGB_LUMINANCE_RED + + green * RGB_LUMINANCE_GREEN + + blue * RGB_LUMINANCE_BLUE; + luma = babl_trc_from_linear (trc, luminance); + + ((float *) dst)[0] = luma * used_alpha; + ((float *) dst)[1] = alpha; + + src += 4 * sizeof (float); + dst += 2 * sizeof (float); + } +} + +static void +gray_perceptual_associated_alpha2rgba_float (Babl *conversion, + char *src, + char *dst, + long n) +{ + const Babl *trc = perceptual_trc; + + while (n--) + { + float luma = ((float *) src)[0]; + float luminance; + float alpha = ((float *) src)[1]; + float used_alpha = babl_epsilon_for_zero_float (alpha); + + luma = luma / used_alpha; + + luminance = babl_trc_to_linear (trc, luma); + + ((float *) dst)[0] = luminance; + ((float *) dst)[1] = luminance; + ((float *) dst)[2] = luminance; + ((float *) dst)[3] = alpha; + + src += 2 * sizeof (float); + dst += 4 * sizeof (float); + } +} + +static void init_single_precision (void) +{ + babl_format_new ( + babl_model ("Y"), + babl_type_from_id (BABL_FLOAT), + babl_component ("Y"), + NULL); + babl_format_new ( + babl_model ("Y'"), + babl_type_from_id (BABL_FLOAT), + babl_component ("Y'"), + NULL); + babl_format_new ( + babl_model ("Y~"), + babl_type_from_id (BABL_FLOAT), + babl_component ("Y~"), + NULL); + + + babl_format_new ( + babl_model ("YA"), + babl_type_from_id (BABL_FLOAT), + babl_component ("Y"), + babl_component ("A"), + NULL); + babl_format_new ( + babl_model ("Y'A"), + babl_type_from_id (BABL_FLOAT), + babl_component ("Y'"), + babl_component ("A"), + NULL); + babl_format_new ( + babl_model ("Y~A"), + babl_type_from_id (BABL_FLOAT), + babl_component ("Y~"), + babl_component ("A"), + NULL); + + + babl_format_new ( + babl_model ("YaA"), + babl_type_from_id (BABL_FLOAT), + babl_component ("Ya"), + babl_component ("A"), + NULL); + babl_format_new ( + babl_model ("Y'aA"), + babl_type_from_id (BABL_FLOAT), + babl_component ("Y'a"), + babl_component ("A"), + NULL); + babl_format_new ( + babl_model ("Y~aA"), + babl_type_from_id (BABL_FLOAT), + babl_component ("Y~a"), + babl_component ("A"), + NULL); + + babl_conversion_new ( + babl_format ("Y' float"), + babl_format ("RGBA float"), + "planar", gray_nonlinear_to_rgb_float, + NULL + ); + + babl_conversion_new ( + babl_format ("RGBA float"), + babl_format ("Y' float"), + "planar", rgb_to_gray_nonlinear_float, + NULL + ); + + babl_conversion_new ( + babl_format ("Y'A float"), + babl_format ("RGBA float"), + "planar", gray_nonlinear_to_rgb_float, + NULL + ); + + babl_conversion_new ( + babl_format ("RGBA float"), + babl_format ("Y'A float"), + "planar", rgb_to_gray_nonlinear_float, + NULL + ); + + + babl_conversion_new ( + babl_format ("Y'aA float"), + babl_format ("RGBA float"), + "linear", gray_nonlinear_associated_alpha2rgba_float, + NULL + ); + + babl_conversion_new ( + babl_format ("Y~aA float"), + babl_format ("RGBA float"), + "linear", gray_perceptual_associated_alpha2rgba_float, + NULL + ); + + babl_conversion_new ( + babl_format ("RGBA float"), + babl_format ("Y'aA float"), + "linear", rgba2gray_nonlinear_associated_alpha_float, + NULL + ); + + babl_conversion_new ( + babl_format ("RGBA float"), + babl_format ("Y~aA float"), + "linear", rgba2gray_perceptual_associated_alpha_float, + NULL + ); + + babl_conversion_new ( + babl_format ("Y~ float"), + babl_format ("RGBA float"), + "planar", gray_perceptual_to_rgb_float, + NULL + ); + + babl_conversion_new ( + babl_format ("RGBA float"), + babl_format ("Y~ float"), + "planar", rgb_to_gray_perceptual_float, + NULL + ); + + babl_conversion_new ( + babl_format ("Y~A float"), + babl_format ("RGBA float"), + "planar", gray_perceptual_to_rgb_float, + NULL + ); + + babl_conversion_new ( + babl_format ("RGBA float"), + babl_format ("Y~A float"), + "planar", rgb_to_gray_perceptual_float, + NULL + ); + + + babl_conversion_new ( + babl_format ("Y float"), + babl_format ("RGBA float"), + "linear", gray_to_rgba_float, + NULL + ); + + babl_conversion_new ( + babl_format ("YA float"), + babl_format ("RGBA float"), + "linear", graya_to_rgba_float, + NULL + ); + + babl_conversion_new ( + babl_format ("RGBA float"), + babl_format ("YA float"), + "linear", rgba_to_graya_float, + NULL + ); + + babl_conversion_new ( + babl_format ("RGBA float"), + babl_format ("Y float"), + "linear", rgba_to_gray_float, + NULL + ); + + babl_conversion_new ( + babl_format ("YA float"), + babl_format ("YaA float"), + "planar", separate_alpha_to_associated_alpha_float, + NULL + ); + + babl_conversion_new ( + babl_format ("YaA float"), + babl_format ("YA float"), + "planar", associated_alpha_to_separate_alpha_float, + NULL + ); + + babl_conversion_new ( + babl_format ("YaA float"), + babl_format ("RGBA float"), + "planar", gray_alpha_associated_alpha_to_rgba_float, + NULL + ); + + babl_conversion_new ( + babl_format ("RGBA float"), + babl_format ("YaA float"), + "planar", rgba_to_gray_alpha_associated_alpha_float, + NULL + ); +} diff --git a/babl/base/model-rgb.c b/babl/base/model-rgb.c new file mode 100644 index 0000000..a3064ef --- /dev/null +++ b/babl/base/model-rgb.c @@ -0,0 +1,1501 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include +#include + +#include "babl-internal.h" +#include "babl-classes.h" +#include "babl-ids.h" +#include "babl-base.h" + +static void models (void); +static void components (void); +static void conversions (void); +static void formats (void); +static void init_single_precision (void); + +void +babl_base_model_rgb (void) +{ + components (); + models (); + conversions (); + formats (); + init_single_precision (); +} + +static void +components (void) +{ + babl_component_new ( + "Ra", + "id", BABL_RED_MUL_ALPHA, + "luma", + "chroma", + "alpha", + NULL); + babl_component_new ( + "Ga", + "id", BABL_GREEN_MUL_ALPHA, + "luma", + "chroma", + "alpha", + NULL); + babl_component_new ( + "Ba", + "id", BABL_BLUE_MUL_ALPHA, + "luma", + "chroma", + "alpha", + NULL); + + babl_component_new ( + "R'", + "id", BABL_RED_NONLINEAR, + "luma", + "chroma", + NULL); + + babl_component_new ( + "G'", + "id", BABL_GREEN_NONLINEAR, + "luma", + "chroma", + NULL); + + babl_component_new ( + "B'", + "id", BABL_BLUE_NONLINEAR, + "luma", + "chroma", + NULL); + + babl_component_new ( + "R~", + "id", BABL_RED_PERCEPTUAL, + "luma", + "chroma", + NULL); + + babl_component_new ( + "G~", + "id", BABL_GREEN_PERCEPTUAL, + "luma", + "chroma", + NULL); + + babl_component_new ( + "B~", + "id", BABL_BLUE_PERCEPTUAL, + "luma", + "chroma", + NULL); + + babl_component_new ( + "R'a", + "id", BABL_RED_NONLINEAR_MUL_ALPHA, + "luma", + "chroma", + NULL); + + babl_component_new ( + "G'a", + "id", BABL_GREEN_NONLINEAR_MUL_ALPHA, + "luma", + "chroma", + NULL); + + babl_component_new ( + "B'a", + "id", BABL_BLUE_NONLINEAR_MUL_ALPHA, + "luma", + "chroma", + NULL); + + babl_component_new ( + "R~a", + "id", BABL_RED_PERCEPTUAL_MUL_ALPHA, + "luma", + "chroma", + NULL); + + babl_component_new ( + "G~a", + "id", BABL_GREEN_PERCEPTUAL_MUL_ALPHA, + "luma", + "chroma", + NULL); + + babl_component_new ( + "B~a", + "id", BABL_BLUE_PERCEPTUAL_MUL_ALPHA, + "luma", + "chroma", + NULL); +} + +static void +models (void) +{ + babl_model_new ( + "id", BABL_RGB, + babl_component_from_id (BABL_RED), + babl_component_from_id (BABL_GREEN), + babl_component_from_id (BABL_BLUE), + "rgb", + "linear", + NULL); + + babl_model_new ( + "id", BABL_RGBA_PREMULTIPLIED, + babl_component_from_id (BABL_RED_MUL_ALPHA), + babl_component_from_id (BABL_GREEN_MUL_ALPHA), + babl_component_from_id (BABL_BLUE_MUL_ALPHA), + babl_component_from_id (BABL_ALPHA), + "rgb", + "linear", + "associated", + "alpha", + NULL); + + babl_model_new ( + "id", BABL_RGB_NONLINEAR, + babl_component_from_id (BABL_RED_NONLINEAR), + babl_component_from_id (BABL_GREEN_NONLINEAR), + babl_component_from_id (BABL_BLUE_NONLINEAR), + "rgb", + "nonlinear", + NULL); + + babl_model_new ( + "id", BABL_RGB_PERCEPTUAL, + babl_component_from_id (BABL_RED_PERCEPTUAL), + babl_component_from_id (BABL_GREEN_PERCEPTUAL), + babl_component_from_id (BABL_BLUE_PERCEPTUAL), + "rgb", + "perceptual", + NULL); + + babl_model_new ( + "id", BABL_RGBA_NONLINEAR, + babl_component_from_id (BABL_RED_NONLINEAR), + babl_component_from_id (BABL_GREEN_NONLINEAR), + babl_component_from_id (BABL_BLUE_NONLINEAR), + babl_component_from_id (BABL_ALPHA), + "rgb", + "nonlinear", + "alpha", + NULL); + + babl_model_new ( + "id", BABL_RGBA_PERCEPTUAL, + babl_component_from_id (BABL_RED_PERCEPTUAL), + babl_component_from_id (BABL_GREEN_PERCEPTUAL), + babl_component_from_id (BABL_BLUE_PERCEPTUAL), + babl_component_from_id (BABL_ALPHA), + "rgb", + "perceptual", + "alpha", + NULL); + + babl_model_new ( + "id", BABL_RGBA_NONLINEAR_PREMULTIPLIED, + babl_component_from_id (BABL_RED_NONLINEAR_MUL_ALPHA), + babl_component_from_id (BABL_GREEN_NONLINEAR_MUL_ALPHA), + babl_component_from_id (BABL_BLUE_NONLINEAR_MUL_ALPHA), + babl_component_from_id (BABL_ALPHA), + "rgb", + "nonlinear", + "associated", + "alpha", + NULL); + + babl_model_new ( + "id", BABL_RGBA_PERCEPTUAL_PREMULTIPLIED, + babl_component_from_id (BABL_RED_PERCEPTUAL_MUL_ALPHA), + babl_component_from_id (BABL_GREEN_PERCEPTUAL_MUL_ALPHA), + babl_component_from_id (BABL_BLUE_PERCEPTUAL_MUL_ALPHA), + babl_component_from_id (BABL_ALPHA), + "rgb", + "perceptual", + "associated", + "alpha", + NULL); +} + +static void +copy_strip_1 (Babl *conversion, + int src_bands, + char **src, + int *src_pitch, + int dst_bands, + char **dst, + int *dst_pitch, + long samples) +{ + long n = samples; + + BABL_PLANAR_SANITY + while (n--) + { + int i; + + for (i = 0; i < dst_bands; i++) + { + double foo; + if (i < src_bands) + foo = *(double *) src[i]; + else + foo = 1.0; + *(double *) dst[i] = foo; + } + + BABL_PLANAR_STEP + } +} + +static void +g3_nonlinear_from_linear (Babl *conversion, + int src_bands, + char **src, + int *src_pitch, + int dst_bands, + char **dst, + int *dst_pitch, + long samples) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + const Babl **trc = (void*)space->space.trc; + + long n = samples; + + BABL_PLANAR_SANITY + while (n--) + { + int band; + for (band = 0; band < 3; band++) + *(double *) dst[band] = babl_trc_from_linear (trc[band], (*(double *) src[band])); + for (; band < dst_bands; band++) + *(double *) dst[band] = *(double *) src[band]; + + BABL_PLANAR_STEP + } +} + + +static void +g3_nonlinear_to_linear (Babl *conversion, + int src_bands, + char **src, + int *src_pitch, + int dst_bands, + char **dst, + int *dst_pitch, + long samples) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + const Babl **trc = (void*)space->space.trc; + long n = samples; + + BABL_PLANAR_SANITY + while (n--) + { + int band; + for (band = 0; band < 3; band++) + { + *(double *) dst[band] = babl_trc_to_linear (trc[band], (*(double *) src[band])); + } + for (; band < dst_bands; band++) + { + if (band < src_bands) + *(double *) dst[band] = *(double *) src[band]; + else + *(double *) dst[band] = 1.0; + } + BABL_PLANAR_STEP + } +} + + +static void +separate_alpha_to_associated_alpha (Babl *conversion, + int src_bands, + char **src, + int *src_pitch, + int dst_bands, + char **dst, + int *dst_pitch, + long samples) +{ + long n = samples; + + BABL_PLANAR_SANITY + while (n--) + { + double alpha = *(double *) src[src_bands - 1]; + int band; + + double used_alpha = babl_epsilon_for_zero (alpha); + + for (band = 0; band < src_bands - 1; band++) + { + *(double *) dst[band] = *(double *) src[band] * used_alpha; + } + *(double *) dst[dst_bands - 1] = alpha; + + BABL_PLANAR_STEP + } +} + + + + +static void +associated_alpha_to_separate_alpha (Babl *conversion, + int src_bands, + char **src, + int *src_pitch, + int dst_bands, + char **dst, + int *dst_pitch, + long samples) +{ + long n = samples; + + BABL_PLANAR_SANITY + while (n--) + { + double alpha = *(double *) src[src_bands - 1]; + int band; + double used_alpha = babl_epsilon_for_zero (alpha); + double recip_alpha = 1.0 / used_alpha; + + for (band = 0; band < src_bands - 1; band++) + *(double *) dst[band] = *(double *) src[band] * recip_alpha; + *(double *) dst[dst_bands - 1] = alpha; + + BABL_PLANAR_STEP + } +} + + +static void +rgba2rgba_nonlinear_associated_alpha (Babl *conversion, + char *src, + char *dst, + long samples) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + const Babl **trc = (void*)space->space.trc; + long n = samples; + + while (n--) + { + double alpha = ((double *) src)[3]; + double used_alpha = babl_epsilon_for_zero (alpha); + + ((double *) dst)[0] = babl_trc_from_linear (trc[0], ((double *) src)[0]) * used_alpha; + ((double *) dst)[1] = babl_trc_from_linear (trc[1], ((double *) src)[1]) * used_alpha; + ((double *) dst)[2] = babl_trc_from_linear (trc[2], ((double *) src)[2]) * used_alpha; + ((double *) dst)[3] = alpha; + src += 4 * sizeof (double); + dst += 4 * sizeof (double); + } +} + + + + +static void +rgba_nonlinear_associated_alpha2rgba (Babl *conversion, + char *src, + char *dst, + long samples) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + const Babl **trc = (void*)space->space.trc; + long n = samples; + + while (n--) + { + double alpha = ((double *) src)[3]; + double used_alpha = babl_epsilon_for_zero (alpha); + double reciprocal = 1.0 / used_alpha; + + ((double *) dst)[0] = babl_trc_to_linear (trc[0], ((double *) src)[0] * reciprocal); + ((double *) dst)[1] = babl_trc_to_linear (trc[1], ((double *) src)[1] * reciprocal); + ((double *) dst)[2] = babl_trc_to_linear (trc[2], ((double *) src)[2] * reciprocal); + ((double *) dst)[3] = alpha; + + src += 4 * sizeof (double); + dst += 4 * sizeof (double); + } +} + + + + +static void +rgba2rgba_nonlinear (Babl *conversion, + char *src, + char *dst, + long samples) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + const Babl **trc = (void*)space->space.trc; + long n = samples; + + while (n--) + { + double alpha = ((double *) src)[3]; + ((double *) dst)[0] = babl_trc_from_linear (trc[0], ((double *) src)[0]); + ((double *) dst)[1] = babl_trc_from_linear (trc[1], ((double *) src)[1]); + ((double *) dst)[2] = babl_trc_from_linear (trc[2], ((double *) src)[2]); + ((double *) dst)[3] = alpha; + src += 4 * sizeof (double); + dst += 4 * sizeof (double); + } +} + + +static void +rgba_nonlinear2rgba (Babl *conversion, + char *src, + char *dst, + long samples) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + const Babl **trc = (void*)(space->space.trc); + long n = samples; + + while (n--) + { + double alpha = ((double *) src)[3]; + ((double *) dst)[0] = babl_trc_to_linear (trc[0], ((double *) src)[0]); + ((double *) dst)[1] = babl_trc_to_linear (trc[1], ((double *) src)[1]); + ((double *) dst)[2] = babl_trc_to_linear (trc[2], ((double *) src)[2]); + ((double *) dst)[3] = alpha; + + src += 4 * sizeof (double); + dst += 4 * sizeof (double); + } +} + + +static const Babl *perceptual_trc = NULL; + +static void +g3_perceptual_from_linear (Babl *conversion, + int src_bands, + char **src, + int *src_pitch, + int dst_bands, + char **dst, + int *dst_pitch, + long samples) +{ + const Babl *trc = perceptual_trc; + + long n = samples; + + BABL_PLANAR_SANITY + while (n--) + { + int band; + for (band = 0; band < 3; band++) + *(double *) dst[band] = babl_trc_from_linear (trc, (*(double *) src[band])); + for (; band < dst_bands; band++) + *(double *) dst[band] = *(double *) src[band]; + + BABL_PLANAR_STEP + } +} + +static void +g3_perceptual_to_linear (Babl *conversion, + int src_bands, + char **src, + int *src_pitch, + int dst_bands, + char **dst, + int *dst_pitch, + long samples) +{ + const Babl *trc = perceptual_trc; + long n = samples; + + BABL_PLANAR_SANITY + while (n--) + { + int band; + for (band = 0; band < 3; band++) + { + *(double *) dst[band] = babl_trc_to_linear (trc, (*(double *) src[band])); + } + for (; band < dst_bands; band++) + { + if (band < src_bands) + *(double *) dst[band] = *(double *) src[band]; + else + *(double *) dst[band] = 1.0; + } + BABL_PLANAR_STEP + } +} + +static void +rgba2rgba_perceptual_associated_alpha (Babl *conversion, + char *src, + char *dst, + long samples) +{ + const Babl *trc = perceptual_trc; + long n = samples; + + while (n--) + { + double alpha = ((double *) src)[3]; + double used_alpha = babl_epsilon_for_zero (alpha); + + ((double *) dst)[0] = babl_trc_from_linear (trc, ((double *) src)[0]) * used_alpha; + ((double *) dst)[1] = babl_trc_from_linear (trc, ((double *) src)[1]) * used_alpha; + ((double *) dst)[2] = babl_trc_from_linear (trc, ((double *) src)[2]) * used_alpha; + ((double *) dst)[3] = alpha; + src += 4 * sizeof (double); + dst += 4 * sizeof (double); + } +} + + +static void +rgba_perceptual_associated_alpha2rgba (Babl *conversion, + char *src, + char *dst, + long samples) +{ + const Babl *trc = perceptual_trc; + long n = samples; + + while (n--) + { + double alpha = ((double *) src)[3]; + double used_alpha = babl_epsilon_for_zero (alpha); + double reciprocal = 1.0/used_alpha; + + ((double *) dst)[0] = babl_trc_to_linear (trc, ((double *) src)[0] * reciprocal); + ((double *) dst)[1] = babl_trc_to_linear (trc, ((double *) src)[1] * reciprocal); + ((double *) dst)[2] = babl_trc_to_linear (trc, ((double *) src)[2] * reciprocal); + ((double *) dst)[3] = alpha; + + src += 4 * sizeof (double); + dst += 4 * sizeof (double); + } +} + + +static void +rgba2rgba_perceptual (Babl *conversion, + char *src, + char *dst, + long samples) +{ + const Babl *trc = perceptual_trc; + long n = samples; + + while (n--) + { + double alpha = ((double *) src)[3]; + ((double *) dst)[0] = babl_trc_from_linear (trc, ((double *) src)[0]); + ((double *) dst)[1] = babl_trc_from_linear (trc, ((double *) src)[1]); + ((double *) dst)[2] = babl_trc_from_linear (trc, ((double *) src)[2]); + ((double *) dst)[3] = alpha; + src += 4 * sizeof (double); + dst += 4 * sizeof (double); + } +} + +static void +rgba_perceptual2rgba (Babl *conversion, + char *src, + char *dst, + long samples) +{ + const Babl *trc = perceptual_trc; + long n = samples; + + while (n--) + { + double alpha = ((double *) src)[3]; + ((double *) dst)[0] = babl_trc_to_linear (trc, ((double *) src)[0]); + ((double *) dst)[1] = babl_trc_to_linear (trc, ((double *) src)[1]); + ((double *) dst)[2] = babl_trc_to_linear (trc, ((double *) src)[2]); + ((double *) dst)[3] = alpha; + + src += 4 * sizeof (double); + dst += 4 * sizeof (double); + } +} + +static void +conversions (void) +{ + if (!perceptual_trc) + perceptual_trc = babl_trc ("sRGB"); + + babl_conversion_new ( + babl_model_from_id (BABL_RGBA), + babl_model_from_id (BABL_RGBA), + "planar", copy_strip_1, + NULL + ); + + + babl_conversion_new ( + babl_model_from_id (BABL_RGB), + babl_model_from_id (BABL_RGBA), + "planar", copy_strip_1, + NULL + ); + + babl_conversion_new ( + babl_model_from_id (BABL_RGBA), + babl_model_from_id (BABL_RGB), + "planar", copy_strip_1, + NULL + ); + + babl_conversion_new ( + babl_model_from_id (BABL_RGBA), + babl_model_from_id (BABL_RGBA_PREMULTIPLIED), + "planar", separate_alpha_to_associated_alpha, + NULL + ); + babl_conversion_new ( + babl_model_from_id (BABL_RGBA_PREMULTIPLIED), + babl_model_from_id (BABL_RGBA), + "planar", associated_alpha_to_separate_alpha, + NULL + ); + + babl_conversion_new ( + babl_model_from_id (BABL_RGBA), + babl_model_from_id (BABL_RGB_NONLINEAR), + "planar", g3_nonlinear_from_linear, + NULL + ); + babl_conversion_new ( + babl_model_from_id (BABL_RGB_NONLINEAR), + babl_model_from_id (BABL_RGBA), + "planar", g3_nonlinear_to_linear, + NULL + ); + + + babl_conversion_new ( + babl_model_from_id (BABL_RGBA), + babl_model_from_id (BABL_RGBA_NONLINEAR), + "linear", rgba2rgba_nonlinear, + NULL); + babl_conversion_new ( + babl_model_from_id (BABL_RGBA_NONLINEAR), + babl_model_from_id (BABL_RGBA), + "linear", rgba_nonlinear2rgba, + NULL); + + babl_conversion_new ( + babl_model_from_id (BABL_RGBA), + babl_model_from_id (BABL_RGBA_NONLINEAR_PREMULTIPLIED), + "linear", rgba2rgba_nonlinear_associated_alpha, + NULL); + babl_conversion_new ( + babl_model_from_id (BABL_RGBA_NONLINEAR_PREMULTIPLIED), + babl_model_from_id (BABL_RGBA), + "linear", rgba_nonlinear_associated_alpha2rgba, + NULL); +////////// + + babl_conversion_new ( + babl_model_from_id (BABL_RGBA), + babl_model_from_id (BABL_RGB_PERCEPTUAL), + "planar", g3_perceptual_from_linear, + NULL + ); + babl_conversion_new ( + babl_model_from_id (BABL_RGB_PERCEPTUAL), + babl_model_from_id (BABL_RGBA), + "planar", g3_perceptual_to_linear, + NULL + ); + + babl_conversion_new ( + babl_model_from_id (BABL_RGBA), + babl_model_from_id (BABL_RGBA_PERCEPTUAL), + "linear", rgba2rgba_perceptual, + NULL); + babl_conversion_new ( + babl_model_from_id (BABL_RGBA_PERCEPTUAL), + babl_model_from_id (BABL_RGBA), + "linear", rgba_perceptual2rgba, + NULL); + + babl_conversion_new ( + babl_model_from_id (BABL_RGBA), + babl_model_from_id (BABL_RGBA_PERCEPTUAL_PREMULTIPLIED), + "linear", rgba2rgba_perceptual_associated_alpha, + NULL); + babl_conversion_new ( + babl_model_from_id (BABL_RGBA_PERCEPTUAL_PREMULTIPLIED), + babl_model_from_id (BABL_RGBA), + "linear", rgba_perceptual_associated_alpha2rgba, + NULL); +} + +static void +formats (void) +{ + babl_format_new ( + "id", BABL_SRGB, + babl_model_from_id (BABL_RGB_PERCEPTUAL), + babl_type_from_id (BABL_U8), + babl_component_from_id (BABL_RED_PERCEPTUAL), + babl_component_from_id (BABL_GREEN_PERCEPTUAL), + babl_component_from_id (BABL_BLUE_PERCEPTUAL), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_RGB_NONLINEAR), + babl_type_from_id (BABL_U8), + babl_component_from_id (BABL_RED_NONLINEAR), + babl_component_from_id (BABL_GREEN_NONLINEAR), + babl_component_from_id (BABL_BLUE_NONLINEAR), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_RGBA_NONLINEAR), + babl_type_from_id (BABL_U8), + babl_component_from_id (BABL_RED_NONLINEAR), + babl_component_from_id (BABL_GREEN_NONLINEAR), + babl_component_from_id (BABL_BLUE_NONLINEAR), + babl_component_from_id (BABL_ALPHA), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_RGBA_PERCEPTUAL), + babl_type_from_id (BABL_U8), + babl_component_from_id (BABL_RED_PERCEPTUAL), + babl_component_from_id (BABL_GREEN_PERCEPTUAL), + babl_component_from_id (BABL_BLUE_PERCEPTUAL), + babl_component_from_id (BABL_ALPHA), + NULL); + + babl_format_new ( + "id", BABL_RGBA_FLOAT, + babl_model_from_id (BABL_RGBA), + babl_type_from_id (BABL_FLOAT), + babl_component_from_id (BABL_RED), + babl_component_from_id (BABL_GREEN), + babl_component_from_id (BABL_BLUE), + babl_component_from_id (BABL_ALPHA), + NULL); + + babl_format_new ( + "id", BABL_RGB_FLOAT, + babl_model_from_id (BABL_RGB), + babl_type_from_id (BABL_FLOAT), + babl_component_from_id (BABL_RED), + babl_component_from_id (BABL_GREEN), + babl_component_from_id (BABL_BLUE), + NULL); + + babl_format_new ( + "id", BABL_RGB_HALF, + babl_model_from_id (BABL_RGB), + babl_type_from_id (BABL_HALF), + babl_component_from_id (BABL_RED), + babl_component_from_id (BABL_GREEN), + babl_component_from_id (BABL_BLUE), + NULL); + + babl_format_new ( + "id", BABL_RGBA_HALF, + babl_model_from_id (BABL_RGBA), + babl_type_from_id (BABL_HALF), + babl_component_from_id (BABL_RED), + babl_component_from_id (BABL_GREEN), + babl_component_from_id (BABL_BLUE), + babl_component_from_id (BABL_ALPHA), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_RGBA_PREMULTIPLIED), + babl_type_from_id (BABL_HALF), + babl_component_from_id (BABL_RED_MUL_ALPHA), + babl_component_from_id (BABL_GREEN_MUL_ALPHA), + babl_component_from_id (BABL_BLUE_MUL_ALPHA), + babl_component_from_id (BABL_ALPHA), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_RGB_NONLINEAR), + babl_type_from_id (BABL_HALF), + babl_component_from_id (BABL_RED_NONLINEAR), + babl_component_from_id (BABL_GREEN_NONLINEAR), + babl_component_from_id (BABL_BLUE_NONLINEAR), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_RGBA_NONLINEAR), + babl_type_from_id (BABL_HALF), + babl_component_from_id (BABL_RED_NONLINEAR), + babl_component_from_id (BABL_GREEN_NONLINEAR), + babl_component_from_id (BABL_BLUE_NONLINEAR), + babl_component_from_id (BABL_ALPHA), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_RGBA_NONLINEAR_PREMULTIPLIED), + babl_type_from_id (BABL_HALF), + babl_component_from_id (BABL_RED_NONLINEAR_MUL_ALPHA), + babl_component_from_id (BABL_GREEN_NONLINEAR_MUL_ALPHA), + babl_component_from_id (BABL_BLUE_NONLINEAR_MUL_ALPHA), + babl_component_from_id (BABL_ALPHA), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_RGB_PERCEPTUAL), + babl_type_from_id (BABL_HALF), + babl_component_from_id (BABL_RED_PERCEPTUAL), + babl_component_from_id (BABL_GREEN_PERCEPTUAL), + babl_component_from_id (BABL_BLUE_PERCEPTUAL), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_RGBA_PERCEPTUAL), + babl_type_from_id (BABL_HALF), + babl_component_from_id (BABL_RED_PERCEPTUAL), + babl_component_from_id (BABL_GREEN_PERCEPTUAL), + babl_component_from_id (BABL_BLUE_PERCEPTUAL), + babl_component_from_id (BABL_ALPHA), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_RGBA_PERCEPTUAL_PREMULTIPLIED), + babl_type_from_id (BABL_HALF), + babl_component_from_id (BABL_RED_PERCEPTUAL_MUL_ALPHA), + babl_component_from_id (BABL_GREEN_PERCEPTUAL_MUL_ALPHA), + babl_component_from_id (BABL_BLUE_PERCEPTUAL_MUL_ALPHA), + babl_component_from_id (BABL_ALPHA), + NULL); + + /******/ + babl_format_new ( + babl_model_from_id (BABL_RGB), + babl_type ("u15"), + babl_component_from_id (BABL_RED), + babl_component_from_id (BABL_GREEN), + babl_component_from_id (BABL_BLUE), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_RGBA), + babl_type ("u15"), + babl_component_from_id (BABL_RED), + babl_component_from_id (BABL_GREEN), + babl_component_from_id (BABL_BLUE), + babl_component_from_id (BABL_ALPHA), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_RGBA_PREMULTIPLIED), + babl_type ("u15"), + babl_component_from_id (BABL_RED_MUL_ALPHA), + babl_component_from_id (BABL_GREEN_MUL_ALPHA), + babl_component_from_id (BABL_BLUE_MUL_ALPHA), + babl_component_from_id (BABL_ALPHA), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_RGB_NONLINEAR), + babl_type ("u15"), + babl_component_from_id (BABL_RED_NONLINEAR), + babl_component_from_id (BABL_GREEN_NONLINEAR), + babl_component_from_id (BABL_BLUE_NONLINEAR), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_RGB_NONLINEAR), + babl_type ("float"), + babl_component_from_id (BABL_RED_NONLINEAR), + babl_component_from_id (BABL_GREEN_NONLINEAR), + babl_component_from_id (BABL_BLUE_NONLINEAR), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_RGBA_NONLINEAR), + babl_type ("u15"), + babl_component_from_id (BABL_RED_NONLINEAR), + babl_component_from_id (BABL_GREEN_NONLINEAR), + babl_component_from_id (BABL_BLUE_NONLINEAR), + babl_component_from_id (BABL_ALPHA), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_RGBA_NONLINEAR_PREMULTIPLIED), + babl_type ("u15"), + babl_component_from_id (BABL_RED_NONLINEAR_MUL_ALPHA), + babl_component_from_id (BABL_GREEN_NONLINEAR_MUL_ALPHA), + babl_component_from_id (BABL_BLUE_NONLINEAR_MUL_ALPHA), + babl_component_from_id (BABL_ALPHA), + NULL); + + + babl_format_new ( + babl_model_from_id (BABL_RGB), + babl_type_from_id (BABL_U32), + babl_component_from_id (BABL_RED), + babl_component_from_id (BABL_GREEN), + babl_component_from_id (BABL_BLUE), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_RGBA), + babl_type_from_id (BABL_U32), + babl_component_from_id (BABL_RED), + babl_component_from_id (BABL_GREEN), + babl_component_from_id (BABL_BLUE), + babl_component_from_id (BABL_ALPHA), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_RGBA_PREMULTIPLIED), + babl_type_from_id (BABL_U32), + babl_component_from_id (BABL_RED_MUL_ALPHA), + babl_component_from_id (BABL_GREEN_MUL_ALPHA), + babl_component_from_id (BABL_BLUE_MUL_ALPHA), + babl_component_from_id (BABL_ALPHA), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_RGB_NONLINEAR), + babl_type_from_id (BABL_U32), + babl_component_from_id (BABL_RED_NONLINEAR), + babl_component_from_id (BABL_GREEN_NONLINEAR), + babl_component_from_id (BABL_BLUE_NONLINEAR), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_RGBA_NONLINEAR), + babl_type_from_id (BABL_U32), + babl_component_from_id (BABL_RED_NONLINEAR), + babl_component_from_id (BABL_GREEN_NONLINEAR), + babl_component_from_id (BABL_BLUE_NONLINEAR), + babl_component_from_id (BABL_ALPHA), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_RGBA_NONLINEAR_PREMULTIPLIED), + babl_type_from_id (BABL_U32), + babl_component_from_id (BABL_RED_NONLINEAR_MUL_ALPHA), + babl_component_from_id (BABL_GREEN_NONLINEAR_MUL_ALPHA), + babl_component_from_id (BABL_BLUE_NONLINEAR_MUL_ALPHA), + babl_component_from_id (BABL_ALPHA), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_RGBA_NONLINEAR_PREMULTIPLIED), + babl_type_from_id (BABL_FLOAT), + babl_component_from_id (BABL_RED_NONLINEAR_MUL_ALPHA), + babl_component_from_id (BABL_GREEN_NONLINEAR_MUL_ALPHA), + babl_component_from_id (BABL_BLUE_NONLINEAR_MUL_ALPHA), + babl_component_from_id (BABL_ALPHA), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_RGB_PERCEPTUAL), + babl_type_from_id (BABL_U32), + babl_component_from_id (BABL_RED_PERCEPTUAL), + babl_component_from_id (BABL_GREEN_PERCEPTUAL), + babl_component_from_id (BABL_BLUE_PERCEPTUAL), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_RGBA_PERCEPTUAL), + babl_type_from_id (BABL_U32), + babl_component_from_id (BABL_RED_PERCEPTUAL), + babl_component_from_id (BABL_GREEN_PERCEPTUAL), + babl_component_from_id (BABL_BLUE_PERCEPTUAL), + babl_component_from_id (BABL_ALPHA), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_RGBA_PERCEPTUAL_PREMULTIPLIED), + babl_type_from_id (BABL_U32), + babl_component_from_id (BABL_RED_PERCEPTUAL_MUL_ALPHA), + babl_component_from_id (BABL_GREEN_PERCEPTUAL_MUL_ALPHA), + babl_component_from_id (BABL_BLUE_PERCEPTUAL_MUL_ALPHA), + babl_component_from_id (BABL_ALPHA), + NULL); + + +#ifdef XXXX + babl_format_new ( + "id", BABL_RGB565, + babl_model_from_id (BABL_RGB), + babl_component_from_id (BABL_RED), + babl_component_from_id (BABL_GREEN), + babl_component_from_id (BABL_BLUE), + + ); +#endif + + +} + + +static void +g3_nonlinear_from_linear_float (Babl *conversion, + int src_bands, + char **src, + int *src_pitch, + int dst_bands, + char **dst, + int *dst_pitch, + long samples) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + const Babl **trc = (void*)space->space.trc; + + long n = samples; + + BABL_PLANAR_SANITY + while (n--) + { + int band; + for (band = 0; band < 3; band++) + *(float *) dst[band] = babl_trc_from_linear (trc[band], (*(float *) src[band])); + for (; band < dst_bands; band++) + *(float *) dst[band] = *(float *) src[band]; + + BABL_PLANAR_STEP + } +} + + +static void +g3_nonlinear_to_linear_float (Babl *conversion, + int src_bands, + char **src, + int *src_pitch, + int dst_bands, + char **dst, + int *dst_pitch, + long samples) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + const Babl **trc = (void*)space->space.trc; + long n = samples; + + BABL_PLANAR_SANITY + while (n--) + { + int band; + for (band = 0; band < 3; band++) + { + *(float *) dst[band] = babl_trc_to_linear (trc[band], (*(float *) src[band])); + } + for (; band < dst_bands; band++) + { + if (band < src_bands) + *(float *) dst[band] = *(float *) src[band]; + else + *(float *) dst[band] = 1.0f; + } + BABL_PLANAR_STEP + } +} + + +static void +separate_alpha_to_associated_alpha_float (Babl *conversion, + int src_bands, + char **src, + int *src_pitch, + int dst_bands, + char **dst, + int *dst_pitch, + long samples) +{ + long n = samples; + + BABL_PLANAR_SANITY + while (n--) + { + float alpha = *(float *) src[src_bands - 1]; + float used_alpha = babl_epsilon_for_zero_float (alpha); + int band; + + for (band = 0; band < src_bands - 1; band++) + { + *(float *) dst[band] = *(float *) src[band] * used_alpha; + } + *(float *) dst[dst_bands - 1] = alpha; + + BABL_PLANAR_STEP + } +} + + +static void +associated_alpha_to_separate_alpha_float (Babl *conversion, + int src_bands, + char **src, + int *src_pitch, + int dst_bands, + char **dst, + int *dst_pitch, + long samples) +{ + long n = samples; + + BABL_PLANAR_SANITY + while (n--) + { + int band; + float alpha = *(float *) src[src_bands - 1]; + float used_alpha = babl_epsilon_for_zero_float (alpha); + float recip_alpha = 1.0f / used_alpha; + + for (band = 0; band < src_bands - 1; band++) + *(float *) dst[band] = *(float *) src[band] * recip_alpha; + *(float *) dst[dst_bands - 1] = alpha; + + BABL_PLANAR_STEP + } +} + + +static void +rgba2rgba_nonlinear_associated_alpha_float (Babl *conversion, + char *src, + char *dst, + long samples) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + const Babl **trc = (void*)space->space.trc; + long n = samples; + + while (n--) + { + float alpha = ((float *) src)[3]; + float used_alpha = babl_epsilon_for_zero_float (alpha); + + ((float *) dst)[0] = babl_trc_from_linear (trc[0], ((float *) src)[0]) * used_alpha; + ((float *) dst)[1] = babl_trc_from_linear (trc[1], ((float *) src)[1]) * used_alpha; + ((float *) dst)[2] = babl_trc_from_linear (trc[2], ((float *) src)[2]) * used_alpha; + ((float *) dst)[3] = alpha; + src += 4 * sizeof (float); + dst += 4 * sizeof (float); + } +} + + +static void +rgba_nonlinear_associated_alpha2rgba_float (Babl *conversion, + char *src, + char *dst, + long samples) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + const Babl **trc = (void*)space->space.trc; + long n = samples; + + while (n--) + { + float alpha = ((float *) src)[3]; + float used_alpha = babl_epsilon_for_zero_float (alpha); + float reciprocal= 1.0f / used_alpha; + + ((float *) dst)[0] = babl_trc_to_linear (trc[0], ((float *) src)[0] * reciprocal); + ((float *) dst)[1] = babl_trc_to_linear (trc[1], ((float *) src)[1] * reciprocal); + ((float *) dst)[2] = babl_trc_to_linear (trc[2], ((float *) src)[2] * reciprocal); + ((float *) dst)[3] = alpha; + + src += 4 * sizeof (float); + dst += 4 * sizeof (float); + } +} + + +static void +rgba2rgba_float (Babl *conversion, + char *src, + char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + ((float *) dst)[0] = ((float *) src)[0]; + ((float *) dst)[1] = ((float *) src)[1]; + ((float *) dst)[2] = ((float *) src)[2]; + ((float *) dst)[3] = ((float *) src)[3]; + src += 4 * sizeof (float); + dst += 4 * sizeof (float); + } +} + + +static void +rgba2rgba_perceptual_float (Babl *conversion, + char *src, + char *dst, + long samples) +{ + const Babl *trc = perceptual_trc; + long n = samples; + + while (n--) + { + float alpha = ((float *) src)[3]; + ((float *) dst)[0] = babl_trc_from_linear (trc, ((float *) src)[0]); + ((float *) dst)[1] = babl_trc_from_linear (trc, ((float *) src)[1]); + ((float *) dst)[2] = babl_trc_from_linear (trc, ((float *) src)[2]); + ((float *) dst)[3] = alpha; + src += 4 * sizeof (float); + dst += 4 * sizeof (float); + } +} + +static void +rgba_perceptual2rgba_float (Babl *conversion, + char *src, + char *dst, + long samples) +{ + const Babl *trc = perceptual_trc; + long n = samples; + + while (n--) + { + float alpha = ((float *) src)[3]; + ((float *) dst)[0] = babl_trc_to_linear (trc, ((float *) src)[0]); + ((float *) dst)[1] = babl_trc_to_linear (trc, ((float *) src)[1]); + ((float *) dst)[2] = babl_trc_to_linear (trc, ((float *) src)[2]); + ((float *) dst)[3] = alpha; + + src += 4 * sizeof (float); + dst += 4 * sizeof (float); + } +} + + +static void +g3_perceptual_from_linear_float (Babl *conversion, + int src_bands, + char **src, + int *src_pitch, + int dst_bands, + char **dst, + int *dst_pitch, + long samples) +{ + const Babl *trc = perceptual_trc; + + long n = samples; + + BABL_PLANAR_SANITY + while (n--) + { + int band; + for (band = 0; band < 3; band++) + *(float *) dst[band] = babl_trc_from_linear (trc, (*(float *) src[band])); + for (; band < dst_bands; band++) + *(float *) dst[band] = *(float *) src[band]; + + BABL_PLANAR_STEP + } +} + +static void +g3_perceptual_to_linear_float (Babl *conversion, + int src_bands, + char **src, + int *src_pitch, + int dst_bands, + char **dst, + int *dst_pitch, + long samples) +{ + const Babl *trc = perceptual_trc; + long n = samples; + + BABL_PLANAR_SANITY + while (n--) + { + int band; + for (band = 0; band < 3; band++) + { + *(float *) dst[band] = babl_trc_to_linear (trc, (*(float *) src[band])); + } + for (; band < dst_bands; band++) + { + if (band < src_bands) + *(float *) dst[band] = *(float *) src[band]; + else + *(float *) dst[band] = 1.0; + } + BABL_PLANAR_STEP + } +} + + +static void +init_single_precision (void) +{ + + babl_format_new ( + babl_model_from_id (BABL_RGBA_PREMULTIPLIED), + babl_type_from_id (BABL_FLOAT), + babl_component_from_id (BABL_RED_MUL_ALPHA), + babl_component_from_id (BABL_GREEN_MUL_ALPHA), + babl_component_from_id (BABL_BLUE_MUL_ALPHA), + babl_component_from_id (BABL_ALPHA), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_RGBA_NONLINEAR), + babl_type_from_id (BABL_FLOAT), + babl_component_from_id (BABL_RED_NONLINEAR), + babl_component_from_id (BABL_GREEN_NONLINEAR), + babl_component_from_id (BABL_BLUE_NONLINEAR), + babl_component_from_id (BABL_ALPHA), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_RGBA_PERCEPTUAL), + babl_type_from_id (BABL_FLOAT), + babl_component_from_id (BABL_RED_PERCEPTUAL), + babl_component_from_id (BABL_GREEN_PERCEPTUAL), + babl_component_from_id (BABL_BLUE_PERCEPTUAL), + babl_component_from_id (BABL_ALPHA), + NULL); + + babl_format_new ( + babl_model_from_id (BABL_RGB_PERCEPTUAL), + babl_type_from_id (BABL_FLOAT), + babl_component_from_id (BABL_RED_PERCEPTUAL), + babl_component_from_id (BABL_GREEN_PERCEPTUAL), + babl_component_from_id (BABL_BLUE_PERCEPTUAL), + NULL); + + + babl_conversion_new ( + babl_format ("RGBA float"), + babl_format ("RGBA float"), + "linear", rgba2rgba_float, + NULL + ); + + babl_conversion_new ( + babl_format ("R'G'B' float"), + babl_format ("RGBA float"), + "planar", g3_nonlinear_to_linear_float, + NULL + ); + + babl_conversion_new ( + babl_format ("RGBA float"), + babl_format ("R'G'B' float"), + "planar", g3_nonlinear_from_linear_float, + NULL + ); + babl_conversion_new ( + babl_format ("R'G'B'A float"), + babl_format ("RGBA float"), + "planar", g3_nonlinear_to_linear_float, + NULL + ); + + + babl_conversion_new ( + babl_format ("R~G~B~ float"), + babl_format ("RGBA float"), + "planar", g3_perceptual_to_linear_float, + NULL + ); + + babl_conversion_new ( + babl_format ("RGBA float"), + babl_format ("R~G~B~ float"), + "planar", g3_perceptual_from_linear_float, + NULL + ); + + + + babl_conversion_new ( + babl_format ("RGBA float"), + babl_format ("R~G~B~A float"), + "linear", rgba2rgba_perceptual_float, + NULL + ); + babl_conversion_new ( + babl_format ("R~G~B~A float"), + babl_format ("RGBA float"), + "linear", rgba_perceptual2rgba_float, + NULL + ); + + babl_conversion_new ( + babl_format ("RGBA float"), + babl_format ("R'G'B'A float"), + "planar", g3_nonlinear_from_linear_float, + NULL + ); + + + babl_conversion_new ( + babl_format ("RGBA float"), + babl_format ("R'aG'aB'aA float"), + "linear", rgba2rgba_nonlinear_associated_alpha_float, + NULL); + babl_conversion_new ( + babl_format ("R'aG'aB'aA float"), + babl_format ("RGBA float"), + "linear", rgba_nonlinear_associated_alpha2rgba_float, + NULL); + + + babl_conversion_new ( + babl_format ("RGBA float"), + babl_format ("RaGaBaA float"), + "planar", separate_alpha_to_associated_alpha_float, + NULL + ); + babl_conversion_new ( + babl_format ("RaGaBaA float"), + babl_format ("RGBA float"), + "planar", associated_alpha_to_separate_alpha_float, + NULL + ); + + +} diff --git a/babl/base/model-ycbcr.c b/babl/base/model-ycbcr.c new file mode 100644 index 0000000..64db6a2 --- /dev/null +++ b/babl/base/model-ycbcr.c @@ -0,0 +1,308 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include +#include +#include + +#include "babl.h" +#include "babl-classes.h" +#include "babl-ids.h" +#include "babl-base.h" + +#include "util.h" + +static void components (void); +static void models (void); +static void conversions (void); +static void formats (void); + +void +babl_base_model_ycbcr (void) +{ + components (); + models (); + conversions (); + formats (); +} + +static void +components (void) +{ + babl_component_new ( + "Cb", + "id", BABL_CB, + "chroma", + NULL); + + babl_component_new ( + "Cr", + "id", BABL_CR, + "chroma", + NULL); +} + +static void +models (void) +{ + babl_model_new ( + "id", BABL_YCBCR, + "doc", "Y'CbCr video format model, NB! math is tuned to sRGB space", + babl_component_from_id (BABL_GRAY_NONLINEAR), + babl_component_from_id (BABL_CB), + babl_component_from_id (BABL_CR), + NULL); + + babl_model_new ( + "id", BABL_YCBCR_ALPHA, + "doc", "Y'CbCr video format model, separate alpha NB! math is tuned to sRGB space", + babl_component_from_id (BABL_GRAY_NONLINEAR), + babl_component_from_id (BABL_CB), + babl_component_from_id (BABL_CR), + babl_component_from_id (BABL_ALPHA), + "alpha", + NULL); +} + +static void +rgba_to_ycbcra (BablConversion *conversion, + char *src, + char *dst, + long n) +{ + while (n--) + { + double red = ((double *) src)[0]; + double green = ((double *) src)[1]; + double blue = ((double *) src)[2]; + double alpha = ((double *) src)[3]; + + double luminance, cb, cr; + + red = linear_to_gamma_2_2 (red); + green = linear_to_gamma_2_2 (green); + blue = linear_to_gamma_2_2 (blue); + + luminance = 0.299 * red + 0.587 * green + 0.114 * blue; + cb = -0.168736 * red - 0.331264 * green + 0.5 * blue; + cr = 0.5 * red - 0.418688 * green - 0.081312 * blue; + + ((double *) dst)[0] = luminance; + ((double *) dst)[1] = cb; + ((double *) dst)[2] = cr; + ((double *) dst)[3] = alpha; + + src += sizeof (double) * 4; + dst += sizeof (double) * 4; + } +} + + +static void +rgba_to_ycbcr (BablConversion *conversion, + char *src, + char *dst, + long n) +{ + while (n--) + { + double red = ((double *) src)[0]; + double green = ((double *) src)[1]; + double blue = ((double *) src)[2]; + + double luminance, cb, cr; + + red = linear_to_gamma_2_2 (red); + green = linear_to_gamma_2_2 (green); + blue = linear_to_gamma_2_2 (blue); + + luminance = 0.299 * red + 0.587 * green + 0.114 * blue; + cb = -0.168736 * red - 0.331264 * green + 0.5 * blue; + cr = 0.5 * red - 0.418688 * green - 0.081312 * blue; + + ((double *) dst)[0] = luminance; + ((double *) dst)[1] = cb; + ((double *) dst)[2] = cr; + + src += sizeof (double) * 4; + dst += sizeof (double) * 3; + } +} + +static void +ycbcra_to_rgba (BablConversion *conversion, + char *src, + char *dst, + long n) +{ + while (n--) + { + double luminance = ((double *) src)[0]; + double cb = ((double *) src)[1]; + double cr = ((double *) src)[2]; + double alpha = ((double *) src)[3]; + + double red, green, blue; + + red = 1.0 * luminance + 0.0 * cb + 1.40200 * cr; + green = 1.0 * luminance - 0.344136 * cb - 0.71414136 * cr; + blue = 1.0 * luminance + 1.772 * cb + 0.0 * cr; + + red = gamma_2_2_to_linear (red); + green = gamma_2_2_to_linear (green); + blue = gamma_2_2_to_linear (blue); + + ((double *) dst)[0] = red; + ((double *) dst)[1] = green; + ((double *) dst)[2] = blue; + ((double *) dst)[3] = alpha; + + src += sizeof (double) * 4; + dst += sizeof (double) * 4; + } +} + +static void +ycbcr_to_rgba (BablConversion *conversion, + char *src, + char *dst, + long n) +{ + while (n--) + { + double luminance = ((double *) src)[0]; + double cb = ((double *) src)[1]; + double cr = ((double *) src)[2]; + + double red, green, blue; + + red = 1.0 * luminance + 0.0 * cb + 1.40200 * cr; + green = 1.0 * luminance - 0.344136 * cb - 0.71414136 * cr; + blue = 1.0 * luminance + 1.772 * cb + 0.0 * cr; + + red = gamma_2_2_to_linear (red); + green = gamma_2_2_to_linear (green); + blue = gamma_2_2_to_linear (blue); + + ((double *) dst)[0] = red; + ((double *) dst)[1] = green; + ((double *) dst)[2] = blue; + ((double *) dst)[3] = 1.0; + + src += sizeof (double) * 3; + dst += sizeof (double) * 4; + } +} + +static void +conversions (void) +{ + babl_conversion_new ( + babl_model_from_id (BABL_RGBA), + babl_model_from_id (BABL_YCBCR), + "linear", rgba_to_ycbcr, + NULL + ); + babl_conversion_new ( + babl_model_from_id (BABL_YCBCR), + babl_model_from_id (BABL_RGBA), + "linear", ycbcr_to_rgba, + NULL + ); + babl_conversion_new ( + babl_model_from_id (BABL_RGBA), + babl_model_from_id (BABL_YCBCR_ALPHA), + "linear", rgba_to_ycbcra, + NULL + ); + babl_conversion_new ( + babl_model_from_id (BABL_YCBCR_ALPHA), + babl_model_from_id (BABL_RGBA), + "linear", ycbcra_to_rgba, + NULL + ); +} + +static void +formats (void) +{ + babl_format_new ( + "name", "Y'CbCr u8", + "planar", + babl_model_from_id (BABL_YCBCR), + babl_type_from_id (BABL_U8_LUMA), + babl_sampling (1, 1), + babl_component_from_id (BABL_GRAY_NONLINEAR), + babl_type_from_id (BABL_U8_CHROMA), + babl_sampling (2, 2), + babl_component_from_id (BABL_CB), + babl_sampling (2, 2), + babl_component_from_id (BABL_CR), + NULL); + +/* deactivate these for now */ +if (0) +{ + babl_format_new ( + "name", "y'cbcr420", + "id", BABL_YCBCR420, + "planar", + babl_model_from_id (BABL_YCBCR), + babl_type_from_id (BABL_U8_LUMA), + babl_sampling (1, 1), + babl_component_from_id (BABL_GRAY_NONLINEAR), + babl_type_from_id (BABL_U8_CHROMA), + babl_sampling (2, 2), + babl_component_from_id (BABL_CB), + babl_sampling (2, 2), + babl_component_from_id (BABL_CR), + NULL); + + + babl_format_new ( + "name", "y'cbcr422", + "id", BABL_YCBCR422, + "planar", + babl_model_from_id (BABL_YCBCR), + babl_type_from_id (BABL_U8_LUMA), + babl_sampling (1, 1), + babl_component_from_id (BABL_GRAY_NONLINEAR), + babl_type_from_id (BABL_U8_CHROMA), + babl_sampling (2, 1), + babl_component_from_id (BABL_CB), + babl_sampling (2, 1), + babl_component_from_id (BABL_CR), + NULL); + + babl_format_new ( + "name", "y'cbcr411", + "id", BABL_YCBCR411, + "planar", + babl_model_from_id (BABL_YCBCR), + babl_type_from_id (BABL_U8_LUMA), + babl_sampling (1, 1), + babl_component_from_id (BABL_GRAY_NONLINEAR), + babl_type_from_id (BABL_U8_CHROMA), + babl_sampling (4, 1), + babl_component_from_id (BABL_CB), + babl_sampling (4, 1), + babl_component_from_id (BABL_CR), + NULL); +} +} diff --git a/babl/base/pow-24.c b/babl/base/pow-24.c new file mode 100644 index 0000000..3bf11c8 --- /dev/null +++ b/babl/base/pow-24.c @@ -0,0 +1,156 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2013 Loren Merritt + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include +#include "util.h" +#if 0 +/* a^b = exp(b*log(a)) + * + * Extracting the exponent from a float gives us an approximate log. + * Or better yet, reinterpret the bitpattern of the whole float as an int. + * + * However, the output values of 12throot vary by less than a factor of 2 + * over the domain we care about, so we only get log() that way, not exp(). + * + * Approximate exp() with a low-degree polynomial; not exactly equal to the + * Taylor series since we're minimizing maximum error over a certain finite + * domain. It's not worthwhile to use lots of terms, since Newton's method + * has a better convergence rate once you get reasonably close to the answer. + */ +static inline double +init_newton (double x, + double exponent, + double c0, + double c1, + double c2) +{ + int iexp; + double y = frexp(x, &iexp); + y = 2*y+(iexp-2); + c1 *= M_LN2*exponent; + c2 *= M_LN2*M_LN2*exponent*exponent; + return y = c0 + c1*y + c2*y*y; +} + +/* Returns x^2.4 == (x*(x^(-1/5)))^3, using Newton's method for x^(-1/5). + */ +double +babl_pow_24 (double x) +{ + double y; + int i; + if (x > 16.0) { + /* for large values, fall back to a slower but more accurate version */ + return exp (log (x) * 2.4); + } + y = init_newton (x, -1./5, 0.9953189663, 0.9594345146, 0.6742970332); + for (i = 0; i < 3; i++) + y = (1.+1./5)*y - ((1./5)*x*(y*y))*((y*y)*(y*y)); + x *= y; + return x*x*x; +} + +/* Returns x^(1/2.4) == x*((x^(-1/6))^(1/2))^7, using Newton's method for x^(-1/6). + */ +double +babl_pow_1_24 (double x) +{ + double y; + int i; + double z; + if (x > 1024.0) { + /* for large values, fall back to a slower but more accurate version */ + return exp (log (x) * (1.0 / 2.4)); + } + y = init_newton (x, -1./12, 0.9976800269, 0.9885126933, 0.5908575383); + x = sqrt (x); + /* newton's method for x^(-1/6) */ + z = (1./6.) * x; + for (i = 0; i < 3; i++) + y = (7./6.) * y - z * ((y*y)*(y*y)*(y*y*y)); + return x*y; +} + +////////////////////////////////////////////// +/* a^b = exp(b*log(a)) + * + * Extracting the exponent from a float gives us an approximate log. + * Or better yet, reinterpret the bitpattern of the whole float as an int. + * + * However, the output values of 12throot vary by less than a factor of 2 + * over the domain we care about, so we only get log() that way, not exp(). + * + * Approximate exp() with a low-degree polynomial; not exactly equal to the + * Taylor series since we're minimizing maximum error over a certain finite + * domain. It's not worthwhile to use lots of terms, since Newton's method + * has a better convergence rate once you get reasonably close to the answer. + */ +static inline float +init_newtonf (float x, + float exponent, + float c0, + float c1, + float c2) +{ + int iexp; + float y = frexpf(x, &iexp); + y = 2*y+(iexp-2); + c1 *= M_LN2*exponent; + c2 *= M_LN2*M_LN2*exponent*exponent; + return y = c0 + c1*y + c2*y*y; +} + +/* Returns x^2.4 == (x*(x^(-1/5)))^3, using Newton's method for x^(-1/5). + */ +float +babl_pow_24f (float x) +{ + float y; + int i; + if (x > 16.0f) { + /* for large values, fall back to a slower but more accurate version */ + return expf (logf (x) * 2.4f); + } + y = init_newtonf (x, -1.f/5, 0.9953189663f, 0.9594345146f, 0.6742970332f); + for (i = 0; i < 3; i++) + y = (1.f+1.f/5)*y - ((1.f/5)*x*(y*y))*((y*y)*(y*y)); + x *= y; + return x*x*x; +} + +/* Returns x^(1/2.4) == x*((x^(-1/6))^(1/2))^7, using Newton's method for x^(-1/6). + */ +float +babl_pow_1_24f (float x) +{ + float y; + int i; + float z; + if (x > 1024.0f) { + /* for large values, fall back to a slower but more accurate version */ + return expf (logf (x) * (1.0f / 2.4f)); + } + y = init_newtonf (x, -1.f/12, 0.9976800269f, 0.9885126933f, 0.5908575383f); + x = sqrtf (x); + /* newton's method for x^(-1/6) */ + z = (1.f/6.f) * x; + for (i = 0; i < 3; i++) + y = (7.f/6.f) * y - z * ((y*y)*(y*y)*(y*y*y)); + return x*y; +} +#endif diff --git a/babl/base/pow-24.h b/babl/base/pow-24.h new file mode 100644 index 0000000..ecd1282 --- /dev/null +++ b/babl/base/pow-24.h @@ -0,0 +1,182 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#ifndef _BASE_POW_24_H +#define _BASE_POW_24_H + +static double babl_pow_1_24 (double x); +static double babl_pow_24 (double x); +static float babl_pow_1_24f (float x); +static float babl_pow_24f (float x); + + +/* a^b = exp(b*log(a)) + * + * Extracting the exponent from a float gives us an approximate log. + * Or better yet, reinterpret the bitpattern of the whole float as an int. + * + * However, the output values of 12throot vary by less than a factor of 2 + * over the domain we care about, so we only get log() that way, not exp(). + * + * Approximate exp() with a low-degree polynomial; not exactly equal to the + * Taylor series since we're minimizing maximum error over a certain finite + * domain. It's not worthwhile to use lots of terms, since Newton's method + * has a better convergence rate once you get reasonably close to the answer. + */ +static inline double +init_newton (double x, double exponent, double c0, double c1, double c2) +{ + int iexp; + double y = frexp(x, &iexp); + y = 2*y+(iexp-2); + c1 *= M_LN2*exponent; + c2 *= M_LN2*M_LN2*exponent*exponent; + return y = c0 + c1*y + c2*y*y; +} + +/* Returns x^2.4 == (x*(x^(-1/5)))^3, using Newton's method for x^(-1/5). + */ +static inline double +babl_pow_24 (double x) +{ + double y; + int i; + if (x > 16.0) { + /* for large values, fall back to a slower but more accurate version */ + return exp (log (x) * 2.4); + } + y = init_newton (x, -1./5, 0.9953189663, 0.9594345146, 0.6742970332); + for (i = 0; i < 3; i++) + y = (1.+1./5)*y - ((1./5)*x*(y*y))*((y*y)*(y*y)); + x *= y; + return x*x*x; +} + +/* Returns x^(1/2.4) == x*((x^(-1/6))^(1/2))^7, using Newton's method for x^(-1/6). + */ +static inline double +babl_pow_1_24 (double x) +{ + double y; + int i; + double z; + if (x > 1024.0) { + /* for large values, fall back to a slower but more accurate version */ + return exp (log (x) * (1.0 / 2.4)); + } + y = init_newton (x, -1./12, 0.9976800269, 0.9885126933, 0.5908575383); + x = sqrt (x); + /* newton's method for x^(-1/6) */ + z = (1./6.) * x; + for (i = 0; i < 3; i++) + y = (7./6.) * y - z * ((y*y)*(y*y)*(y*y*y)); + return x*y; +} + + +#include +/* frexpf copied from musl */ +static inline float babl_frexpf(float x, int *e) +{ + union { float f; uint32_t i; } y = { x }; + int ee = y.i>>23 & 0xff; + + if (!ee) { + if (x) { + x = babl_frexpf(x*18446744073709551616.0, e); + *e -= 64; + } else *e = 0; + return x; + } else if (ee == 0xff) { + return x; + } + + *e = ee - 0x7e; + y.i &= 0x807ffffful; + y.i |= 0x3f000000ul; + return y.f; +} + + +////////////////////////////////////////////// +/* a^b = exp(b*log(a)) + * + * Extracting the exponent from a float gives us an approximate log. + * Or better yet, reinterpret the bitpattern of the whole float as an int. + * + * However, the output values of 12throot vary by less than a factor of 2 + * over the domain we care about, so we only get log() that way, not exp(). + * + * Approximate exp() with a low-degree polynomial; not exactly equal to the + * Taylor series since we're minimizing maximum error over a certain finite + * domain. It's not worthwhile to use lots of terms, since Newton's method + * has a better convergence rate once you get reasonably close to the answer. + */ +static inline float +init_newtonf (float x, float exponent, float c0, float c1, float c2) +{ + int iexp = 0; + float y = babl_frexpf(x, &iexp); + y = 2*y+(iexp-2); + c1 *= M_LN2*exponent; + c2 *= M_LN2*M_LN2*exponent*exponent; + return y = c0 + c1*y + c2*y*y; +} + +/* Returns x^2.4 == (x*(x^(-1/5)))^3, using Newton's method for x^(-1/5). + */ +static inline float +babl_pow_24f (float x) +{ + float y; + int i; + if (x > 16.0f) { + /* for large values, fall back to a slower but more accurate version */ + return expf (logf (x) * 2.4f); + } + y = init_newtonf (x, -1.f/5, 0.9953189663f, 0.9594345146f, 0.6742970332f); + for (i = 0; i < 3; i++) + y = (1.f+1.f/5)*y - ((1.f/5)*x*(y*y))*((y*y)*(y*y)); + x *= y; + return x*x*x; +} + +/* Returns x^(1/2.4) == x*((x^(-1/6))^(1/2))^7, using Newton's method for x^(-1/6). + */ +static inline float +babl_pow_1_24f (float x) +{ + float y; + int i; + float z; + if (x > 1024.0f) { + /* for large values, fall back to a slower but more accurate version */ + return expf (logf (x) * (1.0f / 2.4f)); + } + y = init_newtonf (x, -1.f/12, 0.9976800269f, 0.9885126933f, 0.5908575383f); + x = sqrtf (x); + /* newton's method for x^(-1/6) */ + z = (1.f/6.f) * x; + for (i = 0; i < 3; i++) + y = (7.f/6.f) * y - z * ((y*y)*(y*y)*(y*y*y)); + return x*y; +} + + + +#endif diff --git a/babl/base/type-float.c b/babl/base/type-float.c new file mode 100644 index 0000000..5b03b3f --- /dev/null +++ b/babl/base/type-float.c @@ -0,0 +1,115 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include +#include + +#include "babl.h" +#include "babl-classes.h" +#include "babl-ids.h" +#include "babl-base.h" + +static void +convert_double_float (BablConversion *conversion, + char *src, + char *dst, + int src_pitch, + int dst_pitch, + long n) +{ + while (n--) + { + (*(float *) dst) = (*(double *) src); + dst += dst_pitch; + src += src_pitch; + } +} + +static void +convert_float_double (BablConversion *conversion, + char *src, + char *dst, + int src_pitch, + int dst_pitch, + long n) +{ + while (n--) + { + (*(double *) dst) = (*(float *) src); + dst += dst_pitch; + src += src_pitch; + } +} + +static long +convert_float_float (const Babl *babl, + char *src, + char *dst, + int src_pitch, + int dst_pitch, + long n) +{ + if (src_pitch == 32 && + dst_pitch == 32) + { + memcpy (dst, src, n / 4); + return n; + } + + while (n--) + { + (*(float *) dst) = (*(float *) src); + dst += dst_pitch; + src += src_pitch; + } + return n; +} + + +void +babl_base_type_float (void) +{ + babl_type_new ( + "float", + "id", BABL_FLOAT, + "bits", 32, + "doc", "IEEE 754 single precision", + NULL); + + babl_conversion_new ( + babl_type_from_id (BABL_FLOAT), + babl_type_from_id (BABL_DOUBLE), + "plane", convert_float_double, + NULL + ); + + babl_conversion_new ( + babl_type_from_id (BABL_DOUBLE), + babl_type_from_id (BABL_FLOAT), + "plane", convert_double_float, + NULL + ); + + babl_conversion_new ( + babl_type_from_id (BABL_FLOAT), + babl_type_from_id (BABL_FLOAT), + "plane", convert_float_float, + NULL + ); +} diff --git a/babl/base/type-half.c b/babl/base/type-half.c new file mode 100644 index 0000000..862d662 --- /dev/null +++ b/babl/base/type-half.c @@ -0,0 +1,434 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2012, Øyvind Kolås. + * + * MATLAB (R) is a trademark of The Mathworks (R) Corporation + * + * Function: halfprecision + * Filename: halfprecision.c + * Programmer: James Tursa + * Version: 1.0 + * Date: March 3, 2009 + * Copyright: (c) 2009 by James Tursa, All Rights Reserved + * + * This code uses the BSD License: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * halfprecision converts the input argument to/from a half precision floating + * point bit pattern corresponding to IEEE 754r. The bit pattern is stored in a + * uint16 class variable. Please note that halfprecision is *not* a class. That + * is, you cannot do any arithmetic with the half precision bit patterns. + * halfprecision is simply a function that converts the IEEE 754r half precision + * bit pattern to/from other numeric MATLAB variables. You can, however, take + * the half precision bit patterns, convert them to single or double, do the + * operation, and then convert the result back manually. + * + * 1 bit sign bit + * 5 bits exponent, biased by 15 + * 10 bits mantissa, hidden leading bit, normalized to 1.0 + * + * Special floating point bit patterns recognized and supported: + * + * All exponent bits zero: + * - If all mantissa bits are zero, then number is zero (possibly signed) + * - Otherwise, number is a denormalized bit pattern + * + * All exponent bits set to 1: + * - If all mantissa bits are zero, then number is +Infinity or -Infinity + * - Otherwise, number is NaN (Not a Number) + */ + +#include "config.h" +#include +#include +#include + +#include "babl.h" +#include "babl-classes.h" +#include "babl-ids.h" +#include "babl-base.h" + +static int next = 1; /* should be 0 for big endian */ + +//----------------------------------------------------------------------------- + +static void +doubles2halfp(void *target, + void *source, + long numel) +{ + uint16_t *hp = (uint16_t *) target; // Type pun output as an unsigned 16-bit int + uint32_t *xp = (uint32_t *) source; // Type pun input as an unsigned 32-bit int + uint16_t hs, he, hm; + uint32_t x, xs, xe, xm; + int hes; + + xp += next; // Little Endian adjustment if necessary + + if( source == NULL || target == NULL ) { // Nothing to convert (e.g., imag part of pure real) + return; + } + while( numel-- ) { + x = *xp++; xp++; // The extra xp++ is to skip over the remaining 32 bits of the mantissa + if( (x & 0x7FFFFFFFu) == 0 ) { // Signed zero + *hp++ = (uint16_t) (x >> 16); // Return the signed zero + } else { // Not zero + xs = x & 0x80000000u; // Pick off sign bit + xe = x & 0x7FF00000u; // Pick off exponent bits + xm = x & 0x000FFFFFu; // Pick off mantissa bits + if( xe == 0 ) { // Denormal will underflow, return a signed zero + *hp++ = (uint16_t) (xs >> 16); + } else if( xe == 0x7FF00000u ) { // Inf or NaN (all the exponent bits are set) + if( xm == 0 ) { // If mantissa is zero ... + *hp++ = (uint16_t) ((xs >> 16) | 0x7C00u); // Signed Inf + } else { + *hp++ = (uint16_t) 0xFE00u; // NaN, only 1st mantissa bit set + } + } else { // Normalized number + hs = (uint16_t) (xs >> 16); // Sign bit + hes = ((int)(xe >> 20)) - 1023 + 15; // Exponent unbias the double, then bias the halfp + if( hes >= 0x1F ) { // Overflow + *hp++ = (uint16_t) ((xs >> 16) | 0x7C00u); // Signed Inf + } else if( hes <= 0 ) { // Underflow + if( (10 - hes) > 21 ) { // Mantissa shifted all the way off & no rounding possibility + hm = (uint16_t) 0u; // Set mantissa to zero + } else { + xm |= 0x00100000u; // Add the hidden leading bit + hm = (uint16_t) (xm >> (11 - hes)); // Mantissa + if( (xm >> (10 - hes)) & 0x00000001u ) // Check for rounding + hm += (uint16_t) 1u; // Round, might overflow into exp bit, but this is OK + } + *hp++ = (hs | hm); // Combine sign bit and mantissa bits, biased exponent is zero + } else { + he = (uint16_t) (hes << 10); // Exponent + hm = (uint16_t) (xm >> 10); // Mantissa + if( xm & 0x00000200u ) // Check for rounding + *hp++ = (hs | he | hm) + (uint16_t) 1u; // Round, might overflow to inf, this is OK + else + *hp++ = (hs | he | hm); // No rounding + } + } + } + } +} + +static void +halfp2doubles(void *target, + void *source, + long numel) +{ + uint16_t *hp = (uint16_t *) source; // Type pun input as an unsigned 16-bit int + uint32_t *xp = (uint32_t *) target; // Type pun output as an unsigned 32-bit int + uint16_t h, hs, he, hm; + uint32_t xs, xe, xm; + int32_t xes; + int e; + + if( source == NULL || target == NULL ) // Nothing to convert (e.g., imag part of pure real) + return; + while( numel-- ) { + uint32_t x; + + h = *hp++; + if( (h & 0x7FFFu) == 0 ) { // Signed zero + x = ((uint32_t) h) << 16; // Return the signed zero + } else { // Not zero + hs = h & 0x8000u; // Pick off sign bit + he = h & 0x7C00u; // Pick off exponent bits + hm = h & 0x03FFu; // Pick off mantissa bits + if( he == 0 ) { // Denormal will convert to normalized + e = -1; // The following loop figures out how much extra to adjust the exponent + do { + e++; + hm <<= 1; + } while( (hm & 0x0400u) == 0 ); // Shift until leading bit overflows into exponent bit + xs = ((uint32_t) hs) << 16; // Sign bit + xes = ((int32_t) (he >> 10)) - 15 + 1023 - e; // Exponent unbias the halfp, then bias the double + xe = (uint32_t) (xes << 20); // Exponent + xm = ((uint32_t) (hm & 0x03FFu)) << 10; // Mantissa + x = (xs | xe | xm); // Combine sign bit, exponent bits, and mantissa bits + } else if( he == 0x7C00u ) { // Inf or NaN (all the exponent bits are set) + if( hm == 0 ) { // If mantissa is zero ... + x = (((uint32_t) hs) << 16) | ((uint32_t) 0x7FF00000u); // Signed Inf + } else { + x = (uint32_t) 0xFFF80000u; // NaN, only the 1st mantissa bit set + } + } else { + xs = ((uint32_t) hs) << 16; // Sign bit + xes = ((int32_t) (he >> 10)) - 15 + 1023; // Exponent unbias the halfp, then bias the double + xe = (uint32_t) (xes << 20); // Exponent + xm = ((uint32_t) hm) << 10; // Mantissa + x = (xs | xe | xm); // Combine sign bit, exponent bits, and mantissa bits + } + } + + xp[1 - next] = 0; + xp[next] = x; + + xp += 2; + } +} + + +static void +singles2halfp(uint16_t *hp, + const uint32_t *xp, + int numel) +{ + + uint16_t hs, he, hm; + uint32_t x, xs, xe, xm; + int hes; + + + + if( hp== NULL || xp== NULL ) { // Nothing to convert (e.g., imag part of pure real) + return; + } + + while( numel-- ) { + x = *xp++; + if( (x & 0x7FFFFFFFu) == 0 ) { // Signed zero + *hp++ = (uint16_t) (x >> 16); // Return the signed zero + } else { // Not zero + xs = x & 0x80000000u; // Pick off sign bit + xe = x & 0x7F800000u; // Pick off exponent bits + xm = x & 0x007FFFFFu; // Pick off mantissa bits + if( xe == 0 ) { // Denormal will underflow, return a signed zero + *hp++ = (uint16_t) (xs >> 16); + } else if( xe == 0x7F800000u ) { // Inf or NaN (all the exponent bits are set) + if( xm == 0 ) { // If mantissa is zero ... + *hp++ = (uint16_t) ((xs >> 16) | 0x7C00u); // Signed Inf + } else { + *hp++ = (uint16_t) 0xFE00u; // NaN, only 1st mantissa bit set + } + } else { // Normalized number + hs = (uint16_t) (xs >> 16); // Sign bit + hes = ((int)(xe >> 23)) - 127 + 15; // Exponent unbias the single, then bias the halfp + if( hes >= 0x1F ) { // Overflow + *hp++ = (uint16_t) ((xs >> 16) | 0x7C00u); // Signed Inf + } else if( hes <= 0 ) { // Underflow + if( (14 - hes) > 24 ) { // Mantissa shifted all the way off & no rounding possibility + hm = (uint16_t) 0u; // Set mantissa to zero + } else { + xm |= 0x00800000u; // Add the hidden leading bit + hm = (uint16_t) (xm >> (14 - hes)); // Mantissa + if( (xm >> (13 - hes)) & 0x00000001u ) // Check for rounding + hm += (uint16_t) 1u; // Round, might overflow into exp bit, but this is OK + } + *hp++ = (hs | hm); // Combine sign bit and mantissa bits, biased exponent is zero + } else { + he = (uint16_t) (hes << 10); // Exponent + hm = (uint16_t) (xm >> 13); // Mantissa + if( xm & 0x00001000u ) // Check for rounding + *hp++ = (hs | he | hm) + (uint16_t) 1u; // Round, might overflow to inf, this is OK + else + *hp++ = (hs | he | hm); // No rounding + } + } + } + } + return; +} + + + + + +//----------------------------------------------------------------------------- +// +// Routine: halfp2singles +// +// Input: source = address of 16-bit data to convert +// numel = Number of values at that address to convert +// +// Output: target = Address of 32-bit floating point data to hold output (numel values) +// +// +// Programmer: James Tursa +// +//----------------------------------------------------------------------------- + +static void +halfp2singles(uint32_t *xp, + const uint16_t *hp, + int numel) +{ + + uint16_t h, hs, he, hm; + uint32_t xs, xe, xm; + int32_t xes; + int e; + + + + if( xp == NULL || hp == NULL ) // Nothing to convert (e.g., imag part of pure real) + return; + + while( numel-- ) { + h = *hp++; + if( (h & 0x7FFFu) == 0 ) { // Signed zero + *xp++ = ((uint32_t) h) << 16; // Return the signed zero + } else { // Not zero + hs = h & 0x8000u; // Pick off sign bit + he = h & 0x7C00u; // Pick off exponent bits + hm = h & 0x03FFu; // Pick off mantissa bits + if( he == 0 ) { // Denormal will convert to normalized + e = -1; // The following loop figures out how much extra to adjust the exponent + do { + e++; + hm <<= 1; + } while( (hm & 0x0400u) == 0 ); // Shift until leading bit overflows into exponent bit + xs = ((uint32_t) hs) << 16; // Sign bit + xes = ((int32_t) (he >> 10)) - 15 + 127 - e; // Exponent unbias the halfp, then bias the single + xe = (uint32_t) (xes << 23); // Exponent + xm = ((uint32_t) (hm & 0x03FFu)) << 13; // Mantissa + *xp++ = (xs | xe | xm); // Combine sign bit, exponent bits, and mantissa bits + } else if( he == 0x7C00u ) { // Inf or NaN (all the exponent bits are set) + if( hm == 0 ) { // If mantissa is zero ... + *xp++ = (((uint32_t) hs) << 16) | ((uint32_t) 0x7F800000u); // Signed Inf + } else { + *xp++ = (uint32_t) 0xFFC00000u; // NaN, only 1st mantissa bit set + } + } else { // Normalized number + xs = ((uint32_t) hs) << 16; // Sign bit + xes = ((int32_t) (he >> 10)) - 15 + 127; // Exponent unbias the halfp, then bias the single + xe = (uint32_t) (xes << 23); // Exponent + xm = ((uint32_t) hm) << 13; // Mantissa + *xp++ = (xs | xe | xm); // Combine sign bit, exponent bits, and mantissa bits + } + } + } + return; +} + + + + + +static void +convert_double_half (BablConversion *conversion, + char *src, + char *dst, + int src_pitch, + int dst_pitch, + long n) +{ + while (n--) + { + doubles2halfp (dst, src, 1); + dst += dst_pitch; + src += src_pitch; + } +} + +static void +convert_half_double (BablConversion *conversion, + char *src, + char *dst, + int src_pitch, + int dst_pitch, + long n) +{ + while (n--) + { + halfp2doubles (dst, src, 1); + dst += dst_pitch; + src += src_pitch; + } +} + + +static void +convert_float_half (BablConversion *conversion, + char *src, + char *dst, + int src_pitch, + int dst_pitch, + long n) +{ + while (n--) + { + singles2halfp ((void*)dst, (void*)src, 1); + dst += dst_pitch; + src += src_pitch; + } +} + +static void +convert_half_float (BablConversion *conversion, + char *src, + char *dst, + int src_pitch, + int dst_pitch, + long n) +{ + while (n--) + { + halfp2singles ((void*)dst, (void*)src, 1); + dst += dst_pitch; + src += src_pitch; + } +} + + + + +void +babl_base_type_half (void) +{ + babl_type_new ( + "half", + "id", BABL_HALF, + "bits", 16, + "doc", "IEEE 754 half precision.", + NULL); + + babl_conversion_new ( + babl_type_from_id (BABL_HALF), + babl_type_from_id (BABL_DOUBLE), + "plane", convert_half_double, + NULL + ); + + babl_conversion_new ( + babl_type_from_id (BABL_DOUBLE), + babl_type_from_id (BABL_HALF), + "plane", convert_double_half, + NULL + ); + + babl_conversion_new ( + babl_type_from_id (BABL_HALF), + babl_type_from_id (BABL_FLOAT), + "plane", convert_half_float, + NULL + ); + + babl_conversion_new ( + babl_type_from_id (BABL_FLOAT), + babl_type_from_id (BABL_HALF), + "plane", convert_float_half, + NULL + ); +} diff --git a/babl/base/type-u15.c b/babl/base/type-u15.c new file mode 100644 index 0000000..ea35453 --- /dev/null +++ b/babl/base/type-u15.c @@ -0,0 +1,238 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include +#include +#include +#include + +#include "babl-internal.h" +#include "babl-base.h" + + +static inline void +convert_double_u15_scaled (BablConversion *conversion, + double min_val, + double max_val, + uint16_t min, + uint16_t max, + char *src, + char *dst, + int src_pitch, + int dst_pitch, + long n) +{ + while (n--) + { + double dval = *(double *) src; + uint16_t u15val; + + if (dval < min_val) + u15val = min; + else if (dval > max_val) + u15val = max; + else + u15val = rint ((dval - min_val) / (max_val - min_val) * (max - min) + min); + + *(uint16_t *) dst = u15val; + dst += dst_pitch; + src += src_pitch; + } +} + +static inline void +convert_u15_double_scaled (BablConversion *conversion, + double min_val, + double max_val, + uint16_t min, + uint16_t max, + char *src, + char *dst, + int src_pitch, + int dst_pitch, + long n) +{ + while (n--) + { + int u15val = *(uint16_t *) src; + double dval; + + if (u15val < min) + dval = min_val; + else if (u15val > max) + dval = max_val; + else + dval = (u15val - min) / (double) (max - min) * (max_val - min_val) + min_val; + + (*(double *) dst) = dval; + dst += dst_pitch; + src += src_pitch; + } +} + +#define MAKE_CONVERSIONS(name, min_val, max_val, min, max) \ + static void \ + convert_ ## name ## _double (BablConversion *conversion, \ + void *src, \ + void *dst, \ + int src_pitch, \ + int dst_pitch, \ + long n) \ + { \ + convert_u15_double_scaled (conversion, min_val, max_val, min, max, \ + src, dst, src_pitch, dst_pitch, n); \ + } \ + static void \ + convert_double_ ## name (BablConversion *conversion, void *src, \ + void *dst, \ + int src_pitch, \ + int dst_pitch, \ + long n) \ + { \ + convert_double_u15_scaled (conversion, min_val, max_val, min, max, \ + src, dst, src_pitch, dst_pitch, n); \ + } + +MAKE_CONVERSIONS (u15, 0.0, 1.0, 0, (1<<15)) + + +static inline void +convert_float_u15_scaled (BablConversion *conversion, + float min_val, + float max_val, + uint16_t min, + uint16_t max, + char *src, + char *dst, + int src_pitch, + int dst_pitch, + long n) +{ + while (n--) + { + float dval = *(float *) src; + uint16_t u15val; + + if (dval < min_val) + u15val = min; + else if (dval > max_val) + u15val = max; + else + u15val = rint ((dval - min_val) / (max_val - min_val) * (max - min) + min); + + *(uint16_t *) dst = u15val; + dst += dst_pitch; + src += src_pitch; + } +} + +static inline void +convert_u15_float_scaled (BablConversion *conversion, + float min_val, + float max_val, + uint16_t min, + uint16_t max, + char *src, + char *dst, + int src_pitch, + int dst_pitch, + long n) +{ + while (n--) + { + int u15val = *(uint16_t *) src; + float dval; + + if (u15val < min) + dval = min_val; + else if (u15val > max) + dval = max_val; + else + dval = (u15val - min) / (float) (max - min) * (max_val - min_val) + min_val; + + (*(float *) dst) = dval; + dst += dst_pitch; + src += src_pitch; + } +} + +#define MAKE_CONVERSIONS_float(name, min_val, max_val, min, max) \ + static void \ + convert_ ## name ## _float (BablConversion *conversion, \ + void *src, \ + void *dst, \ + int src_pitch, \ + int dst_pitch, \ + long n) \ + { \ + convert_u15_float_scaled (conversion, min_val, max_val, min, max, \ + src, dst, src_pitch, dst_pitch, n); \ + } \ + static void \ + convert_float_ ## name (BablConversion *conversion, void *src, \ + void *dst, \ + int src_pitch, \ + int dst_pitch, \ + long n) \ + { \ + convert_float_u15_scaled (conversion, min_val, max_val, min, max, \ + src, dst, src_pitch, dst_pitch, n); \ + } + +MAKE_CONVERSIONS_float (u15, 0.0, 1.0, 0, (1<<15)) + +void +babl_base_type_u15 (void) +{ + babl_hmpf_on_name_lookups--; + babl_type_new ( + "u15", + "bits", 16, + NULL); + + babl_conversion_new ( + babl_type ("u15"), + babl_type_from_id (BABL_DOUBLE), + "plane", convert_u15_double, + NULL + ); + + babl_conversion_new ( + babl_type_from_id (BABL_DOUBLE), + babl_type ("u15"), + "plane", convert_double_u15, + NULL + ); + + babl_conversion_new ( + babl_type ("u15"), + babl_type_from_id (BABL_FLOAT), + "plane", convert_u15_float, + NULL + ); + + babl_conversion_new ( + babl_type_from_id (BABL_FLOAT), + babl_type ("u15"), + "plane", convert_float_u15, + NULL + ); + + babl_hmpf_on_name_lookups++; +} diff --git a/babl/base/type-u16.c b/babl/base/type-u16.c new file mode 100644 index 0000000..c5a41dc --- /dev/null +++ b/babl/base/type-u16.c @@ -0,0 +1,234 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include +#include +#include +#include + +#include "babl-internal.h" +#include "babl-base.h" + + +static inline void +convert_double_u16_scaled (BablConversion *conversion, + double min_val, + double max_val, + uint16_t min, + uint16_t max, + char *src, + char *dst, + int src_pitch, + int dst_pitch, + long n) +{ + while (n--) + { + double dval = *(double *) src; + uint16_t u16val; + + if (dval < min_val) + u16val = min; + else if (dval > max_val) + u16val = max; + else + u16val = rint ((dval - min_val) / (max_val - min_val) * (max - min) + min); + + *(uint16_t *) dst = u16val; + dst += dst_pitch; + src += src_pitch; + } +} + +static inline void +convert_u16_double_scaled (BablConversion *conversion, + double min_val, + double max_val, + uint16_t min, + uint16_t max, + char *src, + char *dst, + int src_pitch, + int dst_pitch, + long n) +{ + while (n--) + { + int u16val = *(uint16_t *) src; + double dval; + + if (u16val < min) + dval = min_val; + else if (u16val > max) + dval = max_val; + else + dval = (u16val - min) / (double) (max - min) * (max_val - min_val) + min_val; + + (*(double *) dst) = dval; + dst += dst_pitch; + src += src_pitch; + } +} + +#define MAKE_CONVERSIONS(name, min_val, max_val, min, max) \ + static void \ + convert_ ## name ## _double (BablConversion *c, void *src, \ + void *dst, \ + int src_pitch, \ + int dst_pitch, \ + long n) \ + { \ + convert_u16_double_scaled (c, min_val, max_val, min, max, \ + src, dst, src_pitch, dst_pitch, n); \ + } \ + static void \ + convert_double_ ## name (BablConversion *c, void *src, \ + void *dst, \ + int src_pitch, \ + int dst_pitch, \ + long n) \ + { \ + convert_double_u16_scaled (c, min_val, max_val, min, max, \ + src, dst, src_pitch, dst_pitch, n); \ + } + +MAKE_CONVERSIONS (u16, 0.0, 1.0, 0, UINT16_MAX) + +static inline void +convert_float_u16_scaled (BablConversion *conversion, + double min_val, + double max_val, + uint16_t min, + uint16_t max, + char *src, + char *dst, + int src_pitch, + int dst_pitch, + long n) +{ + while (n--) + { + float dval = *(float *) src; + uint16_t u16val; + + if (dval < min_val) + u16val = min; + else if (dval > max_val) + u16val = max; + else + u16val = rint ((dval - min_val) / (max_val - min_val) * (max - min) + min); + + *(uint16_t *) dst = u16val; + dst += dst_pitch; + src += src_pitch; + } +} + +static inline void +convert_u16_float_scaled (BablConversion *conversion, + double min_val, + double max_val, + uint16_t min, + uint16_t max, + char *src, + char *dst, + int src_pitch, + int dst_pitch, + long n) +{ + while (n--) + { + int u16val = *(uint16_t *) src; + float dval; + + if (u16val < min) + dval = min_val; + else if (u16val > max) + dval = max_val; + else + dval = (u16val - min) / (float) (max - min) * (max_val - min_val) + min_val; + + (*(float *) dst) = dval; + dst += dst_pitch; + src += src_pitch; + } +} + +#define MAKE_CONVERSIONS_float(name, min_val, max_val, min, max) \ + static void \ + convert_ ## name ## _float (BablConversion *c, void *src, \ + void *dst, \ + int src_pitch, \ + int dst_pitch, \ + long n) \ + { \ + convert_u16_float_scaled (c, min_val, max_val, min, max, \ + src, dst, src_pitch, dst_pitch, n); \ + } \ + static void \ + convert_float_ ## name (BablConversion *c, void *src, \ + void *dst, \ + int src_pitch, \ + int dst_pitch, \ + long n) \ + { \ + convert_float_u16_scaled (c, min_val, max_val, min, max, \ + src, dst, src_pitch, dst_pitch, n); \ + } + +MAKE_CONVERSIONS_float (u16, 0.0, 1.0, 0, UINT16_MAX) + + +void +babl_base_type_u16 (void) +{ + babl_type_new ( + "u16", + "id", BABL_U16, + "bits", 16, + NULL); + + babl_conversion_new ( + babl_type_from_id (BABL_U16), + babl_type_from_id (BABL_DOUBLE), + "plane", convert_u16_double, + NULL + ); + + babl_conversion_new ( + babl_type_from_id (BABL_DOUBLE), + babl_type_from_id (BABL_U16), + "plane", convert_double_u16, + NULL + ); + + babl_conversion_new ( + babl_type_from_id (BABL_U16), + babl_type_from_id (BABL_FLOAT), + "plane", convert_u16_float, + NULL + ); + + babl_conversion_new ( + babl_type_from_id (BABL_FLOAT), + babl_type_from_id (BABL_U16), + "plane", convert_float_u16, + NULL + ); +} diff --git a/babl/base/type-u32.c b/babl/base/type-u32.c new file mode 100644 index 0000000..48b1506 --- /dev/null +++ b/babl/base/type-u32.c @@ -0,0 +1,234 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include +#include +#include +#include + +#include "babl-internal.h" +#include "babl-base.h" + +static inline void +convert_double_u32_scaled (BablConversion *c, + double min_val, + double max_val, + uint32_t min, + uint32_t max, + char *src, + char *dst, + int src_pitch, + int dst_pitch, + long n) +{ + while (n--) + { + double dval = *(double *) src; + uint32_t u32val; + + if (dval < min_val) + u32val = min; + else if (dval > max_val) + u32val = max; + else + u32val = rint ((dval - min_val) / (max_val - min_val) * (max - min) + min); + + *(uint32_t *) dst = u32val; + dst += dst_pitch; + src += src_pitch; + } +} + +static inline void +convert_u32_double_scaled (BablConversion *c, + double min_val, + double max_val, + uint32_t min, + uint32_t max, + char *src, + char *dst, + int src_pitch, + int dst_pitch, + long n) +{ + while (n--) + { + int u32val = *(uint32_t *) src; + double dval; + + if (u32val < min) + dval = min_val; + else if (u32val > max) + dval = max_val; + else + dval = (u32val - min) / (double) (max - min) * (max_val - min_val) + min_val; + + (*(double *) dst) = dval; + dst += dst_pitch; + src += src_pitch; + } +} + +#define MAKE_CONVERSIONS(name, min_val, max_val, min, max) \ + static void \ + convert_ ## name ## _double (BablConversion *c, void *src, \ + void *dst, \ + int src_pitch, \ + int dst_pitch, \ + long n) \ + { \ + convert_u32_double_scaled (c, min_val, max_val, min, max, \ + src, dst, src_pitch, dst_pitch, n); \ + } \ + static void \ + convert_double_ ## name (BablConversion *c, void *src, \ + void *dst, \ + int src_pitch, \ + int dst_pitch, \ + long n) \ + { \ + convert_double_u32_scaled (c, min_val, max_val, min, max, \ + src, dst, src_pitch, dst_pitch, n); \ + } + +MAKE_CONVERSIONS (u32, 0.0, 1.0, 0, UINT32_MAX) + + +static inline void +convert_float_u32_scaled (BablConversion *c, + float min_val, + float max_val, + uint32_t min, + uint32_t max, + char *src, + char *dst, + int src_pitch, + int dst_pitch, + long n) +{ + while (n--) + { + float dval = *(float *) src; + uint32_t u32val; + + if (dval < min_val) + u32val = min; + else if (dval > max_val) + u32val = max; + else + u32val = rint ((dval - min_val) / (max_val - min_val) * (max - min) + min); + + *(uint32_t *) dst = u32val; + dst += dst_pitch; + src += src_pitch; + } +} + +static inline void +convert_u32_float_scaled (BablConversion *c, + float min_val, + float max_val, + uint32_t min, + uint32_t max, + char *src, + char *dst, + int src_pitch, + int dst_pitch, + long n) +{ + while (n--) + { + int u32val = *(uint32_t *) src; + float dval; + + if (u32val < min) + dval = min_val; + else if (u32val > max) + dval = max_val; + else + dval = (u32val - min) / (float) (max - min) * (max_val - min_val) + min_val; + + (*(float *) dst) = dval; + dst += dst_pitch; + src += src_pitch; + } +} + +#define MAKE_CONVERSIONS_float(name, min_val, max_val, min, max) \ + static void \ + convert_ ## name ## _float (BablConversion *c, void *src, \ + void *dst, \ + int src_pitch, \ + int dst_pitch, \ + long n) \ + { \ + convert_u32_float_scaled (c, min_val, max_val, min, max, \ + src, dst, src_pitch, dst_pitch, n); \ + } \ + static void \ + convert_float_ ## name (BablConversion *c, void *src, \ + void *dst, \ + int src_pitch, \ + int dst_pitch, \ + long n) \ + { \ + convert_float_u32_scaled (c, min_val, max_val, min, max, \ + src, dst, src_pitch, dst_pitch, n); \ + } + +MAKE_CONVERSIONS_float(u32, 0.0, 1.0, 0, UINT32_MAX) + + +void +babl_base_type_u32 (void) +{ + babl_type_new ( + "u32", + "id", BABL_U32, + "bits", 32, + NULL); + + babl_conversion_new ( + babl_type_from_id (BABL_U32), + babl_type_from_id (BABL_DOUBLE), + "plane", convert_u32_double, + NULL + ); + + babl_conversion_new ( + babl_type_from_id (BABL_DOUBLE), + babl_type_from_id (BABL_U32), + "plane", convert_double_u32, + NULL + ); + + babl_conversion_new ( + babl_type_from_id (BABL_U32), + babl_type_from_id (BABL_FLOAT), + "plane", convert_u32_float, + NULL + ); + + babl_conversion_new ( + babl_type_from_id (BABL_FLOAT), + babl_type_from_id (BABL_U32), + "plane", convert_float_u32, + NULL + ); +} diff --git a/babl/base/type-u8.c b/babl/base/type-u8.c new file mode 100644 index 0000000..d41d5e0 --- /dev/null +++ b/babl/base/type-u8.c @@ -0,0 +1,310 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include +#include +#include + +#include "babl-internal.h" +#include "babl-base.h" + +#include +static inline void +convert_double_u8_scaled (BablConversion *c, + double min_val, + double max_val, + unsigned char min, + unsigned char max, + char *src, + char *dst, + int src_pitch, + int dst_pitch, + long n) +{ + while (n--) + { + double dval = *(double *) src; + unsigned char u8val; + + if (dval < min_val) + u8val = min; + else if (dval > max_val) + u8val = max; + else + u8val = rint ((dval - min_val) / (max_val - min_val) * (max - min) + min); + + *(unsigned char *) dst = u8val; + src += src_pitch; + dst += dst_pitch; + } +} + +static inline void +convert_u8_double_scaled (BablConversion *c, + double min_val, + double max_val, + unsigned char min, + unsigned char max, + char *src, + char *dst, + int src_pitch, + int dst_pitch, + long n) +{ + while (n--) + { + int u8val = *(unsigned char *) src; + double dval; + + if (u8val < min) + dval = min_val; + else if (u8val > max) + dval = max_val; + else + dval = (u8val - min) / (double) (max - min) * (max_val - min_val) + min_val; + + (*(double *) dst) = dval; + + dst += dst_pitch; + src += src_pitch; + } +} + +#define MAKE_CONVERSIONS(name, min_val, max_val, min, max) \ + static void \ + convert_ ## name ## _double (BablConversion *c, void *src, \ + void *dst, \ + int src_pitch, \ + int dst_pitch, \ + long n) \ + { \ + convert_u8_double_scaled (c, min_val, max_val, min, max, \ + src, dst, src_pitch, dst_pitch, n); \ + } \ + static void \ + convert_double_ ## name (BablConversion *c, void *src, \ + void *dst, \ + int src_pitch, \ + int dst_pitch, \ + long n) \ + { \ + convert_double_u8_scaled (c, min_val, max_val, min, max, \ + src, dst, src_pitch, dst_pitch, n); \ + } + +MAKE_CONVERSIONS (u8, 0.0, 1.0, 0x00, UINT8_MAX) +MAKE_CONVERSIONS (u8_luma, 0.0, 1.0, 16, 235) +MAKE_CONVERSIONS (u8_chroma, -0.5, 0.5, 16, 240) + + +static inline void +convert_float_u8_scaled (BablConversion *c, + double min_val, + double max_val, + unsigned char min, + unsigned char max, + char *src, + char *dst, + int src_pitch, + int dst_pitch, + long n) +{ + while (n--) + { + float dval = *(float *) src; + unsigned char u8val; + + if (dval < min_val) + u8val = min; + else if (dval > max_val) + u8val = max; + else + u8val = rint ((dval - min_val) / (max_val - min_val) * (max - min) + min); + + *(unsigned char *) dst = u8val; + src += src_pitch; + dst += dst_pitch; + } +} + +static inline void +convert_u8_float_scaled (BablConversion *c, + double min_val, + double max_val, + unsigned char min, + unsigned char max, + char *src, + char *dst, + int src_pitch, + int dst_pitch, + long n) +{ + while (n--) + { + int u8val = *(unsigned char *) src; + float dval; + + if (u8val < min) + dval = min_val; + else if (u8val > max) + dval = max_val; + else + dval = (u8val - min) / (float) (max - min) * (max_val - min_val) + min_val; + + (*(float *) dst) = dval; + + dst += dst_pitch; + src += src_pitch; + } +} + +#define MAKE_CONVERSIONS_float(name, min_val, max_val, min, max) \ + static void \ + convert_ ## name ## _float (BablConversion *c, void *src, \ + void *dst, \ + int src_pitch, \ + int dst_pitch, \ + long n) \ + { \ + convert_u8_float_scaled (c, min_val, max_val, min, max, \ + src, dst, src_pitch, dst_pitch, n); \ + } \ + static void \ + convert_float_ ## name (BablConversion *c, void *src, \ + void *dst, \ + int src_pitch, \ + int dst_pitch, \ + long n) \ + { \ + convert_float_u8_scaled (c, min_val, max_val, min, max, \ + src, dst, src_pitch, dst_pitch, n); \ + } + +MAKE_CONVERSIONS_float (u8, 0.0, 1.0, 0x00, UINT8_MAX) +MAKE_CONVERSIONS_float (u8_luma, 0.0, 1.0, 16, 235) +MAKE_CONVERSIONS_float (u8_chroma, -0.5, 0.5, 16, 240) + + +void +babl_base_type_u8 (void) +{ + babl_type_new ( + "u8", + "id", BABL_U8, + "bits", 8, + "doc", "uint8_t, 8 bit unsigned integer, values from 0-255", + NULL); + + babl_type_new ( + "u8-luma", + "id", BABL_U8_LUMA, + "bits", 8, + "doc", "8 bit unsigned integer, values from 16-235", + NULL + ); + + babl_type_new ( + "u8-chroma", + "id", BABL_U8_CHROMA, + "integer", + "unsigned", + "bits", 8, + "min", (long) 16, + "max", (long) 240, + "min_val", -0.5, + "max_val", 0.5, + "doc", "8 bit unsigned integer -0.5 to 0.5 maps to 16-240", + NULL + ); + babl_conversion_new ( + babl_type_from_id (BABL_U8), + babl_type_from_id (BABL_DOUBLE), + "plane", convert_u8_double, + NULL + ); + babl_conversion_new ( + babl_type_from_id (BABL_DOUBLE), + babl_type_from_id (BABL_U8), + "plane", convert_double_u8, + NULL + ); + babl_conversion_new ( + babl_type_from_id (BABL_U8_LUMA), + babl_type_from_id (BABL_DOUBLE), + "plane", convert_u8_luma_double, + NULL + ); + babl_conversion_new ( + babl_type_from_id (BABL_DOUBLE), + babl_type_from_id (BABL_U8_LUMA), + "plane", convert_double_u8_luma, + NULL + ); + babl_conversion_new ( + babl_type_from_id (BABL_U8_CHROMA), + babl_type_from_id (BABL_DOUBLE), + "plane", convert_u8_chroma_double, + NULL + ); + babl_conversion_new ( + babl_type_from_id (BABL_DOUBLE), + babl_type_from_id (BABL_U8_CHROMA), + "plane", convert_double_u8_chroma, + NULL + ); + + + + babl_conversion_new ( + babl_type_from_id (BABL_U8), + babl_type_from_id (BABL_FLOAT), + "plane", convert_u8_float, + NULL + ); + babl_conversion_new ( + babl_type_from_id (BABL_FLOAT), + babl_type_from_id (BABL_U8), + "plane", convert_float_u8, + NULL + ); + babl_conversion_new ( + babl_type_from_id (BABL_U8_LUMA), + babl_type_from_id (BABL_FLOAT), + "plane", convert_u8_luma_float, + NULL + ); + babl_conversion_new ( + babl_type_from_id (BABL_FLOAT), + babl_type_from_id (BABL_U8_LUMA), + "plane", convert_float_u8_luma, + NULL + ); + babl_conversion_new ( + babl_type_from_id (BABL_U8_CHROMA), + babl_type_from_id (BABL_FLOAT), + "plane", convert_u8_chroma_float, + NULL + ); + babl_conversion_new ( + babl_type_from_id (BABL_FLOAT), + babl_type_from_id (BABL_U8_CHROMA), + "plane", convert_float_u8_chroma, + NULL + ); +} diff --git a/babl/base/util.h b/babl/base/util.h new file mode 100644 index 0000000..aba9c61 --- /dev/null +++ b/babl/base/util.h @@ -0,0 +1,135 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#ifndef _BASE_UTIL_H +#define _BASE_UTIL_H + +#include +#include +#include "pow-24.h" +#include + + +#define BABL_PLANAR_SANITY \ + { \ + assert(src_bands>0); \ + assert(dst_bands>0); \ + assert(src); \ + assert(*src); \ + assert(dst); \ + assert(*dst); \ + assert(n>0); \ + assert(*src_pitch); \ + } + +#define BABL_PLANAR_STEP \ + { \ + int i; \ + for (i=0; i< src_bands; i++) \ + src[i]+=src_pitch[i]; \ + for (i=0; i< dst_bands; i++) \ + dst[i]+=dst_pitch[i]; \ + } + + +static inline double +babl_epsilon_for_zero (double value) +{ + if (value <= BABL_ALPHA_FLOOR && + value >= -BABL_ALPHA_FLOOR) + { + return BABL_ALPHA_FLOOR; + } + return value; +} + +static inline float +babl_epsilon_for_zero_float (float value) +{ + if (value <= BABL_ALPHA_FLOOR_F && + value >= -BABL_ALPHA_FLOOR_F) + { + return BABL_ALPHA_FLOOR_F; + } + return value; +} + + +#define BABL_USE_SRGB_GAMMA + +#ifdef BABL_USE_SRGB_GAMMA +static inline double +linear_to_gamma_2_2 (double value) +{ + if (value > 0.003130804954) + return 1.055 * pow (value, (1.0/2.4)) - 0.055; + return 12.92 * value; +} + +static inline double +gamma_2_2_to_linear (double value) +{ + if (value > 0.04045) + return pow ((value + 0.055) / 1.055, 2.4); + return value / 12.92; +} +static inline double +babl_linear_to_gamma_2_2 (double value) +{ + if (value > 0.003130804954) + return 1.055 * babl_pow_1_24 (value) - 0.055; + return 12.92 * value; +} +static inline float +babl_linear_to_gamma_2_2f (float value) +{ + if (value > 0.003130804954f) + { + return 1.055f * babl_pow_1_24f (value) - + (0.055f - + 3.0f / (float) (1 << 24)); + /* ^ offset the result such that 1 maps to 1 */ + } + return 12.92f * value; +} + + +static inline double +babl_gamma_2_2_to_linear (double value) +{ + if (value > 0.04045) + return babl_pow_24 ((value + 0.055) / 1.055); + return value / 12.92; +} +static inline float +babl_gamma_2_2_to_linearf (float value) +{ + if (value > 0.04045f) + return babl_pow_24f ((value + 0.055f) / 1.055f); + return value / 12.92f; +} + +#else + #define linear_to_gamma_2_2(value) (pow((value), (1.0F/2.2F))) + #define gamma_2_2_to_linear(value) (pow((value), 2.2F)) + + #define babl_linear_to_gamma_2_2f(value) (powf((value), (1.0f/2.2f))) + #define babl_gamma_2_2_to_linearf(value) (powf((value), 2.2f)) +#endif + +#endif diff --git a/babl/gettimeofday.c b/babl/gettimeofday.c new file mode 100644 index 0000000..169d609 --- /dev/null +++ b/babl/gettimeofday.c @@ -0,0 +1,71 @@ +/* + * timeval.h 1.0 01/12/19 + * + * Defines gettimeofday, timeval, etc. for Win32 + * + * By Wu Yongwei + * + */ +#include "config.h" + +#ifdef _WIN32 + +#define WIN32_LEAN_AND_MEAN +#include +#include + +#ifndef __GNUC__ +#define EPOCHFILETIME (116444736000000000i 64) +#else +#define EPOCHFILETIME (116444736000000000LL) +#endif + +struct timeval +{ + long tv_sec; /* seconds */ + long tv_usec; /* microseconds */ +}; + +struct timezone +{ + int tz_minuteswest; /* minutes W of Greenwich */ + int tz_dsttime; /* type of dst correction */ +}; + + +int +gettimeofday (struct timeval *tv, + struct timezone *tz) +{ + FILETIME ft; + LARGE_INTEGER li; + __int64 t; + static int tzflag; + + if (tv) + { + GetSystemTimeAsFileTime (&ft); + li.LowPart = ft.dwLowDateTime; + li.HighPart = ft.dwHighDateTime; + t = li.QuadPart;/* In 100-nanosecond intervals */ + t -= EPOCHFILETIME;/* Offset to the Epoch time */ + t /= 10; /* In microseconds */ + tv->tv_sec = (long) (t / 1000000); + tv->tv_usec = (long) (t % 1000000); + } + + if (tz) + { + if (!tzflag) + { + _tzset (); + tzflag++; + } + tz->tz_minuteswest = _timezone / 60; + tz->tz_dsttime = _daylight; + } + + return 0; +} + +#endif /* _WIN32 */ diff --git a/babl/git-version.h b/babl/git-version.h new file mode 100644 index 0000000..3b05425 --- /dev/null +++ b/babl/git-version.h @@ -0,0 +1,6 @@ +#ifndef __GIT_VERSION_H__ +#define __GIT_VERSION_H__ + +#define BABL_GIT_VERSION "BABL_0_1_80-5-gaab3029" + +#endif /* __GIT_VERSION_H__ */ diff --git a/babl/git-version.h.in b/babl/git-version.h.in new file mode 100644 index 0000000..a9f87e2 --- /dev/null +++ b/babl/git-version.h.in @@ -0,0 +1,6 @@ +#ifndef __GIT_VERSION_H__ +#define __GIT_VERSION_H__ + +#define BABL_GIT_VERSION "@BABL_GIT_VERSION@" + +#endif /* __GIT_VERSION_H__ */ diff --git a/babl/identfilter.py b/babl/identfilter.py new file mode 100644 index 0000000..e592de4 --- /dev/null +++ b/babl/identfilter.py @@ -0,0 +1,37 @@ +# Copyright 2014 Emmanuele Bassi +# +# SPDX-License-Identifier: MIT +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +import sys +import re + +def rename_babl_object(text): + # We need this to rename the Babl type into BablObject + # Otherwise the type clashes with the namespace + if text == 'Babl': + return 'BablObject' + + # Leave the rest unharmed + return text + +if __name__ == '__main__': + in_text = sys.stdin.read() + sys.stdout.write(rename_babl_object(in_text)) diff --git a/babl/meson.build b/babl/meson.build new file mode 100644 index 0000000..fed8fe9 --- /dev/null +++ b/babl/meson.build @@ -0,0 +1,177 @@ + +babl_library_build_dir = meson.current_build_dir() +bablInclude = include_directories('.') + +subdir('base') + + +# c compiler arguments +babl_c_args = [ + sse2_cflags, + '-DLIBDIR="@0@"'.format(babl_libdir), +] + +# symbol maps +version_script = custom_target('babl.map', + input : meson.source_root() / 'export-symbols', + output: ['babl.map', 'babl.map.clang'], + command: [ + find_program(meson.source_root() / 'gen_babl_map.py'), + '@INPUT@', + '@OUTPUT0@', + ], +) + +# Linker arguments +if cc.links('', + name: '-Wl,--version-script', + args: ['-shared', '-Wl,--version-script=' + + meson.current_source_dir() / 'test-gnu.map'] + ) + babl_link_args = [ + '-Wl,--version-script=' + version_script[0].full_path() + ] +elif cc.get_id() == 'clang' + if cc.links('', + name: '-Wl,-exported_symbols_list', + args: ['-Wl,-exported_symbols_list', + meson.current_source_dir() / 'test-clang.map'] + ) + # Clang on Darwin + babl_link_args = [ + '-Wl,-exported_symbols_list', version_script[1].full_path() + ] + else + # Clang on msys/mingw + babl_link_args = [] + endif +else + error( + 'Linker doesn\'t support --version-script or -exported_symbols_list' + ) +endif +if platform_win32 + babl_link_args += no_undefined +endif + +babl_version_h = configure_file( + input: 'babl-version.h.in', + output: 'babl-version.h', + configuration: conf, +) + +# If git is available, always check if git-version.h should be +# updated. If git is not available, don't do anything if git-version.h +# already exists because then we are probably working with a tarball +# in which case the git-version.h we ship is correct. +if git_bin.found() and run_command( + git_bin, + 'rev-parse', + '--is-inside-work-tree', +).returncode() == 0 + git_version_h = vcs_tag( + input : 'git-version.h.in', + output: 'git-version.h', + replace_string: '@BABL_GIT_VERSION@', + command: [ git_bin.path(), 'describe', '--always' ], + ) + + if env_bin.found() + meson.add_dist_script( + [ 'ninja', 'babl/git-version.h', ], + ) + meson.add_dist_script( + [ 'sh', '-c', ' '.join( + [ 'cp', git_version_h.full_path(), '${MESON_DIST_ROOT}/babl' ] + )] + ) + endif +else + git_version_h = files('git-version.h') +endif + +babl_sources = [ + 'babl-cache.c', + 'babl-component.c', + 'babl-conversion.c', + 'babl-core.c', + 'babl-cpuaccel.c', + 'babl-db.c', + 'babl-extension.c', + 'babl-fish-path.c', + 'babl-fish-reference.c', + 'babl-fish-simple.c', + 'babl-fish.c', + 'babl-format.c', + 'babl-hash-table.c', + 'babl-icc.c', + 'babl-image.c', + 'babl-internal.c', + 'babl-introspect.c', + 'babl-list.c', + 'babl-memory.c', + 'babl-model.c', + 'babl-mutex.c', + 'babl-palette.c', + 'babl-polynomial.c', + 'babl-ref-pixels.c', + 'babl-sampling.c', + 'babl-sanity.c', + 'babl-space.c', + 'babl-trc.c', + 'babl-type.c', + 'babl-util.c', + 'babl-version.c', + 'babl.c', + babl_version_h, + git_version_h, +] + +babl_headers = [ + 'babl-introspect.h', + 'babl-macros.h', + 'babl-types.h', + 'babl.h', + babl_version_h, +] + +install_headers(babl_headers, + subdir: join_paths(lib_name, 'babl') +) + +babl = library( + lib_name, + babl_sources, + include_directories: [rootInclude, bablBaseInclude], + c_args: babl_c_args, + link_whole: babl_base, + link_args: babl_link_args, + dependencies: [math, thread, dl, lcms], + link_depends: version_script, + version: so_version, + install: true, +) + +if build_gir + # identity filter, so GIR doesn't choke on the Babl type + # (since it has the same name as the Babl namespace) + babl_gir = gnome.generate_gir(babl, + sources: babl_headers, + extra_args: [ + '--identifier-filter-cmd=@0@ @1@'.format(python.path(), + meson.current_source_dir() / 'identfilter.py'), + '-DBABL_IS_BEING_COMPILED', + ], + namespace: 'Babl', + nsversion: api_version, + header: 'babl.h', + install: true, + ) + + if build_vapi + gnome.generate_vapi(lib_name, + sources: babl_gir[0], + install: true, + ) + endif +endif diff --git a/babl/test-clang.map b/babl/test-clang.map new file mode 100644 index 0000000..2ad2526 --- /dev/null +++ b/babl/test-clang.map @@ -0,0 +1 @@ +babl_* diff --git a/babl/test-gnu.map b/babl/test-gnu.map new file mode 100644 index 0000000..c27b37d --- /dev/null +++ b/babl/test-gnu.map @@ -0,0 +1,6 @@ +{ + global: + babl_*; + local: + *; +}; diff --git a/build/archlinux/PKGBUILD b/build/archlinux/PKGBUILD new file mode 100644 index 0000000..60be23a --- /dev/null +++ b/build/archlinux/PKGBUILD @@ -0,0 +1,48 @@ +# Maintainer: Alexander Hunziker +# Contributor: Alessio Biancalana +# Contributor: Massimiliano Torromeo +# Contributor: Salamandar + +_pkgname=babl +pkgname="${_pkgname}-git" +pkgver=0.1.38.23.g5aa4a51 +pkgrel=1 +pkgdesc="babl is a dynamic, any to any, pixel format translation library." +arch=('i686' 'x86_64') +url="https://www.gegl.org/babl" +license=('LGPL3') +depends=('glibc') +makedepends=('meson') +provides=("babl=${pkgver}") +conflicts=('babl') +options=(!libtool) +source=(git://git.gnome.org/babl) +md5sums=('SKIP') + +_gitname=babl + +build() { + mkdir "${srcdir}/build" -p + + meson "${srcdir}/${_gitname}"\ + "${srcdir}/build" \ + --prefix=/usr \ + -Dbuildtype=release \ + -Db_lto=true \ + -Dwith-docs=false + + ninja -C "${srcdir}/build" +} + +package() { + DESTDIR="${pkgdir}" ninja -C "${srcdir}/build" install +} + +pkgver() { + cd "${_gitname}" + git describe --always | sed -e 's/BABL_//g' -e 's/[_-]/./g' +} + +check() { + meson test -C "${srcdir}/build" +} diff --git a/build/buildbot/suppressed-warnings.txt b/build/buildbot/suppressed-warnings.txt new file mode 100644 index 0000000..ed7082a --- /dev/null +++ b/build/buildbot/suppressed-warnings.txt @@ -0,0 +1,9 @@ +# This is a 'suppressionFile' for the 'Test' buildbot build step + +# These doesn't seem like important warnings, we typically get them +# during make distcheck when the test install is performed +: ^libtool: install: warning: relinking `.*'$ +: ^libtool: install: warning: remember to run `libtool --finish .*_inst.*'$ + +# Comes from AM_PROG_LIBTOOL, not much we can do +: ^configure.ac:105: warning: AC_LANG_CONFTEST: no AC_LANG_SOURCE call detected in body$ diff --git a/build/mingw/PKGBUILD b/build/mingw/PKGBUILD new file mode 100644 index 0000000..f3014b3 --- /dev/null +++ b/build/mingw/PKGBUILD @@ -0,0 +1,49 @@ +# Maintainer: Alexander Hunziker +# Contributor: Alessio Biancalana +# Contributor: Massimiliano Torromeo +# Contributor: Salamandar + +_pkgname=babl +pkgname="${MINGW_PACKAGE_PREFIX}-${_pkgname}-git" +pkgver=0.1.38.29.gd6e78b1 +pkgrel=1 +pkgdesc="babl is a dynamic, any to any, pixel format translation library." +arch=('i686' 'x86_64') +url="https://www.gegl.org/babl" +license=('LGPL3') +makedepends=( + "${MINGW_PACKAGE_PREFIX}-meson" +) +provides=("${MINGW_PACKAGE_PREFIX}-babl=${pkgver}") +conflicts=("${MINGW_PACKAGE_PREFIX}-babl") +options=(!libtool) +#source=(git://git.gnome.org/babl) +source=(git+https://github.com/salamandar/babl) +md5sums=('SKIP') +_gitname=babl + +build() { + mkdir "${srcdir}/build" -p + + meson "${srcdir}/${_gitname}"\ + "${srcdir}/build" \ + --prefix=/${MINGW_PREFIX} \ + --buildtype=release \ + -Db_lto=true \ + -Dwith-docs=false + + ninja -C "${srcdir}/build" +} + +package() { + DESTDIR="${pkgdir}" ninja -C "${srcdir}/build" install +} + +pkgver() { + cd "${_gitname}" + git describe --always | sed -e 's/BABL_//g' -e 's/[_-]/./g' +} + +check() { + meson test -C "${srcdir}/build" +} diff --git a/docs/CMYK-static.html b/docs/CMYK-static.html new file mode 100644 index 0000000..4730494 --- /dev/null +++ b/docs/CMYK-static.html @@ -0,0 +1,61 @@ + + + + + + + + CMYK - babl + + + + + + + +
+ +
+ + +
+
+ +

CMYK

+ +

CMYK handling is done using babl-spaces created with ICC profiles +containing CMYK profiles. BablSpaces for these ICC profiles handle color conversions using lcms2 - or if compiled without lcms2 support a naive profile independent fallback.

+

When a babl space derived from a CMYK ICC profile is used to instantiate +RGB formats, the resulting formats are using the default/NULL space for +primaries and TRCs.

+ +

The CMYK formats that use lcms2 for color interchange with the rest of +babl are the following, which are available for all data types, u8, u16, half +and float:

+
+
CMYK
Cyan Magenta Yellow Key, with 0 being white and 1.0 full ink coverage.
+
CMYKA
as previous, with separate alpha channel
+
CaMaYaKaA
as previous but associated alpha
+
cmyk
inverted CMYK, where 0.0 is full ink coverage and 1.0 is none
+
cmykA
as previous, with separate alpha channel
+
camayakaA
as previous but associated alpha
+
+ + + /babl +
+
+ +
+
+  +
+
+ + + diff --git a/docs/COPYING b/docs/COPYING new file mode 100644 index 0000000..76525e7 --- /dev/null +++ b/docs/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/docs/COPYING.LESSER b/docs/COPYING.LESSER new file mode 100644 index 0000000..fc8a5de --- /dev/null +++ b/docs/COPYING.LESSER @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/docs/ColorManagement-static.html b/docs/ColorManagement-static.html new file mode 100644 index 0000000..5a8f913 --- /dev/null +++ b/docs/ColorManagement-static.html @@ -0,0 +1,64 @@ + + + + + + + + babl color management + + + + + + + + + + + +
+
+

Color Management

+ +

By default the babl API is assuming data to be (unbounded) sRGB data, data + being sRGB defines the conversion to and from gray-scale as well as the gamma + - or Transfer Response Curve, TRC, used for converting between linear and + non-linear variants of the data. +

+ +

babl has API for creating a format for a specific space: + babl_format_with_space("R'G'B' u16", babl_space ("Rec2020")) creates + a 16 bit integer format for the Rec2020 color space. Babl knows internally + about "sRGB", "Rec2020", "Adobe", "Apple" and "ProPhoto" spaces, as they are + defined with constants on their wikipedia pages. +

+ +

Additional spaces can be loaded from monitor-class matrix+TRC ICC v2 and + v4 profiles. Using babl_icc_make_space (see babl.h for details). The space of + a babl format can also be queried with babl_format_get_space. +

+ +

The conversions babl does with ICC profiles are according to what is known + as the relative-colorimetric intent, monitor profiles containing both the + matrices used by babl and 3d CLUTs (color look up tables) sometimes also do + relative-colorimetric transfer for the "perceptual" intent CLUTs, but with + a more flexible and possibly higher accuracy conversions.

+ +

Handling of CMYK is in a separate document.

+ + /babl +
+
+ +
+
+  +
+
+ + + diff --git a/docs/Glossary-static.html b/docs/Glossary-static.html new file mode 100644 index 0000000..7f91b77 --- /dev/null +++ b/docs/Glossary-static.html @@ -0,0 +1,98 @@ + + + + + + babl - glossary + + + + + + + +
+ +
+ + +
+
+ +

Glossary

+ +

This vocabulary is meant as a guide to the concepts involved in babl to +help with understanding of the code and APIs, and help continued development to +keep the vocabulary small.

+ +
+ +
Alpha
+
Alpha is the name used for transparency in computer programming, two main forms exist associated alpha and separate alpha.
+ +
Associated alpha
+
Alpha in an additive light representation where each component has its +own associated alpha. This representation is useful for avoiding color from +empty pixels bleeding into surroundings. It is also able to represent emittance +in addition to opacity. +Babl uses Unified alpha transformations between separate alpha and associated alpha.
+ + +
BablFish
+
The objects used for processing pixels, it converts between two +BablFormats, the first time a pair of formats are passed to +babl_fish(format_in, format_out) a benchmark is run, and the fastest +combination of conversions available in babl to achieve the conversion within +configured accuracy is returned and cached for subsequent requests.
+ +
BablFormat
+
The data type used to describe a pixel format encoding, it consists of the specific order of components.
+ +
BablSpace
+
a BablSpace describes the specifics of a BablModel - current types of BablSpaces in use in babl are RGB and CMYK based ones; the space encodes the specific parameters like custom TRCs and Primaries.
+ +
BablModel
+
In babl a model describes a specific family of color encodings - with its list of color components. For the RGB and Grayscale spaces, the model also specifies any nonlinearities as TRCs.
+ +
CIE
+ +
ICC Profile
+
A blob/file format from the International Color Consortium, that can be used for specifies RGB or CMYK color spaces, babl has support for v2 and v4 RGB matrix profiles, as well as support for CMYK based profiles by using LCMS2.
+ +
EncodingIn babl, the encoding +refers to the part of a bablformat comprised by model, and choice and order of +components + data type. In other words all the aspects of the format apart from +the BablSpace. A babl format can be recreated from its encoding and - for +relevant spaces - the ICC profile for the space.
+ +
Luminance
+
The photometric measure of luminious intensity of per unit area of light. The luminance in babl is proportional to luminance - though it doesn't use the SI unit of candela per square meter.
+ +
Premultiplied alpha
+
deprecated term, see associated alpha
+ +
Straight alpha
+
Straight or separate alpha has alpha as a fully separate component, +that can be adjusted without affecting the color. +Babl uses symetric alpha transformations between straight and associated alpha.
+ +
TRC
+ +
+ + /babl +
+
+ +
+
+  +
+
+ + + diff --git a/docs/OldNews-static.html b/docs/OldNews-static.html new file mode 100644 index 0000000..2fb81c4 --- /dev/null +++ b/docs/OldNews-static.html @@ -0,0 +1,236 @@ + + + + + + babl - old releases + + + + + + + +
+ +
+ + +
+
+

old babl releases

+
+ +2018-10-05 babl-0.1.60
+Improved thread safety, acceleration for R'G'B'A u8 -> cairo-ARGB32 conversion. +
+2018-10-05 babl-0.1.58
+Preserve color of transparent pixels in conversion to premultiplied alpha, +Added single precision code-paths for faster fallback/reference conversions. +New BABL_ICC_INTENT_PERFORMANCE bitflag for combining with intent as bitflags, +use of matrix+trc when relative colorimetric CLUT is present. New color model +and formats, CIE xyY. + +
+2018-08-14 babl-0.1.56
+Improvements to the caching of profiled conversion chains between invocations +by ignoring unknown bits in cache file and remember which conversions yielded +reference fishes. + +2018-07-23 babl-0.1.54
+
+Export babl_space_get_icc, babl_space_get, babl_model_with_space, +babl_space_with_trc, babl_format_get_encoding, babl_model_is, SSE2 versions of +YA float and Y float to CIE L float. +
+2018-06-02 babl-0.1.52
+Concurrency fixes and fixes to handling of 0/1 entry palettes, do not +pre-equalize XYZ conversion matrices for sRGB, internal clean-ups, pre-define +ACES2065-1 and ACEScg BablSpaces, add R~G~B~ set of spaces, which for all +BablSpaces mean use sRGB TRC. +
+2018-05-20 babl-0.1.50
+Improvements to speed and precision of indexed code, improvements to meson +build. +
+2018-05-15 babl-0.1.48
+fix u8 <-> double conversions for chroma, SSE2 version of RGBA float to +CIE L / Lab. Build with -Ofast by default. +
+2018-04-10 babl-0.1.46
+added extensions with more coverage for u32, half and other utilit fast paths +improving fast path coverage. +
+2018-02-18 babl-0.1.44
+Fix bug in custom primaries/ICC fast paths, improve meson build
+
+2018-01-23 babl-0.1.42
+Fully initialize fishes when loading from cache.
+
+2018-01-16 babl-0.1.40
+Added format "CIE XYZ alpha" color model and formats. +New API babl_process_rows for reduced overhead in some scenarios; though bigger +gains seen also for regular babl_process with reimplemented branch-free +dispatch, and faster cbrt. Added meson build; being tested in parallel with +auotmake, Improved reference conversions for formats skipping some of models +components, Fixed gamma handling in indexed/palettized formats and improved +gamma precision consistenct in sse2 conversions.
+
+2017-11-15 babl-0.1.38
+Added format "CIE L float", a couple of protections against division by 0.0 +
+2017-11-10 babl-0.1.36
+Optimized customized primary aware code paths for CIE Lab<->RGB conversions, +improved accuracy of gamma approximations. New API babl_format_exists() for +checking validity of babl format name, crash proofing of cache handling and use +of environment variables. +
+2017-10-06 babl-0.1.34
+Brown paper bag release, Fix indexed / custom primaries conflict, and re-export +a symbol used by old GEGL/GIMPs. +
+2017-10-03 babl-0.1.32
+Added custom primaries and TRC support through ICC parsing, improved +float<->half performance, rewrite of all conversions functions to adhere to new +signature. +
+2017-07-15 babl-0.1.30
+Thread stability for palette modes, stricter alpha preservation, now +cross-compilable on android. +
+2017-05-30 babl-0.1.28
+Fast paths for Lav <-> Lch, release triggered by pending GIMP release. +
+2017-05-09 babl-0.1.26
+Build and install HCY color space, platform independences fixes to fish cache. +
+2017-02-01 babl-0.1.24
+Improvements to profile cache persistance, fast paths that improve actual GIMP +use on various precisions, use single precision constants for some more of CIE +computions. +
+2016-11-05 babl-0.1.22
+Added cache of profiled conversions, added HCY color model, some precision and +performance updated for fast paths. +
+2016-11-05 babl-0.1.20
+Fix run-time errors, leaks, and race conditions. Add conditional fast paths. +
+2016-06-13 babl-0.1.18
+Bugfix: take alpha threshold in consideration when processing floats in SSE2. +
+2016-02-12 babl-0.1.16
+Improvements to half float reference, SIMD, and fast-paths, and CIE float fast +paths; cleanups of fast path extensions. +
+2015-11-19 babl-0.1.14
+sRGB precision tuning, stability fixes, locale fix for setting error tolerance. +
+2015-02-03 babl-0.1.12
+optimizations for floating point conversions, HSV and HSL color models, +removal of dead code, fixed CIE Lab conversions. +
+2012-03-30 babl-0.1.10
+LUT based speedups for gamma correction / uncorrection. +
+2012-03-30 babl-0.1.8
+Added support for indexed/pallette based formats, constified API. +
+2011-11-18 babl-0.1.6
+Build improvements, remove blatantly wrong conversions from extensions, +made it possible to distinguish format_n formats from others, improvements +to vala/gobject introspection support. + +
+2011-01-20 babl-0.1.4
+Improved cross platform build ability, added code to handle n-component formats, +remove extraenous runtime profiling that impacted performance. + +
+2010-01-15 babl-0.1.2
+Made babl mostly threadsafe (sufficient for GIMP/GEGLs needs). Streamlined core functionality, reducing number of function calls and removing overeager instrumentation. +
+2009-05-20 babl-0.1.0
+Support for RGBA representation in the frequency domain, +un-pre-multiply close-to-zero alpha values to complete black instead +of slightly brighter than black, add a BABL_ALPHA_THRESHOLD constant +to the API, do a complete overhaul of the babl API and do some +changes to increase portability of the library. +
+2008-06-12 babl-0.0.22
+Speed improvements due to: coalesced hashing, early bail out upon creation of +duplicate formats, caching of non existing paths. Large amounts of the core has +also been reviewed and refactored. Improved conversion coverage in the matrix. +
+2008-02-27 babl-0.0.20
+Builds on OSX +Check <0.0 and >1.0 values conversions for accuracy as well. + +
+ + + + + babl + + + + + + + + + + + +
+ +
+ + + +
+
+
+ + +

Vocabulary

+ + + + + /babl +
+
+
+
+  +
+
+ + + diff --git a/docs/UnifiedAlpha-static.html b/docs/UnifiedAlpha-static.html new file mode 100644 index 0000000..9b94806 --- /dev/null +++ b/docs/UnifiedAlpha-static.html @@ -0,0 +1,110 @@ + + + + + + + + Unified Alpha - babl + + + + + + + +
+ +
+ + +
+
+ +

Symmetric transformations for floating point alpha

+ + +

babl clamps the alpha used when going from separate alpha to associated +alpha or from associated alpha to separate alpha to BABL_ALPHA_FLOOR. This +replaces asymptotic behavior and direct precision loss of color precision when +multiplying or dividing by alphas near 0.0 with a consistent symmetric +transformation.

+ +

Original intent of data as well as non-asymptotic precision loss is thus +maintained when the processing chain might temporarily use the other alpha +representation.

+ +
+    #define BABL_ALPHA_FLOOR    (1.0/65536.0)
+    #define BABL_ALPHA_FLOOR_F  (1.0f/65536.0f)
+
+ +

The deviation from not clamping near 0.0 is within the quantization margin +of 16bit integer alpha, thus no adaptations for any SIMD or and similar 8bit +and 16bit extensions of pixel format conversions are needed. +

+ +

This is the clamping function in use:

+
+static inline float
+babl_epsilon_for_zero_float (float value)
+{
+ if (value <= BABL_ALPHA_FLOOR_F &&
+     value >= -BABL_ALPHA_FLOOR_F)
+   return BABL_ALPHA_FLOOR_F;
+ else
+   return value;
+}
+
+

And an example use of this clamping function that is consistent with babls behavior:

+
+static inline void
+associated_to_separate_rgba (const float *associated_rgba,
+                                   float *separate_rgba)
+{
+  float alpha = associated_rgba[3];
+  float reciprocal_alpha = 1.0f / babl_epsilon_for_zero_float (alpha);
+
+  separate_rgba[0] = associated_rgba[0] * reciprocal_alpha;
+  separate_rgba[1] = associated_rgba[1] * reciprocal_alpha;
+  separate_rgba[2] = associated_rgba[2] * reciprocal_alpha;
+  separate_rgba[3] = alpha;
+}
+
+
+static inline void
+separate_to_associated_rgba (const float *separate_rgba,
+                                   float *associated_rgba)
+{
+  float alpha = associated_rgba[3];
+  float limited_alpha = babl_epsilon_for_zero_float (alpha);
+
+  associated_rgba[0] = separate_rgba[0] * limited_alpha;
+  associated_rgba[1] = separate_rgba[1] * limited_alpha;
+  associated_rgba[2] = separate_rgba[2] * limited_alpha;
+  associated_rgba[3] = alpha;
+}
+
+ + +

For more detils see the commit message of the most recent refinement as well as blog post with further background.

+ + + + /babl +
+
+ +
+
+  +
+
+ + + diff --git a/docs/babl.css b/docs/babl.css new file mode 100644 index 0000000..ecfe47e --- /dev/null +++ b/docs/babl.css @@ -0,0 +1,324 @@ + + body { + margin: 0; + padding: 0; + font-size: 14pt; + } + div.paper { + background-color: #fff; + margin: 1em; + margin-right: 3em; + margin-left: 280px; + } + iframe { + background-color: #aaa; + } + div.content { + padding: 1em; + padding-right: 3em; + padding-left: 2em; + max-width: 45em; + } + div.graphic { + position: absolute; + position: fixed; + color: #fff; + width: 256px; + height: 362px; + bottom: 0; + left: 0; + text-align: right; + padding-bottom: 1em; + } + p { + line-height: 1.2em; + } + h1 { + margin-top: 0em; + } + h1, h2, h3 { + color: #112266; + } + h1 { + font-size: 2em; + } + h2 { + font-size: 1.5em; + } + h3 { + font-size: 1.2em; + } + dl { + margin-top: 1em; + margin-bottom: 1em; + } + + div.expander { + border: 1px solid #bbb; + } + div.expander_title { + border-bottom: 1px solid #aaa; + } + div.expander_content { + margin-left: 3em; + padding-bottom: 1em; + } + div.expander_content dl{ + margin: 0; + padding: 0; + } + + table th { + font-weight: normal; + background-color: #ccc; + text-align: left; + } + span.component { + background-color: #060; + padding-left: 0.5em; + padding-top: 0.1em; + padding-bottom: 0.1em; + display: block; + float: left; + overflow: hidden; + width: 4em; + color: white; + border: 1px solid gray; + border: 1px solid white; + clear: both; + } + span.type { + display: block; + background-color: #006; + padding-left: 0.5em; + clear: both; + padding-top: 0.1em; + padding-bottom: 0.1em; + float: left; + overflow: hidden; + width: 4em; + color: white; + border: 1px solid white; + } + + .nopad { + margin :0; + padding:0; + } + + td.component { + background-color: #060; + padding-left: 0.5em; + padding-top: 0.1em; + padding-bottom: 0.1em; + overflow: hidden; + width: 4em; + color: white; + border: 1px solid white; + } + td.type { + background-color: #006; + padding-left: 0.5em; + padding-top: 0.1em; + padding-bottom: 0.1em; + overflow: hidden; + width: 4em; + color: white; + border: 1px solid white; + } + span.spacer { + float: left; + display: block; + overflow: hidden; + width: 0.2em; + } + span.name { + width: 100%; + display: block; + overflow: hidden; + border-top: 1px solid #ccc; + } + span.string { + color: #060; + } + span.function { + color: #006; + } + span.paren { + color: #555; + } + span.NULL { + color: #555; + } + tt { font-size: 110%; } + pre.authors { + font-size: 100%; + font-family: FreeSans, Verdana, sans-serif; + position: relative; + top: -2em; + } + img.BablFish { + float: right; + position: relative; + top: -8px; + border: none; + } + @media screen { + body { + background-color: #405070; + font-family: FreeSans, Verdana, sans-serif; + } + a { + text-decoration: none; + } + pre { + overflow: auto; + } + div.toc { + position: absolute; + position: fixed; + width: 256px; + top: 0; + left: 0; + padding-top: 2em; + z-index: 2; + } + div.toc ul { + padding-left: 0em; + float: right; + margin: 0; + } + div.toc li { + display: block; + padding-right: 1em; + } + div.toc li a{ + display: block; + padding-left: 1em; + padding-right: 1em; + color: #fff; + } + div.toc li a:hover { + color: #fff; + background-color: #506080; + } + div.paper { + max-width: 50em; + -moz-border-radius: 1em; + } + div.content { + } + div.graphic { + background: url("graphics/babl-a4poster.png"); + z-index: 1; + } + div.print { + display: none; + } + } + + @media print { + body { + background-color: none; + font-family: FreeSans, Verdana, sans-serif; + } + a, em { + /* XXX: work-around for rendering bug, should investigate whether + * this issue is fixed in the latest gecko + */ + padding-right: 3em; + padding-left: 1em; + } + a { + text-decoration: none; + } + + div.toc ul { + padding-left: 0em; + float: right; + margin: 0; + } + div.toc li { + display: block; + padding-right: 1em; + } + div.toc li a{ + display: block; + padding-left: 1em; + padding-right: 1em; + color: #fff; + } + div.toc li a:hover { + color: #fff; + background-color: #506080; + } + div.toc ul { + padding-left: 0em; + float: none; + margin: 0; + margin-left: 1em; + } + div.toc { + position: absolute; + width: 256px; + top: 0; + left: 2em; + padding-top: 2em; + z-index: 2; + } + div.toc ul { + margin-left: 0; + } + div.toc li a { + color : #000; + } + div toc h2 { + margin: 0; + padding: 0; + } + h1 { + margin-left: -0.75em; + } + h2 { + margin-left: -1em; + } + span.component { + background-color: #7f7; + color: black; + } + span.type { + background-color: #aaf; + color: black; + } + table th { + font-weight: bold; + } + div.print_title { + position: absolute; + top: 3em; + padding-left: 2em; + margin-left: 280px; + } + div.paper { + padding-top: 4em; + } + div.graphic { + background-color: #bbf; + height: 100%; + } + div.graphic img { + position: absolute; + bottom: 0; + left: 0; + } + div.screen { + display: none; + } + } + +.item_title { font-weight: bold; margin-top: 2.5em; margin-bottom: 0.6em; +} + + +.item_body { +} diff --git a/docs/graphics/babl-16x16.svg b/docs/graphics/babl-16x16.svg new file mode 100644 index 0000000..ea1a89d --- /dev/null +++ b/docs/graphics/babl-16x16.svg @@ -0,0 +1,524 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/graphics/babl-48x48.svg b/docs/graphics/babl-48x48.svg new file mode 100644 index 0000000..70e93a1 --- /dev/null +++ b/docs/graphics/babl-48x48.svg @@ -0,0 +1,695 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + Babl icon + 2005-08-20 + + + Øyvind Kolås + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/graphics/babl-a4poster.svg b/docs/graphics/babl-a4poster.svg new file mode 100644 index 0000000..d309b5c --- /dev/null +++ b/docs/graphics/babl-a4poster.svg @@ -0,0 +1,8107 @@ + + + + + + image/svg+xml + + + BablFish + 2005-08-20 + + + Øyvind Kolås + + + + + pippin.gimp.org + + + babl logo (as a poster) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/graphics/index.html b/docs/graphics/index.html new file mode 100644 index 0000000..091449c --- /dev/null +++ b/docs/graphics/index.html @@ -0,0 +1,56 @@ + + + + + + babl graphics + + + + + + + + + + + +
+
+ +

Babl graphics

+ +

The babl logo is a fish, the inspiration for babl itself, and it's + mascot is the original babel fish of Douglas Adams.

+ +

Icons

+ +

16x16 pixels

+ babl-16x16.png
+ Inkscape SVG source + +

48x48 pixels

+ babl-48x48.png
+ Inkscape SVG source + +

A4 poster

+ babl-a4poster.png
+ Inkscape SVG source + + +
+
+
+
+  +
+
+ + + diff --git a/docs/graphics/meson.build b/docs/graphics/meson.build new file mode 100644 index 0000000..1e1c55d --- /dev/null +++ b/docs/graphics/meson.build @@ -0,0 +1,42 @@ + +graphic_files = [ + 'babl-16x16.svg', + 'babl-48x48.svg', + 'babl-a4poster.svg', +] + +graphic_files_install = [] + +# Copy index.html to build +graphic_files_install += configure_file( + input: 'index.html', + output: '@PLAINNAME@', + copy: true +) + +foreach _file : graphic_files + # Copy svg files to build + graphic_files_install += configure_file( + input: _file, + output: '@PLAINNAME@', + copy: true + ) +endforeach + +if rsvg_convert_bin.found() + foreach _file : graphic_files + sizeinfo = _file.contains('a4poster') ? ['-w', '256'] : [] + graphic_files_install += custom_target(_file, + input: _file, + output: '@BASENAME@.png', + command: [ + rsvg_convert_bin, + sizeinfo, + '-o', '@OUTPUT@', + '@INPUT@', + ], + install: false, + build_by_default: true, + ) + endforeach +endif diff --git a/docs/index-static.html.in b/docs/index-static.html.in new file mode 100644 index 0000000..e1f389c --- /dev/null +++ b/docs/index-static.html.in @@ -0,0 +1,292 @@ + + + + + + + babl + + + + + + + + + +
+ +
+ + + +
+
+
+ + +

+
+ babl is pixel encoding and color space conversion engine in C. +
+

+

It allows converting between different methods of storing pixels known as + pixel formats that have with different bitdepths and other data + representations, color models, color spaces and component permutations.

+ +

A vocabulary to formulate new pixel formats from existing + primitives is provided as well as the framework to add new color models, + spaces and data types.

+ + +

Features

+ +
    +
  • Dynamically extendable with new formats, color models, components and datatypes, and SIMD code paths.
  • +
  • Reference 64bit floating point conversions for datatypes and color + models, with 32bit floating point reference speed-ups in some places. +
  • +
  • Runtime profiling/validating and code-path optimizing with persistence of profiling data across runs, with caching of results.
  • +
  • Can load Color Spaces from ICC v2 and v4 profiles containing RGB matrix + TRC and with lcms2 dependency also CMYK profiles.
  • +
  • Uses Unified Alpha conversions for conversions between separate and associate alpha, avoiding loss of color fidelity due to asymptotic behavior when dividing by 0.0 in floating point.
  • +
  • Portable self contained C code working on win32, linux, bsds and mac +on 32bit and 64bit systems.
  • +
  • Stable, small API, with singleton objects returned.
  • +
+ +

The pixel data storage in GIMP uses +GEGL's GeglBuffer which internally stores +tiles and provides an API for retrieving and storing pixel data with implicit +conversions using babl formats. +

+ + +

Download

+ +

The latest versioned development version of babl can be found in + https://download.gimp.org/pub/babl/. +

+ +

Babl uses git. The main repository is hosted by GNOME. + It can be browsed online and cloned with: +

+
git clone https://gitlab.gnome.org/GNOME/babl.git/
+ + +

News

+ +

The following is a list of the major changes that have gone into + each babl release. If there are significant improvements to babl when + a GEGL release is done a babl release is most often put out just prior + to the GEGL release.

+ + + +

For more detailed changes see git log.

+ + + +

Usage

+

Most users of babl do not know they are using babl and it is GIMP itself + which uses babl, this is documentation for such uses - and others that might + want to use babl for pixel format or color space conversion in other software. +

+ +

When using BablFishes to do your conversions, you request a fish to + convert between two formats, and an optimal fish to babls capability is + provided that you can use to do your conversions. Babl also provides + the capability to describe new formats based on a vocabulary of user + registered color models and data types. +

+ +

Babl provides a base vocabulary in BablBase and some extensions + that are thought to be generally useful.

+ +

When performing further extensions to the vocabulary of babl, the + internal consistency is governed by reference conversions that operate + on double (64 bit floating point values). Color Spaces can + be created from chromaticity coordinates or ICC profiles. The reference + color space - to maintain fast and bit-accurate conversions on with + sRGB is similar to scRGB using + 64bit floating point. +

+ +

To speed up operations, fast path conversions are used. + The registered shortcut might also be used by babl as an intermediate +conversion when constructing BablFishes for other conversions. +

+ +

Babl extensions are shared objects. If you have already developed + some fast conversion functions, wrapping them as babl extensions should + not take much time and will speed up babl for other users as well. +

+ +
babl_process (babl_fish (source_format, destination_format),
+              source_buffer, destination_buffer,
+              pixel_count);
+ +

The processing operation that babl performs is copying including + conversions if needed between linear buffers containing the same count + of pixels, with different pixel formats. +

+ +
+int width = 123, height = 581, pixel_count = width * height;
+
+const Babl *srgb             = babl_format ("R'G'B' u8");
+const Babl *lab              = babl_format ("CIE Lab float");
+const Babl *srgb_to_lab_fish = babl_fish (srgb, lab);
+
+float         *lab_buffer;
+unsigned char *srgb_buffer;
+
+babl_init ();
+
+srgb_buffer = malloc (pixel_count * babl_format_get_bytes_per_pixel (srgb));
+lab_buffer  = malloc (pixel_count * 3 * sizeof (float));
+
+...... load data into srgb_buffer .......
+
+babl_process (srgb_to_lab_fish, srgb_buffer, lab_buffer, pixel_count);
+
+...... do operation in lab space ........
+
+babl_process (babl_fish(lab, srgb),
+              lab_buffer, srgb_buffer, pixel_count);
+
+/* the data has now been transformed back to srgb data */
+ +

If the existing pixel formats are not sufficient for your conversion + needs, new ones can be created on the fly. The constructor + needs, new ones can be created on the fly. The constructor + will provide the prior created one if duplicates are registered.

+
const Babl *format = babl_format_new (babl_model ("R'G'B'"),
+                                      babl_type ("u16"),
+                                      babl_component ("B'"),
+                                      babl_component ("G'"),
+                                      babl_component ("R'"),
+                                      NULL);
+ + + + + + + + + +

Environment

+ +

Through the environment variable BABL_TOLERANCE you can control + a speed/performance trade off that by default is set very low (0.000001) + values in the range 0.01-0.1 can provide reasonable preview performance + by allowing lower numerical accuracy

. + +

BABL_PATH contains the path of the directory, containing the .so extensions to babl. +

+ + +

Extending

+ +

For samples of how the current internal API specification of + data types, color models, and conversions look in the extensions/ + directory. The tables in this HTML file is directly generated + based on the data registered by BablCore (double and RGBA), BablBase + (core datatypes, and RGB models), extensions (CIE Lab, naive CMYK, + various shortcut conversions). +

+ + + +

Directory Overview

+
babl-dist-root
+ │
+ ├──babl       the babl core
+ │   └──base   reference implementations for RGB and Grayscale Color Models,
+ │             8bit 16bit, and 32bit and 64bit floating point.
+ ├──extensions CIE-Lab color model as well as a naive-CMYK color model.
+ │             also contains a random cribbage of old conversion optimized
+ │             code from gggl. Finding more exsisting conversions in third
+ │             part libraries (hermes, lcms?, liboil?) could improve the
+ │             speed of babl.
+ ├──tools      various commandline tools used for verifying accuracy of extensions.
+ ├──tests      tests used to keep babl sane during development.
+ └──docs       Documentation/webpage for babl (the document you are reading
+               originated there.
+ + + + + + + + +

Copyright

+ +

Babl is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version.

+ + +

Authors

+ + + + babl +
+
+
+
+  +
+
+ + diff --git a/docs/meson.build b/docs/meson.build new file mode 100644 index 0000000..eefeb91 --- /dev/null +++ b/docs/meson.build @@ -0,0 +1,111 @@ +subdir('graphics') + +host = 'pippin.gimp.org' +location= 'public_html/babl' +scptarget = host + ':' + location + '/' + + +xml_insert = find_program( + meson.source_root() / 'tools' / 'xml-insert.py', + native: true +) + +index_static_html = configure_file( + input : 'index-static.html.in', + output: 'index-static.html', + configuration: conf, +) + +babl_css = configure_file( + input : 'babl.css', + output : 'babl.css', + copy: true +) + +index_html_tmp_env = [ + 'BABL_PATH=' + babl_extensions_build_dir, +] + +# Don't build babl ref if cannot run compiled objects in this env +if env_bin.found() and can_run_host_binaries + index_html_tmp = custom_target('index.html.tmp', + input : babl_html_dump, + output:'index.html.tmp', + command: [ + env_bin, + index_html_tmp_env, + babl_html_dump + ], + capture: true, + ) +else + warning('Cannot create babl reference in this environment') + index_html_tmp = 'index.html.tmp' +endif + +TOC = files('toc') +html_files = { + 'index': [index_static_html, [ + ['AUTHORS', files(meson.source_root() / 'AUTHORS')], + ['TODO', files(meson.source_root() / 'TODO')], + ['NEWS', files(meson.source_root() / 'NEWS')], + ['TOC', TOC], + ]], + 'Reference': ['auto', [ + ['BablBase', index_html_tmp], + ['TOC', TOC], + ]], + 'CMYK': ['auto', [ + ['TOC', TOC] + ]], + 'OldNews': ['auto', [ + ['TOC', TOC], + ]], + 'Glossary': ['auto', [ + ['TOC', TOC], + ]], + 'ColorManagement': ['auto', [ + ['TOC', TOC], + ]], + 'UnifiedAlpha': ['auto', [ + ['TOC', TOC], + ]], +} + +foreach _file, _parms : html_files + if '@0@'.format(_parms[0]) == 'auto' + _in = '@0@-static.html'.format(_file) + else + _in = _parms[0] + endif + _out = '@0@.html'.format(_file) + + inserts = [] + foreach _parm : _parms[1] + inserts += ['--insert', _parm[0], _parm[1]] + endforeach + + _tgt = custom_target(_out, + input: _in, + output: _out, + command: [ + xml_insert, + '--output' , '@OUTPUT@', + inserts, + '@INPUT@', + ], + build_by_default: true + ) + if _file == 'index' + index_html = _tgt + endif +endforeach + + +run_target('push_web', + command: [ + 'scp', index_html, index_static_html, babl_css, scptarget, + '&&', + 'scp', graphic_files_install, scptarget + 'graphics/' + ], +) diff --git a/docs/toc b/docs/toc new file mode 100644 index 0000000..95f70f5 --- /dev/null +++ b/docs/toc @@ -0,0 +1,28 @@ + diff --git a/docs/tools/changelog2rss b/docs/tools/changelog2rss new file mode 100755 index 0000000..62b92f0 --- /dev/null +++ b/docs/tools/changelog2rss @@ -0,0 +1,117 @@ +#!/usr/bin/env ruby + +require 'parsedate' + +class ChangeLogEntry + attr_accessor :category, :time, :title, :content, :author + + def initialize category = 'foo', + time = Time.now, + title = 'no title', + author = 'no author set', + content = '' + @category = category + @time = time + @title = title + @content = content + @author = author + end + + def to_s + @title+@content + end + + def to_rss + str = "\n" + str += "#{author}, #{time.strftime '%y%m%d'}\n" + str += "#{time.to_s}\n" + str += "#{time.to_s}\n" + str += "#{content}\n" + str += "\n" + end +end + +$newest = Time.now + +class ChangeLog + attr_accessor :entries + attr_reader :title + + def initialize + @entries = Array.new + end + + def load file, title=File.basename(file) + @title = title + + entry = nil + + File.open file do + |file| + file.each_line do + |line| + if line =~ /^(\d\d\d\d-\d\d-\d\d.*) (.*) (.*)/ + @entries.push entry unless entry == nil + date = ParseDate.parsedate $1 + time = Time.mktime date[0], date[1], date[2], date[3] + + entry = ChangeLogEntry.new(title, time, line, $2) + else + entry.content += line unless entry == nil + end + end + + @entries.push entry unless entry == nil + end + end + + def sort! + @entries.reverse! + @entries = @entries.sort { |x,y| (x.time <=> y.time)* -1 } + end + + def to_s + previous_category = 'foo' + str = "A combination of ChangeLogs related to the aluminium platform" + + @entries.each do + |entry| + if entry.category != previous_category + str+="\n\n__"+entry.category + "_"*(78-entry.category.length) + "\n\n" + previous_category = entry.category + end + str += entry.to_s + end + str + end + + def to_rss + previous_category = 'foo' + str = "\n" + str += "\n" + str += "\n" + + str += "\n" + + str += "bazfoo\n" + str += "\n" + + @entries.each do + |entry| + str += entry.to_rss + end + + str += "\n" + str += "\n" + + str + end +end + +changelog = ChangeLog.new +changelog.load ARGV[0] +#changelog.load 'path to another changelog', 'name' + +changelog.sort! + +puts changelog.to_rss diff --git a/export-symbols b/export-symbols new file mode 100644 index 0000000..82269f5 --- /dev/null +++ b/export-symbols @@ -0,0 +1,87 @@ +babl_component +babl_component_new +babl_conversion_get_destination_space +babl_conversion_get_source_space +babl_conversion_new +babl_cpu_accel_get_support +babl_exit +babl_fast_fish +babl_fish +babl_format +babl_format_exists +babl_format_get_bytes_per_pixel +babl_format_get_model +babl_format_get_n_components +babl_format_get_space +babl_format_get_type +babl_format_get_encoding +babl_format_has_alpha +babl_format_is_format_n +babl_format_is_palette +babl_format_n +babl_format_new +babl_format_with_space +babl_free +babl_get_model_flags +babl_get_name +babl_get_name +babl_get_user_data +babl_get_version +babl_init +babl_introspect +babl_malloc +babl_model +babl_model_is +babl_model_with_space +babl_model_new +babl_new_palette +babl_new_palette_with_space +babl_palette_reset +babl_palette_set_palette +babl_process +babl_process_rows +babl_sampling +babl_set_user_data +babl_space +babl_space_from_rgbxyz_matrix +babl_space_from_chromaticities +babl_space_from_icc +babl_space_get +babl_space_get_icc +babl_space_get_rgbtoxyz +babl_space_get_rgb_luminance +babl_space_to_xyz +babl_space_from_xyz +babl_space_to_icc +babl_space_with_trc +babl_space_is_cmyk +babl_space_is_gray +babl_space_get_gamma +babl_icc_make_space +babl_icc_get_key +babl_ticks +babl_type +babl_type_new +babl_trc +babl_trc_gamma +babl_db_exist_by_name +babl_db_find +babl_db_init +babl_db_exist_by_id +babl_db_each +babl_formats_count +babl_format_class_for_each +babl_model_class_for_each +babl_type_class_for_each +babl_conversion_class_for_each +babl_set_extender +babl_extension_quiet_log +babl_fish_path +babl_extender +babl_class_name +babl_sanity +babl_type_is_symmetric +babl_model_is_symmetric +babl_fish_db +babl_polynomial_approximate_gamma +babl_backtrack diff --git a/extensions/CIE.c b/extensions/CIE.c new file mode 100644 index 0000000..1607b27 --- /dev/null +++ b/extensions/CIE.c @@ -0,0 +1,3570 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, 2014, 2019 Øyvind Kolås. + * Copyright (C) 2009, Martin Nordholts + * Copyright (C) 2014, 2019 Elle Stone + * Copyright (C) 2017, 2018 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include +#include +#include + +#if defined(USE_SSE2) +#include +#endif /* defined(USE_SSE2) */ + +#include "babl-internal.h" +#include "extensions/util.h" + +#define DEGREES_PER_RADIAN (180 / 3.14159265358979323846) +#define RADIANS_PER_DEGREE (1 / DEGREES_PER_RADIAN) + +#define LAB_EPSILON (216.0f / 24389.0f) +#define LAB_KAPPA (24389.0f / 27.0f) + +/* The constants below hard-code the D50-adapted sRGB ICC profile + * reference white, aka the ICC profile D50 illuminant. + * + * In a properly ICC profile color-managed application, the profile + * illuminant values should be retrieved from the image's + * ICC profile's illuminant. + * + * At present, the ICC profile illuminant is always D50. This might + * change when the next version of the ICC specs is released. + * + * As encoded in an actual V2 or V4 ICC profile, + * the illuminant values are hexadecimal-rounded, as are the following + * hard-coded D50 ICC profile illuminant values: + */ + +#define D50_WHITE_REF_X 0.964202880f +#define D50_WHITE_REF_Y 1.000000000f +#define D50_WHITE_REF_Z 0.824905400f + +#define NEAR_ZERO 0.0000000001f +#define near_zero(a) ((a) < NEAR_ZERO && (a) > -NEAR_ZERO) + +#define D50_WHITE_REF_x 0.345702921222f +#define D50_WHITE_REF_y 0.358537532290f + + +static void types (void); +static void components (void); +static void models (void); +static void conversions (void); +static void formats (void); + +int init (void); + +int +init (void) +{ + types (); + components (); + models (); + formats (); + conversions (); + return 0; +} + +static void +components (void) +{ + babl_component_new ("CIE L", "doc", "Luminance, range 0.0-100.0 in float", NULL); + babl_component_new ("CIE a", "chroma", "doc", "chroma component 0.0 is no saturation", NULL); + babl_component_new ("CIE b", "chroma", "doc", "chroma component 0.0 is no saturation", NULL); + babl_component_new ("CIE C(ab)", "chroma", "doc", "chrominance/saturation", NULL); + babl_component_new ("CIE H(ab)", "chroma", "doc", "hue value range 0.0-360.0", NULL); + babl_component_new ("CIE X", NULL); + babl_component_new ("CIE Y", NULL); + babl_component_new ("CIE Z", NULL); + babl_component_new ("CIE x", NULL); + babl_component_new ("CIE y", NULL); + /* CIE 1976 UCS */ + babl_component_new ("CIE u", NULL); + babl_component_new ("CIE v", NULL); +/* babl_component_new ("CIE z", NULL);*/ +} + +static void +models (void) +{ + babl_model_new ( + "name", "CIE Lab", + "doc", "CIE Lab color model, a perceptually uniform space, euclidian distance in this space represents delta E.", + babl_component ("CIE L"), + babl_component ("CIE a"), + babl_component ("CIE b"), + "CIE", + NULL); + + babl_model_new ( + "name", "CIE Lab alpha", + "doc", "CIE Lab color model, with separate alpha", + babl_component ("CIE L"), + babl_component ("CIE a"), + babl_component ("CIE b"), + babl_component ("A"), + "CIE", + "alpha", + NULL); + + babl_model_new ( + "name", "CIE LCH(ab)", + "doc", "CIE LCH color model, using cylindrical coordinates", + babl_component ("CIE L"), + babl_component ("CIE C(ab)"), + babl_component ("CIE H(ab)"), + "CIE", + NULL); + + babl_model_new ( + "name", "CIE LCH(ab) alpha", + "doc", "CIE LCH color model, using cylindrical coordinates, with separate alpha", + babl_component ("CIE L"), + babl_component ("CIE C(ab)"), + babl_component ("CIE H(ab)"), + babl_component ("A"), + "CIE", + "alpha", + NULL); + + babl_model_new ( + "name", "CIE XYZ", + babl_component ("CIE X"), + babl_component ("CIE Y"), + babl_component ("CIE Z"), + "CIE", + NULL); + + babl_model_new ( + "name", "CIE XYZ alpha", + babl_component ("CIE X"), + babl_component ("CIE Y"), + babl_component ("CIE Z"), + babl_component ("A"), + "CIE", + "alpha", + NULL); + + babl_model_new ( + "name", "CIE xyY", + "doc", "the coordinate system often used for drawing chromaticity diagrams. Y is luminance.", + babl_component ("CIE x"), + babl_component ("CIE y"), + babl_component ("CIE Y"), + "CIE", + NULL); + + babl_model_new ( + "name", "CIE xyY alpha", + "doc", "the coordinate system often used for drawing chromaticity diagrams. Y is luminance, with separate alpha", + babl_component ("CIE x"), + babl_component ("CIE y"), + babl_component ("CIE Y"), + babl_component ("A"), + "CIE", + "alpha", + NULL); + +/* CIE 1976 UCS */ + babl_model_new ( + "name", "CIE Yuv", + "doc", "A newer more perceptually uniform space than xyY for chromaticity diagrams.", + babl_component ("CIE Y"), + babl_component ("CIE u"), + babl_component ("CIE v"), + NULL); + + babl_model_new ( + "name", "CIE Yuv alpha", + "doc", "A newer more perceptually uniform space than xyY for chromaticity diagrams, with separate alpha.", + babl_component ("CIE Y"), + babl_component ("CIE u"), + babl_component ("CIE v"), + babl_component ("A"), + NULL); +} + +static void rgbcie_init (void); + +/******** begin double RGB/CIE color space conversions ****************/ + +static inline void ab_to_CHab (double a, + double b, + double *to_C, + double *to_H); + +static inline void CHab_to_ab (double C, + double H, + double *to_a, + double *to_b); + +static inline void XYZ_to_LAB (double X, + double Y, + double Z, + double *to_L, + double *to_a, + double *to_b + ); + +static inline void LAB_to_XYZ (double L, + double a, + double b, + double *to_X, + double *to_Y, + double *to_Z + ); + +static inline void XYZ_to_xyY (double X, + double Y, + double Z, + double *to_x, + double *to_y, + double *to_Y + ); + +static inline void xyY_to_XYZ (double x, + double y, + double Y, + double *to_X, + double *to_Y, + double *to_Z + ); + +/* CIE 1976 UCS */ +static inline void XYZ_to_Yuv (double X, + double Y, + double Z, + double *to_Y, + double *to_u, + double *to_v + ); + +static inline void Yuv_to_XYZ (double Y, + double u, + double v, + double *to_X, + double *to_Y, + double *to_Z + ); + +static inline void +XYZ_to_LAB (double X, + double Y, + double Z, + double *to_L, + double *to_a, + double *to_b) +{ + double xr = X / D50_WHITE_REF_X; + double yr = Y / D50_WHITE_REF_Y; + double zr = Z / D50_WHITE_REF_Z; + + double fx = xr > LAB_EPSILON ? cbrt (xr) : (LAB_KAPPA * xr + 16.0) / 116.0; + double fy = yr > LAB_EPSILON ? cbrt (yr) : (LAB_KAPPA * yr + 16.0) / 116.0; + double fz = zr > LAB_EPSILON ? cbrt (zr) : (LAB_KAPPA * zr + 16.0) / 116.0; + + *to_L = 116.0 * fy - 16.0; + *to_a = 500.0 * (fx - fy); + *to_b = 200.0 * (fy - fz); +} + +static inline void +LAB_to_XYZ (double L, + double a, + double b, + double *to_X, + double *to_Y, + double *to_Z) +{ + double fy = (L + 16.0) / 116.0; + double fy_cubed = fy * fy * fy; + + double fx = fy + a / 500.0; + double fx_cubed = fx * fx * fx; + + double fz = fy - b / 200.0; + double fz_cubed = fz * fz * fz; + + double yr = L > LAB_KAPPA * LAB_EPSILON ? fy_cubed : L / LAB_KAPPA; + double xr = fx_cubed > LAB_EPSILON ? fx_cubed : (fx * 116.0 - 16.0) / LAB_KAPPA; + double zr = fz_cubed > LAB_EPSILON ? fz_cubed : (fz * 116.0 - 16.0) / LAB_KAPPA; + + *to_X = xr * D50_WHITE_REF_X; + *to_Y = yr * D50_WHITE_REF_Y; + *to_Z = zr * D50_WHITE_REF_Z; +} + +/* CIE xyY */ +static inline void +XYZ_to_xyY (double X, + double Y, + double Z, + double *to_x, + double *to_y, + double *to_Y) +{ + double sum = X + Y + Z; + if (near_zero (sum)) + { *to_Y = 0.0; + *to_x = D50_WHITE_REF_x; + *to_y = D50_WHITE_REF_y; + } + else + { + *to_x = X / sum; + *to_y = Y / sum; + *to_Y = Y; + } +} + +static inline void +xyY_to_XYZ (double x, + double y, + double Y, + double *to_X, + double *to_Y, + double *to_Z) +{ + if (near_zero (Y)) + { + *to_X = 0.0; + *to_Y = 0.0; + *to_Z = 0.0; + } + else + { + *to_X = (x * Y) / y; + *to_Y = Y; + *to_Z = ((1 - x - y) * Y) / y; + } +} + + +/* CIE 1976 UCS */ + +/* Code for near-zero XYZ and RGB for CIE 1976 UCS patterned + * after code written by and used with kind permission of Graeme Gill. + * Graeme Gill's code is in "icc.c" + * downloadable from http://argyllcms.com/ */ + +static inline void +XYZ_to_Yuv (double X, + double Y, + double Z, + double *to_Y, + double *to_u, + double *to_v) +{ + double sum = X + (15.0 * Y) + (3.0 * Z); + if (near_zero (sum)) + { + *to_Y = 0.0; + *to_u = 4.0/19.0; + *to_v = 9.0/19.0; + } + else + { + *to_Y = Y; + *to_u = (4.0 * X) / sum; + *to_v = (9.0 * Y) / sum; + } +} + +static inline void +Yuv_to_XYZ (double Y, + double u, + double v, + double *to_X, + double *to_Y, + double *to_Z) +{ + if (near_zero (v)) + { + *to_X = 0.0; + *to_Y = 0.0; + *to_Z = 0.0; + } + else + { + *to_X = ((9.0 * u * Y)/(4.0 * v)); + *to_Y = Y; + *to_Z = -(((20.0 * v + 3.0 * u - 12.0) * Y)/(4.0 * v)); + } +} + +/* rgb <-> XYZ */ + +static void +rgba_to_xyz (const Babl *conversion, + char *src, + char *dst, + long n) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + while (n--) + { + double RGB[3] = {((double *) src)[0], + ((double *) src)[1], + ((double *) src)[2] }; + babl_space_to_xyz (space, RGB, (double*)dst); + + src += sizeof (double) * 4; + dst += sizeof (double) * 3; + } +} + +static void +xyz_to_rgba (const Babl *conversion, + char *src, + char *dst, + long n) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + while (n--) + { + babl_space_from_xyz (space, (double*)src, (double*) dst); + ((double *) dst)[3] = 1.0; + src += sizeof (double) * 3; + dst += sizeof (double) * 4; + } +} + +static void +rgba_to_xyza (const Babl *conversion,char *src, + char *dst, + long n) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + while (n--) + { + babl_space_to_xyz (space, (double*)src, (double*)dst); + ((double *) dst)[3] = ((double *) src)[3]; + + src += sizeof (double) * 4; + dst += sizeof (double) * 4; + } +} + +static void +xyza_to_rgba (const Babl *conversion,char *src, + char *dst, + long n) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + while (n--) + { + babl_space_from_xyz (space, (double*)src, (double*) dst); + ((double *) dst)[3] = ((double *) src)[3]; + + src += sizeof (double) * 4; + dst += sizeof (double) * 4; + } +} + + +/* rgb -> xyY */ +static void +rgba_to_xyY (const Babl *conversion, + char *src, + char *dst, + long n) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + while (n--) + { + double XYZ[3], x, y, Y; + + babl_space_to_xyz (space, (double*)src, XYZ); + XYZ_to_xyY (XYZ[0], XYZ[1], XYZ[2], &x, &y, &Y); + + ((double *) dst)[0] = x; + ((double *) dst)[1] = y; + ((double *) dst)[2] = Y; + + src += sizeof (double) * 4; + dst += sizeof (double) * 3; + } +} + +static void +rgba_to_xyYa (const Babl *conversion,char *src, + char *dst, + long n) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + while (n--) + { + double alpha = ((double *) src)[3]; + double XYZ[3], x, y, Y; + + //convert RGB to XYZ + babl_space_to_xyz (space, (double*)src, XYZ); + + //convert XYZ to xyY + XYZ_to_xyY (XYZ[0], XYZ[1], XYZ[2], &x, &y, &Y); + + ((double *) dst)[0] = x; + ((double *) dst)[1] = y; + ((double *) dst)[2] = Y; + ((double *) dst)[3] = alpha; + + src += sizeof (double) * 4; + dst += sizeof (double) * 4; + } +} + + + +/* rgb -> Yuv */ +static void +rgba_to_Yuv (const Babl *conversion,char *src, + char *dst, + long n) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + while (n--) + { + double XYZ[3], Y, u, v; + + babl_space_to_xyz (space, (double*)src, XYZ); + XYZ_to_Yuv (XYZ[0], XYZ[1], XYZ[2], &Y, &u, &v); + + ((double *) dst)[0] = Y; + ((double *) dst)[1] = u; + ((double *) dst)[2] = v; + + src += sizeof (double) * 4; + dst += sizeof (double) * 3; + } +} + +static void +rgba_to_Yuva (const Babl *conversion,char *src, + char *dst, + long n) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + while (n--) + { + double alpha = ((double *) src)[3]; + double XYZ[3], Y, u, v; + + //convert RGB to XYZ + babl_space_to_xyz (space, (double*)src, XYZ); + + //convert XYZ to Yuv + XYZ_to_Yuv (XYZ[0], XYZ[1], XYZ[2], &Y, &u, &v); + + ((double *) dst)[0] = Y; + ((double *) dst)[1] = u; + ((double *) dst)[2] = v; + ((double *) dst)[3] = alpha; + + src += sizeof (double) * 4; + dst += sizeof (double) * 4; + } +} + + +/* rgbf <->xyYf */ +static void +rgbaf_to_xyYaf (const Babl *conversion, + float *src, + float *dst, + long samples) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + float m_0_0 = space->space.RGBtoXYZf[0] / D50_WHITE_REF_X; + float m_0_1 = space->space.RGBtoXYZf[1] / D50_WHITE_REF_X; + float m_0_2 = space->space.RGBtoXYZf[2] / D50_WHITE_REF_X; + float m_1_0 = space->space.RGBtoXYZf[3] / D50_WHITE_REF_Y; + float m_1_1 = space->space.RGBtoXYZf[4] / D50_WHITE_REF_Y; + float m_1_2 = space->space.RGBtoXYZf[5] / D50_WHITE_REF_Y; + float m_2_0 = space->space.RGBtoXYZf[6] / D50_WHITE_REF_Z; + float m_2_1 = space->space.RGBtoXYZf[7] / D50_WHITE_REF_Z; + float m_2_2 = space->space.RGBtoXYZf[8] / D50_WHITE_REF_Z; + long n = samples; + + while (n--) + { + float x, y, X, Y, Z, r, g, b, a; + r = src[0]; + g = src[1]; + b = src[2]; + a = src[3]; + + if (near_zero(r) && near_zero(g) && near_zero(b)) + { + Y = 0.0f; + x = D50_WHITE_REF_x; + y = D50_WHITE_REF_y; + } + else + { + X = m_0_0 * r + m_0_1 * g + m_0_2 * b; + Y = m_1_0 * r + m_1_1 * g + m_1_2 * b; + Z = m_2_0 * r + m_2_1 * g + m_2_2 * b; + + x = X / (X + Y + Z); + y = Y / (X + Y + Z); + } + + dst[0] = x; + dst[1] = y; + dst[2] = Y; + dst[3] = a; + + src += 4; + dst += 4; + } +} + +static void +rgbf_to_xyYf (const Babl *conversion,float *src, + float *dst, + long samples) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + float m_0_0 = space->space.RGBtoXYZf[0] / D50_WHITE_REF_X; + float m_0_1 = space->space.RGBtoXYZf[1] / D50_WHITE_REF_X; + float m_0_2 = space->space.RGBtoXYZf[2] / D50_WHITE_REF_X; + float m_1_0 = space->space.RGBtoXYZf[3] / D50_WHITE_REF_Y; + float m_1_1 = space->space.RGBtoXYZf[4] / D50_WHITE_REF_Y; + float m_1_2 = space->space.RGBtoXYZf[5] / D50_WHITE_REF_Y; + float m_2_0 = space->space.RGBtoXYZf[6] / D50_WHITE_REF_Z; + float m_2_1 = space->space.RGBtoXYZf[7] / D50_WHITE_REF_Z; + float m_2_2 = space->space.RGBtoXYZf[8] / D50_WHITE_REF_Z; + long n = samples; + + while (n--) + { + float x, y, X, Y, Z, r, g, b; + r = src[0]; + g = src[1]; + b = src[2]; + + if (near_zero(r) && near_zero(g) && near_zero(b)) + { + Y = 0.0f; + x = D50_WHITE_REF_x; + y = D50_WHITE_REF_y; + } + else + { + X = m_0_0 * r + m_0_1 * g + m_0_2 * b; + Y = m_1_0 * r + m_1_1 * g + m_1_2 * b; + Z = m_2_0 * r + m_2_1 * g + m_2_2 * b; + + x = X / (X + Y + Z); + y = Y / (X + Y + Z); + } + + dst[0] = x; + dst[1] = y; + dst[2] = Y; + + src += 3; + dst += 3; + } +} + + +static void +rgbaf_to_xyYf (const Babl *conversion, + float *src, + float *dst, + long samples) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + float m_0_0 = space->space.RGBtoXYZf[0] / D50_WHITE_REF_X; + float m_0_1 = space->space.RGBtoXYZf[1] / D50_WHITE_REF_X; + float m_0_2 = space->space.RGBtoXYZf[2] / D50_WHITE_REF_X; + float m_1_0 = space->space.RGBtoXYZf[3] / D50_WHITE_REF_Y; + float m_1_1 = space->space.RGBtoXYZf[4] / D50_WHITE_REF_Y; + float m_1_2 = space->space.RGBtoXYZf[5] / D50_WHITE_REF_Y; + float m_2_0 = space->space.RGBtoXYZf[6] / D50_WHITE_REF_Z; + float m_2_1 = space->space.RGBtoXYZf[7] / D50_WHITE_REF_Z; + float m_2_2 = space->space.RGBtoXYZf[8] / D50_WHITE_REF_Z; + long n = samples; + + while (n--) + { + float x, y, X, Y, Z, r, g, b; + r = src[0]; + g = src[1]; + b = src[2]; + + if (near_zero(r) && near_zero(g) && near_zero(b)) + { + Y = 0.0f; + x = D50_WHITE_REF_x; + y = D50_WHITE_REF_y; + } + else + { + X = m_0_0 * r + m_0_1 * g + m_0_2 * b; + Y = m_1_0 * r + m_1_1 * g + m_1_2 * b; + Z = m_2_0 * r + m_2_1 * g + m_2_2 * b; + + x = X / (X + Y + Z); + y = Y / (X + Y + Z); + } + + dst[0] = x; + dst[1] = y; + dst[2] = Y; + + src += 4; + dst += 3; + } +} + + + +/* rgbf -> Yuv */ +static void +rgbaf_to_Yuvaf (const Babl *conversion, + float *src, + float *dst, + long samples) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + float m_0_0 = space->space.RGBtoXYZf[0] / D50_WHITE_REF_X; + float m_0_1 = space->space.RGBtoXYZf[1] / D50_WHITE_REF_X; + float m_0_2 = space->space.RGBtoXYZf[2] / D50_WHITE_REF_X; + float m_1_0 = space->space.RGBtoXYZf[3] / D50_WHITE_REF_Y; + float m_1_1 = space->space.RGBtoXYZf[4] / D50_WHITE_REF_Y; + float m_1_2 = space->space.RGBtoXYZf[5] / D50_WHITE_REF_Y; + float m_2_0 = space->space.RGBtoXYZf[6] / D50_WHITE_REF_Z; + float m_2_1 = space->space.RGBtoXYZf[7] / D50_WHITE_REF_Z; + float m_2_2 = space->space.RGBtoXYZf[8] / D50_WHITE_REF_Z; + long n = samples; + + while (n--) + { + float u, v, X, Y, Z, r, g, b, a, sum; + r = src[0]; + g = src[1]; + b = src[2]; + a = src[3]; + + if (near_zero(r) && near_zero(g) && near_zero(b)) + { + Y = 0.0f; + u = 4.0/19.0; + v = 9.0/19.0; + } + else + { + X = m_0_0 * r + m_0_1 * g + m_0_2 * b; + Y = m_1_0 * r + m_1_1 * g + m_1_2 * b; + Z = m_2_0 * r + m_2_1 * g + m_2_2 * b; + + sum = (X + 15.0 * Y + 3.0 * Z); + u = (4.0 * X) / sum; + v = (9.0 * Y) / sum; + } + + dst[0] = Y; + dst[1] = u; + dst[2] = v; + dst[3] = a; + + src += 4; + dst += 4; + } +} + +static void +rgbf_to_Yuvf (const Babl *conversion,float *src, + float *dst, + long samples) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + float m_0_0 = space->space.RGBtoXYZf[0] / D50_WHITE_REF_X; + float m_0_1 = space->space.RGBtoXYZf[1] / D50_WHITE_REF_X; + float m_0_2 = space->space.RGBtoXYZf[2] / D50_WHITE_REF_X; + float m_1_0 = space->space.RGBtoXYZf[3] / D50_WHITE_REF_Y; + float m_1_1 = space->space.RGBtoXYZf[4] / D50_WHITE_REF_Y; + float m_1_2 = space->space.RGBtoXYZf[5] / D50_WHITE_REF_Y; + float m_2_0 = space->space.RGBtoXYZf[6] / D50_WHITE_REF_Z; + float m_2_1 = space->space.RGBtoXYZf[7] / D50_WHITE_REF_Z; + float m_2_2 = space->space.RGBtoXYZf[8] / D50_WHITE_REF_Z; + long n = samples; + + while (n--) + { + float u, v, X, Y, Z, r, g, b, sum; + r = src[0]; + g = src[1]; + b = src[2]; + + if (near_zero(r) && near_zero(g) && near_zero(b)) + { + Y = 0.0f; + u = 4.0/19.0; + v = 9.0/19.0; + } + else + { + X = m_0_0 * r + m_0_1 * g + m_0_2 * b; + Y = m_1_0 * r + m_1_1 * g + m_1_2 * b; + Z = m_2_0 * r + m_2_1 * g + m_2_2 * b; + + sum = (X + 15.0 * Y + 3.0 * Z); + u = (4.0 * X) / sum; + v = (9.0 * Y) / sum; + } + + dst[0] = Y; + dst[1] = u; + dst[2] = v; + + src += 3; + dst += 3; + } +} + + +static void +rgbaf_to_Yuvf (const Babl *conversion, + float *src, + float *dst, + long samples) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + float m_0_0 = space->space.RGBtoXYZf[0] / D50_WHITE_REF_X; + float m_0_1 = space->space.RGBtoXYZf[1] / D50_WHITE_REF_X; + float m_0_2 = space->space.RGBtoXYZf[2] / D50_WHITE_REF_X; + float m_1_0 = space->space.RGBtoXYZf[3] / D50_WHITE_REF_Y; + float m_1_1 = space->space.RGBtoXYZf[4] / D50_WHITE_REF_Y; + float m_1_2 = space->space.RGBtoXYZf[5] / D50_WHITE_REF_Y; + float m_2_0 = space->space.RGBtoXYZf[6] / D50_WHITE_REF_Z; + float m_2_1 = space->space.RGBtoXYZf[7] / D50_WHITE_REF_Z; + float m_2_2 = space->space.RGBtoXYZf[8] / D50_WHITE_REF_Z; + long n = samples; + + while (n--) + { + float u, v, X, Y, Z, r, g, b, sum; + r = src[0]; + g = src[1]; + b = src[2]; + + if (near_zero(r) && near_zero(g) && near_zero(b)) + { + Y = 0.0f; + u = 4.0/19.0; + v = 9.0/19.0; + } + else + { + X = m_0_0 * r + m_0_1 * g + m_0_2 * b; + Y = m_1_0 * r + m_1_1 * g + m_1_2 * b; + Z = m_2_0 * r + m_2_1 * g + m_2_2 * b; + + sum = (X + 15.0 * Y + 3.0 * Z); + u = (4.0 * X) / sum; + v = (9.0 * Y) / sum; + } + + dst[0] = Y; + dst[1] = u; + dst[2] = v; + + src += 4; + dst += 3; + } +} + + + + +/* xyY -> rgb */ + +static void +xyY_to_rgba (const Babl *conversion, + char *src, + char *dst, + long n) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + while (n--) + { + double x = ((double *) src)[0]; + double y = ((double *) src)[1]; + double Y = ((double *) src)[2]; + + double R, G, B, X, Z; + + //convert xyY to XYZ + xyY_to_XYZ (x, y, Y, &X, &Y, &Z); + + //convert XYZ to RGB + { + double XYZ[3] = {X,Y,Z}; + double RGB[3]; + babl_space_from_xyz (space, XYZ, RGB); + R = RGB[0]; + G = RGB[1]; + B = RGB[2]; + } + + ((double *) dst)[0] = R; + ((double *) dst)[1] = G; + ((double *) dst)[2] = B; + ((double *) dst)[3] = 1.0; + + src += sizeof (double) * 3; + dst += sizeof (double) * 4; + } +} + + +static void +xyYa_to_rgba (const Babl *conversion,char *src, + char *dst, + long n) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + while (n--) + { + double x = ((double *) src)[0]; + double y = ((double *) src)[1]; + double Y = ((double *) src)[2]; + double alpha = ((double *) src)[3]; + + double X, Z; + + //convert xyY to XYZ + xyY_to_XYZ (x, y, Y, &X, &Y, &Z); + + { + //convert XYZ to RGB + double XYZ[3] = {X,Y,Z}; + babl_space_from_xyz (space, XYZ, (double*)dst); + } + ((double *) dst)[3] = alpha; + + src += sizeof (double) * 4; + dst += sizeof (double) * 4; + } +} + + + +/* Yuv -> rgb */ + +static void +Yuv_to_rgba (const Babl *conversion,char *src, + char *dst, + long n) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + while (n--) + { + double Y = ((double *) src)[0]; + double u = ((double *) src)[1]; + double v = ((double *) src)[2]; + + double R, G, B, X, Z; + + //convert Yuv to XYZ + Yuv_to_XYZ (Y, u, v, &X, &Y, &Z); + + //convert XYZ to RGB + { + double XYZ[3] = {X,Y,Z}; + double RGB[3]; + babl_space_from_xyz (space, XYZ, RGB); + R = RGB[0]; + G = RGB[1]; + B = RGB[2]; + } + + ((double *) dst)[0] = R; + ((double *) dst)[1] = G; + ((double *) dst)[2] = B; + ((double *) dst)[3] = 1.0; + + src += sizeof (double) * 3; + dst += sizeof (double) * 4; + } +} + + +static void +Yuva_to_rgba (const Babl *conversion,char *src, + char *dst, + long n) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + while (n--) + { + double Y = ((double *) src)[0]; + double u = ((double *) src)[1]; + double v = ((double *) src)[2]; + double alpha = ((double *) src)[3]; + + double X, Z; + + //convert Yuv to XYZ + Yuv_to_XYZ (Y, u, v, &X, &Y, &Z); + + { + //convert XYZ to RGB + double XYZ[3] = {X,Y,Z}; + babl_space_from_xyz (space, XYZ, (double*)dst); + } + ((double *) dst)[3] = alpha; + + src += sizeof (double) * 4; + dst += sizeof (double) * 4; + } +} + + +/* xyYf -> rgbf */ + +static void +xyYf_to_rgbf (const Babl *conversion,float *src, + float *dst, + long samples) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + float m_0_0 = space->space.XYZtoRGBf[0] * D50_WHITE_REF_X; + float m_0_1 = space->space.XYZtoRGBf[1] * D50_WHITE_REF_Y; + float m_0_2 = space->space.XYZtoRGBf[2] * D50_WHITE_REF_Z; + float m_1_0 = space->space.XYZtoRGBf[3] * D50_WHITE_REF_X; + float m_1_1 = space->space.XYZtoRGBf[4] * D50_WHITE_REF_Y; + float m_1_2 = space->space.XYZtoRGBf[5] * D50_WHITE_REF_Z; + float m_2_0 = space->space.XYZtoRGBf[6] * D50_WHITE_REF_X; + float m_2_1 = space->space.XYZtoRGBf[7] * D50_WHITE_REF_Y; + float m_2_2 = space->space.XYZtoRGBf[8] * D50_WHITE_REF_Z; + long n = samples; + + while (n--) + { + float X, Z, r, g, b; + float x = src[0]; + float y = src[1]; + float Y = src[2]; + + if (near_zero (y)) + { + X = 0.0f; + Y = 0.0f; + Z = 0.0f; + } + else + { + X = (x * Y) / y; + //Y = Y; + Z = ((1 - x - y) * Y) / y; + } + + r = m_0_0 * X + m_0_1 * Y + m_0_2 * Z; + g = m_1_0 * X + m_1_1 * Y + m_1_2 * Z; + b = m_2_0 * X + m_2_1 * Y + m_2_2 * Z; + + dst[0] = r; + dst[1] = g; + dst[2] = b; + + src += 3; + dst += 3; + } +} + + + +static void +xyYf_to_rgbaf (const Babl *conversion, + float *src, + float *dst, + long samples) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + float m_0_0 = space->space.XYZtoRGBf[0] * D50_WHITE_REF_X; + float m_0_1 = space->space.XYZtoRGBf[1] * D50_WHITE_REF_Y; + float m_0_2 = space->space.XYZtoRGBf[2] * D50_WHITE_REF_Z; + float m_1_0 = space->space.XYZtoRGBf[3] * D50_WHITE_REF_X; + float m_1_1 = space->space.XYZtoRGBf[4] * D50_WHITE_REF_Y; + float m_1_2 = space->space.XYZtoRGBf[5] * D50_WHITE_REF_Z; + float m_2_0 = space->space.XYZtoRGBf[6] * D50_WHITE_REF_X; + float m_2_1 = space->space.XYZtoRGBf[7] * D50_WHITE_REF_Y; + float m_2_2 = space->space.XYZtoRGBf[8] * D50_WHITE_REF_Z; + long n = samples; + + while (n--) + { + float X, Z, r, g, b; + float x = src[0]; + float y = src[1]; + float Y = src[2]; + + + if (near_zero (Y)) + { + X = 0.0f; + Y = 0.0f; + Z = 0.0f; + } + else + { + X = (x * Y) / y; + //Y = Y; + Z = ((1 - x - y) * Y) / y; + } + + r = m_0_0 * X + m_0_1 * Y + m_0_2 * Z; + g = m_1_0 * X + m_1_1 * Y + m_1_2 * Z; + b = m_2_0 * X + m_2_1 * Y + m_2_2 * Z; + + dst[0] = r; + dst[1] = g; + dst[2] = b; + dst[3] = 1.0f; + + src += 3; + dst += 4; + } +} + +static void +xyYaf_to_rgbaf (const Babl *conversion, + float *src, + float *dst, + long samples) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + float m_0_0 = space->space.XYZtoRGBf[0] * D50_WHITE_REF_X; + float m_0_1 = space->space.XYZtoRGBf[1] * D50_WHITE_REF_Y; + float m_0_2 = space->space.XYZtoRGBf[2] * D50_WHITE_REF_Z; + float m_1_0 = space->space.XYZtoRGBf[3] * D50_WHITE_REF_X; + float m_1_1 = space->space.XYZtoRGBf[4] * D50_WHITE_REF_Y; + float m_1_2 = space->space.XYZtoRGBf[5] * D50_WHITE_REF_Z; + float m_2_0 = space->space.XYZtoRGBf[6] * D50_WHITE_REF_X; + float m_2_1 = space->space.XYZtoRGBf[7] * D50_WHITE_REF_Y; + float m_2_2 = space->space.XYZtoRGBf[8] * D50_WHITE_REF_Z; + long n = samples; + + while (n--) + { + float X, Z, r, g, b; + float x = src[0]; + float y = src[1]; + float Y = src[2]; + float a = src[3]; + + if (near_zero (Y)) + { + X = 0.0f; + Y = 0.0f; + Z = 0.0f; + } + else + { + X = (x * Y) / y; + //Y = Y; + Z = ((1 - x - y) * Y) / y; + } + + r = m_0_0 * X + m_0_1 * Y + m_0_2 * Z; + g = m_1_0 * X + m_1_1 * Y + m_1_2 * Z; + b = m_2_0 * X + m_2_1 * Y + m_2_2 * Z; + + dst[0] = r; + dst[1] = g; + dst[2] = b; + dst[3] = a; + + src += 4; + dst += 4; + } +} + + + +/* Yuvf -> rgbf */ + +static void +Yuvf_to_rgbf (const Babl *conversion,float *src, + float *dst, + long samples) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + float m_0_0 = space->space.XYZtoRGBf[0] * D50_WHITE_REF_X; + float m_0_1 = space->space.XYZtoRGBf[1] * D50_WHITE_REF_Y; + float m_0_2 = space->space.XYZtoRGBf[2] * D50_WHITE_REF_Z; + float m_1_0 = space->space.XYZtoRGBf[3] * D50_WHITE_REF_X; + float m_1_1 = space->space.XYZtoRGBf[4] * D50_WHITE_REF_Y; + float m_1_2 = space->space.XYZtoRGBf[5] * D50_WHITE_REF_Z; + float m_2_0 = space->space.XYZtoRGBf[6] * D50_WHITE_REF_X; + float m_2_1 = space->space.XYZtoRGBf[7] * D50_WHITE_REF_Y; + float m_2_2 = space->space.XYZtoRGBf[8] * D50_WHITE_REF_Z; + long n = samples; + + while (n--) + { + float X, Z, r, g, b; + float Y = src[0]; + float u = src[1]; + float v = src[2]; + + if (near_zero (v)) + { + X = 0.0f; + Y = 0.0f; + Z = 0.0f; + } + else + { + X = ((9.0 * u * Y)/(4.0 * v)); + //Y = Y; + Z = -(((20.0 * v + 3.0 * u - 12.0) * Y)/(4.0 * v)); + } + + r = m_0_0 * X + m_0_1 * Y + m_0_2 * Z; + g = m_1_0 * X + m_1_1 * Y + m_1_2 * Z; + b = m_2_0 * X + m_2_1 * Y + m_2_2 * Z; + + dst[0] = r; + dst[1] = g; + dst[2] = b; + + src += 3; + dst += 3; + } +} + + + +static void +Yuvf_to_rgbaf (const Babl *conversion, + float *src, + float *dst, + long samples) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + float m_0_0 = space->space.XYZtoRGBf[0] * D50_WHITE_REF_X; + float m_0_1 = space->space.XYZtoRGBf[1] * D50_WHITE_REF_Y; + float m_0_2 = space->space.XYZtoRGBf[2] * D50_WHITE_REF_Z; + float m_1_0 = space->space.XYZtoRGBf[3] * D50_WHITE_REF_X; + float m_1_1 = space->space.XYZtoRGBf[4] * D50_WHITE_REF_Y; + float m_1_2 = space->space.XYZtoRGBf[5] * D50_WHITE_REF_Z; + float m_2_0 = space->space.XYZtoRGBf[6] * D50_WHITE_REF_X; + float m_2_1 = space->space.XYZtoRGBf[7] * D50_WHITE_REF_Y; + float m_2_2 = space->space.XYZtoRGBf[8] * D50_WHITE_REF_Z; + long n = samples; + + while (n--) + { + float X, Z, r, g, b; + float Y = src[0]; + float u = src[1]; + float v = src[2]; + + if (near_zero (v)) + { + X = 0.0f; + Y = 0.0f; + Z = 0.0f; + } + else + { + X = ((9.0 * u * Y)/(4.0 * v)); + //Y = Y; + Z = -(((20.0 * v + 3.0 * u - 12.0) * Y)/(4.0 * v)); + } + + r = m_0_0 * X + m_0_1 * Y + m_0_2 * Z; + g = m_1_0 * X + m_1_1 * Y + m_1_2 * Z; + b = m_2_0 * X + m_2_1 * Y + m_2_2 * Z; + + dst[0] = r; + dst[1] = g; + dst[2] = b; + dst[3] = 1.0f; + + src += 3; + dst += 4; + } +} + +static void +Yuvaf_to_rgbaf (const Babl *conversion, + float *src, + float *dst, + long samples) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + float m_0_0 = space->space.XYZtoRGBf[0] * D50_WHITE_REF_X; + float m_0_1 = space->space.XYZtoRGBf[1] * D50_WHITE_REF_Y; + float m_0_2 = space->space.XYZtoRGBf[2] * D50_WHITE_REF_Z; + float m_1_0 = space->space.XYZtoRGBf[3] * D50_WHITE_REF_X; + float m_1_1 = space->space.XYZtoRGBf[4] * D50_WHITE_REF_Y; + float m_1_2 = space->space.XYZtoRGBf[5] * D50_WHITE_REF_Z; + float m_2_0 = space->space.XYZtoRGBf[6] * D50_WHITE_REF_X; + float m_2_1 = space->space.XYZtoRGBf[7] * D50_WHITE_REF_Y; + float m_2_2 = space->space.XYZtoRGBf[8] * D50_WHITE_REF_Z; + long n = samples; + + while (n--) + { + float X, Z, r, g, b; + float Y = src[0]; + float u = src[1]; + float v = src[2]; + float a = src[3]; + + if (near_zero (v)) + { + X = 0.0f; + Y = 0.0f; + Z = 0.0f; + } + else + { + X = ((9.0 * u * Y)/(4.0 * v)); + //Y = Y; + Z = -(((20.0 * v + 3.0 * u - 12.0) * Y)/(4.0 * v)); + } + + r = m_0_0 * X + m_0_1 * Y + m_0_2 * Z; + g = m_1_0 * X + m_1_1 * Y + m_1_2 * Z; + b = m_2_0 * X + m_2_1 * Y + m_2_2 * Z; + + dst[0] = r; + dst[1] = g; + dst[2] = b; + dst[3] = a; + + src += 4; + dst += 4; + } +} + + +/* rgb <-> LAB */ + +static void +rgba_to_lab (const Babl *conversion, + char *src, + char *dst, + long n) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + while (n--) + { + double XYZ[3], L, a, b; + + babl_space_to_xyz (space, (double*)src, XYZ); + XYZ_to_LAB (XYZ[0], XYZ[1], XYZ[2], &L, &a, &b); + + ((double *) dst)[0] = L; + ((double *) dst)[1] = a; + ((double *) dst)[2] = b; + + src += sizeof (double) * 4; + dst += sizeof (double) * 3; + } +} + + +static void +lab_to_rgba (const Babl *conversion, + char *src, + char *dst, + long n) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + while (n--) + { + double L = ((double *) src)[0]; + double a = ((double *) src)[1]; + double b = ((double *) src)[2]; + + double X, Y, Z, R, G, B; + + //convert Lab to XYZ + LAB_to_XYZ (L, a, b, &X, &Y, &Z); + + //convert XYZ to RGB + { + double XYZ[3] = {X,Y,Z}; + double RGB[3]; + babl_space_from_xyz (space, XYZ, RGB); + R = RGB[0]; + G = RGB[1]; + B = RGB[2]; + } + + ((double *) dst)[0] = R; + ((double *) dst)[1] = G; + ((double *) dst)[2] = B; + ((double *) dst)[3] = 1.0; + + src += sizeof (double) * 3; + dst += sizeof (double) * 4; + } +} + +static void +rgba_to_laba (const Babl *conversion, + char *src, + char *dst, + long n) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + while (n--) + { + double alpha = ((double *) src)[3]; + double XYZ[3], L, a, b; + + //convert RGB to XYZ + babl_space_to_xyz (space, (double*)src, XYZ); + + //convert XYZ to Lab + XYZ_to_LAB (XYZ[0], XYZ[1], XYZ[2], &L, &a, &b); + + ((double *) dst)[0] = L; + ((double *) dst)[1] = a; + ((double *) dst)[2] = b; + ((double *) dst)[3] = alpha; + + src += sizeof (double) * 4; + dst += sizeof (double) * 4; + } +} + +static void +laba_to_rgba (const Babl *conversion, + char *src, + char *dst, + long n) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + while (n--) + { + double L = ((double *) src)[0]; + double a = ((double *) src)[1]; + double b = ((double *) src)[2]; + double alpha = ((double *) src)[3]; + + double X, Y, Z; + + //convert Lab to XYZ + LAB_to_XYZ (L, a, b, &X, &Y, &Z); + + { + //convert XYZ to RGB + double XYZ[3] = {X,Y,Z}; + babl_space_from_xyz (space, XYZ, (double*)dst); + } + ((double *) dst)[3] = alpha; + + src += sizeof (double) * 4; + dst += sizeof (double) * 4; + } +} + + +/* rgb <-> LCh */ + +static inline void +CHab_to_ab (double C, + double H, + double *to_a, + double *to_b) +{ + *to_a = cos (H * RADIANS_PER_DEGREE) * C; + *to_b = sin (H * RADIANS_PER_DEGREE) * C; +} + +static inline void +ab_to_CHab (double a, + double b, + double *to_C, + double *to_H) +{ + *to_C = sqrt ( (a * a) + (b * b) ); + *to_H = atan2 (b, a) * DEGREES_PER_RADIAN; + + // Keep H within the range 0-360 + if (*to_H < 0.0) + *to_H += 360; +} + +static void +rgba_to_lchab (const Babl *conversion, + char *src, + char *dst, + long n) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + + while (n--) + { + double XYZ[3], L, a, b, C, H; + + //convert RGB to XYZ + babl_space_to_xyz (space, (double *)src, XYZ); + + //convert XYZ to Lab + XYZ_to_LAB (XYZ[0], XYZ[1], XYZ[2], &L, &a, &b); + + + //convert Lab to LCH(ab) + ab_to_CHab (a, b, &C, &H); + + ((double *) dst)[0] = L; + ((double *) dst)[1] = C; + ((double *) dst)[2] = H; + + src += sizeof (double) * 4; + dst += sizeof (double) * 3; + } +} + +static void +lchab_to_rgba (const Babl *conversion, + char *src, + char *dst, + long n) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + + while (n--) + { + double L = ((double *) src)[0]; + double C = ((double *) src)[1]; + double H = ((double *) src)[2]; + double a, b, X, Y, Z; + + //Convert LCH(ab) to Lab + CHab_to_ab (C, H, &a, &b); + + //Convert LAB to XYZ + LAB_to_XYZ (L, a, b, &X, &Y, &Z); + + //Convert XYZ to RGB + { + double XYZ[3] = {X,Y,Z}; + babl_space_from_xyz (space, XYZ, (double*)dst); + } + + ((double *) dst)[3] = 1.0; + + src += sizeof (double) * 3; + dst += sizeof (double) * 4; + } +} + +static void +rgba_to_lchaba (const Babl *conversion, + char *src, + char *dst, + long n) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + + while (n--) + { + double alpha = ((double *) src)[3]; + double XYZ[3], L, a, b, C, H; + + //convert RGB to XYZ + babl_space_to_xyz (space, (double*)src, XYZ); + + //convert XYZ to Lab + XYZ_to_LAB (XYZ[0], XYZ[1], XYZ[2], &L, &a, &b); + + //convert Lab to LCH(ab) + ab_to_CHab (a, b, &C, &H); + + ((double *) dst)[0] = L; + ((double *) dst)[1] = C; + ((double *) dst)[2] = H; + ((double *) dst)[3] = alpha; + + src += sizeof (double) * 4; + dst += sizeof (double) * 4; + } +} + +static void +lchaba_to_rgba (const Babl *conversion, + char *src, + char *dst, + long n) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + while (n--) + { + double L = ((double *) src)[0]; + double C = ((double *) src)[1]; + double H = ((double *) src)[2]; + double alpha = ((double *) src)[3]; + double a, b, X, Y, Z; + + //Convert LCH(ab) to Lab + CHab_to_ab (C, H, &a, &b); + + //Convert Lab to XYZ + LAB_to_XYZ (L, a, b, &X, &Y, &Z); + + //Convert XYZ to RGB + { + double XYZ[3] = {X,Y,Z}; + babl_space_from_xyz (space, XYZ, (double*)dst); + } + ((double *) dst)[3] = alpha; + + src += sizeof (double) * 4; + dst += sizeof (double) * 4; + } +} + + +/******** end double RGB/CIE color space conversions ******************/ + +/******** begin floating point RGB/CIE color space conversions ********/ + +/* origin: http://www.hackersdelight.org/hdcodetxt/acbrt.c.txt + * permissions: http://www.hackersdelight.org/permissions.htm + */ +/* _cbrtf(x) + * Return cube root of x + */ + +static inline float +_cbrtf (float x) +{ + union { float f; uint32_t i; } u = { x }; + + u.i = u.i / 4 + u.i / 16; + u.i = u.i + u.i / 16; + u.i = u.i + u.i / 256; + u.i = 0x2a5137a0 + u.i; + u.f = 0.33333333f * (2.0f * u.f + x / (u.f * u.f)); + u.f = 0.33333333f * (2.0f * u.f + x / (u.f * u.f)); + + return u.f; +} + +static inline float +cubef (float f) +{ + return f * f * f; +} + +static void +Yf_to_Lf (const Babl *conversion, + float *src, + float *dst, + long samples) +{ + long n = samples; + + while (n--) + { + float yr = src[0]; + float L = yr > LAB_EPSILON ? 116.0f * _cbrtf (yr) - 16 : LAB_KAPPA * yr; + + dst[0] = L; + + src++; + dst++; + } +} + +static void +Yaf_to_Lf (const Babl *conversion, + float *src, + float *dst, + long samples) +{ + long n = samples; + + while (n--) + { + float yr = src[0]; + float L = yr > LAB_EPSILON ? 116.0f * _cbrtf (yr) - 16 : LAB_KAPPA * yr; + + dst[0] = L; + + src += 2; + dst += 1; + } +} + +static void +Yaf_to_Laf (const Babl *conversion, + float *src, + float *dst, + long samples) +{ + long n = samples; + + while (n--) + { + float yr = src[0]; + float a = src[1]; + float L = yr > LAB_EPSILON ? 116.0f * _cbrtf (yr) - 16 : LAB_KAPPA * yr; + + dst[0] = L; + dst[1] = a; + + src += 2; + dst += 2; + } +} + +static void +rgbf_to_Labf (const Babl *conversion, + float *src, + float *dst, + long samples) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + float m_0_0 = space->space.RGBtoXYZf[0] / D50_WHITE_REF_X; + float m_0_1 = space->space.RGBtoXYZf[1] / D50_WHITE_REF_X; + float m_0_2 = space->space.RGBtoXYZf[2] / D50_WHITE_REF_X; + float m_1_0 = space->space.RGBtoXYZf[3] / D50_WHITE_REF_Y; + float m_1_1 = space->space.RGBtoXYZf[4] / D50_WHITE_REF_Y; + float m_1_2 = space->space.RGBtoXYZf[5] / D50_WHITE_REF_Y; + float m_2_0 = space->space.RGBtoXYZf[6] / D50_WHITE_REF_Z; + float m_2_1 = space->space.RGBtoXYZf[7] / D50_WHITE_REF_Z; + float m_2_2 = space->space.RGBtoXYZf[8] / D50_WHITE_REF_Z; + long n = samples; + + while (n--) + { + float r = src[0]; + float g = src[1]; + float b = src[2]; + + float xr = m_0_0 * r + m_0_1 * g + m_0_2 * b; + float yr = m_1_0 * r + m_1_1 * g + m_1_2 * b; + float zr = m_2_0 * r + m_2_1 * g + m_2_2 * b; + + float fx = xr > LAB_EPSILON ? _cbrtf (xr) : (LAB_KAPPA * xr + 16.0f) / 116.0f; + float fy = yr > LAB_EPSILON ? _cbrtf (yr) : (LAB_KAPPA * yr + 16.0f) / 116.0f; + float fz = zr > LAB_EPSILON ? _cbrtf (zr) : (LAB_KAPPA * zr + 16.0f) / 116.0f; + + float L = 116.0f * fy - 16.0f; + float A = 500.0f * (fx - fy); + float B = 200.0f * (fy - fz); + + dst[0] = L; + dst[1] = A; + dst[2] = B; + + src += 3; + dst += 3; + } +} + +static void +rgbaf_to_Lf (const Babl *conversion, + float *src, + float *dst, + long samples) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + float m_1_0 = space->space.RGBtoXYZf[3] / D50_WHITE_REF_Y; + float m_1_1 = space->space.RGBtoXYZf[4] / D50_WHITE_REF_Y; + float m_1_2 = space->space.RGBtoXYZf[5] / D50_WHITE_REF_Y; + long n = samples; + + while (n--) + { + float r = src[0]; + float g = src[1]; + float b = src[2]; + + float yr = m_1_0 * r + m_1_1 * g + m_1_2 * b; + float L = yr > LAB_EPSILON ? 116.0f * _cbrtf (yr) - 16 : LAB_KAPPA * yr; + + dst[0] = L; + + src += 4; + dst += 1; + } +} + +static void +rgbaf_to_Labf (const Babl *conversion, + float *src, + float *dst, + long samples) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + float m_0_0 = space->space.RGBtoXYZf[0] / D50_WHITE_REF_X; + float m_0_1 = space->space.RGBtoXYZf[1] / D50_WHITE_REF_X; + float m_0_2 = space->space.RGBtoXYZf[2] / D50_WHITE_REF_X; + float m_1_0 = space->space.RGBtoXYZf[3] / D50_WHITE_REF_Y; + float m_1_1 = space->space.RGBtoXYZf[4] / D50_WHITE_REF_Y; + float m_1_2 = space->space.RGBtoXYZf[5] / D50_WHITE_REF_Y; + float m_2_0 = space->space.RGBtoXYZf[6] / D50_WHITE_REF_Z; + float m_2_1 = space->space.RGBtoXYZf[7] / D50_WHITE_REF_Z; + float m_2_2 = space->space.RGBtoXYZf[8] / D50_WHITE_REF_Z; + long n = samples; + + while (n--) + { + float r = src[0]; + float g = src[1]; + float b = src[2]; + + float xr = m_0_0 * r + m_0_1 * g + m_0_2 * b; + float yr = m_1_0 * r + m_1_1 * g + m_1_2 * b; + float zr = m_2_0 * r + m_2_1 * g + m_2_2 * b; + + float fx = xr > LAB_EPSILON ? _cbrtf (xr) : (LAB_KAPPA * xr + 16.0f) / 116.0f; + float fy = yr > LAB_EPSILON ? _cbrtf (yr) : (LAB_KAPPA * yr + 16.0f) / 116.0f; + float fz = zr > LAB_EPSILON ? _cbrtf (zr) : (LAB_KAPPA * zr + 16.0f) / 116.0f; + + float L = 116.0f * fy - 16.0f; + float A = 500.0f * (fx - fy); + float B = 200.0f * (fy - fz); + + dst[0] = L; + dst[1] = A; + dst[2] = B; + + src += 4; + dst += 3; + } +} + +static void +rgbaf_to_Labaf (const Babl *conversion, + float *src, + float *dst, + long samples) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + float m_0_0 = space->space.RGBtoXYZf[0] / D50_WHITE_REF_X; + float m_0_1 = space->space.RGBtoXYZf[1] / D50_WHITE_REF_X; + float m_0_2 = space->space.RGBtoXYZf[2] / D50_WHITE_REF_X; + float m_1_0 = space->space.RGBtoXYZf[3] / D50_WHITE_REF_Y; + float m_1_1 = space->space.RGBtoXYZf[4] / D50_WHITE_REF_Y; + float m_1_2 = space->space.RGBtoXYZf[5] / D50_WHITE_REF_Y; + float m_2_0 = space->space.RGBtoXYZf[6] / D50_WHITE_REF_Z; + float m_2_1 = space->space.RGBtoXYZf[7] / D50_WHITE_REF_Z; + float m_2_2 = space->space.RGBtoXYZf[8] / D50_WHITE_REF_Z; + long n = samples; + + while (n--) + { + float r = src[0]; + float g = src[1]; + float b = src[2]; + float a = src[3]; + + float xr = m_0_0 * r + m_0_1 * g + m_0_2 * b; + float yr = m_1_0 * r + m_1_1 * g + m_1_2 * b; + float zr = m_2_0 * r + m_2_1 * g + m_2_2 * b; + + float fx = xr > LAB_EPSILON ? _cbrtf (xr) : (LAB_KAPPA * xr + 16.0f) / 116.0f; + float fy = yr > LAB_EPSILON ? _cbrtf (yr) : (LAB_KAPPA * yr + 16.0f) / 116.0f; + float fz = zr > LAB_EPSILON ? _cbrtf (zr) : (LAB_KAPPA * zr + 16.0f) / 116.0f; + + float L = 116.0f * fy - 16.0f; + float A = 500.0f * (fx - fy); + float B = 200.0f * (fy - fz); + + dst[0] = L; + dst[1] = A; + dst[2] = B; + dst[3] = a; + + src += 4; + dst += 4; + } +} + +static void +Labf_to_Lf (const Babl *conversion, + float *src, + float *dst, + long samples) +{ + long n = samples; + + while (n--) + { + dst[0] = src[0]; + + src += 3; + dst += 1; + } +} + +static void +Labaf_to_Lf (const Babl *conversion, + float *src, + float *dst, + long samples) +{ + long n = samples; + + while (n--) + { + dst[0] = src[0]; + + src += 4; + dst += 1; + } +} + +static void +Labf_to_rgbf (const Babl *conversion, + float *src, + float *dst, + long samples) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + float m_0_0 = space->space.XYZtoRGBf[0] * D50_WHITE_REF_X; + float m_0_1 = space->space.XYZtoRGBf[1] * D50_WHITE_REF_Y; + float m_0_2 = space->space.XYZtoRGBf[2] * D50_WHITE_REF_Z; + float m_1_0 = space->space.XYZtoRGBf[3] * D50_WHITE_REF_X; + float m_1_1 = space->space.XYZtoRGBf[4] * D50_WHITE_REF_Y; + float m_1_2 = space->space.XYZtoRGBf[5] * D50_WHITE_REF_Z; + float m_2_0 = space->space.XYZtoRGBf[6] * D50_WHITE_REF_X; + float m_2_1 = space->space.XYZtoRGBf[7] * D50_WHITE_REF_Y; + float m_2_2 = space->space.XYZtoRGBf[8] * D50_WHITE_REF_Z; + long n = samples; + + while (n--) + { + float L = src[0]; + float A = src[1]; + float B = src[2]; + + float fy = (L + 16.0f) / 116.0f; + float fx = fy + A / 500.0f; + float fz = fy - B / 200.0f; + + float yr = L > LAB_KAPPA * LAB_EPSILON ? cubef (fy) : L / LAB_KAPPA; + float xr = cubef (fx) > LAB_EPSILON ? cubef (fx) : (fx * 116.0f - 16.0f) / LAB_KAPPA; + float zr = cubef (fz) > LAB_EPSILON ? cubef (fz) : (fz * 116.0f - 16.0f) / LAB_KAPPA; + + float r = m_0_0 * xr + m_0_1 * yr + m_0_2 * zr; + float g = m_1_0 * xr + m_1_1 * yr + m_1_2 * zr; + float b = m_2_0 * xr + m_2_1 * yr + m_2_2 * zr; + + dst[0] = r; + dst[1] = g; + dst[2] = b; + + src += 3; + dst += 3; + } +} + + +static void +Labf_to_rgbaf (const Babl *conversion,float *src, + float *dst, + long samples) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + float m_0_0 = space->space.XYZtoRGBf[0] * D50_WHITE_REF_X; + float m_0_1 = space->space.XYZtoRGBf[1] * D50_WHITE_REF_Y; + float m_0_2 = space->space.XYZtoRGBf[2] * D50_WHITE_REF_Z; + float m_1_0 = space->space.XYZtoRGBf[3] * D50_WHITE_REF_X; + float m_1_1 = space->space.XYZtoRGBf[4] * D50_WHITE_REF_Y; + float m_1_2 = space->space.XYZtoRGBf[5] * D50_WHITE_REF_Z; + float m_2_0 = space->space.XYZtoRGBf[6] * D50_WHITE_REF_X; + float m_2_1 = space->space.XYZtoRGBf[7] * D50_WHITE_REF_Y; + float m_2_2 = space->space.XYZtoRGBf[8] * D50_WHITE_REF_Z; + long n = samples; + + while (n--) + { + float L = src[0]; + float A = src[1]; + float B = src[2]; + + float fy = (L + 16.0f) / 116.0f; + float fx = fy + A / 500.0f; + float fz = fy - B / 200.0f; + + float yr = L > LAB_KAPPA * LAB_EPSILON ? cubef (fy) : L / LAB_KAPPA; + float xr = cubef (fx) > LAB_EPSILON ? cubef (fx) : (fx * 116.0f - 16.0f) / LAB_KAPPA; + float zr = cubef (fz) > LAB_EPSILON ? cubef (fz) : (fz * 116.0f - 16.0f) / LAB_KAPPA; + + float r = m_0_0 * xr + m_0_1 * yr + m_0_2 * zr; + float g = m_1_0 * xr + m_1_1 * yr + m_1_2 * zr; + float b = m_2_0 * xr + m_2_1 * yr + m_2_2 * zr; + + dst[0] = r; + dst[1] = g; + dst[2] = b; + dst[3] = 1.0f; + + src += 3; + dst += 4; + } +} + +static void +Labaf_to_rgbaf (const Babl *conversion, + float *src, + float *dst, + long samples) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + float m_0_0 = space->space.XYZtoRGBf[0] * D50_WHITE_REF_X; + float m_0_1 = space->space.XYZtoRGBf[1] * D50_WHITE_REF_Y; + float m_0_2 = space->space.XYZtoRGBf[2] * D50_WHITE_REF_Z; + float m_1_0 = space->space.XYZtoRGBf[3] * D50_WHITE_REF_X; + float m_1_1 = space->space.XYZtoRGBf[4] * D50_WHITE_REF_Y; + float m_1_2 = space->space.XYZtoRGBf[5] * D50_WHITE_REF_Z; + float m_2_0 = space->space.XYZtoRGBf[6] * D50_WHITE_REF_X; + float m_2_1 = space->space.XYZtoRGBf[7] * D50_WHITE_REF_Y; + float m_2_2 = space->space.XYZtoRGBf[8] * D50_WHITE_REF_Z; + long n = samples; + + while (n--) + { + float L = src[0]; + float A = src[1]; + float B = src[2]; + float a = src[3]; + + float fy = (L + 16.0f) / 116.0f; + float fx = fy + A / 500.0f; + float fz = fy - B / 200.0f; + + float yr = L > LAB_KAPPA * LAB_EPSILON ? cubef (fy) : L / LAB_KAPPA; + float xr = cubef (fx) > LAB_EPSILON ? cubef (fx) : (fx * 116.0f - 16.0f) / LAB_KAPPA; + float zr = cubef (fz) > LAB_EPSILON ? cubef (fz) : (fz * 116.0f - 16.0f) / LAB_KAPPA; + + float r = m_0_0 * xr + m_0_1 * yr + m_0_2 * zr; + float g = m_1_0 * xr + m_1_1 * yr + m_1_2 * zr; + float b = m_2_0 * xr + m_2_1 * yr + m_2_2 * zr; + + dst[0] = r; + dst[1] = g; + dst[2] = b; + dst[3] = a; + + src += 4; + dst += 4; + } +} + +static void +Labf_to_Lchabf (const Babl *conversion, + float *src, + float *dst, + long samples) +{ + long n = samples; + + while (n--) + { + float L = src[0]; + float A = src[1]; + float B = src[2]; + + float C = sqrtf (A * A + B * B); + float H = atan2f (B, A) * DEGREES_PER_RADIAN; + + // Keep H within the range 0-360 + if (H < 0.0f) + H += 360.0f; + + dst[0] = L; + dst[1] = C; + dst[2] = H; + + src += 3; + dst += 3; + } +} + +static void +Lchabf_to_Labf (const Babl *conversion, + float *src, + float *dst, + long samples) +{ + long n = samples; + + while (n--) + { + float L = src[0]; + float C = src[1]; + float H = src[2]; + + float A = C * cosf (H * RADIANS_PER_DEGREE); + float B = C * sinf (H * RADIANS_PER_DEGREE); + + dst[0] = L; + dst[1] = A; + dst[2] = B; + + src += 3; + dst += 3; + } +} + +static void +Labaf_to_Lchabaf (const Babl *conversion, + float *src, + float *dst, + long samples) +{ + long n = samples; + + while (n--) + { + float L = src[0]; + float A = src[1]; + float B = src[2]; + float a = src[3]; + + float C = sqrtf (A * A + B * B); + float H = atan2f (B, A) * DEGREES_PER_RADIAN; + + // Keep H within the range 0-360 + if (H < 0.0f) + H += 360.0f; + + dst[0] = L; + dst[1] = C; + dst[2] = H; + dst[3] = a; + + src += 4; + dst += 4; + } +} + +static void +Lchabaf_to_Labaf (const Babl *conversion, + float *src, + float *dst, + long samples) +{ + long n = samples; + + while (n--) + { + float L = src[0]; + float C = src[1]; + float H = src[2]; + float a = src[3]; + + float A = C * cosf (H * RADIANS_PER_DEGREE); + float B = C * sinf (H * RADIANS_PER_DEGREE); + + dst[0] = L; + dst[1] = A; + dst[2] = B; + dst[3] = a; + + src += 4; + dst += 4; + } +} + +#if defined(USE_SSE2) + +/* This is an SSE2 version of Halley's method for approximating the + * cube root of an IEEE float implementation. + * + * The scalar version is as follows: + * + * static inline float + * _cbrt_5f (float x) + * { + * union { float f; uint32_t i; } u = { x }; + * + * u.i = u.i / 3 + 709921077; + * return u.f; + * } + * + * static inline float + * _cbrta_halleyf (float a, float R) + * { + * float a3 = a * a * a; + * float b = a * (a3 + R + R) / (a3 + a3 + R); + * return b; + * } + * + * static inline float + * _cbrtf (float x) + * { + * float a; + * + * a = _cbrt_5f (x); + * a = _cbrta_halleyf (a, x); + * a = _cbrta_halleyf (a, x); + * return a; + * } + * + * The above scalar version seems to have originated from + * http://metamerist.com/cbrt/cbrt.htm but that's not accessible + * anymore. At present there's a copy in CubeRoot.cpp in the Skia + * sources that's licensed under a BSD-style license. There's some + * discussion on the implementation at + * http://www.voidcn.com/article/p-gpwztojr-wt.html. + * + * Note that Darktable also has an SSE2 version of the same algorithm, + * but uses only a single iteration of Halley's method, which is too + * coarse. + */ +/* Return cube roots of the four single-precision floating point + * components of x. + */ +static inline __m128 +_cbrtf_ps_sse2 (__m128 x) +{ + const __m128i magic = _mm_set1_epi32 (709921077); + + __m128i xi = _mm_castps_si128 (x); + __m128 xi_3 = _mm_div_ps (_mm_cvtepi32_ps (xi), _mm_set1_ps (3.0f)); + __m128i ai = _mm_add_epi32 (_mm_cvtps_epi32 (xi_3), magic); + __m128 a = _mm_castsi128_ps (ai); + + __m128 a3 = _mm_mul_ps (_mm_mul_ps (a, a), a); + __m128 divisor = _mm_add_ps (_mm_add_ps (a3, a3), x); + a = _mm_div_ps (_mm_mul_ps (a, _mm_add_ps (a3, _mm_add_ps (x, x))), divisor); + + a3 = _mm_mul_ps (_mm_mul_ps (a, a), a); + divisor = _mm_add_ps (_mm_add_ps (a3, a3), x); + a = _mm_div_ps (_mm_mul_ps (a, _mm_add_ps (a3, _mm_add_ps (x, x))), divisor); + + return a; +} + +static inline __m128 +lab_r_to_f_sse2 (__m128 r) +{ + const __m128 epsilon = _mm_set1_ps (LAB_EPSILON); + const __m128 kappa = _mm_set1_ps (LAB_KAPPA); + + const __m128 f_big = _cbrtf_ps_sse2 (r); + + const __m128 f_small = _mm_div_ps (_mm_add_ps (_mm_mul_ps (kappa, r), _mm_set1_ps (16.0f)), + _mm_set1_ps (116.0f)); + + const __m128 mask = _mm_cmpgt_ps (r, epsilon); + const __m128 f = _mm_or_ps (_mm_and_ps (mask, f_big), _mm_andnot_ps (mask, f_small)); + return f; +} + +static void +Yf_to_Lf_sse2 (const Babl *conversion, + const float *src, + float *dst, + long samples) +{ + long i = 0; + long remainder; + + if (((uintptr_t) src % 16) + ((uintptr_t) dst % 16) == 0) + { + const long n = (samples / 4) * 4; + + for ( ; i < n; i += 4) + { + __m128 Y = _mm_load_ps (src); + + __m128 fy = lab_r_to_f_sse2 (Y); + + __m128 L = _mm_sub_ps (_mm_mul_ps (_mm_set1_ps (116.0f), fy), _mm_set1_ps (16.0f)); + + _mm_store_ps (dst, L); + + src += 4; + dst += 4; + } + } + + remainder = samples - i; + while (remainder--) + { + float yr = src[0]; + float L = yr > LAB_EPSILON ? 116.0f * _cbrtf (yr) - 16 : LAB_KAPPA * yr; + + dst[0] = L; + + src++; + dst++; + } +} + +static void +Yaf_to_Lf_sse2 (const Babl *conversion, + const float *src, + float *dst, + long samples) +{ + long i = 0; + long remainder; + + if (((uintptr_t) src % 16) + ((uintptr_t) dst % 16) == 0) + { + const long n = (samples / 4) * 4; + + for ( ; i < n; i += 4) + { + __m128 YaYa0 = _mm_load_ps (src); + __m128 YaYa1 = _mm_load_ps (src + 4); + + __m128 Y = _mm_shuffle_ps (YaYa0, YaYa1, _MM_SHUFFLE (2, 0, 2, 0)); + + __m128 fy = lab_r_to_f_sse2 (Y); + + __m128 L = _mm_sub_ps (_mm_mul_ps (_mm_set1_ps (116.0f), fy), _mm_set1_ps (16.0f)); + + _mm_store_ps (dst, L); + + src += 8; + dst += 4; + } + } + + remainder = samples - i; + while (remainder--) + { + float yr = src[0]; + float L = yr > LAB_EPSILON ? 116.0f * _cbrtf (yr) - 16 : LAB_KAPPA * yr; + + dst[0] = L; + + src += 2; + dst += 1; + } +} + +static void +rgbaf_to_Lf_sse2 (const Babl *conversion, + const float *src, + float *dst, + long samples) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + const float m_1_0 = space->space.RGBtoXYZf[3] / D50_WHITE_REF_Y; + const float m_1_1 = space->space.RGBtoXYZf[4] / D50_WHITE_REF_Y; + const float m_1_2 = space->space.RGBtoXYZf[5] / D50_WHITE_REF_Y; + long i = 0; + long remainder; + + if (((uintptr_t) src % 16) + ((uintptr_t) dst % 16) == 0) + { + const long n = (samples / 4) * 4; + const __m128 m_1_0_v = _mm_set1_ps (m_1_0); + const __m128 m_1_1_v = _mm_set1_ps (m_1_1); + const __m128 m_1_2_v = _mm_set1_ps (m_1_2); + + for ( ; i < n; i += 4) + { + __m128 rgba0 = _mm_load_ps (src); + __m128 rgba1 = _mm_load_ps (src + 4); + __m128 rgba2 = _mm_load_ps (src + 8); + __m128 rgba3 = _mm_load_ps (src + 12); + + __m128 r = rgba0; + __m128 g = rgba1; + __m128 b = rgba2; + __m128 a = rgba3; + _MM_TRANSPOSE4_PS (r, g, b, a); + + { + __m128 yr = _mm_add_ps (_mm_add_ps (_mm_mul_ps (m_1_0_v, r), _mm_mul_ps (m_1_1_v, g)), + _mm_mul_ps (m_1_2_v, b)); + + __m128 fy = lab_r_to_f_sse2 (yr); + + __m128 L = _mm_sub_ps (_mm_mul_ps (_mm_set1_ps (116.0f), fy), _mm_set1_ps (16.0f)); + + _mm_store_ps (dst, L); + } + + src += 16; + dst += 4; + } + } + + remainder = samples - i; + while (remainder--) + { + float r = src[0]; + float g = src[1]; + float b = src[2]; + + float yr = m_1_0 * r + m_1_1 * g + m_1_2 * b; + float L = yr > LAB_EPSILON ? 116.0f * _cbrtf (yr) - 16 : LAB_KAPPA * yr; + + dst[0] = L; + + src += 4; + dst += 1; + } +} + +static void +rgbaf_to_Labaf_sse2 (const Babl *conversion, + const float *src, + float *dst, + long samples) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + const float m_0_0 = space->space.RGBtoXYZf[0] / D50_WHITE_REF_X; + const float m_0_1 = space->space.RGBtoXYZf[1] / D50_WHITE_REF_X; + const float m_0_2 = space->space.RGBtoXYZf[2] / D50_WHITE_REF_X; + const float m_1_0 = space->space.RGBtoXYZf[3] / D50_WHITE_REF_Y; + const float m_1_1 = space->space.RGBtoXYZf[4] / D50_WHITE_REF_Y; + const float m_1_2 = space->space.RGBtoXYZf[5] / D50_WHITE_REF_Y; + const float m_2_0 = space->space.RGBtoXYZf[6] / D50_WHITE_REF_Z; + const float m_2_1 = space->space.RGBtoXYZf[7] / D50_WHITE_REF_Z; + const float m_2_2 = space->space.RGBtoXYZf[8] / D50_WHITE_REF_Z; + long i = 0; + long remainder; + + if (((uintptr_t) src % 16) + ((uintptr_t) dst % 16) == 0) + { + const long n = (samples / 4) * 4; + const __m128 m_0_0_v = _mm_set1_ps (m_0_0); + const __m128 m_0_1_v = _mm_set1_ps (m_0_1); + const __m128 m_0_2_v = _mm_set1_ps (m_0_2); + const __m128 m_1_0_v = _mm_set1_ps (m_1_0); + const __m128 m_1_1_v = _mm_set1_ps (m_1_1); + const __m128 m_1_2_v = _mm_set1_ps (m_1_2); + const __m128 m_2_0_v = _mm_set1_ps (m_2_0); + const __m128 m_2_1_v = _mm_set1_ps (m_2_1); + const __m128 m_2_2_v = _mm_set1_ps (m_2_2); + + for ( ; i < n; i += 4) + { + __m128 Laba0; + __m128 Laba1; + __m128 Laba2; + __m128 Laba3; + + __m128 rgba0 = _mm_load_ps (src); + __m128 rgba1 = _mm_load_ps (src + 4); + __m128 rgba2 = _mm_load_ps (src + 8); + __m128 rgba3 = _mm_load_ps (src + 12); + + __m128 r = rgba0; + __m128 g = rgba1; + __m128 b = rgba2; + __m128 a = rgba3; + _MM_TRANSPOSE4_PS (r, g, b, a); + + { + __m128 xr = _mm_add_ps (_mm_add_ps (_mm_mul_ps (m_0_0_v, r), _mm_mul_ps (m_0_1_v, g)), + _mm_mul_ps (m_0_2_v, b)); + __m128 yr = _mm_add_ps (_mm_add_ps (_mm_mul_ps (m_1_0_v, r), _mm_mul_ps (m_1_1_v, g)), + _mm_mul_ps (m_1_2_v, b)); + __m128 zr = _mm_add_ps (_mm_add_ps (_mm_mul_ps (m_2_0_v, r), _mm_mul_ps (m_2_1_v, g)), + _mm_mul_ps (m_2_2_v, b)); + + __m128 fx = lab_r_to_f_sse2 (xr); + __m128 fy = lab_r_to_f_sse2 (yr); + __m128 fz = lab_r_to_f_sse2 (zr); + + __m128 L = _mm_sub_ps (_mm_mul_ps (_mm_set1_ps (116.0f), fy), _mm_set1_ps (16.0f)); + __m128 A = _mm_mul_ps (_mm_set1_ps (500.0f), _mm_sub_ps (fx, fy)); + __m128 B = _mm_mul_ps (_mm_set1_ps (200.0f), _mm_sub_ps (fy, fz)); + + Laba0 = L; + Laba1 = A; + Laba2 = B; + Laba3 = a; + _MM_TRANSPOSE4_PS (Laba0, Laba1, Laba2, Laba3); + } + + _mm_store_ps (dst, Laba0); + _mm_store_ps (dst + 4, Laba1); + _mm_store_ps (dst + 8, Laba2); + _mm_store_ps (dst + 12, Laba3); + + src += 16; + dst += 16; + } + } + + remainder = samples - i; + while (remainder--) + { + float r = src[0]; + float g = src[1]; + float b = src[2]; + float a = src[3]; + + float xr = m_0_0 * r + m_0_1 * g + m_0_2 * b; + float yr = m_1_0 * r + m_1_1 * g + m_1_2 * b; + float zr = m_2_0 * r + m_2_1 * g + m_2_2 * b; + + float fx = xr > LAB_EPSILON ? _cbrtf (xr) : (LAB_KAPPA * xr + 16.0f) / 116.0f; + float fy = yr > LAB_EPSILON ? _cbrtf (yr) : (LAB_KAPPA * yr + 16.0f) / 116.0f; + float fz = zr > LAB_EPSILON ? _cbrtf (zr) : (LAB_KAPPA * zr + 16.0f) / 116.0f; + + float L = 116.0f * fy - 16.0f; + float A = 500.0f * (fx - fy); + float B = 200.0f * (fy - fz); + + dst[0] = L; + dst[1] = A; + dst[2] = B; + dst[3] = a; + + src += 4; + dst += 4; + } +} + +#endif /* defined(USE_SSE2) */ + +static void +conversions (void) +{ + /* babl_model */ + + babl_conversion_new ( + babl_model ("RGBA"), + babl_model ("CIE Lab"), + "linear", rgba_to_lab, + NULL + ); + babl_conversion_new ( + babl_model ("CIE Lab"), + babl_model ("RGBA"), + "linear", lab_to_rgba, + NULL + ); + babl_conversion_new ( + babl_model ("RGBA"), + babl_model ("CIE Lab alpha"), + "linear", rgba_to_laba, + NULL + ); + babl_conversion_new ( + babl_model ("CIE Lab alpha"), + babl_model ("RGBA"), + "linear", laba_to_rgba, + NULL + ); + babl_conversion_new ( + babl_model ("RGBA"), + babl_model ("CIE LCH(ab)"), + "linear", rgba_to_lchab, + NULL + ); + babl_conversion_new ( + babl_model ("CIE LCH(ab)"), + babl_model ("RGBA"), + "linear", lchab_to_rgba, + NULL + ); + babl_conversion_new ( + babl_model ("RGBA"), + babl_model ("CIE LCH(ab) alpha"), + "linear", rgba_to_lchaba, + NULL + ); + babl_conversion_new ( + babl_model ("CIE LCH(ab) alpha"), + babl_model ("RGBA"), + "linear", lchaba_to_rgba, + NULL + ); + babl_conversion_new ( + babl_model ("RGBA"), + babl_model ("CIE XYZ"), + "linear", rgba_to_xyz, + NULL + ); + babl_conversion_new ( + babl_model ("CIE XYZ"), + babl_model ("RGBA"), + "linear", xyz_to_rgba, + NULL + ); + babl_conversion_new ( + babl_model ("RGBA"), + babl_model ("CIE XYZ alpha"), + "linear", rgba_to_xyza, + NULL + ); + babl_conversion_new ( + babl_model ("CIE XYZ alpha"), + babl_model ("RGBA"), + "linear", xyza_to_rgba, + NULL + ); + + /* CIE xyY */ + babl_conversion_new ( + babl_model ("RGBA"), + babl_model ("CIE xyY"), + "linear", rgba_to_xyY, + NULL + ); + babl_conversion_new ( + babl_model ("CIE xyY"), + babl_model ("RGBA"), + "linear", xyY_to_rgba, + NULL + ); + babl_conversion_new ( + babl_model ("RGBA"), + babl_model ("CIE xyY alpha"), + "linear", rgba_to_xyYa, + NULL + ); + babl_conversion_new ( + babl_model ("CIE xyY alpha"), + babl_model ("RGBA"), + "linear", xyYa_to_rgba, + NULL + ); + + /* CIE 1976 UCS */ + babl_conversion_new ( + babl_model ("RGBA"), + babl_model ("CIE Yuv"), + "linear", rgba_to_Yuv, + NULL + ); + babl_conversion_new ( + babl_model ("CIE Yuv"), + babl_model ("RGBA"), + "linear", Yuv_to_rgba, + NULL + ); + babl_conversion_new ( + babl_model ("RGBA"), + babl_model ("CIE Yuv alpha"), + "linear", rgba_to_Yuva, + NULL + ); + babl_conversion_new ( + babl_model ("CIE Yuv alpha"), + babl_model ("RGBA"), + "linear", Yuva_to_rgba, + NULL + ); + + /* babl_format */ + + babl_conversion_new ( + babl_format ("RGB float"), + babl_format ("CIE Lab float"), + "linear", rgbf_to_Labf, + NULL + ); + babl_conversion_new ( + babl_format ("RGBA float"), + babl_format ("CIE Lab float"), + "linear", rgbaf_to_Labf, + NULL + ); + babl_conversion_new ( + babl_format ("RGBA float"), + babl_format ("CIE Lab alpha float"), + "linear", rgbaf_to_Labaf, + NULL + ); + babl_conversion_new ( + babl_format ("CIE Lab float"), + babl_format ("RGB float"), + "linear", Labf_to_rgbf, + NULL + ); + babl_conversion_new ( + babl_format ("CIE Lab float"), + babl_format ("RGBA float"), + "linear", Labf_to_rgbaf, + NULL + ); + babl_conversion_new ( + babl_format ("CIE Lab alpha float"), + babl_format ("RGBA float"), + "linear", Labaf_to_rgbaf, + NULL + ); + babl_conversion_new ( + babl_format ("Y float"), + babl_format ("CIE L float"), + "linear", Yf_to_Lf, + NULL + ); + babl_conversion_new ( + babl_format ("YA float"), + babl_format ("CIE L float"), + "linear", Yaf_to_Lf, + NULL + ); + babl_conversion_new ( + babl_format ("YA float"), + babl_format ("CIE L alpha float"), + "linear", Yaf_to_Laf, + NULL + ); + babl_conversion_new ( + babl_format ("RGBA float"), + babl_format ("CIE L float"), + "linear", rgbaf_to_Lf, + NULL + ); + babl_conversion_new ( + babl_format ("CIE Lab float"), + babl_format ("CIE L float"), + "linear", Labf_to_Lf, + NULL + ); + babl_conversion_new ( + babl_format ("CIE Lab alpha float"), + babl_format ("CIE L float"), + "linear", Labaf_to_Lf, + NULL + ); + babl_conversion_new ( + babl_format ("CIE Lab float"), + babl_format ("CIE LCH(ab) float"), + "linear", Labf_to_Lchabf, + NULL + ); + babl_conversion_new ( + babl_format ("CIE LCH(ab) float"), + babl_format ("CIE Lab float"), + "linear", Lchabf_to_Labf, + NULL + ); + babl_conversion_new ( + babl_format ("CIE Lab alpha float"), + babl_format ("CIE LCH(ab) alpha float"), + "linear", Labaf_to_Lchabaf, + NULL + ); + babl_conversion_new ( + babl_format ("CIE LCH(ab) alpha float"), + babl_format ("CIE Lab alpha float"), + "linear", Lchabaf_to_Labaf, + NULL + ); + + /* CIE xyY */ + babl_conversion_new ( + babl_format ("RGB float"), + babl_format ("CIE xyY float"), + "linear", rgbf_to_xyYf, + NULL + ); + babl_conversion_new ( + babl_format ("RGBA float"), + babl_format ("CIE xyY alpha float"), + "linear", rgbaf_to_xyYaf, + NULL + ); + babl_conversion_new ( + babl_format ("RGBA float"), + babl_format ("CIE xyY float"), + "linear", rgbaf_to_xyYf, + NULL + ); + babl_conversion_new ( + babl_format ("CIE xyY float"), + babl_format ("RGB float"), + "linear", xyYf_to_rgbf, + NULL + ); + babl_conversion_new ( + babl_format ("CIE xyY float"), + babl_format ("RGBA float"), + "linear", xyYf_to_rgbaf, + NULL + ); + babl_conversion_new ( + babl_format ("CIE xyY alpha float"), + babl_format ("RGBA float"), + "linear", xyYaf_to_rgbaf, + NULL + ); + /* CIE 1976 UCS */ + babl_conversion_new ( + babl_format ("RGB float"), + babl_format ("CIE Yuv float"), + "linear", rgbf_to_Yuvf, + NULL + ); + babl_conversion_new ( + babl_format ("RGBA float"), + babl_format ("CIE Yuv alpha float"), + "linear", rgbaf_to_Yuvaf, + NULL + ); + babl_conversion_new ( + babl_format ("RGBA float"), + babl_format ("CIE Yuv float"), + "linear", rgbaf_to_Yuvf, + NULL + ); + babl_conversion_new ( + babl_format ("CIE Yuv float"), + babl_format ("RGB float"), + "linear", Yuvf_to_rgbf, + NULL + ); + babl_conversion_new ( + babl_format ("CIE Yuv float"), + babl_format ("RGBA float"), + "linear", Yuvf_to_rgbaf, + NULL + ); + babl_conversion_new ( + babl_format ("CIE Yuv alpha float"), + babl_format ("RGBA float"), + "linear", Yuvaf_to_rgbaf, + NULL + ); +#if defined(USE_SSE2) + + if (babl_cpu_accel_get_support () & BABL_CPU_ACCEL_X86_SSE2) + { + babl_conversion_new ( + babl_format ("RGBA float"), + babl_format ("CIE Lab alpha float"), + "linear", rgbaf_to_Labaf_sse2, + NULL + ); + babl_conversion_new ( + babl_format ("Y float"), + babl_format ("CIE L float"), + "linear", Yf_to_Lf_sse2, + NULL + ); + babl_conversion_new ( + babl_format ("YA float"), + babl_format ("CIE L float"), + "linear", Yaf_to_Lf_sse2, + NULL + ); + babl_conversion_new ( + babl_format ("RGBA float"), + babl_format ("CIE L float"), + "linear", rgbaf_to_Lf_sse2, + NULL + ); + } + +#endif /* defined(USE_SSE2) */ + + rgbcie_init (); +} + +static void +formats (void) +{ + babl_format_new ( + "name", "CIE Lab float", + babl_model ("CIE Lab"), + + babl_type ("float"), + babl_component ("CIE L"), + babl_component ("CIE a"), + babl_component ("CIE b"), + NULL); + + babl_format_new ( + "name", "CIE XYZ float", + babl_model ("CIE XYZ"), + + babl_type ("float"), + babl_component ("CIE X"), + babl_component ("CIE Y"), + babl_component ("CIE Z"), + NULL); + + babl_format_new ( + "name", "CIE XYZ alpha float", + babl_model ("CIE XYZ"), + + babl_type ("float"), + babl_component ("CIE X"), + babl_component ("CIE Y"), + babl_component ("CIE Z"), + babl_component ("A"), + NULL); + + babl_format_new ( + "name", "CIE Lab alpha float", + babl_model ("CIE Lab alpha"), + + babl_type ("float"), + babl_component ("CIE L"), + babl_component ("CIE a"), + babl_component ("CIE b"), + babl_component ("A"), + NULL); + + babl_format_new ( + "name", "CIE LCH(ab) float", + babl_model ("CIE LCH(ab)"), + + babl_type ("float"), + babl_component ("CIE L"), + babl_component ("CIE C(ab)"), + babl_component ("CIE H(ab)"), + NULL); + + babl_format_new ( + "name", "CIE LCH(ab) alpha float", + babl_model ("CIE LCH(ab) alpha"), + + babl_type ("float"), + babl_component ("CIE L"), + babl_component ("CIE C(ab)"), + babl_component ("CIE H(ab)"), + babl_component ("A"), + NULL); + + babl_format_new ( + "name", "CIE L float", + babl_model ("CIE Lab"), + babl_type ("float"), + babl_component ("CIE L"), + NULL); + + babl_format_new ( + "name", "CIE L alpha float", + babl_model ("CIE Lab alpha"), + babl_type ("float"), + babl_component ("CIE L"), + babl_component ("A"), + NULL); + + babl_format_new ( + "name", "CIE Lab u8", + babl_model ("CIE Lab"), + + babl_type ("CIE u8 L"), + babl_component ("CIE L"), + babl_type ("CIE u8 ab"), + babl_component ("CIE a"), + babl_type ("CIE u8 ab"), + babl_component ("CIE b"), + NULL); + + babl_format_new ( + "name", "CIE Lab u16", + babl_model ("CIE Lab"), + + babl_type ("CIE u16 L"), + babl_component ("CIE L"), + babl_type ("CIE u16 ab"), + babl_component ("CIE a"), + babl_type ("CIE u16 ab"), + babl_component ("CIE b"), + NULL); + + babl_format_new ( + "name", "CIE xyY float", + babl_model ("CIE xyY"), + + babl_type ("float"), + babl_component ("CIE x"), + babl_component ("CIE y"), + babl_component ("CIE Y"), + NULL); + + babl_format_new ( + "name", "CIE xyY alpha float", + babl_model ("CIE xyY alpha"), + + babl_type ("float"), + babl_component ("CIE x"), + babl_component ("CIE y"), + babl_component ("CIE Y"), + babl_component ("A"), + NULL); + + /* CIE 1976 UCS */ + babl_format_new ( + "name", "CIE Yuv float", + babl_model ("CIE Yuv"), + + babl_type ("float"), + babl_component ("CIE Y"), + babl_component ("CIE u"), + babl_component ("CIE v"), + NULL); + + babl_format_new ( + "name", "CIE Yuv alpha float", + babl_model ("CIE Yuv alpha"), + + babl_type ("float"), + babl_component ("CIE Y"), + babl_component ("CIE u"), + babl_component ("CIE v"), + babl_component ("A"), + NULL); +} + + +/******** end floating point RGB/CIE color space conversions **********/ + +/******** begin integer RGB/CIE color space conversions **************/ + +static inline void +convert_double_u8_scaled (const Babl *conversion, + double min_val, + double max_val, + unsigned char min, + unsigned char max, + char *src, + char *dst, + int src_pitch, + int dst_pitch, + long n) +{ + while (n--) + { + double dval = *(double *) src; + unsigned char u8val; + + if (dval < min_val) + u8val = min; + else if (dval > max_val) + u8val = max; + else + u8val = rint ((dval - min_val) / (max_val - min_val) * (max - min) + min); + + *(unsigned char *) dst = u8val; + src += src_pitch; + dst += dst_pitch; + } +} + +static inline void +convert_u8_double_scaled (const Babl *conversion, + double min_val, + double max_val, + unsigned char min, + unsigned char max, + char *src, + char *dst, + int src_pitch, + int dst_pitch, + long n) +{ + while (n--) + { + int u8val = *(unsigned char *) src; + double dval; + + if (u8val < min) + dval = min_val; + else if (u8val > max) + dval = max_val; + else + dval = (u8val - min) / (double) (max - min) * (max_val - min_val) + min_val; + + (*(double *) dst) = dval; + + dst += dst_pitch; + src += src_pitch; + } +} + +#define MAKE_CONVERSIONS(name, min_val, max_val, min, max) \ + static void \ + convert_ ## name ## _double (const Babl *c, char *src, \ + char *dst, \ + int src_pitch, \ + int dst_pitch, \ + long n) \ + { \ + convert_u8_double_scaled (c, min_val, max_val, min, max, \ + src, dst, src_pitch, dst_pitch, n); \ + } \ + static void \ + convert_double_ ## name (const Babl *c, char *src, \ + char *dst, \ + int src_pitch, \ + int dst_pitch, \ + long n) \ + { \ + convert_double_u8_scaled (c, min_val, max_val, min, max, \ + src, dst, src_pitch, dst_pitch, n); \ + } + +/* source ICC.1:2004-10 */ + +MAKE_CONVERSIONS (u8_l, 0.0, 100.0, 0x00, 0xff) +MAKE_CONVERSIONS (u8_ab, -128.0, 127.0, 0x00, 0xff) + +#undef MAKE_CONVERSIONS + +static inline void +convert_float_u8_scaled (const Babl *conversion, + float min_val, + float max_val, + unsigned char min, + unsigned char max, + char *src, + char *dst, + int src_pitch, + int dst_pitch, + long n) +{ + while (n--) + { + float dval = *(float *) src; + unsigned char u8val; + + if (dval < min_val) + u8val = min; + else if (dval > max_val) + u8val = max; + else + u8val = rint ((dval - min_val) / (max_val - min_val) * (max - min) + min); + + *(unsigned char *) dst = u8val; + src += src_pitch; + dst += dst_pitch; + } +} + +static inline void +convert_u8_float_scaled (const Babl *conversion, + float min_val, + float max_val, + unsigned char min, + unsigned char max, + char *src, + char *dst, + int src_pitch, + int dst_pitch, + long n) +{ + while (n--) + { + int u8val = *(unsigned char *) src; + float dval; + + if (u8val < min) + dval = min_val; + else if (u8val > max) + dval = max_val; + else + dval = (u8val - min) / (float) (max - min) * (max_val - min_val) + min_val; + + (*(float *) dst) = dval; + + dst += dst_pitch; + src += src_pitch; + } +} + +#define MAKE_CONVERSIONS(name, min_val, max_val, min, max) \ + static void \ + convert_ ## name ## _float (const Babl *c, char *src, \ + char *dst, \ + int src_pitch, \ + int dst_pitch, \ + long n) \ + { \ + convert_u8_float_scaled (c, min_val, max_val, min, max, \ + src, dst, src_pitch, dst_pitch, n); \ + } \ + static void \ + convert_float_ ## name (const Babl *c, char *src, \ + char *dst, \ + int src_pitch, \ + int dst_pitch, \ + long n) \ + { \ + convert_float_u8_scaled (c, min_val, max_val, min, max, \ + src, dst, src_pitch, dst_pitch, n); \ + } + +/* source ICC.1:2004-10 */ + +MAKE_CONVERSIONS (u8_l, 0.0, 100.0, 0x00, 0xff) +MAKE_CONVERSIONS (u8_ab, -128.0, 127.0, 0x00, 0xff) + +#undef MAKE_CONVERSIONS + +static void +types_u8 (void) +{ + babl_type_new ( + "CIE u8 L", + "integer", + "unsigned", + "bits", 8, + "min_val", 0.0, + "max_val", 100.0, + NULL + ); + + babl_type_new ( + "CIE u8 ab", + "integer", + "unsigned", + "bits", 8, + "min_val", -128.0, + "max_val", 127.0, + NULL + ); + + babl_conversion_new ( + babl_type ("CIE u8 L"), + babl_type ("double"), + "plane", convert_u8_l_double, + NULL + ); + babl_conversion_new ( + babl_type ("double"), + babl_type ("CIE u8 L"), + "plane", convert_double_u8_l, + NULL + ); + + babl_conversion_new ( + babl_type ("CIE u8 ab"), + babl_type ("double"), + "plane", convert_u8_ab_double, + NULL + ); + babl_conversion_new ( + babl_type ("double"), + babl_type ("CIE u8 ab"), + "plane", convert_double_u8_ab, + NULL + ); + + babl_conversion_new ( + babl_type ("CIE u8 L"), + babl_type ("float"), + "plane", convert_u8_l_float, + NULL + ); + babl_conversion_new ( + babl_type ("float"), + babl_type ("CIE u8 L"), + "plane", convert_float_u8_l, + NULL + ); + + babl_conversion_new ( + babl_type ("CIE u8 ab"), + babl_type ("float"), + "plane", convert_u8_ab_float, + NULL + ); + babl_conversion_new ( + babl_type ("float"), + babl_type ("CIE u8 ab"), + "plane", convert_float_u8_ab, + NULL + ); +} + +static inline void +convert_double_u16_scaled (const Babl *conversion, + double min_val, + double max_val, + unsigned short min, + unsigned short max, + char *src, + char *dst, + int src_pitch, + int dst_pitch, + long n) +{ + while (n--) + { + double dval = *(double *) src; + unsigned short u16val; + + if (dval < min_val) + u16val = min; + else if (dval > max_val) + u16val = max; + else + u16val = rint ((dval - min_val) / (max_val - min_val) * (max - min) + min); + + *(unsigned short *) dst = u16val; + dst += dst_pitch; + src += src_pitch; + } +} + +static inline void +convert_u16_double_scaled (const Babl *conversion, + double min_val, + double max_val, + unsigned short min, + unsigned short max, + char *src, + char *dst, + int src_pitch, + int dst_pitch, + long n) +{ + while (n--) + { + int u16val = *(unsigned short *) src; + double dval; + + if (u16val < min) + dval = min_val; + else if (u16val > max) + dval = max_val; + else + dval = (u16val - min) / (double) (max - min) * (max_val - min_val) + min_val; + + (*(double *) dst) = dval; + dst += dst_pitch; + src += src_pitch; + } +} + +#define MAKE_CONVERSIONS(name, min_val, max_val, min, max) \ + static void \ + convert_ ## name ## _double (const Babl *c, char *src, \ + char *dst, \ + int src_pitch, \ + int dst_pitch, \ + long n) \ + { \ + convert_u16_double_scaled (c, min_val, max_val, min, max, \ + src, dst, src_pitch, dst_pitch, n); \ + } \ + static void \ + convert_double_ ## name (const Babl *c, char *src, \ + char *dst, \ + int src_pitch, \ + int dst_pitch, \ + long n) \ + { \ + convert_double_u16_scaled (c, min_val, max_val, min, max, \ + src, dst, src_pitch, dst_pitch, n); \ + } + +MAKE_CONVERSIONS (u16_l, 0.0, 100.0, 0x00, 0xffff) +MAKE_CONVERSIONS (u16_ab, -128.0, 127.0, 0x00, 0xffff) + +#undef MAKE_CONVERSIONS + + +static inline void +convert_float_u16_scaled (const Babl *conversion, + float min_val, + float max_val, + unsigned short min, + unsigned short max, + char *src, + char *dst, + int src_pitch, + int dst_pitch, + long n) +{ + while (n--) + { + float dval = *(float *) src; + unsigned short u16val; + + if (dval < min_val) + u16val = min; + else if (dval > max_val) + u16val = max; + else + u16val = rint ((dval - min_val) / (max_val - min_val) * (max - min) + min); + + *(unsigned short *) dst = u16val; + dst += dst_pitch; + src += src_pitch; + } +} + +static inline void +convert_u16_float_scaled (const Babl *conversion, + float min_val, + float max_val, + unsigned short min, + unsigned short max, + char *src, + char *dst, + int src_pitch, + int dst_pitch, + long n) +{ + while (n--) + { + int u16val = *(unsigned short *) src; + float dval; + + if (u16val < min) + dval = min_val; + else if (u16val > max) + dval = max_val; + else + dval = (u16val - min) / (float) (max - min) * (max_val - min_val) + min_val; + + (*(float *) dst) = dval; + dst += dst_pitch; + src += src_pitch; + } +} + +#define MAKE_CONVERSIONS(name, min_val, max_val, min, max) \ + static void \ + convert_ ## name ## _float (const Babl *c, char *src, \ + char *dst, \ + int src_pitch, \ + int dst_pitch, \ + long n) \ + { \ + convert_u16_float_scaled (c, min_val, max_val, min, max, \ + src, dst, src_pitch, dst_pitch, n); \ + } \ + static void \ + convert_float_ ## name (const Babl *c, char *src, \ + char *dst, \ + int src_pitch, \ + int dst_pitch, \ + long n) \ + { \ + convert_float_u16_scaled (c, min_val, max_val, min, max, \ + src, dst, src_pitch, dst_pitch, n); \ + } + +MAKE_CONVERSIONS (u16_l, 0.0, 100.0, 0x00, 0xffff) +MAKE_CONVERSIONS (u16_ab, -128.0, 127.0, 0x00, 0xffff) + +#undef MAKE_CONVERSIONS + +static void +types_u16 (void) +{ + babl_type_new ( + "CIE u16 L", + "integer", + "unsigned", + "bits", 16, + "min_val", 0.0, + "max_val", 100.0, + NULL + ); + + babl_type_new ( + "CIE u16 ab", + "integer", + "unsigned", + "bits", 16, + "min_val", -128.0, + "max_val", 127.0, + NULL + ); + + + babl_conversion_new ( + babl_type ("CIE u16 L"), + babl_type ("double"), + "plane", convert_u16_l_double, + NULL + ); + babl_conversion_new ( + babl_type ("double"), + babl_type ("CIE u16 L"), + "plane", convert_double_u16_l, + NULL + ); + + babl_conversion_new ( + babl_type ("CIE u16 ab"), + babl_type ("double"), + "plane", convert_u16_ab_double, + NULL + ); + babl_conversion_new ( + babl_type ("double"), + babl_type ("CIE u16 ab"), + "plane", convert_double_u16_ab, + NULL + ); + + babl_conversion_new ( + babl_type ("CIE u16 L"), + babl_type ("float"), + "plane", convert_u16_l_float, + NULL + ); + babl_conversion_new ( + babl_type ("float"), + babl_type ("CIE u16 L"), + "plane", convert_float_u16_l, + NULL + ); + + babl_conversion_new ( + babl_type ("CIE u16 ab"), + babl_type ("float"), + "plane", convert_u16_ab_float, + NULL + ); + babl_conversion_new ( + babl_type ("float"), + babl_type ("CIE u16 ab"), + "plane", convert_float_u16_ab, + NULL + ); +} + +static void +types (void) +{ + types_u8 (); + types_u16 (); +} + +/******** end integer RGB/CIE color space conversions ****************/ + +static void +rgbxyzrgb_init (void) +{ +} + +static void +rgbcie_init (void) +{ + static int initialized = 0; + + if (!initialized) + { + rgbxyzrgb_init (); + initialized = 1; + } +} diff --git a/extensions/HCY.c b/extensions/HCY.c new file mode 100644 index 0000000..31cb8b4 --- /dev/null +++ b/extensions/HCY.c @@ -0,0 +1,394 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2016, Sirio Bolaños Puchet + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + + /* + * Adding support for HCY colorspace, based on the reference implementation by + * Kuzma Shapran (https://code.google.com/archive/p/colour-space-viewer) + */ + +#include "config.h" + +#include +#include + +#include "babl.h" +#include "base/util.h" + +#define EPSILON 1e-10 + +static void rgba_to_hcya (const Babl *conversion, + char *src, + char *dst, + long samples); + +static void hcya_to_rgba (const Babl *conversion, + char *src, + char *dst, + long samples); + +static void rgba_to_hcy (const Babl *conversion, + char *src, + char *dst, + long samples); + +static void hcy_to_rgba (const Babl *conversion, + char *src, + char *dst, + long samples); + +static void +rgba_to_hcy_step (char *src, + char *dst, + const double weights[3]); + +static void +hcy_to_rgba_step (char *src, + char *dst, + const double weights[3]); + +static void components (void); +static void models (void); +static void conversions (void); +static void formats (void); + +int init (void); + +int +init (void) +{ + components (); + models (); + conversions (); + formats (); + + return 0; +} + + +static void +components (void) +{ + babl_component_new ("hue", NULL); + babl_component_new ("HCY chroma", "chroma", NULL); + babl_component_new ("HCY luma", "luma", NULL); + babl_component_new ("alpha", NULL); +} + +static void +models (void) +{ + babl_model_new ( + "name", "HCYA", + babl_component ("hue"), + babl_component ("HCY chroma"), + babl_component ("HCY luma"), + babl_component ("alpha"), + "alpha", + NULL + ); + + babl_model_new ( + "name", "HCY", + babl_component ("hue"), + babl_component ("HCY chroma"), + babl_component ("HCY luma"), + NULL + ); +} + +static void +conversions (void) +{ + babl_conversion_new ( + babl_model ("RGBA"), + babl_model ("HCYA"), + "linear", rgba_to_hcya, + NULL + ); + + babl_conversion_new ( + babl_model ("RGBA"), + babl_model ("HCY"), + "linear", rgba_to_hcy, + NULL + ); + + babl_conversion_new ( + babl_model ("HCYA"), + babl_model ("RGBA"), + "linear", hcya_to_rgba, + NULL + ); + + babl_conversion_new ( + babl_model ("HCY"), + babl_model ("RGBA"), + "linear", hcy_to_rgba, + NULL + ); +} + +static void +formats (void) +{ + + babl_format_new ( + "name", "HCY float", + babl_model ("HCY"), + babl_type ("float"), + babl_component ("hue"), + babl_component ("HCY chroma"), + babl_component ("HCY luma"), + NULL + ); + + babl_format_new ( + "name", "HCYA float", + babl_model ("HCYA"), + babl_type ("float"), + babl_component ("hue"), + babl_component ("HCY chroma"), + babl_component ("HCY luma"), + babl_component ("alpha"), + NULL + ); +} + +static void +rgba_to_hcy_step (char *src, + char *dst, + const double weights[3]) +{ + double hue, chroma, luma; + double X, Y_peak = 0.; + int H_sec = 4, t = -1; + + double rgb[3] = {linear_to_gamma_2_2 (((double *) src)[0]), + linear_to_gamma_2_2 (((double *) src)[1]), + linear_to_gamma_2_2 (((double *) src)[2])}; + int ix[3] = {0,1,2}; + + if (rgb[0] < rgb[1]) { + if (rgb[1] > rgb[2]) { + if (rgb[0] < rgb[2]) { ix[1] = 2; ix[2] = 1; H_sec = 2; t = 1; } + else { ix[0] = 2; ix[1] = 0; ix[2] = 1; H_sec = 2; } + } + } else { + if (rgb[1] < rgb[2]) { + if (rgb[0] < rgb[2]) { ix[0] = 1; ix[1] = 0; H_sec = 4; t = 1; } + else { ix[0] = 1; ix[1] = 2; ix[2] = 0; H_sec = 6; } + } else { ix[0] = 2; ix[2] = 0; H_sec = 0; t = 1; } + } + + luma = weights[0] * rgb[0] + weights[1] * rgb[1] + weights[2] * rgb[2]; + chroma = rgb[ix[2]] - rgb[ix[0]]; + + if (chroma >= EPSILON) + { + X = (rgb[ix[1]] - rgb[ix[0]]) / chroma; + + Y_peak = weights[ix[2]] + X * weights[ix[1]]; + if (luma != 0. && luma != 1.) + chroma /= luma < Y_peak ? luma/Y_peak : (1. - luma)/(1. - Y_peak); + + hue = (H_sec + t * X) / 6.; + } + else + chroma = hue = 0.0; + + ((double *) dst)[0] = hue; + ((double *) dst)[1] = chroma; + ((double *) dst)[2] = luma; +} + +static void +hcy_to_rgba_step (char *src, + char *dst, + const double weights[3]) +{ + double red, green, blue; + double Y_peak = 0., H_insec, X, m; + int H_sec; + + double hue = ((double *) src)[0]; + double chroma = ((double *) src)[1]; + double luma = ((double *) src)[2]; + + if(chroma < EPSILON) { + red = green = blue = luma; + } else { + hue = fmod (hue, 1.0); + hue += hue < 0.0; + hue *= 6.0; + + H_sec = (int) hue; + + switch (H_sec) + { + case 0: + H_insec = hue - H_sec; + Y_peak = weights[0] + H_insec * weights[1]; + chroma *= luma < Y_peak ? luma/Y_peak : (1. - luma)/(1. - Y_peak); + X = chroma * H_insec; + m = luma - (weights[0] * chroma + weights[1] * X); + red = m + chroma; green = m + X; blue = m; + break; + case 1: + H_insec = 1. - (hue - H_sec); + Y_peak = weights[1] + H_insec * weights[0]; + chroma *= luma < Y_peak ? luma/Y_peak : (1. - luma)/(1. - Y_peak); + X = chroma * H_insec; + m = luma - (weights[0] * X + weights[1] * chroma); + red = m + X; green = m + chroma; blue = m; + break; + case 2: + H_insec = hue - H_sec; + Y_peak = weights[1] + H_insec * weights[2]; + chroma *= luma < Y_peak ? luma/Y_peak : (1. - luma)/(1. - Y_peak); + X = chroma * H_insec; + m = luma - (weights[1] * chroma + weights[2] * X); + red = m; green = m + chroma; blue = m + X; + break; + case 3: + H_insec = 1. - (hue - H_sec); + Y_peak = weights[2] + H_insec * weights[1]; + chroma *= luma < Y_peak ? luma/Y_peak : (1. - luma)/(1. - Y_peak); + X = chroma * H_insec; + m = luma - (weights[1] * X + weights[2] * chroma); + red = m; green = m + X; blue = m + chroma; + break; + case 4: + H_insec = hue - H_sec; + Y_peak = weights[2] + H_insec * weights[0]; + chroma *= luma < Y_peak ? luma/Y_peak : (1. - luma)/(1. - Y_peak); + X = chroma * H_insec; + m = luma - (weights[0] * X + weights[2] * chroma); + red = m + X; green = m; blue = m + chroma; + break; + default: + H_insec = 1. - (hue - H_sec); + Y_peak = weights[0] + H_insec * weights[2]; + chroma *= luma < Y_peak ? luma/Y_peak : (1. - luma)/(1. - Y_peak); + X = chroma * H_insec; + m = luma - (weights[0] * chroma + weights[2] * X); + red = m + chroma; green = m; blue = m + X; + break; + } + } + + ((double *) dst)[0] = gamma_2_2_to_linear (red); + ((double *) dst)[1] = gamma_2_2_to_linear (green); + ((double *) dst)[2] = gamma_2_2_to_linear (blue); +} + +static void +rgba_to_hcya (const Babl *conversion, + char *src, + char *dst, + long samples) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + long n = samples; + double weights[3]; + + + babl_space_get_rgb_luminance (space, &weights[0], &weights[1], &weights[2]); + + while (n--) + { + double alpha = ((double *) src)[3]; + + rgba_to_hcy_step (src, dst, weights); + + ((double *) dst)[3] = alpha; + + src += 4 * sizeof (double); + dst += 4 * sizeof (double); + } +} + +static void +hcya_to_rgba (const Babl *conversion,char *src, + char *dst, + long samples) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + long n = samples; + double weights[3]; + + space = babl_conversion_get_source_space (conversion); + babl_space_get_rgb_luminance (space, &weights[0], &weights[1], &weights[2]); + + while (n--) + { + double alpha = ((double *) src)[3]; + + hcy_to_rgba_step (src, dst, weights); + + ((double *) dst)[3] = alpha; + + src += 4 * sizeof (double); + dst += 4 * sizeof (double); + } +} + +static void +rgba_to_hcy (const Babl *conversion, + char *src, + char *dst, + long samples) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + long n = samples; + double weights[3]; + + space = babl_conversion_get_source_space (conversion); + babl_space_get_rgb_luminance (space, &weights[0], &weights[1], &weights[2]); + + while (n--) + { + rgba_to_hcy_step (src, dst, weights); + + src += 4 * sizeof (double); + dst += 3 * sizeof (double); + } +} + +static void +hcy_to_rgba (const Babl *conversion, + char *src, + char *dst, + long samples) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + long n = samples; + double weights[3]; + + space = babl_conversion_get_source_space (conversion); + babl_space_get_rgb_luminance (space, &weights[0], &weights[1], &weights[2]); + + while (n--) + { + hcy_to_rgba_step (src, dst, weights); + + ((double *) dst)[3] = 1.0; + + src += 3 * sizeof (double); + dst += 4 * sizeof (double); + } +} diff --git a/extensions/HSL.c b/extensions/HSL.c new file mode 100644 index 0000000..bf48f34 --- /dev/null +++ b/extensions/HSL.c @@ -0,0 +1,307 @@ +/* babl - dynamically extendable universal pixel conversion library. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" + +#include +#include + +#include "babl.h" +#include "base/util.h" + +#define MIN(a,b) ((a > b) ? b : a) +#define MAX(a,b) ((a < b) ? b : a) +#define EPSILON 1.0e-10 + +static void +rgba_to_hsla (const Babl *conversion, + char *src, + char *dst, + long samples); +static void +hsla_to_rgba (const Babl *conversion, + char *src, + char *dst, + long samples); +static void +rgba_to_hsl (const Babl *conversion, + char *src, + char *dst, + long samples); +static void +hsl_to_rgba (const Babl *conversion, + char *src, + char *dst, + long samples); + +static void +rgb_to_hsl_step (double *src, + double *dst); + +static void +hsl_to_rgb_step (double *src, + double *dst); + +static inline double +hue2cpn (double p, + double q, + double hue); + +int init (void); + + +int +init (void) +{ + babl_component_new ("hue", NULL); + babl_component_new ("saturation", NULL); + babl_component_new ("lightness", NULL); + babl_component_new ("alpha", NULL); + + babl_model_new ("name", "HSL", + "doc", "HSL - Hue Saturation Lightness, an improvement over HSV; which uses lightness; defined as (MAX(R,G,B) + MIN(R,G,B))/2 for the grayscale axis; better than HSV, but look into the CIE based spaces for better perceptual uniformity. The HSL space is relative to the RGB space associated with the format.", + babl_component ("hue"), + babl_component ("saturation"), + babl_component ("lightness"), + NULL); + babl_model_new ("name", "HSLA", + "doc", "HSL - with separate alpha component.", + babl_component ("hue"), + babl_component ("saturation"), + babl_component ("lightness"), + babl_component ("alpha"), + "alpha", + NULL); + + + babl_conversion_new (babl_model ("RGBA"), + babl_model ("HSLA"), + "linear", rgba_to_hsla, + NULL); + babl_conversion_new (babl_model ("RGBA"), + babl_model ("HSL"), + "linear", rgba_to_hsl, + NULL); + babl_conversion_new (babl_model ("HSLA"), + babl_model ("RGBA"), + "linear", hsla_to_rgba, + NULL); + babl_conversion_new (babl_model ("HSL"), + babl_model ("RGBA"), + "linear", hsl_to_rgba, + NULL); + + babl_format_new ("name", "HSLA float", + babl_model ("HSLA"), + babl_type ("float"), + babl_component ("hue"), + babl_component ("saturation"), + babl_component ("lightness"), + babl_component ("alpha"), + NULL); + babl_format_new ("name", "HSL float", + babl_model ("HSL"), + babl_type ("float"), + babl_component ("hue"), + babl_component ("saturation"), + babl_component ("lightness"), + NULL); + return 0; +} + + +static inline void +rgb_to_hsl_step (double* src, + double* dst) +{ + + double min, max; + double hue, saturation, lightness; + int cpn_max; + + double red = linear_to_gamma_2_2 (src[0]); + double green = linear_to_gamma_2_2 (src[1]); + double blue = linear_to_gamma_2_2 (src[2]); + + max = MAX (red, MAX (green, blue)); + min = MIN (red, MIN (green, blue)); + + if (max - red < EPSILON) + cpn_max = 0; + else if (max - green < EPSILON) + cpn_max = 1; + else + cpn_max = 2; + + lightness = (max + min) / 2.0; + + if (max - min < EPSILON) + { + hue = saturation = 0; + } + else + { + double diff = max - min; + double sum = max + min; + saturation = lightness > 0.5 ? diff / (2.0 - sum) : diff / sum; + switch (cpn_max) + { + case 0: hue = (green - blue) / diff + (green < blue ? 6.0 : 0.0); break; + case 1: hue = (blue - red) / diff + 2.0; break; + case 2: hue = (red - green) / diff + 4.0; break; + default: hue = 0.0; + break; + } + hue /= 6.0; + } + + dst[0] = hue; + dst[1] = saturation; + dst[2] = lightness; +} + + +static void +rgba_to_hsla (const Babl *conversion, + char *src, + char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + double alpha = ((double *) src)[3]; + + rgb_to_hsl_step ((double *) src, (double *) dst); + + ((double *) dst)[3] = alpha; + + src += 4 * sizeof (double); + dst += 4 * sizeof (double); + } +} + + +static void +rgba_to_hsl (const Babl *conversion, + char *src, + char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + rgb_to_hsl_step ((double *) src, (double *) dst); + + src += 4 * sizeof (double); + dst += 3 * sizeof (double); + } +} + + +static inline double +hue2cpn (double p, + double q, + double hue) +{ + if (hue < 0.0) hue += 1.0; + if (hue > 1.0) hue -= 1.0; + if (hue < 1.0 / 6.0) return p + (q - p) * 6.0 * hue; + if (hue < 1.0 / 2.0) return q; + if (hue < 2.0 / 3.0) return p + (q - p) * (2.0 / 3.0 - hue) * 6.0; + return p; +} + + +static void +hsl_to_rgb_step (double *src, + double *dst) +{ + double hue = src[0]; + double saturation = src[1]; + double lightness = src[2]; + + double red = 0, green = 0, blue = 0; + + if (saturation < 1e-7) + { + red = green = blue = lightness; + } + else + { + double q = lightness < 0.5 ? + lightness * (1 + saturation) : + lightness + saturation - lightness * saturation; + + double p = 2 * lightness - q; + + hue = fmod (hue, 1.0); + hue += hue < 0.0; + + red = hue2cpn (p, q, hue + 1.0/3.0); + green = hue2cpn (p, q, hue); + blue = hue2cpn (p, q, hue - 1.0/3.0); + } + + dst[0] = gamma_2_2_to_linear (red); + dst[1] = gamma_2_2_to_linear (green); + dst[2] = gamma_2_2_to_linear (blue); +} + + +static void +hsla_to_rgba (const Babl *conversion, + char *src, + char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + double alpha = ((double *) src)[3]; + + hsl_to_rgb_step ((double *) src, (double *) dst); + + ((double *) dst)[3] = alpha; + + src += 4 * sizeof (double); + dst += 4 * sizeof (double); + } +} + + +static void +hsl_to_rgba (const Babl *conversion, + char *src, + char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + hsl_to_rgb_step ((double *) src, (double *) dst); + + ((double *) dst)[3] = 1.0; + + src += 3 * sizeof (double); + dst += 4 * sizeof (double); + } +} diff --git a/extensions/HSV.c b/extensions/HSV.c new file mode 100644 index 0000000..ad2e002 --- /dev/null +++ b/extensions/HSV.c @@ -0,0 +1,370 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2012, Maxime Nicco + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + + /* + * Adding support for HSV colorspace + */ + +#include "config.h" + +#include +#include + +#include "babl.h" +#include "base/util.h" + +#define MIN(a,b) (a > b) ? b : a; +#define MAX(a,b) (a < b) ? b : a; +#define EPSILON 1.0e-10 + +static void +rgba_to_hsva (const Babl *conversion, + char *src, + char *dst, + long samples); + +static void +hsva_to_rgba (const Babl *conversion, + char *src, + char *dst, + long samples); + +static void +rgba_to_hsv (const Babl *conversion, + char *src, + char *dst, + long samples); + +static void +hsv_to_rgba (const Babl *conversion, + char *src, + char *dst, + long samples); + +static void +rgba_to_hsv_step (char *src, + char *dst); + +static void +hsv_to_rgba_step (char *src, + char *dst); + +static void components (void); +static void models (void); +static void conversions (void); +static void formats (void); + +int init (void); + +int +init (void) +{ + components (); + models (); + conversions (); + formats (); + + return 0; +} + + +static void +components (void) +{ + babl_component_new ("hue", NULL); + babl_component_new ("saturation", NULL); + babl_component_new ("value", NULL); + babl_component_new ("alpha", NULL); +} + +static void +models (void) +{ + + babl_model_new ( + "name", "HSV", + babl_component ("hue"), + babl_component ("saturation"), + babl_component ("value"), + "doc", "A legacy color model that exists for compatibility with old GIMP code, V is MAX(R,G,B).", + NULL + ); + babl_model_new ( + "name", "HSVA", + babl_component ("hue"), + babl_component ("saturation"), + babl_component ("value"), + babl_component ("alpha"), + "alpha", + "doc", "HSV with separate alpha.", + NULL + ); +} + +static void +conversions (void) +{ + babl_conversion_new ( + babl_model ("RGBA"), + babl_model ("HSVA"), + "linear", rgba_to_hsva, + NULL + ); + + babl_conversion_new ( + babl_model ("RGBA"), + babl_model ("HSV"), + "linear", rgba_to_hsv, + NULL + ); + + babl_conversion_new ( + babl_model ("HSVA"), + babl_model ("RGBA"), + "linear", hsva_to_rgba, + NULL + ); + + babl_conversion_new ( + babl_model ("HSV"), + babl_model ("RGBA"), + "linear", hsv_to_rgba, + NULL + ); +} + +static void +formats (void) +{ + babl_format_new ( + "name", "HSVA float", + babl_model ("HSVA"), + babl_type ("float"), + babl_component ("hue"), + babl_component ("saturation"), + babl_component ("value"), + babl_component ("alpha"), + NULL + ); + + babl_format_new ( + "name", "HSV float", + babl_model ("HSV"), + babl_type ("float"), + babl_component ("hue"), + babl_component ("saturation"), + babl_component ("value"), + NULL + ); +} + +static void +rgba_to_hsv_step (char *src, + char *dst) +{ + double hue, saturation, value; + double min, chroma; + + double red = linear_to_gamma_2_2 (((double *) src)[0]); + double green = linear_to_gamma_2_2 (((double *) src)[1]); + double blue = linear_to_gamma_2_2 (((double *) src)[2]); + + if (red > green) + { + value = MAX (red, blue); + min = MIN (green, blue); + } + else + { + value = MAX (green, blue); + min = MIN (red, blue); + } + + chroma = value - min; + + if (value < EPSILON) + saturation = 0.0; + else + saturation = chroma / value; + + if (saturation < EPSILON) + { + hue = 0.0; + } + else + { + if (fabs (red - value) < EPSILON) + { + hue = (green - blue) / chroma; + + if (hue < 0.0) + hue += 6.0; + } + else if (fabs (green - value) < EPSILON) + hue = 2.0 + (blue - red) / chroma; + else + hue = 4.0 + (red - green) / chroma; + + hue /= 6.0; + } + + ((double *) dst)[0] = hue; + ((double *) dst)[1] = saturation; + ((double *) dst)[2] = value; +} + + +static void +hsv_to_rgba_step (char *src, + char *dst) +{ + double hue = ((double *) src)[0]; + double saturation = ((double *) src)[1]; + double value = ((double *) src)[2]; + + double red = 0, green = 0, blue = 0; + + double chroma, h_tmp, x, min; + + chroma = saturation * value; + + h_tmp = fmod (hue, 1.0); + h_tmp += h_tmp < 0.0; + h_tmp *= 6.0; + + x = chroma * (1.0 - fabs (fmod (h_tmp, 2.0) - 1.0)); + + if (h_tmp < 1.0) + { + red = chroma; + green = x; + } + else if (h_tmp < 2.0) + { + red = x; + green = chroma; + } + else if (h_tmp < 3.0) + { + green = chroma; + blue = x; + } + else if (h_tmp < 4.0) + { + green = x; + blue = chroma; + } + else if (h_tmp < 5.0) + { + red = x; + blue = chroma; + } + else if (h_tmp < 6.0) + { + red = chroma; + blue = x; + } + + min = value - chroma; + + red += min; + green += min; + blue += min; + + ((double *) dst)[0] = gamma_2_2_to_linear (red); + ((double *) dst)[1] = gamma_2_2_to_linear (green); + ((double *) dst)[2] = gamma_2_2_to_linear (blue); +} + +static void +rgba_to_hsva (const Babl *conversion, + char *src, + char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + double alpha = ((double *) src)[3]; + + rgba_to_hsv_step (src, dst); + + ((double *) dst)[3] = alpha; + + src += 4 * sizeof (double); + dst += 4 * sizeof (double); + } +} + +static void +hsva_to_rgba (const Babl *conversion, + char *src, + char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + double alpha = ((double *) src)[3]; + + hsv_to_rgba_step (src, dst); + + ((double *) dst)[3] = alpha; + + src += 4 * sizeof (double); + dst += 4 * sizeof (double); + } +} + +static void +rgba_to_hsv (const Babl *conversion, + char *src, + char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + rgba_to_hsv_step (src, dst); + + src += 4 * sizeof (double); + dst += 3 * sizeof (double); + } +} + +static void +hsv_to_rgba (const Babl *conversion, + char *src, + char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + hsv_to_rgba_step (src, dst); + + ((double *) dst)[3] = 1.0; + + src += 3 * sizeof (double); + dst += 4 * sizeof (double); + } +} diff --git a/extensions/avx2-int8-tables.h b/extensions/avx2-int8-tables.h new file mode 100644 index 0000000..96a47d5 --- /dev/null +++ b/extensions/avx2-int8-tables.h @@ -0,0 +1,4617 @@ +/* Gamma table generated from a babl conversion of Y to Y' */ +static const int32_t linear_to_gamma[65536] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, + 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, + 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, + 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, + 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, + 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, + 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 43, + 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, + 43, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 44, 44, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 46, 46, 46, 46, 46, + 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, + 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, + 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, + 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, + 46, 46, 46, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, + 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, + 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, + 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, + 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, + 53, 53, 53, 53, 53, 53, 53, 53, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 57, 57, 57, + 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, + 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, + 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, + 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, + 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, + 57, 57, 57, 57, 57, 57, 57, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, + 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, + 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, + 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, + 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, + 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, + 61, 61, 61, 61, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, 66, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 70, 71, 71, 71, 71, 71, 71, 71, 71, + 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, + 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, + 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, + 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, + 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, + 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, + 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, + 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, + 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, + 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, + 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, + 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, + 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, + 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, + 78, 78, 78, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, + 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, + 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, + 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, + 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, + 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, + 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, + 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, + 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 84, 84, 84, 84, + 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, + 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, + 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, + 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, + 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, + 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, + 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, + 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, + 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 85, 85, 85, 85, 85, 85, + 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, + 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, + 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, + 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, + 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, + 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, + 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, + 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, + 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 87, 87, 87, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, + 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, + 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, + 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, + 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, + 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, + 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, + 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, + 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, + 88, 88, 88, 88, 88, 88, 88, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, + 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, + 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, + 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, + 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, + 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, + 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, + 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, + 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, + 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 91, 91, 91, 91, 92, 92, 92, 92, 92, 92, 92, 92, 92, + 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, + 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, + 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, + 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, + 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, + 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, + 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, + 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, + 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, + 92, 92, 92, 92, 92, 92, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, + 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, + 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, + 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, + 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, + 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, + 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, + 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, + 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, + 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, + 93, 93, 93, 93, 93, 93, 93, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 95, 95, 95, 95, 95, 95, + 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, + 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, + 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, + 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, + 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, + 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, + 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, + 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, + 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, + 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 96, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 98, + 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, + 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, + 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, + 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, + 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, + 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, + 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, + 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, + 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, + 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, + 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 100, 100, 100, 100, 100, 100, 100, +100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, +100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, +100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, +100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, +100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, +100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, +100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, +100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, +100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, +100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, +100, 100, 100, 100, 100, 100, 100, 100, 101, 101, 101, 101, 101, 101, 101, 101, +101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, +101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, +101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, +101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, +101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, +101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, +101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, +101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, +101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, +101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, +101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 102, 102, 102, 102, 102, 102, +102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, +102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, +102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, +102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, +102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, +102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, +102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, +102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, +102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, +102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, +102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 103, 103, +103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, +103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, +103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, +103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, +103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, +103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, +103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, +103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, +103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, +103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, +103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, 103, +103, 103, 103, 103, 103, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, +104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, +104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, +104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, +104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, +104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, +104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, +104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, +104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, +104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, +104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, +104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 104, 105, 105, 105, +105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, +105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, +105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, +105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, +105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, +105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, +105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, +105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, +105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, +105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, +105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, 105, +105, 105, 105, 105, 105, 105, 105, 105, 106, 106, 106, 106, 106, 106, 106, 106, +106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, +106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, +106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, +106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, +106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, +106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, +106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, +106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, +106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, +106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, +106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, +106, 106, 106, 106, 106, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, +107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, +107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, +107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, +107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, +107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, +107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, +107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, +107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, +107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, +107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, +107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, +107, 107, 107, 107, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, +108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, +108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, +108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, +108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, +108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, +108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, +108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, +108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, +108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, +108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, +108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, 108, +108, 108, 108, 108, 108, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, +109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, +109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, +109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, +109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, +109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, +109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, +109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, +109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, +109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, +109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, +109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, +109, 109, 109, 109, 109, 109, 109, 109, 109, 110, 110, 110, 110, 110, 110, 110, +110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, +110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, +110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, +110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, +110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, +110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, +110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, +110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, +110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, +110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, +110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, +110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 111, 111, +111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, +111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, +111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, +111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, +111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, +111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, +111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, +111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, +111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, +111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, +111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, +111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, +111, 111, 111, 111, 111, 111, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, +112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, +112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, +112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, +112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, +112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, +112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, +112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, +112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, +112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, +112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, +112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, +112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, 112, +113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, +113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, +113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, +113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, +113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, +113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, +113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, +113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, +113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, +113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, +113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, +113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, +113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 114, 114, 114, +114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, +114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, +114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, +114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, +114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, +114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, +114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, +114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, +114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, +114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, +114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, +114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, +114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 114, 115, 115, 115, 115, +115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, +115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, +115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, +115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, +115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, +115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, +115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, +115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, +115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, +115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, +115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, +115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, +115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 115, 116, 116, 116, +116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, +116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, +116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, +116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, +116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, +116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, +116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, +116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, +116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, +116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, +116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, +116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, +116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, +117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, +117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, +117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, +117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, +117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, +117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, +117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, +117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, +117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, +117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, +117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, +117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, +117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, +117, 117, 117, 117, 117, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, +118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, +118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, +118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, +118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, +118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, +118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, +118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, +118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, +118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, +118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, +118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, +118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, +118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 119, 119, 119, +119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, +119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, +119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, +119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, +119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, +119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, +119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, +119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, +119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, +119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, +119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, +119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, +119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, +119, 119, 119, 119, 119, 119, 119, 120, 120, 120, 120, 120, 120, 120, 120, 120, +120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, +120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, +120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, +120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, +120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, +120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, +120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, +120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, +120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, +120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, +120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, +120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, +120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120, +120, 120, 120, 120, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, +121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, +121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, +121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, +121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, +121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, +121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, +121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, +121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, +121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, +121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, +121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, +121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, +121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, +121, 121, 121, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, +122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, +122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, +122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, +122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, +122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, +122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, +122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, +122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, +122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, +122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, +122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, +122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, +122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, 122, +122, 122, 122, 122, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, +123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, +123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, +123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, +123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, +123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, +123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, +123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, +123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, +123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, +123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, +123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, +123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, +123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, +123, 123, 123, 123, 123, 123, 123, 124, 124, 124, 124, 124, 124, 124, 124, 124, +124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, +124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, +124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, +124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, +124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, +124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, +124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, +124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, +124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, +124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, +124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, +124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, +124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, +124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 124, 125, 125, 125, +125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, +125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, +125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, +125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, +125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, +125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, +125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, +125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, +125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, +125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, +125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, +125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, +125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, +125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, 125, +125, 125, 125, 125, 125, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, +126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, +126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, +126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, +126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, +126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, +126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, +126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, +126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, +126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, +126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, +126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, +126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, +126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, +126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 126, 127, +127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, +127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, +127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, +127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, +127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, +127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, +127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, +127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, +127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, +127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, +127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, +127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, +127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, +127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, +127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 128, 128, 128, 128, +128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, +128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, +128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, +128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, +128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, +128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, +128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, +128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, +128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, +128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, +128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, +128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, +128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, +128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, +128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 129, 129, 129, 129, 129, +129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, +129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, +129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, +129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, +129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, +129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, +129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, +129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, +129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, +129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, +129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, +129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, +129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, +129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, +129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 130, 130, 130, 130, +130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, +130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, +130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, +130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, +130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, +130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, +130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, +130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, +130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, +130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, +130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, +130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, +130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, +130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, +130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, +131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, +131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, +131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, +131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, +131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, +131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, +131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, +131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, +131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, +131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, +131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, +131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, +131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, +131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, +131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, 131, +131, 131, 131, 131, 131, 131, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, +132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, +132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, +132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, +132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, +132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, +132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, +132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, +132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, +132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, +132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, +132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, +132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, +132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, +132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, +132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 132, 133, +133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, +133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, +133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, +133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, +133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, +133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, +133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, +133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, +133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, +133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, +133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, +133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, +133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, +133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, +133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 133, +133, 133, 133, 133, 133, 133, 133, 133, 133, 133, 134, 134, 134, 134, 134, 134, +134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, +134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, +134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, +134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, +134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, +134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, +134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, +134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, +134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, +134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, +134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, +134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, +134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, +134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, +134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, +134, 134, 134, 134, 134, 134, 134, 135, 135, 135, 135, 135, 135, 135, 135, 135, +135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, +135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, +135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, +135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, +135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, +135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, +135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, +135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, +135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, +135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, +135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, +135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, +135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, +135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, +135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, +135, 135, 135, 135, 135, 135, 135, 136, 136, 136, 136, 136, 136, 136, 136, 136, +136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, +136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, +136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, +136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, +136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, +136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, +136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, +136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, +136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, +136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, +136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, +136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, +136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, +136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, +136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, +136, 136, 136, 136, 136, 136, 136, 136, 136, 137, 137, 137, 137, 137, 137, 137, +137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, +137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, +137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, +137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, +137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, +137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, +137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, +137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, +137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, +137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, +137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, +137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, +137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, +137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, +137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, +137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 138, 138, 138, +138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, +138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, +138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, +138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, +138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, +138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, +138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, +138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, +138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, +138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, +138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, +138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, +138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, +138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, +138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, +138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, 138, +138, 138, 138, 138, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, +139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, +139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, +139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, +139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, +139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, +139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, +139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, +139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, +139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, +139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, +139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, +139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, +139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, +139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, +139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, +139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 140, 140, +140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, +140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, +140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, +140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, +140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, +140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, +140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, +140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, +140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, +140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, +140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, +140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, +140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, +140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, +140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, +140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, +140, 140, 140, 140, 140, 140, 140, 140, 140, 141, 141, 141, 141, 141, 141, 141, +141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, +141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, +141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, +141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, +141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, +141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, +141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, +141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, +141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, +141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, +141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, +141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, +141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, +141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, +141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, +141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, +141, 141, 141, 141, 141, 141, 141, 141, 142, 142, 142, 142, 142, 142, 142, 142, +142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, +142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, +142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, +142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, +142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, +142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, +142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, +142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, +142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, +142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, +142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, +142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, +142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, +142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, +142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, +142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, +142, 142, 142, 142, 142, 142, 142, 142, 143, 143, 143, 143, 143, 143, 143, 143, +143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, +143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, +143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, +143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, +143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, +143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, +143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, +143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, +143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, +143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, +143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, +143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, +143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, +143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, +143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, +143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, +143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 144, 144, 144, 144, 144, +144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, +144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, +144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, +144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, +144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, +144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, +144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, +144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, +144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, +144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, +144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, +144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, +144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, +144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, +144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, +144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, +144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, +144, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, +145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, +145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, +145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, +145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, +145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, +145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, +145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, +145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, +145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, +145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, +145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, +145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, +145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, +145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, +145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, +145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, 145, +145, 145, 145, 145, 145, 145, 145, 145, 145, 146, 146, 146, 146, 146, 146, 146, +146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, +146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, +146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, +146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, +146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, +146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, +146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, +146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, +146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, +146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, +146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, +146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, +146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, +146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, +146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, +146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, +146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, +146, 146, 146, 146, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, +147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, +147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, +147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, +147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, +147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, +147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, +147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, +147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, +147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, +147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, +147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, +147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, +147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, +147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, +147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, +147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, +147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, +148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, +148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, +148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, +148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, +148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, +148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, +148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, +148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, +148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, +148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, +148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, +148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, +148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, +148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, +148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, +148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, +148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, +148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, +149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, +149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, +149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, +149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, +149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, +149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, +149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, +149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, +149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, +149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, +149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, +149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, +149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, +149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, +149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, +149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, +149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, +149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, 149, +149, 149, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, +150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, +150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, +150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, +150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, +150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, +150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, +150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, +150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, +150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, +150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, +150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, +150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, +150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, +150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, +150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, +150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, +150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, +150, 150, 150, 150, 150, 150, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, +151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, +151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, +151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, +151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, +151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, +151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, +151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, +151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, +151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, +151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, +151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, +151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, +151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, +151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, +151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, +151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, +151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, +151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 151, 152, 152, 152, +152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, +152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, +152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, +152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, +152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, +152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, +152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, +152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, +152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, +152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, +152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, +152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, +152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, +152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, +152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, +152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, +152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, +152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, 152, +152, 152, 152, 152, 152, 152, 152, 153, 153, 153, 153, 153, 153, 153, 153, 153, +153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, +153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, +153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, +153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, +153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, +153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, +153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, +153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, +153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, +153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, +153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, +153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, +153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, +153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, +153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, +153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, +153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, +153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, +153, 153, 153, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, +154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, +154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, +154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, +154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, +154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, +154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, +154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, +154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, +154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, +154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, +154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, +154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, +154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, +154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, +154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, +154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, +154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, +154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, 154, +154, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, +155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, +155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, +155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, +155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, +155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, +155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, +155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, +155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, +155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, +155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, +155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, +155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, +155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, +155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, +155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, +155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, +155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, +155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, +155, 155, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, +156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, +156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, +156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, +156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, +156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, +156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, +156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, +156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, +156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, +156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, +156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, +156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, +156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, +156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, +156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, +156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, +156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, +156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, 156, +156, 156, 156, 156, 156, 156, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, +157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, +157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, +157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, +157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, +157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, +157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, +157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, +157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, +157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, +157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, +157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, +157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, +157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, +157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, +157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, +157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, +157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, +157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, +157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 157, 158, 158, 158, 158, +158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, +158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, +158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, +158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, +158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, +158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, +158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, +158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, +158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, +158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, +158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, +158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, +158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, +158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, +158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, +158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, +158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, +158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, +158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, 158, +158, 158, 158, 158, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, +159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, +159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, +159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, +159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, +159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, +159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, +159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, +159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, +159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, +159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, +159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, +159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, +159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, +159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, +159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, +159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, +159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, +159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, +159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, 159, +160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, +160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, +160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, +160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, +160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, +160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, +160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, +160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, +160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, +160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, +160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, +160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, +160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, +160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, +160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, +160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, +160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, +160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, +160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, +160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 161, 161, 161, +161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, +161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, +161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, +161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, +161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, +161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, +161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, +161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, +161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, +161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, +161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, +161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, +161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, +161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, +161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, +161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, +161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, +161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, +161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, +161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 161, 162, 162, +162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, +162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, +162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, +162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, +162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, +162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, +162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, +162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, +162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, +162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, +162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, +162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, +162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, +162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, +162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, +162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, +162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, +162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, +162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, +162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, 162, +163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, +163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, +163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, +163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, +163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, +163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, +163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, +163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, +163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, +163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, +163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, +163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, +163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, +163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, +163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, +163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, +163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, +163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, +163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, +163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, +163, 163, 163, 163, 163, 163, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, +164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, +164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, +164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, +164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, +164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, +164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, +164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, +164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, +164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, +164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, +164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, +164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, +164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, +164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, +164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, +164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, +164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, +164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, +164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, +164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 165, 165, +165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, +165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, +165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, +165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, +165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, +165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, +165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, +165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, +165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, +165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, +165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, +165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, +165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, +165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, +165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, +165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, +165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, +165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, +165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, +165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, +165, 165, 165, 165, 165, 165, 165, 165, 166, 166, 166, 166, 166, 166, 166, 166, +166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, +166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, +166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, +166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, +166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, +166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, +166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, +166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, +166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, +166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, +166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, +166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, +166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, +166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, +166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, +166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, +166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, +166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, +166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, +166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, +166, 166, 166, 166, 166, 166, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, +167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, +167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, +167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, +167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, +167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, +167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, +167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, +167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, +167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, +167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, +167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, +167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, +167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, +167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, +167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, +167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, +167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, +167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, +167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, +167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, +167, 167, 167, 167, 167, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, +168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, +168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, +168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, +168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, +168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, +168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, +168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, +168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, +168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, +168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, +168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, +168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, +168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, +168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, +168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, +168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, +168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, +168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, +168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, +168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, +168, 168, 168, 168, 168, 168, 168, 168, 169, 169, 169, 169, 169, 169, 169, 169, +169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, +169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, +169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, +169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, +169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, +169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, +169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, +169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, +169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, +169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, +169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, +169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, +169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, +169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, +169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, +169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, +169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, +169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, +169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, +169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, +169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 170, 170, 170, +170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, +170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, +170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, +170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, +170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, +170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, +170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, +170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, +170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, +170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, +170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, +170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, +170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, +170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, +170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, +170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, +170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, +170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, +170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, +170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, +170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, +170, 170, 170, 170, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, +171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, +171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, +171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, +171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, +171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, +171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, +171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, +171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, +171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, +171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, +171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, +171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, +171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, +171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, +171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, +171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, +171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, +171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, +171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, +171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, +171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 172, 172, +172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, +172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, +172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, +172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, +172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, +172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, +172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, +172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, +172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, +172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, +172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, +172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, +172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, +172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, +172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, +172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, +172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, +172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, +172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, +172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, +172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, +172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 173, 173, 173, 173, 173, +173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, +173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, +173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, +173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, +173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, +173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, +173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, +173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, +173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, +173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, +173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, +173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, +173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, +173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, +173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, +173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, +173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, +173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, +173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, +173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, +173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, +173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, 174, 174, 174, 174, 174, +174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, +174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, +174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, +174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, +174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, +174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, +174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, +174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, +174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, +174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, +174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, +174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, +174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, +174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, +174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, +174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, +174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, +174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, +174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, +174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, +174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, +174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 175, 175, 175, +175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, +175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, +175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, +175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, +175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, +175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, +175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, +175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, +175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, +175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, +175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, +175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, +175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, +175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, +175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, +175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, +175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, +175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, +175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, +175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, +175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, +175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, 175, +175, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, +176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, +176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, +176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, +176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, +176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, +176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, +176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, +176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, +176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, +176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, +176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, +176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, +176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, +176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, +176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, +176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, +176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, +176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, +176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, +176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, +176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, +176, 176, 176, 176, 176, 176, 176, 176, 176, 177, 177, 177, 177, 177, 177, 177, +177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, +177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, +177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, +177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, +177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, +177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, +177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, +177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, +177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, +177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, +177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, +177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, +177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, +177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, +177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, +177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, +177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, +177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, +177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, +177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, +177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, +177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, 177, +177, 177, 177, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, +178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, +178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, +178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, +178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, +178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, +178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, +178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, +178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, +178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, +178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, +178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, +178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, +178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, +178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, +178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, +178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, +178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, +178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, +178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, +178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, +178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, +178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 178, 179, +179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, +179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, +179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, +179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, +179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, +179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, +179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, +179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, +179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, +179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, +179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, +179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, +179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, +179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, +179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, +179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, +179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, +179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, +179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, +179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, +179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, +179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, +179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 179, 180, +180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, +180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, +180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, +180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, +180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, +180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, +180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, +180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, +180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, +180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, +180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, +180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, +180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, +180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, +180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, +180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, +180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, +180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, +180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, +180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, +180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, +180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, +180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, +180, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, +181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, +181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, +181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, +181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, +181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, +181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, +181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, +181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, +181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, +181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, +181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, +181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, +181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, +181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, +181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, +181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, +181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, +181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, +181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, +181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, +181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, +181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, 181, +181, 181, 181, 181, 181, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, +182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, +182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, +182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, +182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, +182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, +182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, +182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, +182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, +182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, +182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, +182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, +182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, +182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, +182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, +182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, +182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, +182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, +182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, +182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, +182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, +182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, +182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, +182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 183, 183, 183, +183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, +183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, +183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, +183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, +183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, +183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, +183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, +183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, +183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, +183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, +183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, +183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, +183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, +183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, +183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, +183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, +183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, +183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, +183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, +183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, +183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, +183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, +183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, +183, 183, 183, 183, 183, 183, 183, 184, 184, 184, 184, 184, 184, 184, 184, 184, +184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, +184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, +184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, +184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, +184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, +184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, +184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, +184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, +184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, +184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, +184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, +184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, +184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, +184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, +184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, +184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, +184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, +184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, +184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, +184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, +184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, +184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, +184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, 184, +184, 184, 184, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, +185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, +185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, +185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, +185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, +185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, +185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, +185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, +185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, +185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, +185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, +185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, +185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, +185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, +185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, +185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, +185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, +185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, +185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, +185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, +185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, +185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, +185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, +185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, 185, +185, 185, 185, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, +186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, +186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, +186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, +186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, +186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, +186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, +186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, +186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, +186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, +186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, +186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, +186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, +186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, +186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, +186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, +186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, +186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, +186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, +186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, +186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, +186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, +186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, +186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, +186, 186, 186, 186, 186, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, +187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, +187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, +187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, +187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, +187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, +187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, +187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, +187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, +187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, +187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, +187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, +187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, +187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, +187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, +187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, +187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, +187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, +187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, +187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, +187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, +187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, +187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, +187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, +187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 188, 188, 188, 188, 188, 188, +188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, +188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, +188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, +188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, +188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, +188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, +188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, +188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, +188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, +188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, +188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, +188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, +188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, +188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, +188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, +188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, +188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, +188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, +188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, +188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, +188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, +188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, +188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, +188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, +188, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, +189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, +189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, +189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, +189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, +189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, +189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, +189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, +189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, +189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, +189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, +189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, +189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, +189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, +189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, +189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, +189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, +189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, +189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, +189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, +189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, +189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, +189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, +189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, +189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 189, 190, 190, 190, 190, 190, +190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, +190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, +190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, +190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, +190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, +190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, +190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, +190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, +190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, +190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, +190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, +190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, +190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, +190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, +190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, +190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, +190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, +190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, +190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, +190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, +190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, +190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, +190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, +190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, +190, 190, 190, 190, 190, 190, 190, 190, 191, 191, 191, 191, 191, 191, 191, 191, +191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, +191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, +191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, +191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, +191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, +191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, +191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, +191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, +191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, +191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, +191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, +191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, +191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, +191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, +191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, +191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, +191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, +191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, +191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, +191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, +191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, +191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, +191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, +191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, 191, +191, 191, 191, 191, 191, 191, 191, 191, 192, 192, 192, 192, 192, 192, 192, 192, +192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, +192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, +192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, +192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, +192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, +192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, +192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, +192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, +192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, +192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, +192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, +192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, +192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, +192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, +192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, +192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, +192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, +192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, +192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, +192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, +192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, +192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, +192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, +192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, +192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 193, 193, 193, 193, 193, +193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, +193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, +193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, +193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, +193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, +193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, +193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, +193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, +193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, +193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, +193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, +193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, +193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, +193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, +193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, +193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, +193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, +193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, +193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, +193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, +193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, +193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, +193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, +193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, +193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, +194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, +194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, +194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, +194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, +194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, +194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, +194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, +194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, +194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, +194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, +194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, +194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, +194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, +194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, +194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, +194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, +194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, +194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, +194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, +194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, +194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, +194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, +194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, +194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, +194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, 194, +194, 194, 194, 194, 194, 194, 194, 194, 195, 195, 195, 195, 195, 195, 195, 195, +195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, +195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, +195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, +195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, +195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, +195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, +195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, +195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, +195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, +195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, +195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, +195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, +195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, +195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, +195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, +195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, +195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, +195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, +195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, +195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, +195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, +195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, +195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, +195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, +195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, +195, 195, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, +196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, +196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, +196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, +196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, +196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, +196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, +196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, +196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, +196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, +196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, +196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, +196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, +196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, +196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, +196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, +196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, +196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, +196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, +196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, +196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, +196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, +196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, +196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, +196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, +196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, 196, +197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, +197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, +197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, +197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, +197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, +197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, +197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, +197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, +197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, +197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, +197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, +197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, +197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, +197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, +197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, +197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, +197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, +197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, +197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, +197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, +197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, +197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, +197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, +197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, +197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, +197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, 197, +198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, +198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, +198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, +198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, +198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, +198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, +198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, +198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, +198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, +198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, +198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, +198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, +198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, +198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, +198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, +198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, +198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, +198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, +198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, +198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, +198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, +198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, +198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, +198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, +198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, +198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, +198, 198, 198, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, +199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, +199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, +199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, +199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, +199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, +199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, +199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, +199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, +199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, +199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, +199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, +199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, +199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, +199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, +199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, +199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, +199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, +199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, +199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, +199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, +199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, +199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, +199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, +199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, +199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, +199, 199, 199, 199, 199, 199, 199, 199, 200, 200, 200, 200, 200, 200, 200, 200, +200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, +200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, +200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, +200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, +200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, +200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, +200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, +200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, +200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, +200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, +200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, +200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, +200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, +200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, +200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, +200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, +200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, +200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, +200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, +200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, +200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, +200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, +200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, +200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, +200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, +200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, +200, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, +201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, +201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, +201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, +201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, +201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, +201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, +201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, +201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, +201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, +201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, +201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, +201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, +201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, +201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, +201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, +201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, +201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, +201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, +201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, +201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, +201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, +201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, +201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, +201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, +201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, +201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 202, 202, 202, 202, +202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, +202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, +202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, +202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, +202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, +202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, +202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, +202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, +202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, +202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, +202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, +202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, +202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, +202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, +202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, +202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, +202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, +202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, +202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, +202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, +202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, +202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, +202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, +202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, +202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, +202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 202, +202, 202, 202, 202, 202, 202, 202, 202, 202, 202, 203, 203, 203, 203, 203, 203, +203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, +203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, +203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, +203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, +203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, +203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, +203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, +203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, +203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, +203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, +203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, +203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, +203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, +203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, +203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, +203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, +203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, +203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, +203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, +203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, +203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, +203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, +203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, +203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, +203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, +203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, +203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 204, 204, 204, 204, 204, +204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, +204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, +204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, +204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, +204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, +204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, +204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, +204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, +204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, +204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, +204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, +204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, +204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, +204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, +204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, +204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, +204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, +204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, +204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, +204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, +204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, +204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, +204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, +204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, +204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, +204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, +204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 205, 205, +205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, +205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, +205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, +205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, +205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, +205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, +205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, +205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, +205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, +205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, +205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, +205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, +205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, +205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, +205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, +205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, +205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, +205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, +205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, +205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, +205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, +205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, +205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, +205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, +205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, +205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, +205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, 205, +205, 205, 205, 205, 205, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, +206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, +206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, +206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, +206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, +206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, +206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, +206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, +206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, +206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, +206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, +206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, +206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, +206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, +206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, +206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, +206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, +206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, +206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, +206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, +206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, +206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, +206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, +206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, +206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, +206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, +206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, +206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 206, 207, 207, +207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, +207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, +207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, +207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, +207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, +207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, +207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, +207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, +207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, +207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, +207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, +207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, +207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, +207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, +207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, +207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, +207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, +207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, +207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, +207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, +207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, +207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, +207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, +207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, +207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, +207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, +207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 207, +207, 207, 207, 207, 207, 207, 207, 207, 207, 207, 208, 208, 208, 208, 208, 208, +208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, +208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, +208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, +208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, +208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, +208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, +208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, +208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, +208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, +208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, +208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, +208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, +208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, +208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, +208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, +208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, +208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, +208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, +208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, +208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, +208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, +208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, +208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, +208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, +208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, +208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, +208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, +208, 208, 208, 208, 208, 208, 208, 208, 208, 209, 209, 209, 209, 209, 209, 209, +209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, +209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, +209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, +209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, +209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, +209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, +209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, +209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, +209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, +209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, +209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, +209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, +209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, +209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, +209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, +209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, +209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, +209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, +209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, +209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, +209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, +209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, +209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, +209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, +209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, +209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, +209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, +209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 210, 210, 210, 210, 210, +210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, +210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, +210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, +210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, +210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, +210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, +210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, +210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, +210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, +210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, +210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, +210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, +210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, +210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, +210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, +210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, +210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, +210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, +210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, +210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, +210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, +210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, +210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, +210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, +210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, +210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, +210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, +210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 211, +211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, +211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, +211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, +211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, +211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, +211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, +211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, +211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, +211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, +211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, +211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, +211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, +211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, +211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, +211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, +211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, +211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, +211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, +211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, +211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, +211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, +211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, +211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, +211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, +211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, +211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, +211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, +211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, 211, +211, 211, 211, 211, 211, 211, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, +212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, +212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, +212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, +212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, +212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, +212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, +212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, +212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, +212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, +212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, +212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, +212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, +212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, +212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, +212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, +212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, +212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, +212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, +212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, +212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, +212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, +212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, +212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, +212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, +212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, +212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, +212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, +212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, 212, +212, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, +213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, +213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, +213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, +213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, +213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, +213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, +213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, +213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, +213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, +213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, +213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, +213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, +213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, +213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, +213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, +213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, +213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, +213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, +213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, +213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, +213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, +213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, +213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, +213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, +213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, +213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, +213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, +213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 213, 214, 214, +214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, +214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, +214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, +214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, +214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, +214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, +214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, +214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, +214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, +214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, +214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, +214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, +214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, +214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, +214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, +214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, +214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, +214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, +214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, +214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, +214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, +214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, +214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, +214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, +214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, +214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, +214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, +214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, +214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 214, 215, 215, 215, +215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, +215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, +215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, +215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, +215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, +215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, +215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, +215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, +215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, +215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, +215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, +215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, +215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, +215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, +215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, +215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, +215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, +215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, +215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, +215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, +215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, +215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, +215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, +215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, +215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, +215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, +215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, +215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, +215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, +216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, +216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, +216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, +216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, +216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, +216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, +216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, +216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, +216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, +216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, +216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, +216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, +216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, +216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, +216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, +216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, +216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, +216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, +216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, +216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, +216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, +216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, +216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, +216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, +216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, +216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, +216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, +216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, +216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, 216, +216, 216, 216, 216, 216, 216, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, +217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, +217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, +217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, +217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, +217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, +217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, +217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, +217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, +217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, +217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, +217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, +217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, +217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, +217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, +217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, +217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, +217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, +217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, +217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, +217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, +217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, +217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, +217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, +217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, +217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, +217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, +217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, +217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, +217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 217, 218, 218, +218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, +218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, +218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, +218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, +218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, +218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, +218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, +218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, +218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, +218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, +218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, +218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, +218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, +218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, +218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, +218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, +218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, +218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, +218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, +218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, +218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, +218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, +218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, +218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, +218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, +218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, +218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, +218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, +218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, +218, 218, 218, 218, 218, 218, 218, 218, 218, 219, 219, 219, 219, 219, 219, 219, +219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, +219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, +219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, +219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, +219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, +219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, +219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, +219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, +219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, +219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, +219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, +219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, +219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, +219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, +219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, +219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, +219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, +219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, +219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, +219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, +219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, +219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, +219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, +219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, +219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, +219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, +219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, +219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, +219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, +219, 219, 219, 219, 219, 219, 219, 220, 220, 220, 220, 220, 220, 220, 220, 220, +220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, +220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, +220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, +220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, +220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, +220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, +220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, +220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, +220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, +220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, +220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, +220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, +220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, +220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, +220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, +220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, +220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, +220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, +220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, +220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, +220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, +220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, +220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, +220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, +220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, +220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, +220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, +220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, +220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, +220, 220, 220, 220, 220, 220, 220, 220, 221, 221, 221, 221, 221, 221, 221, 221, +221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, +221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, +221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, +221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, +221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, +221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, +221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, +221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, +221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, +221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, +221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, +221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, +221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, +221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, +221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, +221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, +221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, +221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, +221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, +221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, +221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, +221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, +221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, +221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, +221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, +221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, +221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, +221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, +221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, +221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 222, 222, 222, 222, +222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, +222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, +222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, +222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, +222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, +222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, +222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, +222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, +222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, +222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, +222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, +222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, +222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, +222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, +222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, +222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, +222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, +222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, +222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, +222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, +222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, +222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, +222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, +222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, +222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, +222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, +222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, +222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, +222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, +222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, 222, +222, 222, 222, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, +223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, +223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, +223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, +223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, +223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, +223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, +223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, +223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, +223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, +223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, +223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, +223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, +223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, +223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, +223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, +223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, +223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, +223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, +223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, +223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, +223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, +223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, +223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, +223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, +223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, +223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, +223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, +223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, +223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, +223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 223, 224, 224, 224, +224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, +224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, +224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, +224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, +224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, +224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, +224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, +224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, +224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, +224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, +224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, +224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, +224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, +224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, +224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, +224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, +224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, +224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, +224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, +224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, +224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, +224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, +224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, +224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, +224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, +224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, +224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, +224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, +224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, +224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, +224, 224, 224, 224, 224, 224, 224, 224, 224, 225, 225, 225, 225, 225, 225, 225, +225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, +225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, +225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, +225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, +225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, +225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, +225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, +225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, +225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, +225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, +225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, +225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, +225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, +225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, +225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, +225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, +225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, +225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, +225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, +225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, +225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, +225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, +225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, +225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, +225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, +225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, +225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, +225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, +225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, +225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, +225, 225, 225, 225, 225, 225, 225, 225, 225, 226, 226, 226, 226, 226, 226, 226, +226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, +226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, +226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, +226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, +226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, +226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, +226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, +226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, +226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, +226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, +226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, +226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, +226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, +226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, +226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, +226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, +226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, +226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, +226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, +226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, +226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, +226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, +226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, +226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, +226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, +226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, +226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, +226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, +226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, +226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, +226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 226, 227, 227, 227, 227, 227, +227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, +227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, +227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, +227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, +227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, +227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, +227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, +227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, +227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, +227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, +227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, +227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, +227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, +227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, +227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, +227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, +227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, +227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, +227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, +227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, +227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, +227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, +227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, +227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, +227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, +227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, +227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, +227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, +227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, +227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, +227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, +228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, +228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, +228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, +228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, +228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, +228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, +228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, +228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, +228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, +228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, +228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, +228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, +228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, +228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, +228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, +228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, +228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, +228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, +228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, +228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, +228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, +228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, +228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, +228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, +228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, +228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, +228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, +228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, +228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, +228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, +228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, +228, 228, 228, 228, 228, 228, 228, 228, 229, 229, 229, 229, 229, 229, 229, 229, +229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, +229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, +229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, +229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, +229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, +229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, +229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, +229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, +229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, +229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, +229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, +229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, +229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, +229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, +229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, +229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, +229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, +229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, +229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, +229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, +229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, +229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, +229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, +229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, +229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, +229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, +229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, +229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, +229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, +229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, +229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, 229, +229, 229, 229, 229, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, +230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, +230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, +230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, +230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, +230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, +230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, +230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, +230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, +230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, +230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, +230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, +230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, +230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, +230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, +230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, +230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, +230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, +230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, +230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, +230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, +230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, +230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, +230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, +230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, +230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, +230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, +230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, +230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, +230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, +230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, +230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, +230, 230, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, +231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, +231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, +231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, +231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, +231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, +231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, +231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, +231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, +231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, +231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, +231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, +231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, +231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, +231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, +231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, +231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, +231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, +231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, +231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, +231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, +231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, +231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, +231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, +231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, +231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, +231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, +231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, +231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, +231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, +231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, +231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, 231, +231, 231, 231, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, +232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, +232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, +232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, +232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, +232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, +232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, +232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, +232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, +232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, +232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, +232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, +232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, +232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, +232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, +232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, +232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, +232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, +232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, +232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, +232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, +232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, +232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, +232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, +232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, +232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, +232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, +232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, +232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, +232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, +232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, +232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, +232, 232, 232, 232, 232, 232, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, +233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, +233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, +233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, +233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, +233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, +233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, +233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, +233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, +233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, +233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, +233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, +233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, +233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, +233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, +233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, +233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, +233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, +233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, +233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, +233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, +233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, +233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, +233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, +233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, +233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, +233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, +233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, +233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, +233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, +233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, +233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, +233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 234, 234, 234, +234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, +234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, +234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, +234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, +234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, +234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, +234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, +234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, +234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, +234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, +234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, +234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, +234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, +234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, +234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, +234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, +234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, +234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, +234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, +234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, +234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, +234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, +234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, +234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, +234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, +234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, +234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, +234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, +234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, +234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, +234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, +234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, 234, +234, 234, 234, 234, 234, 234, 234, 235, 235, 235, 235, 235, 235, 235, 235, 235, +235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, +235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, +235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, +235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, +235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, +235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, +235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, +235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, +235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, +235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, +235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, +235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, +235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, +235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, +235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, +235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, +235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, +235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, +235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, +235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, +235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, +235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, +235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, +235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, +235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, +235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, +235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, +235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, +235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, +235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, +235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, +235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, 235, +235, 235, 235, 235, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, +236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, +236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, +236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, +236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, +236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, +236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, +236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, +236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, +236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, +236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, +236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, +236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, +236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, +236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, +236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, +236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, +236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, +236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, +236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, +236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, +236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, +236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, +236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, +236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, +236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, +236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, +236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, +236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, +236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, +236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, +236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, +236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, +236, 236, 236, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, +237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, +237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, +237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, +237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, +237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, +237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, +237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, +237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, +237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, +237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, +237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, +237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, +237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, +237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, +237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, +237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, +237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, +237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, +237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, +237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, +237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, +237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, +237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, +237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, +237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, +237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, +237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, +237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, +237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, +237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, +237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, +237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, 237, +237, 237, 237, 237, 237, 237, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, +238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, +238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, +238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, +238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, +238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, +238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, +238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, +238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, +238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, +238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, +238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, +238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, +238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, +238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, +238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, +238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, +238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, +238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, +238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, +238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, +238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, +238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, +238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, +238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, +238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, +238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, +238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, +238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, +238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, +238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, +238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, +238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, +238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238, 239, 239, 239, 239, +239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, +239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, +239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, +239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, +239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, +239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, +239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, +239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, +239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, +239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, +239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, +239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, +239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, +239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, +239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, +239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, +239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, +239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, +239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, +239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, +239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, +239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, +239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, +239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, +239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, +239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, +239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, +239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, +239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, +239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, +239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, +239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, +239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, 239, +239, 239, 239, 239, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, +240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, +240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, +240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, +240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, +240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, +240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, +240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, +240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, +240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, +240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, +240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, +240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, +240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, +240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, +240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, +240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, +240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, +240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, +240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, +240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, +240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, +240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, +240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, +240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, +240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, +240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, +240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, +240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, +240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, +240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, +240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, +240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, +240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, +241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, +241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, +241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, +241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, +241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, +241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, +241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, +241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, +241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, +241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, +241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, +241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, +241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, +241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, +241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, +241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, +241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, +241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, +241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, +241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, +241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, +241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, +241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, +241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, +241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, +241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, +241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, +241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, +241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, +241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, +241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, +241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, +241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, +241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 241, 242, 242, +242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, +242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, +242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, +242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, +242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, +242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, +242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, +242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, +242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, +242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, +242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, +242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, +242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, +242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, +242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, +242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, +242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, +242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, +242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, +242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, +242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, +242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, +242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, +242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, +242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, +242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, +242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, +242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, +242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, +242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, +242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, +242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, +242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, +242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, 242, +243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, +243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, +243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, +243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, +243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, +243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, +243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, +243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, +243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, +243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, +243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, +243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, +243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, +243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, +243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, +243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, +243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, +243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, +243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, +243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, +243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, +243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, +243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, +243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, +243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, +243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, +243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, +243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, +243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, +243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, +243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, +243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, +243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, +243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, +243, 243, 243, 243, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, +244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, +244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, +244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, +244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, +244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, +244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, +244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, +244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, +244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, +244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, +244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, +244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, +244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, +244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, +244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, +244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, +244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, +244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, +244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, +244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, +244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, +244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, +244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, +244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, +244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, +244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, +244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, +244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, +244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, +244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, +244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, +244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, +244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, +244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 245, 245, 245, 245, +245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, +245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, +245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, +245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, +245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, +245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, +245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, +245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, +245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, +245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, +245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, +245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, +245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, +245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, +245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, +245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, +245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, +245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, +245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, +245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, +245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, +245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, +245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, +245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, +245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, +245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, +245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, +245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, +245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, +245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, +245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, +245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, +245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, +245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, +245, 245, 245, 245, 245, 245, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, +246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, +246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, +246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, +246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, +246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, +246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, +246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, +246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, +246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, +246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, +246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, +246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, +246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, +246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, +246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, +246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, +246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, +246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, +246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, +246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, +246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, +246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, +246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, +246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, +246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, +246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, +246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, +246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, +246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, +246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, +246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, +246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, +246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, +246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, 246, +246, 246, 246, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, +247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, +247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, +247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, +247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, +247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, +247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, +247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, +247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, +247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, +247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, +247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, +247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, +247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, +247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, +247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, +247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, +247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, +247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, +247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, +247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, +247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, +247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, +247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, +247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, +247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, +247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, +247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, +247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, +247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, +247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, +247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, +247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, +247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, +247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, 247, +247, 247, 247, 247, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, +248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, +248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, +248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, +248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, +248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, +248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, +248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, +248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, +248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, +248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, +248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, +248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, +248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, +248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, +248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, +248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, +248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, +248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, +248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, +248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, +248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, +248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, +248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, +248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, +248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, +248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, +248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, +248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, +248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, +248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, +248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, +248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, +248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, +248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, 248, +248, 248, 248, 248, 248, 248, 248, 249, 249, 249, 249, 249, 249, 249, 249, 249, +249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, +249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, +249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, +249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, +249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, +249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, +249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, +249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, +249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, +249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, +249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, +249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, +249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, +249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, +249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, +249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, +249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, +249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, +249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, +249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, +249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, +249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, +249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, +249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, +249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, +249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, +249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, +249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, +249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, +249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, +249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, +249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, +249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, +249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, +249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 250, 250, +250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, +250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, +250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, +250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, +250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, +250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, +250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, +250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, +250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, +250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, +250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, +250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, +250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, +250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, +250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, +250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, +250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, +250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, +250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, +250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, +250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, +250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, +250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, +250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, +250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, +250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, +250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, +250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, +250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, +250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, +250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, +250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, +250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, +250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, +250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, +250, 250, 250, 250, 250, 250, 250, 251, 251, 251, 251, 251, 251, 251, 251, 251, +251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, +251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, +251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, +251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, +251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, +251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, +251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, +251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, +251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, +251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, +251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, +251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, +251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, +251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, +251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, +251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, +251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, +251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, +251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, +251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, +251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, +251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, +251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, +251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, +251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, +251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, +251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, +251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, +251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, +251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, +251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, +251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, +251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, +251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, +251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, 251, +251, 251, 251, 251, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, +252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, +252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, +252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, +252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, +252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, +252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, +252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, +252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, +252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, +252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, +252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, +252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, +252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, +252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, +252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, +252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, +252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, +252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, +252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, +252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, +252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, +252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, +252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, +252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, +252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, +252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, +252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, +252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, +252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, +252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, +252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, +252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, +252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, +252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, +252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, 252, +252, 252, 252, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, +253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, +253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, +253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, +253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, +253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, +253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, +253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, +253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, +253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, +253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, +253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, +253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, +253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, +253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, +253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, +253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, +253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, +253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, +253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, +253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, +253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, +253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, +253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, +253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, +253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, +253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, +253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, +253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, +253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, +253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, +253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, +253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, +253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, +253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, +253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, 253, +253, 253, 253, 253, 253, 253, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, +254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, +254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, +254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, +254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, +254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, +254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, +254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, +254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, +254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, +254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, +254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, +254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, +254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, +254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, +254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, +254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, +254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, +254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, +254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, +254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, +254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, +254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, +254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, +254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, +254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, +254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, +254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, +254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, +254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, +254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, +254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, +254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, +254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, +254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, +254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, +254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 254, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, +255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 +}; + +static const float gamma_to_linear[512] = +{ +0x0p+0, +0x1.3e45677c176f7p-12, +0x1.3e45677c176f7p-11, +0x1.dd681b3a23272p-11, +0x1.3e45677c176f7p-10, +0x1.8dd6c15b1d4b4p-10, +0x1.dd681b3a23272p-10, +0x1.167cba8c94818p-9, +0x1.3e45677c176f7p-9, +0x1.660e146b9a5d5p-9, +0x1.8dd6c15b1d4b4p-9, +0x1.b6a31b5259c99p-9, +0x1.e1e31d70c99ddp-9, +0x1.07c38bf8583a9p-8, +0x1.1fcc2beed6421p-8, +0x1.390ffaf95e279p-8, +0x1.53936cc7bc928p-8, +0x1.6f5addb50c915p-8, +0x1.8c6a94031b561p-8, +0x1.aac6c0fb97351p-8, +0x1.ca7381f9f602bp-8, +0x1.eb74e160978dp-8, +0x1.06e76bbda92b8p-7, +0x1.18c2a5a8a8044p-7, +0x1.2b4e09b3f0ae3p-7, +0x1.3e8b7b3bde965p-7, +0x1.527cd60af8b85p-7, +0x1.6723eea8d3709p-7, +0x1.7c8292a3db6b3p-7, +0x1.929a88d67b521p-7, +0x1.a96d91a8016bdp-7, +0x1.c0fd67499fab6p-7, +0x1.d94bbdefd740ep-7, +0x1.f25a44089883fp-7, +0x1.061551372c694p-6, +0x1.135f3e4c2cce2p-6, +0x1.210bb8642b172p-6, +0x1.2f1b8c1ae46bdp-6, +0x1.3d8f839b79c0bp-6, +0x1.4c6866b3e9fa4p-6, +0x1.5ba6fae794313p-6, +0x1.6b4c0380d2deep-6, +0x1.7b5841a1bf3acp-6, +0x1.8bcc74542addbp-6, +0x1.9ca95898dc8b5p-6, +0x1.adefa9761c02p-6, +0x1.bfa0200597bd9p-6, +0x1.d1bb7381aec1fp-6, +0x1.e442595227bcap-6, +0x1.f73585185e1b5p-6, +0x1.054ad45d76878p-5, +0x1.0f31ba386ff26p-5, +0x1.194fcb663747bp-5, +0x1.23a55e62a662ap-5, +0x1.2e32c8e148d11p-5, +0x1.38f85fd21eacfp-5, +0x1.43f67766310ffp-5, +0x1.4f2d6313fa8dp-5, +0x1.5a9d759ba5edp-5, +0x1.6647010b254eep-5, +0x1.722a56c2239eep-5, +0x1.7e47c775d2427p-5, +0x1.8a9fa33494b07p-5, +0x1.973239698b9ccp-5, +0x1.a3ffd8e001389p-5, +0x1.b108cfc6b7fbcp-5, +0x1.be4d6bb31d522p-5, +0x1.cbcdf9a4616f2p-5, +0x1.d98ac60675833p-5, +0x1.e7841cb4f16dfp-5, +0x1.f5ba48fde2048p-5, +0x1.0216cad240765p-4, +0x1.096f2671eb815p-4, +0x1.10e65c38a5192p-4, +0x1.187c90bf8bce2p-4, +0x1.2031e85f5d6dap-4, +0x1.28068731a1952p-4, +0x1.2ffa9111cb94bp-4, +0x1.380e299e53f92p-4, +0x1.40417439ca10fp-4, +0x1.4894940bddbfbp-4, +0x1.5107ac0261e59p-4, +0x1.599aded247aacp-4, +0x1.624e4ef892ed4p-4, +0x1.6b221ebb4817ep-4, +0x1.7416702a539d1p-4, +0x1.7d2b65206b527p-4, +0x1.86611f43e9e6ap-4, +0x1.8fb7c007a4a7p-4, +0x1.992f68abbbc89p-4, +0x1.a2c83a3e6566dp-4, +0x1.ac82559cb3644p-4, +0x1.b65ddb7354604p-4, +0x1.c05aec3f4fe5ep-4, +0x1.ca79a84ebe03p-4, +0x1.d4ba2fc17a6a5p-4, +0x1.df1ca289d34b8p-4, +0x1.e9a1206d34003p-4, +0x1.f447c904cbb4ep-4, +0x1.ff10bbbe302c2p-4, +0x1.04fe0bedfe5f1p-3, +0x1.0a84fe3b36d8fp-3, +0x1.101d443dfc06fp-3, +0x1.15c6ed58eefdfp-3, +0x1.1b8208da5fefp-3, +0x1.214ea5fc9514ap-3, +0x1.272cd3e610123p-3, +0x1.2d1ca1a9d1cfbp-3, +0x1.331e1e479cdf5p-3, +0x1.393158ac3674ep-3, +0x1.3f565fb1a5fd5p-3, +0x1.458d421f735dfp-3, +0x1.4bd60eaae3e73p-3, +0x1.5230d3f736034p-3, +0x1.589da095dbaa1p-3, +0x1.5f1c8306b3a3cp-3, +0x1.65ad89b841a2bp-3, +0x1.6c50c307e53bfp-3, +0x1.73063d420fc8p-3, +0x1.79ce06a279303p-3, +0x1.80a82d5453b5dp-3, +0x1.8794bf727eb3fp-3, +0x1.8e93cb07b8679p-3, +0x1.95a55e0ecec0bp-3, +0x1.9cc98672cf47ep-3, +0x1.a400520f3619cp-3, +0x1.ab49ceb01c003p-3, +0x1.b2a60a1263b0ap-3, +0x1.ba1511e3e632dp-3, +0x1.c196f3c39e76fp-3, +0x1.c92bbd41d41fep-3, +0x1.d0d37be045851p-3, +0x1.d88e3d1250f68p-3, +0x1.e05c0e3d1d3ep-3, +0x1.e83cfcb7c16fp-3, +0x1.f03115cb6bfd3p-3, +0x1.f83866b38924dp-3, +0x1.00297e4ef4553p-2, +0x1.044072557177ap-2, +0x1.086115f6beb3ap-2, +0x1.0c8b6fb5c735ep-2, +0x1.10bf860ef039ap-2, +0x1.14fd5f782a5a6p-2, +0x1.1945026102997p-2, +0x1.1d967532b31b1p-2, +0x1.21f1be50339e7p-2, +0x1.2656e41649ae3p-2, +0x1.2ac5ecdb988f8p-2, +0x1.2f3edef0b0ed8p-2, +0x1.33c1c0a020438p-2, +0x1.384e982e800b1p-2, +0x1.3ce56bda84a81p-2, +0x1.418641dd0c1bcp-2, +0x1.463120692c7afp-2, +0x1.4ae60dac4229dp-2, +0x1.4fa50fcdfde15p-2, +0x1.546e2cf0727a9p-2, +0x1.59416b3022858p-2, +0x1.5e1ed0a40daabp-2, +0x1.6306635dbdd7bp-2, +0x1.67f82969543a2p-2, +0x1.6cf428cd96079p-2, +0x1.71fa678bf915dp-2, +0x1.770aeba0b042ap-2, +0x1.7c25bb02b7ac5p-2, +0x1.814adba3e0bd9p-2, +0x1.867a5370de0b1p-2, +0x1.8bb428514f067p-2, +0x1.90f86027cb84ep-2, +0x1.964700d1ef1b1p-2, +0x1.9ba0102864521p-2, +0x1.a10393feefafdp-2, +0x1.a67192247a9bep-2, +0x1.abea10631e195p-2, +0x1.b16d14802d5cap-2, +0x1.b6faa43c403bbp-2, +0x1.bc92c5533d785p-2, +0x1.c2357d7c64e5dp-2, +0x1.c7e2d26a596dep-2, +0x1.cd9ac9cb2aef2p-2, +0x1.d35d69485ffc5p-2, +0x1.d92ab686ff782p-2, +0x1.df02b7279a10dp-2, +0x1.e4e570c6539c5p-2, +0x1.ead2e8faec526p-2, +0x1.f0cb2558c9ea4p-2, +0x1.f6ce2b6f00983p-2, +0x1.fcdc00c85bec2p-2, +0x1.017a5575b3cb2p-1, +0x1.048c17ad3c04bp-1, +0x1.07a349c9d9837p-1, +0x1.0abfee888c05p-1, +0x1.0de208a4444c8p-1, +0x1.11099ad5e83ebp-1, +0x1.1436a7d456eefp-1, +0x1.176932546ca12p-1, +0x1.1aa13d0906bdap-1, +0x1.1ddecaa307b85p-1, +0x1.2121ddd15aecep-1, +0x1.246a7940f86d1p-1, +0x1.27b89f9ce8c4bp-1, +0x1.2b0c538e48b07p-1, +0x1.2e6597bc4ccap-1, +0x1.31c46ecc4528dp-1, +0x1.3528db61a0f73p-1, +0x1.3892e01df1fccp-1, +0x1.3c027fa0f01ebp-1, +0x1.3f77bc887cd3bp-1, +0x1.42f29970a68f8p-1, +0x1.467318f3ac22dp-1, +0x1.49f93daa00113p-1, +0x1.4d850a2a4bde1p-1, +0x1.51168109734e5p-1, +0x1.54ada4da97a1bp-1, +0x1.584a782f1ac23p-1, +0x1.5becfd96a2698p-1, +0x1.5f95379f1b3edp-1, +0x1.634328d4bbe97p-1, +0x1.66f6d3c2081cfp-1, +0x1.6ab03aefd39aap-1, +0x1.6e6f60e5452b1p-1, +0x1.72344827d98f6p-1, +0x1.75fef33b6669bp-1, +0x1.79cf64a21d1e2p-1, +0x1.7da59edc8dabp-1, +0x1.8181a469a9787p-1, +0x1.856377c6c6224p-1, +0x1.894b1b6fa0377p-1, +0x1.8d3891de5df49p-1, +0x1.912bdd8b91f45p-1, +0x1.952500ee3dda5p-1, +0x1.9923fe7bd4f67p-1, +0x1.9d28d8a83edfcp-1, +0x1.a13391e5da09fp-1, +0x1.a5442ca57e52ep-1, +0x1.a95aab567f88fp-1, +0x1.ad771066afec2p-1, +0x1.b1995e4262a69p-1, +0x1.b5c197546e3f8p-1, +0x1.b9efbe062f086p-1, +0x1.be23d4bf8981bp-1, +0x1.c25ddde6ecbbbp-1, +0x1.c69ddbe154af1p-1, +0x1.cae3d1124c90bp-1, +0x1.cf2fbfdbf11f1p-1, +0x1.d381aa9ef2e82p-1, +0x1.d7d993ba988d4p-1, +0x1.dc377d8cc0fd5p-1, +0x1.e09b6a71e5aa6p-1, +0x1.e5055cc51cbb4p-1, +0x1.e97556e01b351p-1, +0x1.edeb5b1b37216p-1, +0x1.f2676bcd69adep-1, +0x1.f6e98b4c51466p-1, +0x1.fb71bbec33ab2p-1, +0x1p+0, + +0x0p+0, +0x1.010101010101p-8, +0x1.010101010101p-7, +0x1.8181818181818p-7, +0x1.010101010101p-6, +0x1.4141414141414p-6, +0x1.8181818181818p-6, +0x1.c1c1c1c1c1c1cp-6, +0x1.010101010101p-5, +0x1.2121212121212p-5, +0x1.4141414141414p-5, +0x1.6161616161616p-5, +0x1.8181818181818p-5, +0x1.a1a1a1a1a1a1ap-5, +0x1.c1c1c1c1c1c1cp-5, +0x1.e1e1e1e1e1e1ep-5, +0x1.010101010101p-4, +0x1.1111111111111p-4, +0x1.2121212121212p-4, +0x1.3131313131313p-4, +0x1.4141414141414p-4, +0x1.5151515151515p-4, +0x1.6161616161616p-4, +0x1.7171717171717p-4, +0x1.8181818181818p-4, +0x1.9191919191919p-4, +0x1.a1a1a1a1a1a1ap-4, +0x1.b1b1b1b1b1b1bp-4, +0x1.c1c1c1c1c1c1cp-4, +0x1.d1d1d1d1d1d1dp-4, +0x1.e1e1e1e1e1e1ep-4, +0x1.f1f1f1f1f1f1fp-4, +0x1.010101010101p-3, +0x1.0909090909091p-3, +0x1.1111111111111p-3, +0x1.1919191919192p-3, +0x1.2121212121212p-3, +0x1.2929292929293p-3, +0x1.3131313131313p-3, +0x1.3939393939394p-3, +0x1.4141414141414p-3, +0x1.4949494949495p-3, +0x1.5151515151515p-3, +0x1.5959595959596p-3, +0x1.6161616161616p-3, +0x1.6969696969697p-3, +0x1.7171717171717p-3, +0x1.7979797979798p-3, +0x1.8181818181818p-3, +0x1.8989898989899p-3, +0x1.9191919191919p-3, +0x1.999999999999ap-3, +0x1.a1a1a1a1a1a1ap-3, +0x1.a9a9a9a9a9a9bp-3, +0x1.b1b1b1b1b1b1bp-3, +0x1.b9b9b9b9b9b9cp-3, +0x1.c1c1c1c1c1c1cp-3, +0x1.c9c9c9c9c9c9dp-3, +0x1.d1d1d1d1d1d1dp-3, +0x1.d9d9d9d9d9d9ep-3, +0x1.e1e1e1e1e1e1ep-3, +0x1.e9e9e9e9e9e9fp-3, +0x1.f1f1f1f1f1f1fp-3, +0x1.f9f9f9f9f9fap-3, +0x1.010101010101p-2, +0x1.050505050505p-2, +0x1.0909090909091p-2, +0x1.0d0d0d0d0d0d1p-2, +0x1.1111111111111p-2, +0x1.1515151515151p-2, +0x1.1919191919192p-2, +0x1.1d1d1d1d1d1d2p-2, +0x1.2121212121212p-2, +0x1.2525252525252p-2, +0x1.2929292929293p-2, +0x1.2d2d2d2d2d2d3p-2, +0x1.3131313131313p-2, +0x1.3535353535353p-2, +0x1.3939393939394p-2, +0x1.3d3d3d3d3d3d4p-2, +0x1.4141414141414p-2, +0x1.4545454545454p-2, +0x1.4949494949495p-2, +0x1.4d4d4d4d4d4d5p-2, +0x1.5151515151515p-2, +0x1.5555555555555p-2, +0x1.5959595959596p-2, +0x1.5d5d5d5d5d5d6p-2, +0x1.6161616161616p-2, +0x1.6565656565656p-2, +0x1.6969696969697p-2, +0x1.6d6d6d6d6d6d7p-2, +0x1.7171717171717p-2, +0x1.7575757575757p-2, +0x1.7979797979798p-2, +0x1.7d7d7d7d7d7d8p-2, +0x1.8181818181818p-2, +0x1.8585858585858p-2, +0x1.8989898989899p-2, +0x1.8d8d8d8d8d8d9p-2, +0x1.9191919191919p-2, +0x1.9595959595959p-2, +0x1.999999999999ap-2, +0x1.9d9d9d9d9d9dap-2, +0x1.a1a1a1a1a1a1ap-2, +0x1.a5a5a5a5a5a5ap-2, +0x1.a9a9a9a9a9a9bp-2, +0x1.adadadadadadbp-2, +0x1.b1b1b1b1b1b1bp-2, +0x1.b5b5b5b5b5b5bp-2, +0x1.b9b9b9b9b9b9cp-2, +0x1.bdbdbdbdbdbdcp-2, +0x1.c1c1c1c1c1c1cp-2, +0x1.c5c5c5c5c5c5cp-2, +0x1.c9c9c9c9c9c9dp-2, +0x1.cdcdcdcdcdcddp-2, +0x1.d1d1d1d1d1d1dp-2, +0x1.d5d5d5d5d5d5dp-2, +0x1.d9d9d9d9d9d9ep-2, +0x1.ddddddddddddep-2, +0x1.e1e1e1e1e1e1ep-2, +0x1.e5e5e5e5e5e5ep-2, +0x1.e9e9e9e9e9e9fp-2, +0x1.ededededededfp-2, +0x1.f1f1f1f1f1f1fp-2, +0x1.f5f5f5f5f5f5fp-2, +0x1.f9f9f9f9f9fap-2, +0x1.fdfdfdfdfdfep-2, +0x1.010101010101p-1, +0x1.030303030303p-1, +0x1.050505050505p-1, +0x1.070707070707p-1, +0x1.0909090909091p-1, +0x1.0b0b0b0b0b0b1p-1, +0x1.0d0d0d0d0d0d1p-1, +0x1.0f0f0f0f0f0f1p-1, +0x1.1111111111111p-1, +0x1.1313131313131p-1, +0x1.1515151515151p-1, +0x1.1717171717171p-1, +0x1.1919191919192p-1, +0x1.1b1b1b1b1b1b2p-1, +0x1.1d1d1d1d1d1d2p-1, +0x1.1f1f1f1f1f1f2p-1, +0x1.2121212121212p-1, +0x1.2323232323232p-1, +0x1.2525252525252p-1, +0x1.2727272727272p-1, +0x1.2929292929293p-1, +0x1.2b2b2b2b2b2b3p-1, +0x1.2d2d2d2d2d2d3p-1, +0x1.2f2f2f2f2f2f3p-1, +0x1.3131313131313p-1, +0x1.3333333333333p-1, +0x1.3535353535353p-1, +0x1.3737373737373p-1, +0x1.3939393939394p-1, +0x1.3b3b3b3b3b3b4p-1, +0x1.3d3d3d3d3d3d4p-1, +0x1.3f3f3f3f3f3f4p-1, +0x1.4141414141414p-1, +0x1.4343434343434p-1, +0x1.4545454545454p-1, +0x1.4747474747474p-1, +0x1.4949494949495p-1, +0x1.4b4b4b4b4b4b5p-1, +0x1.4d4d4d4d4d4d5p-1, +0x1.4f4f4f4f4f4f5p-1, +0x1.5151515151515p-1, +0x1.5353535353535p-1, +0x1.5555555555555p-1, +0x1.5757575757575p-1, +0x1.5959595959596p-1, +0x1.5b5b5b5b5b5b6p-1, +0x1.5d5d5d5d5d5d6p-1, +0x1.5f5f5f5f5f5f6p-1, +0x1.6161616161616p-1, +0x1.6363636363636p-1, +0x1.6565656565656p-1, +0x1.6767676767676p-1, +0x1.6969696969697p-1, +0x1.6b6b6b6b6b6b7p-1, +0x1.6d6d6d6d6d6d7p-1, +0x1.6f6f6f6f6f6f7p-1, +0x1.7171717171717p-1, +0x1.7373737373737p-1, +0x1.7575757575757p-1, +0x1.7777777777777p-1, +0x1.7979797979798p-1, +0x1.7b7b7b7b7b7b8p-1, +0x1.7d7d7d7d7d7d8p-1, +0x1.7f7f7f7f7f7f8p-1, +0x1.8181818181818p-1, +0x1.8383838383838p-1, +0x1.8585858585858p-1, +0x1.8787878787878p-1, +0x1.8989898989899p-1, +0x1.8b8b8b8b8b8b9p-1, +0x1.8d8d8d8d8d8d9p-1, +0x1.8f8f8f8f8f8f9p-1, +0x1.9191919191919p-1, +0x1.9393939393939p-1, +0x1.9595959595959p-1, +0x1.9797979797979p-1, +0x1.999999999999ap-1, +0x1.9b9b9b9b9b9bap-1, +0x1.9d9d9d9d9d9dap-1, +0x1.9f9f9f9f9f9fap-1, +0x1.a1a1a1a1a1a1ap-1, +0x1.a3a3a3a3a3a3ap-1, +0x1.a5a5a5a5a5a5ap-1, +0x1.a7a7a7a7a7a7ap-1, +0x1.a9a9a9a9a9a9bp-1, +0x1.ababababababbp-1, +0x1.adadadadadadbp-1, +0x1.afafafafafafbp-1, +0x1.b1b1b1b1b1b1bp-1, +0x1.b3b3b3b3b3b3bp-1, +0x1.b5b5b5b5b5b5bp-1, +0x1.b7b7b7b7b7b7bp-1, +0x1.b9b9b9b9b9b9cp-1, +0x1.bbbbbbbbbbbbcp-1, +0x1.bdbdbdbdbdbdcp-1, +0x1.bfbfbfbfbfbfcp-1, +0x1.c1c1c1c1c1c1cp-1, +0x1.c3c3c3c3c3c3cp-1, +0x1.c5c5c5c5c5c5cp-1, +0x1.c7c7c7c7c7c7cp-1, +0x1.c9c9c9c9c9c9dp-1, +0x1.cbcbcbcbcbcbdp-1, +0x1.cdcdcdcdcdcddp-1, +0x1.cfcfcfcfcfcfdp-1, +0x1.d1d1d1d1d1d1dp-1, +0x1.d3d3d3d3d3d3dp-1, +0x1.d5d5d5d5d5d5dp-1, +0x1.d7d7d7d7d7d7dp-1, +0x1.d9d9d9d9d9d9ep-1, +0x1.dbdbdbdbdbdbep-1, +0x1.ddddddddddddep-1, +0x1.dfdfdfdfdfdfep-1, +0x1.e1e1e1e1e1e1ep-1, +0x1.e3e3e3e3e3e3ep-1, +0x1.e5e5e5e5e5e5ep-1, +0x1.e7e7e7e7e7e7ep-1, +0x1.e9e9e9e9e9e9fp-1, +0x1.ebebebebebebfp-1, +0x1.ededededededfp-1, +0x1.efefefefefeffp-1, +0x1.f1f1f1f1f1f1fp-1, +0x1.f3f3f3f3f3f3fp-1, +0x1.f5f5f5f5f5f5fp-1, +0x1.f7f7f7f7f7f7fp-1, +0x1.f9f9f9f9f9fap-1, +0x1.fbfbfbfbfbfcp-1, +0x1.fdfdfdfdfdfep-1, +0x1p+0 +}; diff --git a/extensions/avx2-int8.c b/extensions/avx2-int8.c new file mode 100644 index 0000000..a3ded4d --- /dev/null +++ b/extensions/avx2-int8.c @@ -0,0 +1,610 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2019 Ell + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" + +#if defined(USE_AVX2) + +/* AVX 2 */ +#include + +#include +#include + +#include "babl.h" +#include "babl-cpuaccel.h" +#include "extensions/util.h" +#include "extensions/avx2-int8-tables.h" + +#define TABLE_SIZE (sizeof (linear_to_gamma) / sizeof (linear_to_gamma[0])) +#define SCALE ((float) (TABLE_SIZE - 1)) + +#define CVT1(src, dst) \ + do \ + { \ + float x = *src; \ + \ + if (x < 0.0f) \ + *dst = 0; \ + else if (x <= 1.0f) \ + *dst = linear_to_gamma[(int) (SCALE * x + 0.5f)]; \ + else /* x > 1.0f || isnan (x) */ \ + *dst = 255; \ + \ + src++; \ + dst++; \ + } \ + while (0) + +#define CVTA1(src, dst) \ + do \ + { \ + float x = *src; \ + \ + if (x < 0.0f) \ + *dst = 0; \ + else if (x <= 1.0f) \ + *dst = 255.0f * x + 0.5f; \ + else /* x > 1.0f || isnan (x) */ \ + *dst = 255; \ + \ + src++; \ + dst++; \ + } \ + while (0) + +static inline void +conv_yF_linear_y8_gamma (const Babl *conversion, + const float *src, + uint8_t *dst, + long samples) +{ + const __v8sf *src_vec; + __m256i *dst_vec; + const __v8sf scale = _mm256_set1_ps (SCALE); + const __v8sf zero = _mm256_setzero_ps (); + const __v8sf half = _mm256_set1_ps (0.5f); + + while ((uintptr_t) src % 32 && samples > 0) + { + CVT1 (src, dst); + + samples--; + } + + src_vec = (const __v8sf *) src; + dst_vec = (__m256i *) dst; + + while (samples >= 32) + { + __m256i i32_0, i32_1, i32_2, i32_3; + __m256i i16_01, i16_23; + __m256i i8_0123; + + #define CVT8(i) \ + do \ + { \ + __v8sf yyyyyyyy; \ + \ + yyyyyyyy = scale * src_vec[i] + half; \ + yyyyyyyy = _mm256_max_ps (yyyyyyyy, zero); \ + yyyyyyyy = _mm256_min_ps (yyyyyyyy, scale); \ + i32_##i = _mm256_cvttps_epi32 (yyyyyyyy); \ + i32_##i = _mm256_i32gather_epi32 (linear_to_gamma, i32_##i, 4); \ + } \ + while (0) + + CVT8 (0); + CVT8 (1); + + i16_01 = _mm256_packus_epi32 (i32_0, i32_1); + + CVT8 (2); + CVT8 (3); + + i16_23 = _mm256_packus_epi32 (i32_2, i32_3); + + i8_0123 = _mm256_packus_epi16 (i16_01, i16_23); + i8_0123 = _mm256_permutevar8x32_epi32 ( + i8_0123, + _mm256_setr_epi32 (0, 4, 1, 5, + 2, 6, 3, 7)); + + _mm256_storeu_si256 (dst_vec, i8_0123); + + #undef CVT8 + + src_vec += 4; + dst_vec++; + + samples -= 32; + } + + src = (const float *) src_vec; + dst = (uint8_t *) dst_vec; + + while (samples > 0) + { + CVT1 (src, dst); + + samples--; + } +} + +static inline void +conv_yaF_linear_ya8_gamma (const Babl *conversion, + const float *src, + uint8_t *dst, + long samples) +{ + if ((uintptr_t) src % 8 == 0) + { + const __v8sf *src_vec; + __m256i *dst_vec; + const __v8sf scale = _mm256_setr_ps (SCALE, 255.0f, SCALE, 255.0f, + SCALE, 255.0f, SCALE, 255.0f); + const __v8sf zero = _mm256_setzero_ps (); + const __v8sf half = _mm256_set1_ps (0.5f); + const __m256i mask = _mm256_setr_epi32 (-1, 0, -1, 0, + -1, 0, -1, 0); + + while ((uintptr_t) src % 32 && samples > 0) + { + CVT1 (src, dst); + CVTA1 (src, dst); + + samples--; + } + + src_vec = (const __v8sf *) src; + dst_vec = (__m256i *) dst; + + while (samples >= 16) + { + __m256i i32_0, i32_1, i32_2, i32_3; + __m256i i16_01, i16_23; + __m256i i8_0123; + + #define CVT8(i) \ + do \ + { \ + __v8sf yayayaya; \ + \ + yayayaya = scale * src_vec[i] + half; \ + yayayaya = _mm256_max_ps (yayayaya, zero); \ + yayayaya = _mm256_min_ps (yayayaya, scale); \ + i32_##i = _mm256_cvttps_epi32 (yayayaya); \ + i32_##i = _mm256_mask_i32gather_epi32 (i32_##i, \ + linear_to_gamma, \ + i32_##i, mask, 4); \ + } \ + while (0) + + CVT8 (0); + CVT8 (1); + + i16_01 = _mm256_packus_epi32 (i32_0, i32_1); + + CVT8 (2); + CVT8 (3); + + i16_23 = _mm256_packus_epi32 (i32_2, i32_3); + + i8_0123 = _mm256_packus_epi16 (i16_01, i16_23); + i8_0123 = _mm256_permutevar8x32_epi32 ( + i8_0123, + _mm256_setr_epi32 (0, 4, 1, 5, + 2, 6, 3, 7)); + + _mm256_storeu_si256 (dst_vec, i8_0123); + + #undef CVT8 + + src_vec += 4; + dst_vec++; + + samples -= 16; + } + + src = (const float *) src_vec; + dst = (uint8_t *) dst_vec; + } + + while (samples > 0) + { + CVT1 (src, dst); + CVTA1 (src, dst); + + samples--; + } +} + +static void +conv_rgbF_linear_rgb8_gamma (const Babl *conversion, + const float *src, + uint8_t *dst, + long samples) +{ + conv_yF_linear_y8_gamma (conversion, src, dst, 3 * samples); +} + +static inline void +conv_rgbaF_linear_rgba8_gamma (const Babl *conversion, + const float *src, + uint8_t *dst, + long samples) +{ + if ((uintptr_t) src % 16 == 0) + { + const __v8sf *src_vec; + __m256i *dst_vec; + const __v8sf scale = _mm256_setr_ps (SCALE, SCALE, SCALE, 255.0f, + SCALE, SCALE, SCALE, 255.0f); + const __v8sf zero = _mm256_setzero_ps (); + const __v8sf half = _mm256_set1_ps (0.5f); + const __m256i mask = _mm256_setr_epi32 (-1, -1, -1, 0, + -1, -1, -1, 0); + + while ((uintptr_t) src % 32 && samples > 0) + { + CVT1 (src, dst); + CVT1 (src, dst); + CVT1 (src, dst); + CVTA1 (src, dst); + + samples--; + } + + src_vec = (const __v8sf *) src; + dst_vec = (__m256i *) dst; + + while (samples >= 8) + { + __m256i i32_0, i32_1, i32_2, i32_3; + __m256i i16_01, i16_23; + __m256i i8_0123; + + #define CVT8(i) \ + do \ + { \ + __v8sf rgbargba; \ + \ + rgbargba = scale * src_vec[i] + half; \ + rgbargba = _mm256_max_ps (rgbargba, zero); \ + rgbargba = _mm256_min_ps (rgbargba, scale); \ + i32_##i = _mm256_cvttps_epi32 (rgbargba); \ + i32_##i = _mm256_mask_i32gather_epi32 (i32_##i, \ + linear_to_gamma, \ + i32_##i, mask, 4); \ + } \ + while (0) + + CVT8 (0); + CVT8 (1); + + i16_01 = _mm256_packus_epi32 (i32_0, i32_1); + + CVT8 (2); + CVT8 (3); + + i16_23 = _mm256_packus_epi32 (i32_2, i32_3); + + i8_0123 = _mm256_packus_epi16 (i16_01, i16_23); + i8_0123 = _mm256_permutevar8x32_epi32 ( + i8_0123, + _mm256_setr_epi32 (0, 4, 1, 5, + 2, 6, 3, 7)); + + _mm256_storeu_si256 (dst_vec, i8_0123); + + #undef CVT8 + + src_vec += 4; + dst_vec++; + + samples -= 8; + } + + src = (const float *) src_vec; + dst = (uint8_t *) dst_vec; + } + + while (samples > 0) + { + CVT1 (src, dst); + CVT1 (src, dst); + CVT1 (src, dst); + CVTA1 (src, dst); + + samples--; + } +} + +#undef CVT1 +#undef CVTA1 + +#define CVT1(src, dst) \ + (*dst++ = gamma_to_linear[*src++]) + +#define CVTA1(src, dst) \ + (*dst++ = gamma_to_linear[*src++ + 256]) + +static inline void +conv_y8_gamma_yF_linear (const Babl *conversion, + const uint8_t *src, + float *dst, + long samples) +{ + const __m128i *src_vec; + __v8sf *dst_vec; + + while ((uintptr_t) dst % 32 && samples > 0) + { + CVT1 (src, dst); + + samples--; + } + + src_vec = (const __m128i *) src; + dst_vec = (__v8sf *) dst; + + while (samples >= 16) + { + __m128i i8_01; + __m256i i32_0; + + i8_01 = _mm_loadu_si128 (src_vec++); + + i32_0 = _mm256_cvtepu8_epi32 (i8_01); + *dst_vec++ = _mm256_i32gather_ps (gamma_to_linear, i32_0, 4); + + i8_01 = _mm_shuffle_epi32 (i8_01, _MM_SHUFFLE (1, 0, 3, 2)); + + i32_0 = _mm256_cvtepu8_epi32 (i8_01); + *dst_vec++ = _mm256_i32gather_ps (gamma_to_linear, i32_0, 4); + + samples -= 16; + } + + src = (const uint8_t *) src_vec; + dst = (float *) dst_vec; + + while (samples > 0) + { + CVT1 (src, dst); + + samples--; + } +} + +static inline void +conv_ya8_gamma_yaF_linear (const Babl *conversion, + const uint8_t *src, + float *dst, + long samples) +{ + const __m128i *src_vec; + __v8sf *dst_vec; + const __m256i offset = _mm256_setr_epi32 (0, 256, 0, 256, + 0, 256, 0, 256); + + while ((uintptr_t) dst % 32 && samples > 0) + { + CVT1 (src, dst); + CVTA1 (src, dst); + + samples--; + } + + src_vec = (const __m128i *) src; + dst_vec = (__v8sf *) dst; + + while (samples >= 8) + { + __m128i i8_01; + __m256i i32_0; + + i8_01 = _mm_loadu_si128 (src_vec++); + + i32_0 = _mm256_cvtepu8_epi32 (i8_01); + i32_0 += offset; + *dst_vec++ = _mm256_i32gather_ps (gamma_to_linear, i32_0, 4); + + i8_01 = _mm_shuffle_epi32 (i8_01, _MM_SHUFFLE (1, 0, 3, 2)); + + i32_0 = _mm256_cvtepu8_epi32 (i8_01); + i32_0 += offset; + *dst_vec++ = _mm256_i32gather_ps (gamma_to_linear, i32_0, 4); + + samples -= 8; + } + + src = (const uint8_t *) src_vec; + dst = (float *) dst_vec; + + while (samples > 0) + { + CVT1 (src, dst); + CVTA1 (src, dst); + + samples--; + } +} + +static inline void +conv_rgb8_gamma_rgbF_linear (const Babl *conversion, + const uint8_t *src, + float *dst, + long samples) +{ + conv_y8_gamma_yF_linear (conversion, src, dst, 3 * samples); +} + +static inline void +conv_rgba8_gamma_rgbaF_linear (const Babl *conversion, + const uint8_t *src, + float *dst, + long samples) +{ + const __m128i *src_vec; + __v8sf *dst_vec; + const __m256i offset = _mm256_setr_epi32 (0, 0, 0, 256, + 0, 0, 0, 256); + + while ((uintptr_t) dst % 32 && samples > 0) + { + CVT1 (src, dst); + CVT1 (src, dst); + CVT1 (src, dst); + CVTA1 (src, dst); + + samples--; + } + + src_vec = (const __m128i *) src; + dst_vec = (__v8sf *) dst; + + while (samples >= 4) + { + __m128i i8_01; + __m256i i32_0; + + i8_01 = _mm_loadu_si128 (src_vec++); + + i32_0 = _mm256_cvtepu8_epi32 (i8_01); + i32_0 += offset; + *dst_vec++ = _mm256_i32gather_ps (gamma_to_linear, i32_0, 4); + + i8_01 = _mm_shuffle_epi32 (i8_01, _MM_SHUFFLE (1, 0, 3, 2)); + + i32_0 = _mm256_cvtepu8_epi32 (i8_01); + i32_0 += offset; + *dst_vec++ = _mm256_i32gather_ps (gamma_to_linear, i32_0, 4); + + samples -= 4; + } + + src = (const uint8_t *) src_vec; + dst = (float *) dst_vec; + + while (samples > 0) + { + CVT1 (src, dst); + CVT1 (src, dst); + CVT1 (src, dst); + CVTA1 (src, dst); + + samples--; + } +} + +#undef CVT1 +#undef CVTA1 + +#endif /* defined(USE_AVX2) */ + +int init (void); + +int +init (void) +{ +#if defined(USE_AVX2) + + const Babl *yF_linear = babl_format_new ( + babl_model ("Y"), + babl_type ("float"), + babl_component ("Y"), + NULL); + const Babl *y8_gamma = babl_format_new ( + babl_model ("Y'"), + babl_type ("u8"), + babl_component ("Y'"), + NULL); + const Babl *yaF_linear = babl_format_new ( + babl_model ("YA"), + babl_type ("float"), + babl_component ("Y"), + babl_component ("A"), + NULL); + const Babl *ya8_gamma = babl_format_new ( + babl_model ("Y'A"), + babl_type ("u8"), + babl_component ("Y'"), + babl_component ("A"), + NULL); + const Babl *rgbF_linear = babl_format_new ( + babl_model ("RGB"), + babl_type ("float"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + NULL); + const Babl *rgb8_gamma = babl_format_new ( + babl_model ("R'G'B'"), + babl_type ("u8"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + NULL); + const Babl *rgbaF_linear = babl_format_new ( + babl_model ("RGBA"), + babl_type ("float"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + babl_component ("A"), + NULL); + const Babl *rgba8_gamma = babl_format_new ( + babl_model ("R'G'B'A"), + babl_type ("u8"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + babl_component ("A"), + NULL); + +#define CONV(src, dst) \ + do \ + { \ + babl_conversion_new (src ## _linear, \ + dst ## _gamma, \ + "linear", \ + conv_ ## src ## _linear_ ## dst ## _gamma, \ + NULL); \ + \ + babl_conversion_new (dst ## _gamma, \ + src ## _linear, \ + "linear", \ + conv_ ## dst ## _gamma_ ## src ## _linear, \ + NULL); \ + } \ + while (0) + + if ((babl_cpu_accel_get_support () & BABL_CPU_ACCEL_X86_AVX2)) + { + CONV (yF, y8); + CONV (yaF, ya8); + CONV (rgbF, rgb8); + CONV (rgbaF, rgba8); + } + +#endif /* defined(USE_AVX2) */ + + return 0; +} + diff --git a/extensions/cairo.c b/extensions/cairo.c new file mode 100644 index 0000000..08ccf67 --- /dev/null +++ b/extensions/cairo.c @@ -0,0 +1,753 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2012 Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include +#include +#include +#include "config.h" +#include "babl-internal.h" + +#include "base/util.h" + +int init (void); + +static void +conv_rgba8_cairo24_le (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + uint32_t *srci = (void *)src; + uint32_t *dsti = (void *)dst; + + while (n--) + { + uint32_t orig = *srci++; + uint32_t green_alpha = (orig & 0x0000ff00); + uint32_t red_blue = (orig & 0x00ff00ff); + uint32_t red = red_blue << 16; + uint32_t blue = red_blue >> 16; + *dsti++ = green_alpha | red | blue | 0xff000000; + } +} + +static void +conv_rgb8_cairo24_le (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + while (n--) + { + unsigned char red = *src++; + unsigned char green = *src++; + unsigned char blue = *src++; + *dst++ = blue; + *dst++ = green; + *dst++ = red; + *dst++ = 255; + } + + +} + +#if 0 +static void +conv_rgbA8_cairo32_le (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + while (n--) + { + unsigned char red = *src++; + unsigned char green = *src++; + unsigned char blue = *src++; + unsigned char alpha = *src++; + + *dst++ = blue; + *dst++ = green; + *dst++ = red; + *dst++ = alpha; + } +} +#else + +static void +conv_rgbA8_cairo32_le (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + uint32_t *srci = (void *)src; + uint32_t *dsti = (void *)dst; + + while (n--) + { + uint32_t orig = *srci++; + uint32_t green_alpha = (orig & 0xff00ff00); + uint32_t red_blue = (orig & 0x00ff00ff); + uint32_t red = red_blue << 16; + uint32_t blue = red_blue >> 16; + *dsti++ = green_alpha | red | blue; + } +} +#endif + +static void +conv_cairo32_rgbA8_le (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + while (n--) + { + unsigned char blue = *src++; + unsigned char green = *src++; + unsigned char red = *src++; + unsigned char alpha = *src++; + + *dst++ = red; + *dst++ = green; + *dst++ = blue; + *dst++ = alpha; + } +} + +static void +conv_cairo32_rgba8_le (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + while (n--) + { + unsigned char blue = *src++; + unsigned char green = *src++; + unsigned char red = *src++; + unsigned char alpha = *src++; + + if (alpha == 0) + { + *dst++ = 0; + *dst++ = 0; + *dst++ = 0; + *dst++ = 0; + } + else if (alpha == 255) + { + *dst++ = red; + *dst++ = green; + *dst++ = blue; + *dst++ = alpha; + } + else + { + float falpha = alpha / 255.0; + float recip_alpha = 1.0 / falpha; + // unsigned int aa = ((255 << 16) + alpha) / falpha + 0.5; + + + *dst++ = ((red/255.0) * recip_alpha) * 255 + 0.5f; + *dst++ = ((green/255.0) * recip_alpha) * 255 + 0.5f; + *dst++ = ((blue/255.0) * recip_alpha) * 255 + 0.5f; + +// *dst++ = (red * aa + 0x8000) >> 16; +// *dst++ = (green * aa + 0x8000) >> 16; +// *dst++ = (blue * aa + 0x8000) >> 16; + *dst++ = alpha; + } + } +} + + +static void +conv_cairo32_rgbAF_le (const Babl *conversion, + unsigned char *src, + unsigned char *dst_char, + long samples) +{ + long n = samples; + float *dst = (void*)dst_char; + while (n--) + { + unsigned char blue = *src++; + unsigned char green = *src++; + unsigned char red = *src++; + unsigned char alpha = *src++; + + *dst++ = red / 255.0; + *dst++ = green / 255.0; + *dst++ = blue / 255.0; + *dst++ = alpha / 255.0; + } +} + + +static void +conv_cairo32_rgbaF_le (const Babl *conversion, + unsigned char *src, + unsigned char *dst_char, + long samples) +{ + long n = samples; + float *dst = (void*)dst_char; + while (n--) + { + unsigned char blue = *src++; + unsigned char green = *src++; + unsigned char red = *src++; + unsigned char alpha = *src++; + + float reciprocal_alpha = 0.0f; + + if (alpha) + reciprocal_alpha = 1.0f/(alpha/255.0f) / 255.0f; + + + *dst++ = red * reciprocal_alpha; + *dst++ = green * reciprocal_alpha; + *dst++ = blue * reciprocal_alpha; + *dst++ = alpha / 255.0; + } +} + + +static void +conv_cairo24_cairo32_le (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + while (n--) + { + *dst++ = (*src++); + *dst++ = (*src++); + *dst++ = (*src++); + *dst++ = 255; src++; + } +} + + +static void +conv_rgba8_cairo32_le (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + uint32_t *dsti = (void*) dst; + while (n--) + { + unsigned char alpha = src[3]; +#if SIZE_MAX >= UINT64_MAX /* 64-bit */ + uint64_t rbag = ((uint64_t) src[0] << 48) | + ((uint64_t) src[2] << 32) | + ((uint64_t) 255 << 16) | + ((uint64_t) src[1] << 0); + rbag *= alpha; + rbag += 0x0080008000800080; + rbag += (rbag >> 8) & 0x00ff00ff00ff00ff; + rbag &= 0xff00ff00ff00ff00; + *dsti++ = (uint32_t) (rbag >> 0) | + (uint32_t) (rbag >> 40); +#else /* 32-bit */ + uint32_t rb = ((uint32_t) src[0] << 16) | + ((uint32_t) src[2] << 0); + uint64_t ag = ((uint32_t) 255 << 16) | + ((uint32_t) src[1] << 0); + rb *= alpha; + ag *= alpha; + rb += 0x00800080; + ag += 0x00800080; + rb += (rb >> 8) & 0x00ff00ff; + ag += (ag >> 8) & 0x00ff00ff; + rb &= 0xff00ff00; + ag &= 0xff00ff00; + *dsti++ = (uint32_t) (ag >> 0) | + (uint32_t) (rb >> 8); +#endif + src+=4; + } +} + +static void +conv_rgb8_cairo32_le (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + while (n--) + { + unsigned char red = *src++; + unsigned char green = *src++; + unsigned char blue = *src++; + + *dst++ = blue; + *dst++ = green; + *dst++ = red; + *dst++ = 0xff; + } +} + + + + +static void +conv_yA8_cairo32_le (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + while (n--) + { +#define div_255(a) ((((a)+128)+(((a)+128)>>8))>>8) + + unsigned char gray = *src++; + unsigned char alpha = *src++; + unsigned char val = div_255 (gray * alpha); + +#undef div_255 + + *dst++ = val; + *dst++ = val; + *dst++ = val; + *dst++ = alpha; + } +} + +static void +conv_yA16_cairo32_le (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + uint16_t *ssrc = (void*) src; + while (n--) + { + float alpha = (ssrc[1]) / 65535.0f; + int val = (ssrc[0] * alpha) * (0xff / 65535.0f ) + 0.5f; + *dst++ = val; + *dst++ = val; + *dst++ = val; + *dst++ = (alpha * 0xff + 0.5f); + ssrc+=2; + } +} + +static void +conv_y8_cairo32_le (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + while (n--) + { + unsigned char val = *src++; + *dst++ = val; + *dst++ = val; + *dst++ = val; + *dst++ = 0xff; + } +} + +static void +conv_y16_cairo32_le (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + uint16_t *s16 = (void*)src; + while (n--) + { +#define div_257(a) ((((a)+128)-(((a)+128)>>8))>>8) + uint16_t v16 = *s16++; + unsigned char val = div_257(v16); +#undef dib_257 + *dst++ = val; + *dst++ = val; + *dst++ = val; + *dst++ = 0xff; + } +} + +static void +conv_rgbA_gamma_float_cairo32_le (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + float *fsrc = (float *) src; + unsigned char *cdst = (unsigned char *) dst; + int n = samples; + + while (n--) + { + int val = fsrc[2] * 255.0f + 0.5f; + *cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val; + val = fsrc[1] * 255.0f + 0.5f; + *cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val; + val = fsrc[0] * 255.0f + 0.5f; + *cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val; + val = fsrc[3] * 255.0f + 0.5f; + *cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val; + fsrc+=4; + } +} + +static void +conv_rgbafloat_cairo32_le (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + const Babl **trc = (void*)space->space.trc; + + float *fsrc = (float *) src; + unsigned char *cdst = (unsigned char *) dst; + int n = samples; + + while (n--) + { + float red = *fsrc++; + float green = *fsrc++; + float blue = *fsrc++; + float alpha = *fsrc++; + if (alpha >= 1.0) + { + int val = babl_trc_from_linear (trc[2], blue) * 0xff + 0.5f; + *cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val; + val = babl_trc_from_linear (trc[1], green) * 0xff + 0.5f; + *cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val; + val = babl_trc_from_linear (trc[0], red) * 0xff + 0.5f; + *cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val; + *cdst++ = 0xff; + } + else if (alpha <= 0.0) + { + (*(uint32_t*)cdst)=0; + cdst+=4; + } + else + { + float balpha = alpha * 0xff; + int val = babl_trc_from_linear (trc[2], blue) * balpha + 0.5f; + *cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val; + val = babl_trc_from_linear (trc[1], green) * balpha + 0.5f; + *cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val; + val = babl_trc_from_linear (trc[0], red) * balpha + 0.5f; + *cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val; + *cdst++ = balpha + 0.5f; + } + } +} + + +static void +conv_yafloat_cairo32_le (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + const Babl **trc = (void*)space->space.trc; + float *fsrc = (float *) src; + unsigned char *cdst = (unsigned char *) dst; + int n = samples; + + while (n--) + { + float gray = *fsrc++; + float alpha = *fsrc++; + if (alpha >= 1.0) + { + int val = babl_trc_from_linear (trc[0], gray) * 0xff + 0.5f; + val = val >= 0xff ? 0xff : val <= 0 ? 0 : val; + *cdst++ = val; + *cdst++ = val; + *cdst++ = val; + *cdst++ = 0xff; + } + else if (alpha <= 0.0) + { + (*(uint32_t*)cdst)=0; + cdst+=4; + } + else + { + float balpha = alpha * 0xff; + int val = babl_trc_from_linear (trc[0], gray) * balpha + 0.5f; + val = val >= 0xff ? 0xff : val <= 0 ? 0 : val; + *cdst++ = val; + *cdst++ = val; + *cdst++ = val; + *cdst++ = balpha + 0.5f; + } + } +} + + +static void +conv_yafloat_nl_cairo32_le (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + float *fsrc = (float *) src; + unsigned char *cdst = (unsigned char *) dst; + int n = samples; + + while (n--) + { + float gray = *fsrc++; + float alpha = *fsrc++; + if (alpha >= 1.0) + { + int val = gray * 0xff + 0.5f; + val = val >= 0xff ? 0xff : val <= 0 ? 0 : val; + *cdst++ = val; + *cdst++ = val; + *cdst++ = val; + *cdst++ = 0xff; + } + else if (alpha <= 0.0) + { + (*(uint32_t*)cdst)=0; + cdst+=4; + } + else + { + float balpha = alpha * 0xff; + int val = gray * balpha + 0.5f; + val = val >= 0xff ? 0xff : val <= 0 ? 0 : val; + *cdst++ = val; + *cdst++ = val; + *cdst++ = val; + *cdst++ = balpha + 0.5f; + } + } +} + + +int +init (void) +{ + int testint = 23; + char *testchar = (char*) &testint; + int littleendian = (testchar[0] == 23); + + if (littleendian) + { + const Babl *f32 = babl_format_new ( + "name", "cairo-ARGB32", + "doc", "endianness adaptive native cairo format with alpha", + babl_model ("R'aG'aB'aA"), + babl_type ("u8"), + babl_component ("B'a"), + babl_component ("G'a"), + babl_component ("R'a"), + babl_component ("A"), + NULL + ); + + const Babl *f24 = babl_format_new ( + "name", "cairo-RGB24", + "doc", "endianness adaptive native cairo format without alpha", + babl_model ("R'G'B'"), + babl_type ("u8"), + babl_component ("B'"), + babl_component ("G'"), + babl_component ("R'"), + babl_component ("PAD"), + NULL + ); + + babl_conversion_new (f32, babl_format ("R'aG'aB'aA float"), "linear", + conv_cairo32_rgbAF_le, NULL); + + + babl_conversion_new (f32, babl_format ("R'aG'aB'aA u8"), "linear", + conv_cairo32_rgbA8_le, NULL); + + babl_conversion_new (f32, babl_format ("R'G'B'A u8"), "linear", + conv_cairo32_rgba8_le, NULL); + + + babl_conversion_new (f32, babl_format ("R'G'B'A float"), "linear", + conv_cairo32_rgbaF_le, NULL); + + babl_conversion_new (f24, f32, "linear", + conv_cairo24_cairo32_le, NULL); + + babl_conversion_new (babl_format ("R'aG'aB'aA u8"), f32, "linear", + conv_rgbA8_cairo32_le, NULL); + + babl_conversion_new (babl_format ("R'G'B'A u8"), f32, "linear", + conv_rgba8_cairo32_le, NULL); + + + babl_conversion_new (babl_format ("R'G'B' u8"), f32, "linear", + conv_rgb8_cairo32_le, NULL); + + babl_conversion_new (babl_format ("Y'A u8"), f32, "linear", + conv_yA8_cairo32_le, NULL); + babl_conversion_new (babl_format ("Y'A u16"), f32, "linear", + conv_yA16_cairo32_le, NULL); + + babl_conversion_new (babl_format ("Y' u8"), f32, "linear", + conv_y8_cairo32_le, NULL); + babl_conversion_new (babl_format ("Y' u16"), f32, "linear", + conv_y16_cairo32_le, NULL); + + babl_conversion_new (babl_format ("RGBA float"), f32, "linear", + conv_rgbafloat_cairo32_le, NULL); + babl_conversion_new (babl_format ("YA float"), f32, "linear", + conv_yafloat_cairo32_le, NULL); + babl_conversion_new (babl_format ("Y'A float"), f32, "linear", + conv_yafloat_nl_cairo32_le, NULL); + + babl_conversion_new (babl_format ("R'aG'aB'aA float"), f32, "linear", + conv_rgbA_gamma_float_cairo32_le, NULL); + + babl_conversion_new (babl_format ("R'G'B'A u8"), f24, "linear", + conv_rgba8_cairo24_le, NULL); + babl_conversion_new (babl_format ("R'G'B' u8"), f24, "linear", + conv_rgb8_cairo24_le, NULL); + } + else + { + babl_format_new ( + "name", "cairo-ARGB32", + "doc", "endianness adaptive native cairo format with alpha", + babl_model ("R'aG'aB'aA"), + babl_type ("u8"), + babl_component ("A"), + babl_component ("R'a"), + babl_component ("G'a"), + babl_component ("B'a"), + NULL + ); + babl_format_new ( + "name", "cairo-RGB24", + "doc", "endianness adaptive native cairo format without alpha", + babl_model ("R'G'B'"), + babl_type ("u8"), + babl_component ("PAD"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + NULL + ); + + /* formats are registered - but no fast paths, this will be slow */ + } + babl_format_new ( + "name", "cairo-A8", + babl_model ("YA"), + babl_type ("u8"), + babl_component ("A"), + NULL + ); + + + /* formats that distribute different subset of the additive mixing variants + * of CMYK producing two syntetic RGB formats we run in parallel to derive + * a 4 instead of 3 component result, the same method could be used to + * extend processing/drawing with cairo to spectral data. + */ + if (littleendian) + { + babl_format_new ("name", "cairo-ACMK32", + "doc", "3 component CMYK subset format, to be used to two-pass CMYK processing/rendering with cairo.", + babl_model ("camayakaA"), + babl_type ("u8"), + babl_component ("ka"), + babl_component ("ma"), + babl_component ("ca"), + babl_component ("A"), + NULL); + babl_format_new ("name", "cairo-ACYK32", + "doc", "3 component CMYK subset format, to be used to two-pass CMYK processing/rendering with cairo.", + babl_model ("camayakaA"), + babl_type ("u8"), + babl_component ("ka"), + babl_component ("ya"), + babl_component ("ca"), + babl_component ("A"), + NULL); + } + else + { + babl_format_new ("name", "cairo-ACMK32", + "doc", "3 component CMYK subset format, to be used to two-pass CMYK processing/rendering with cairo.", + babl_model ("camayakaA"), + babl_type ("u8"), + babl_component ("A"), + babl_component ("ca"), + babl_component ("ma"), + babl_component ("ka"), + NULL); + babl_format_new ("name", "cairo-ACYK32", + "doc", "3 component CMYK subset format, to be used to two-pass CMYK processing/rendering with cairo.", + babl_model ("camayakaA"), + babl_type ("u8"), + babl_component ("A"), + babl_component ("ca"), + babl_component ("ya"), + babl_component ("ka"), + NULL); + } + + /* companion subset formats for setting pango u16 RGB color values from cmykA + * */ + babl_format_new ("name", "cykA u16", + "doc", "3 component CMYK subset format, to be used to two-pass CMYK processing/rendering with pango.", + babl_model ("cmykA"), + babl_type ("u16"), + babl_component ("cyan"), + babl_component ("yellow"), + babl_component ("key"), + babl_component ("A"), + NULL); + babl_format_new ("name", "cmkA u16", + "doc", "3 component CMYK subset format, to be used to two-pass CMYK processing/rendering with pango.", + babl_model ("cmykA"), + babl_type ("u16"), + babl_component ("cyan"), + babl_component ("magenta"), + babl_component ("key"), + babl_component ("A"), + NULL); + + + + return 0; +} diff --git a/extensions/double.c b/extensions/double.c new file mode 100644 index 0000000..fe29cd9 --- /dev/null +++ b/extensions/double.c @@ -0,0 +1,293 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2012, Øyvind Kolås + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" + +#include +#include + +#include "babl-internal.h" +#include "babl-cpuaccel.h" +#include "extensions/util.h" +#include "base/util.h" + + +static void +conv_rgbaD_linear_rgbAD_gamma (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + const Babl **trc = (void*)space->space.trc; + + double *fsrc = (double *) src; + double *fdst = (double *) dst; + int n = samples; + + while (n--) + { + double alpha = fsrc[3]; + double used_alpha = babl_epsilon_for_zero (alpha); + *fdst++ = babl_trc_from_linear (trc[0], *fsrc++) * used_alpha; + *fdst++ = babl_trc_from_linear (trc[1], *fsrc++) * used_alpha; + *fdst++ = babl_trc_from_linear (trc[2], *fsrc++) * used_alpha; + *fdst++ = alpha; + fsrc++; + } +} + +static void +conv_rgbAD_linear_rgbAD_gamma (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + const Babl **trc = (void*)space->space.trc; + + double *fsrc = (double *) src; + double *fdst = (double *) dst; + int n = samples; + + while (n--) + { + double alpha = fsrc[3]; + if (alpha == 0.0) + { + *fdst++ = 0.0; + *fdst++ = 0.0; + *fdst++ = 0.0; + *fdst++ = 0.0; + fsrc+=4; + } + else + { + double alpha_recip = 1.0 / alpha; + *fdst++ = babl_trc_from_linear (trc[0], *fsrc++ * alpha_recip) * alpha; + *fdst++ = babl_trc_from_linear (trc[1], *fsrc++ * alpha_recip) * alpha; + *fdst++ = babl_trc_from_linear (trc[2], *fsrc++ * alpha_recip) * alpha; + *fdst++ = *fsrc++; + } + } +} + +static void +conv_rgbaD_linear_rgbaD_gamma (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + const Babl **trc = (void*)space->space.trc; + + double *fsrc = (double *) src; + double *fdst = (double *) dst; + int n = samples; + + while (n--) + { + *fdst++ = babl_trc_from_linear (trc[0], *fsrc++); + *fdst++ = babl_trc_from_linear (trc[1], *fsrc++); + *fdst++ = babl_trc_from_linear (trc[2], *fsrc++); + *fdst++ = *fsrc++; + } +} + +#define conv_rgbaD_linear_rgbD_linear conv_rgbaD_gamma_rgbD_gamma + +static void +conv_rgbaD_linear_rgbD_linear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + double *fsrc = (double *) src; + double *fdst = (double *) dst; + int n = samples; + + while (n--) + { + *fdst++ = *fsrc++; + *fdst++ = *fsrc++; + *fdst++ = *fsrc++; + fsrc++; + } +} + + +static void +conv_rgbD_linear_rgbD_gamma (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + const Babl **trc = (void*)space->space.trc; + double *fsrc = (double *) src; + double *fdst = (double *) dst; + int n = samples; + + while (n--) + { + *fdst++ = babl_trc_from_linear (trc[0], *fsrc++); + *fdst++ = babl_trc_from_linear (trc[1], *fsrc++); + *fdst++ = babl_trc_from_linear (trc[2], *fsrc++); + } +} + + +static void +conv_rgbaD_gamma_rgbaD_linear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + const Babl **trc = (void*)space->space.trc; + double *fsrc = (double *) src; + double *fdst = (double *) dst; + int n = samples; + + while (n--) + { + *fdst++ = babl_trc_to_linear (trc[0], *fsrc++); + *fdst++ = babl_trc_to_linear (trc[1], *fsrc++); + *fdst++ = babl_trc_to_linear (trc[2], *fsrc++); + *fdst++ = *fsrc++; + } +} + +static void +conv_rgbD_gamma_rgbD_linear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + const Babl **trc = (void*)space->space.trc; + double *fsrc = (double *) src; + double *fdst = (double *) dst; + int n = samples; + + while (n--) + { + *fdst++ = babl_trc_to_linear (trc[0], *fsrc++); + *fdst++ = babl_trc_to_linear (trc[1], *fsrc++); + *fdst++ = babl_trc_to_linear (trc[2], *fsrc++); + } +} + + +static void +conv_rgbD_linear_rgbaD_linear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + const Babl **trc = (void*)space->space.trc; + double *fsrc = (double *) src; + double *fdst = (double *) dst; + int n = samples; + + while (n--) + { + *fdst++ = babl_trc_to_linear (trc[0], *fsrc++); + *fdst++ = babl_trc_to_linear (trc[1], *fsrc++); + *fdst++ = babl_trc_to_linear (trc[2], *fsrc++); + *fdst++ = 1.0; + } +} + + +#define conv_rgbD_gamma_rgbaD_gamma conv_rgbD_linear_rgbaD_linear + +#define o(src, dst) \ + babl_conversion_new (src, dst, "linear", conv_ ## src ## _ ## dst, NULL) + +int init (void); + +int +init (void) +{ + const Babl *rgbaD_linear = babl_format_new ( + babl_model ("RGBA"), + babl_type ("double"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + babl_component ("A"), + NULL); + const Babl *rgbAD_linear = babl_format_new ( + babl_model ("RaGaBaA"), + babl_type ("double"), + babl_component ("Ra"), + babl_component ("Ga"), + babl_component ("Ba"), + babl_component ("A"), + NULL); + const Babl *rgbaD_gamma = babl_format_new ( + babl_model ("R'G'B'A"), + babl_type ("double"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + babl_component ("A"), + NULL); + const Babl *rgbAD_gamma = babl_format_new ( + babl_model ("R'aG'aB'aA"), + babl_type ("double"), + babl_component ("R'a"), + babl_component ("G'a"), + babl_component ("B'a"), + babl_component ("A"), + NULL); + const Babl *rgbD_linear = babl_format_new ( + babl_model ("RGB"), + babl_type ("double"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + NULL); + const Babl *rgbD_gamma = babl_format_new ( + babl_model ("R'G'B'"), + babl_type ("double"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + NULL); + + o (rgbAD_linear, rgbAD_gamma); + o (rgbaD_linear, rgbAD_gamma); + o (rgbaD_linear, rgbaD_gamma); + o (rgbaD_gamma, rgbaD_linear); + o (rgbD_linear, rgbD_gamma); + o (rgbD_gamma, rgbD_linear); + o (rgbaD_linear, rgbD_linear); + o (rgbaD_gamma, rgbD_gamma); + + + o (rgbD_linear, rgbaD_linear); + o (rgbD_gamma, rgbaD_gamma); + o (rgbaD_linear, rgbD_linear); + o (rgbaD_gamma, rgbD_gamma); + + return 0; +} + diff --git a/extensions/fast-float.c b/extensions/fast-float.c new file mode 100644 index 0000000..8730046 --- /dev/null +++ b/extensions/fast-float.c @@ -0,0 +1,727 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2012, Øyvind Kolås + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" + +#include +#include + +#include "babl.h" +#include "babl-cpuaccel.h" +#include "extensions/util.h" +#include "base/util.h" + +#define LSHIFT 4 + +typedef float (* BablLookupFunction) (float value, + void *data); +#define babl_LOOKUP_MAX_ENTRIES (819200) + +typedef struct BablLookup +{ + BablLookupFunction function; + void *data; + int shift; + uint32_t positive_min, positive_max, negative_min, negative_max; + uint32_t bitmask[babl_LOOKUP_MAX_ENTRIES/32]; + int entries; + float table[]; +} BablLookup; + + +static BablLookup *babl_lookup_new (BablLookupFunction function, + void * data, + float start, + float end, + float precision); +#if 0 +static void babl_lookup_free (BablLookup *lookup); +#endif + +#include + +static inline float +babl_lookup (BablLookup *lookup, + float number) +{ + union { float f; uint32_t i; } u; + union { float f; uint32_t i; } ub; + union { float f; uint32_t i; } ua; + + uint32_t i; + float dx = 0.0; + + u.f = number; + i = (u.i << LSHIFT ) >> lookup->shift; + + if (i > lookup->positive_min && i < lookup->positive_max) + { + ua.i = ((i) << lookup->shift) >> LSHIFT; + ub.i = ((i+ 1) << lookup->shift) >> LSHIFT; + + i = i - lookup->positive_min; + } + else if (i > lookup->negative_min && i < lookup->negative_max) + { + + ua.i = ((i) << lookup->shift) >> LSHIFT; + ub.i = ((i+ 1) << lookup->shift) >> LSHIFT; + + i = i - lookup->negative_min + (lookup->positive_max - lookup->positive_min); + } + else + { + return lookup->function (number, lookup->data); + } + + { + uint32_t bm =u.i & 0b11110000000000000000000000000000; + ua.i |= bm; + ub.i |= bm; + } + dx = (u.f-ua.f) / (ub.f - ua.f); + + { + + if (!(lookup->bitmask[i/32] & (1UL<<(i & 31)))) + { + lookup->table[i]= lookup->function (ua.f, lookup->data); + lookup->bitmask[i/32] |= (1UL<<(i & 31)); + } + i++; + if (i< lookup->entries-2) + { + if (!(lookup->bitmask[i/32] & (1UL<<(i & 31)))) + { + lookup->table[i]= lookup->function (ub.f, lookup->data); + lookup->bitmask[i/32] |= (1UL<<(i & 31)); + } + + return lookup->table[i-1] * (1.0f-dx) + + lookup->table[i] * (dx); + } + else + { + return lookup->table[i-1]; + } + } +} + +static BablLookup * +babl_lookup_new (BablLookupFunction function, + void * data, + float start, + float end, + float precision) +{ + BablLookup *lookup; + union + { + float f; + uint32_t i; + } u; + int positive_min, positive_max, negative_min, negative_max; + int shift; + + /* normalize input parameters */ + if (start > end) + { /* swap */ + u.f = start; + start = end; + end = u.f; + } + + if (precision <= 0.000005) shift = 0; /* checked for later */ + else if (precision <= 0.000010) shift = 8; + else if (precision <= 0.000020) shift = 9; + else if (precision <= 0.000040) shift = 10; + else if (precision <= 0.000081) shift = 11; + else if (precision <= 0.000161) shift = 12; + else if (precision <= 0.000200) shift = 13; + else if (precision <= 0.000324) shift = 14; + else if (precision <= 0.000649) shift = 15; + else shift = 16; /* a bit better than 8bit sRGB quality */ + + + /* Adjust slightly away from 0.0, saving many entries close to 0, this + * causes lookups very close to zero to be passed directly to the + * function instead. + */ + if (start == 0.0) + start = precision; + if (end == 0.0) + end = -precision; + + /* Compute start and */ + + if (start < 0.0 || end < 0.0) + { + if (end < 0.0) + { + u.f = start; + positive_max = (u.i << LSHIFT) >> shift; + u.f = end; + positive_min = (u.i << LSHIFT) >> shift; + negative_min = positive_max; + negative_max = positive_max; + } + else + { + u.f = 0 - precision; + positive_min = (u.i << LSHIFT) >> shift; + u.f = start; + positive_max = (u.i << LSHIFT) >> shift; + + u.f = 0 + precision; + negative_min = (u.i << LSHIFT) >> shift; + u.f = end; + negative_max = (u.i << LSHIFT) >> shift; + } + } + else + { + u.f = start; + positive_min = (u.i << LSHIFT) >> shift; + u.f = end; + positive_max = (u.i << LSHIFT) >> shift; + negative_min = positive_max; + negative_max = positive_max; + } + + if (shift == 0) /* short circuit, do not use ranges */ + { + positive_min = positive_max = negative_min = negative_max = 0; + } + + if ((positive_max-positive_min) + (negative_max-negative_min) > babl_LOOKUP_MAX_ENTRIES) + { + /* Reduce the size of the cache tables to fit within the bittable + * budget (the maximum allocation is around 2.18mb of memory + */ + + int diff = (positive_max-positive_min) + (negative_max-negative_min) - babl_LOOKUP_MAX_ENTRIES; + + if (negative_max - negative_min > 0) + { + if (negative_max - negative_min >= diff) + { + negative_max -= diff; + diff = 0; + } + else + { + diff -= negative_max - negative_min; + negative_max = negative_min; + } + } + if (diff) + positive_max-=diff; + } + + lookup = calloc (sizeof (BablLookup) + sizeof (float) * + ((positive_max-positive_min)+ + (negative_max-negative_min)), 1); + + lookup->positive_min = positive_min; + lookup->positive_max = positive_max; + lookup->negative_min = negative_min; + lookup->negative_max = negative_max; + lookup->shift = shift; + lookup->function = function; + lookup->data = data; + + lookup->entries = (positive_max-positive_min)+ + (negative_max-negative_min); + + return lookup; +} + +static BablLookup *fast_pow = NULL; + +static inline float core_lookup (float val, void *userdata) +{ + return babl_linear_to_gamma_2_2f (val); +} + +static float +linear_to_gamma_2_2_lut (float val) +{ + return babl_lookup (fast_pow, val); +} + +static BablLookup *fast_rpow = NULL; + +static inline float core_rlookup (float val, void *userdata) +{ + return babl_gamma_2_2_to_linearf (val); +} + +static float +gamma_2_2_to_linear_lut (float val) +{ + return babl_lookup (fast_rpow, val); +} + +#if 0 +static void +babl_lookup_free (BablLookup *lookup) +{ + free (lookup); +} +#endif + +static void +conv_rgbaF_linear_rgbAF_gamma (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + float *fsrc = (float *) src; + float *fdst = (float *) dst; + int n = samples; + + while (n--) + { + float red = *fsrc++; + float green = *fsrc++; + float blue = *fsrc++; + float alpha = *fsrc++; + if (alpha == 1.0) + { + *fdst++ = linear_to_gamma_2_2_lut (red); + *fdst++ = linear_to_gamma_2_2_lut (green); + *fdst++ = linear_to_gamma_2_2_lut (blue); + *fdst++ = alpha; + } + else + { + float used_alpha = babl_epsilon_for_zero_float (alpha); + *fdst++ = linear_to_gamma_2_2_lut (red) * used_alpha; + *fdst++ = linear_to_gamma_2_2_lut (green) * used_alpha; + *fdst++ = linear_to_gamma_2_2_lut (blue) * used_alpha; + *fdst++ = alpha; + } + } +} + + + +static void +conv_rgbaF_linear_rgba8_gamma (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + float *fsrc = (float *) src; + uint8_t *cdst = (uint8_t *) dst; + int n = samples; + + while (n--) + { + float red = *fsrc++; + float green = *fsrc++; + float blue = *fsrc++; + float alpha = *fsrc++; + if (alpha <= 0) /* XXX: we need to drop alpha!! ? */ + { + *cdst++ = 0; + *cdst++ = 0; + *cdst++ = 0; + *cdst++ = 0; + } + else + { + int val = linear_to_gamma_2_2_lut (red) * 0xff + 0.5f; + *cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val; + val = linear_to_gamma_2_2_lut (green) * 0xff + 0.5f; + *cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val; + val = linear_to_gamma_2_2_lut (blue) * 0xff + 0.5f; + *cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val; + val = alpha * 0xff + 0.5; + *cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val; + } + } +} + +static void +conv_rgbaF_linear_rgbA8_gamma (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + float *fsrc = (float *) src; + uint8_t *cdst = (uint8_t *) dst; + int n = samples; + + while (n--) + { + float red = *fsrc++; + float green = *fsrc++; + float blue = *fsrc++; + float alpha = *fsrc++; + if (alpha >= 1.0) + { + int val = linear_to_gamma_2_2_lut (red) * 0xff + 0.5f; + *cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val; + val = linear_to_gamma_2_2_lut (green) * 0xff + 0.5f; + *cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val; + val = linear_to_gamma_2_2_lut (blue) * 0xff + 0.5f; + *cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val; + *cdst++ = 0xff; + } + else + { + float balpha = alpha * 0xff; + int val = linear_to_gamma_2_2_lut (red) * balpha + 0.5f; + *cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val; + val = linear_to_gamma_2_2_lut (green) * balpha + 0.5f; + *cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val; + val = linear_to_gamma_2_2_lut (blue) * balpha + 0.5f; + *cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val; + *cdst++ = balpha + 0.5f; + } + } +} + +static void +conv_yaF_linear_rgbA8_gamma (const Babl *conversion,unsigned char *src, + unsigned char *dst, + long samples) +{ + float *fsrc = (float *) src; + uint8_t *cdst = (uint8_t *) dst; + int n = samples; + + while (n--) + { + float gray = *fsrc++; + float alpha = *fsrc++; + if (alpha >= 1.0) + { + int val = linear_to_gamma_2_2_lut (gray) * 0xff + 0.5f; + *cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val; + *cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val; + *cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val; + *cdst++ = 0xff; + } + else if (alpha <= 0.0) + { + *((uint32_t*)(cdst))=0; + cdst+=4; + } + else + { + float balpha = alpha * 0xff; + int val = linear_to_gamma_2_2_lut (gray) * balpha + 0.5f; + *cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val; + *cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val; + *cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val; + *cdst++ = balpha + 0.5f; + } + } +} + + + +static void +conv_rgbaF_linear_rgbA8_gamma_cairo (const Babl *conversion,unsigned char *src, + unsigned char *dst, + long samples) +{ + float *fsrc = (float *) src; + unsigned char *cdst = (unsigned char *) dst; + int n = samples; + + while (n--) + { + float red = *fsrc++; + float green = *fsrc++; + float blue = *fsrc++; + float alpha = *fsrc++; + if (alpha >= 1.0) + { + int val = linear_to_gamma_2_2_lut (blue) * 0xff + 0.5f; + *cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val; + val = linear_to_gamma_2_2_lut (green) * 0xff + 0.5f; + *cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val; + val = linear_to_gamma_2_2_lut (red) * 0xff + 0.5f; + *cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val; + *cdst++ = 0xff; + } + else + { + float balpha = alpha * 0xff; + int val = linear_to_gamma_2_2_lut (blue) * balpha + 0.5f; + *cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val; + val = linear_to_gamma_2_2_lut (green) * balpha + 0.5f; + *cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val; + val = linear_to_gamma_2_2_lut (red) * balpha + 0.5f; + *cdst++ = val >= 0xff ? 0xff : val <= 0 ? 0 : val; + *cdst++ = balpha + 0.5f; + } + } +} + +static void +conv_rgbAF_linear_rgbAF_gamma (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + float *fsrc = (float *) src; + float *fdst = (float *) dst; + int n = samples; + + while (n--) + { + float red = *fsrc++; + float green = *fsrc++; + float blue = *fsrc++; + float alpha = *fsrc++; + + if (alpha == 1.0) + { + *fdst++ = linear_to_gamma_2_2_lut (red); + *fdst++ = linear_to_gamma_2_2_lut (green); + *fdst++ = linear_to_gamma_2_2_lut (blue); + *fdst++ = *fsrc++; + } + else + { + float alpha_recip = 1.0 / alpha; + *fdst++ = linear_to_gamma_2_2_lut (red * alpha_recip) * alpha; + *fdst++ = linear_to_gamma_2_2_lut (green * alpha_recip) * alpha; + *fdst++ = linear_to_gamma_2_2_lut (blue * alpha_recip) * alpha; + *fdst++ = alpha; + } + } +} + +static void +conv_rgbaF_linear_rgbaF_gamma (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + float *fsrc = (float *) src; + float *fdst = (float *) dst; + int n = samples; + + while (n--) + { + *fdst++ = linear_to_gamma_2_2_lut (*fsrc++); + *fdst++ = linear_to_gamma_2_2_lut (*fsrc++); + *fdst++ = linear_to_gamma_2_2_lut (*fsrc++); + *fdst++ = *fsrc++; + } +} + +static void +conv_rgbF_linear_rgbF_gamma (const Babl *conversion,unsigned char *src, + unsigned char *dst, + long samples) +{ + float *fsrc = (float *) src; + float *fdst = (float *) dst; + int n = samples; + + while (n--) + { + *fdst++ = linear_to_gamma_2_2_lut (*fsrc++); + *fdst++ = linear_to_gamma_2_2_lut (*fsrc++); + *fdst++ = linear_to_gamma_2_2_lut (*fsrc++); + } +} + + +static void +conv_rgbaF_gamma_rgbaF_linear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + float *fsrc = (float *) src; + float *fdst = (float *) dst; + int n = samples; + + while (n--) + { + *fdst++ = gamma_2_2_to_linear_lut (*fsrc++); + *fdst++ = gamma_2_2_to_linear_lut (*fsrc++); + *fdst++ = gamma_2_2_to_linear_lut (*fsrc++); + *fdst++ = *fsrc++; + } +} + +static void +conv_rgbF_gamma_rgbF_linear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + float *fsrc = (float *) src; + float *fdst = (float *) dst; + int n = samples; + + while (n--) + { + *fdst++ = gamma_2_2_to_linear_lut (*fsrc++); + *fdst++ = gamma_2_2_to_linear_lut (*fsrc++); + *fdst++ = gamma_2_2_to_linear_lut (*fsrc++); + } +} + +#define o(src, dst) \ + babl_conversion_new (src, dst, "linear", conv_ ## src ## _ ## dst, NULL) + +int init (void); + +int +init (void) +{ + const Babl *yaF_linear = babl_format_new ( + babl_model ("YA"), + babl_type ("float"), + babl_component ("Y"), + babl_component ("A"), + NULL); + + const Babl *rgbaF_linear = babl_format_new ( + babl_model ("RGBA"), + babl_type ("float"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + babl_component ("A"), + NULL); + const Babl *rgbAF_linear = babl_format_new ( + babl_model ("RaGaBaA"), + babl_type ("float"), + babl_component ("Ra"), + babl_component ("Ga"), + babl_component ("Ba"), + babl_component ("A"), + NULL); + const Babl *rgbaF_gamma = babl_format_new ( + babl_model ("R'G'B'A"), + babl_type ("float"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + babl_component ("A"), + NULL); + const Babl *rgbAF_gamma = babl_format_new ( + babl_model ("R'aG'aB'aA"), + babl_type ("float"), + babl_component ("R'a"), + babl_component ("G'a"), + babl_component ("B'a"), + babl_component ("A"), + NULL); + + const Babl *rgbA8_gamma = babl_format_new ( + babl_model ("R'aG'aB'aA"), + babl_type ("u8"), + babl_component ("R'a"), + babl_component ("G'a"), + babl_component ("B'a"), + babl_component ("A"), + NULL); + + const Babl *rgba8_gamma = babl_format_new ( + babl_model ("R'G'B'A"), + babl_type ("u8"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + babl_component ("A"), + NULL); + + const Babl *rgbF_linear = babl_format_new ( + babl_model ("RGB"), + babl_type ("float"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + NULL); + const Babl *rgbF_gamma = babl_format_new ( + babl_model ("R'G'B'"), + babl_type ("float"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + NULL); + + return 0; // XXX: the fast paths registered here doesn't correctly + // clamp negative values - disabling for now + { + float f; + float a; + + /* tweaking the precision - does impact speed.. */ + fast_pow = babl_lookup_new (core_lookup, NULL, 0.0, 1.0, 0.000199); + fast_rpow = babl_lookup_new (core_rlookup, NULL, 0.0, 1.0, 0.000250); + + for (f = 0.0; f < 1.0; f+= 0.0000001) + { + a = linear_to_gamma_2_2_lut (f); + a = gamma_2_2_to_linear_lut (f); + } + if (a < -10) + f = 2; + + } + + + { + const Babl *f32 = babl_format_new ( + "name", "cairo-ARGB32", + babl_model ("R'aG'aB'aA"), + babl_type ("u8"), + babl_component ("B'a"), + babl_component ("G'a"), + babl_component ("R'a"), + babl_component ("A"), + NULL + ); + + + babl_conversion_new (rgbaF_linear, f32, "linear", conv_rgbaF_linear_rgbA8_gamma_cairo, NULL); + } + + o (rgbaF_linear, rgbA8_gamma); + o (rgbAF_linear, rgbAF_gamma); + o (rgbaF_linear, rgbAF_gamma); + o (rgbaF_linear, rgbaF_gamma); + o (rgbaF_linear, rgba8_gamma); + o (rgbaF_gamma, rgbaF_linear); + o (rgbF_linear, rgbF_gamma); + o (rgbF_gamma, rgbF_linear); + o (yaF_linear, rgbA8_gamma); + return 0; +} + +void destroy (void); + +void +destroy (void) +{ + free (fast_rpow); + free (fast_pow); +} + diff --git a/extensions/float.c b/extensions/float.c new file mode 100644 index 0000000..cd34421 --- /dev/null +++ b/extensions/float.c @@ -0,0 +1,627 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2012, Øyvind Kolås + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" + +#include +#include + +#include "babl-internal.h" +#include "babl-cpuaccel.h" +#include "extensions/util.h" +#include "base/util.h" + +static const Babl *trc_srgb = NULL; + + +static void +conv_yaF_linear_yAF_linear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + float *fsrc = (float *) src; + float *fdst = (float *) dst; + int n = samples; + + while (n--) + { + float alpha = fsrc[1]; + float used_alpha = babl_epsilon_for_zero_float (alpha); + *fdst++ = (*fsrc++) * used_alpha; + *fdst++ = alpha; + fsrc++; + } +} + + +static void +conv_yAF_linear_yaF_linear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + float *fsrc = (float *) src; + float *fdst = (float *) dst; + int n = samples; + + while (n--) + { + float alpha = fsrc[1]; + float alpha_reciprocal = 1.0f/babl_epsilon_for_zero_float (alpha); + *fdst++ = (*fsrc++) * alpha_reciprocal; + *fdst++ = alpha; + fsrc++; + } +} + + +static void +conv_yaF_linear_yAF_nonlinear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + const Babl **trc = (void*)space->space.trc; + + float *fsrc = (float *) src; + float *fdst = (float *) dst; + int n = samples; + + while (n--) + { + float alpha = fsrc[1]; + float used_alpha = babl_epsilon_for_zero_float (alpha); + *fdst++ = babl_trc_from_linear (trc[0], *fsrc++) * used_alpha; + *fdst++ = alpha; + fsrc++; + } +} + +static void +conv_rgbaF_linear_rgbAF_nonlinear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + const Babl **trc = (void*)space->space.trc; + + float *fsrc = (float *) src; + float *fdst = (float *) dst; + int n = samples; + + while (n--) + { + float alpha = fsrc[3]; + float used_alpha = babl_epsilon_for_zero_float (alpha); + *fdst++ = babl_trc_from_linear (trc[0], *fsrc++) * used_alpha; + *fdst++ = babl_trc_from_linear (trc[1], *fsrc++) * used_alpha; + *fdst++ = babl_trc_from_linear (trc[2], *fsrc++) * used_alpha; + *fdst++ = alpha; + fsrc++; + } +} + +static void +conv_rgbaF_linear_rgbAF_perceptual (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + float *fsrc = (float *) src; + float *fdst = (float *) dst; + int n = samples; + + while (n--) + { + float alpha = fsrc[3]; + float used_alpha = babl_epsilon_for_zero (alpha); + *fdst++ = babl_trc_from_linear (trc_srgb, *fsrc++) * used_alpha; + *fdst++ = babl_trc_from_linear (trc_srgb, *fsrc++) * used_alpha; + *fdst++ = babl_trc_from_linear (trc_srgb, *fsrc++) * used_alpha; + *fdst++ = alpha; + fsrc++; + } +} + + +static void +conv_rgbAF_linear_rgbAF_nonlinear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + const Babl **trc = (void*)space->space.trc; + + float *fsrc = (float *) src; + float *fdst = (float *) dst; + int n = samples; + + while (n--) + { + float alpha = fsrc[3]; + if (alpha == 0) + { + *fdst++ = 0.0; + *fdst++ = 0.0; + *fdst++ = 0.0; + *fdst++ = 0.0; + fsrc+=4; + } + else + { + float alpha_recip = 1.0 / alpha; + *fdst++ = babl_trc_from_linear (trc[0], *fsrc++ * alpha_recip) * alpha; + *fdst++ = babl_trc_from_linear (trc[1], *fsrc++ * alpha_recip) * alpha; + *fdst++ = babl_trc_from_linear (trc[2], *fsrc++ * alpha_recip) * alpha; + *fdst++ = *fsrc++; + } + } +} + + +static void +conv_yAF_linear_yAF_nonlinear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + const Babl **trc = (void*)space->space.trc; + + float *fsrc = (float *) src; + float *fdst = (float *) dst; + int n = samples; + + while (n--) + { + float alpha = fsrc[1]; + if (alpha == 0) + { + *fdst++ = 0.0; + *fdst++ = 0.0; + *fdst++ = 0.0; + *fdst++ = 0.0; + fsrc+=4; + } + else + { + float alpha_recip = 1.0 / alpha; + *fdst++ = babl_trc_from_linear (trc[0], *fsrc++ * alpha_recip) * alpha; + *fdst++ = *fsrc++; + } + } +} + + + +static void +conv_rgbAF_linear_rgbAF_perceptual (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + + float *fsrc = (float *) src; + float *fdst = (float *) dst; + int n = samples; + + while (n--) + { + float alpha = fsrc[3]; + if (alpha == 0.0f) + { + *fdst++ = 0.0f; + *fdst++ = 0.0f; + *fdst++ = 0.0f; + *fdst++ = 0.0f; + fsrc+=4; + } + else + { + float alpha_recip = 1.0f / alpha; + *fdst++ = babl_trc_from_linear (trc_srgb, *fsrc++ * alpha_recip) * alpha; + *fdst++ = babl_trc_from_linear (trc_srgb, *fsrc++ * alpha_recip) * alpha; + *fdst++ = babl_trc_from_linear (trc_srgb, *fsrc++ * alpha_recip) * alpha; + *fdst++ = *fsrc++; + } + } +} + + +static void +conv_yaF_linear_yaF_nonlinear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + const Babl **trc = (void*)space->space.trc; + + float *fsrc = (float *) src; + float *fdst = (float *) dst; + int n = samples; + + while (n--) + { + *fdst++ = babl_trc_from_linear (trc[0], *fsrc++); + *fdst++ = *fsrc++; + } +} + +static void +conv_rgbaF_linear_rgbaF_nonlinear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + const Babl **trc = (void*)space->space.trc; + + float *fsrc = (float *) src; + float *fdst = (float *) dst; + int n = samples; + + while (n--) + { + *fdst++ = babl_trc_from_linear (trc[0], *fsrc++); + *fdst++ = babl_trc_from_linear (trc[1], *fsrc++); + *fdst++ = babl_trc_from_linear (trc[2], *fsrc++); + *fdst++ = *fsrc++; + } +} + +static void +conv_rgbaF_linear_rgbaF_perceptual (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + float *fsrc = (float *) src; + float *fdst = (float *) dst; + int n = samples; + + while (n--) + { + *fdst++ = babl_trc_from_linear (trc_srgb, *fsrc++); + *fdst++ = babl_trc_from_linear (trc_srgb, *fsrc++); + *fdst++ = babl_trc_from_linear (trc_srgb, *fsrc++); + *fdst++ = *fsrc++; + } +} + +static void +conv_yF_linear_yF_nonlinear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + const Babl **trc = (void*)space->space.trc; + float *fsrc = (float *) src; + float *fdst = (float *) dst; + int n = samples; + + while (n--) + { + *fdst++ = babl_trc_from_linear (trc[0], *fsrc++); + } +} + + +static void +conv_rgbF_linear_rgbF_nonlinear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + const Babl **trc = (void*)space->space.trc; + float *fsrc = (float *) src; + float *fdst = (float *) dst; + int n = samples; + + while (n--) + { + *fdst++ = babl_trc_from_linear (trc[0], *fsrc++); + *fdst++ = babl_trc_from_linear (trc[1], *fsrc++); + *fdst++ = babl_trc_from_linear (trc[2], *fsrc++); + } +} + +static void +conv_rgbF_linear_rgbF_perceptual (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + float *fsrc = (float *) src; + float *fdst = (float *) dst; + int n = samples; + + while (n--) + { + *fdst++ = babl_trc_from_linear (trc_srgb, *fsrc++); + *fdst++ = babl_trc_from_linear (trc_srgb, *fsrc++); + *fdst++ = babl_trc_from_linear (trc_srgb, *fsrc++); + } +} + +static void +conv_rgbaF_nonlinear_rgbaF_linear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + const Babl **trc = (void*)space->space.trc; + float *fsrc = (float *) src; + float *fdst = (float *) dst; + int n = samples; + + while (n--) + { + *fdst++ = babl_trc_to_linear (trc[0], *fsrc++); + *fdst++ = babl_trc_to_linear (trc[1], *fsrc++); + *fdst++ = babl_trc_to_linear (trc[2], *fsrc++); + *fdst++ = *fsrc++; + } +} + + +static void +conv_yaF_nonlinear_yaF_linear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + const Babl **trc = (void*)space->space.trc; + float *fsrc = (float *) src; + float *fdst = (float *) dst; + int n = samples; + + while (n--) + { + *fdst++ = babl_trc_to_linear (trc[0], *fsrc++); + *fdst++ = *fsrc++; + } +} + + +static void +conv_rgbaF_perceptual_rgbaF_linear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + float *fsrc = (float *) src; + float *fdst = (float *) dst; + int n = samples; + + while (n--) + { + *fdst++ = babl_trc_to_linear (trc_srgb, *fsrc++); + *fdst++ = babl_trc_to_linear (trc_srgb, *fsrc++); + *fdst++ = babl_trc_to_linear (trc_srgb, *fsrc++); + *fdst++ = *fsrc++; + } +} + + +static void +conv_rgbF_nonlinear_rgbF_linear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + const Babl **trc = (void*)space->space.trc; + float *fsrc = (float *) src; + float *fdst = (float *) dst; + int n = samples; + + while (n--) + { + *fdst++ = babl_trc_to_linear (trc[0], *fsrc++); + *fdst++ = babl_trc_to_linear (trc[1], *fsrc++); + *fdst++ = babl_trc_to_linear (trc[2], *fsrc++); + } +} + + +static void +conv_yF_nonlinear_yF_linear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + const Babl *space = babl_conversion_get_destination_space (conversion); + const Babl **trc = (void*)space->space.trc; + float *fsrc = (float *) src; + float *fdst = (float *) dst; + int n = samples; + + while (n--) + { + *fdst++ = babl_trc_to_linear (trc[0], *fsrc++); + } +} + +static void +conv_rgbF_perceptual_rgbF_linear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + float *fsrc = (float *) src; + float *fdst = (float *) dst; + int n = samples; + + while (n--) + { + *fdst++ = babl_trc_to_linear (trc_srgb, *fsrc++); + *fdst++ = babl_trc_to_linear (trc_srgb, *fsrc++); + *fdst++ = babl_trc_to_linear (trc_srgb, *fsrc++); + } +} + + +#define o(src, dst) \ + babl_conversion_new (src, dst, "linear", conv_ ## src ## _ ## dst, NULL) + +int init (void); + +int +init (void) +{ + const Babl *yaF_linear = babl_format_new ( + babl_model ("YA"), + babl_type ("float"), + babl_component ("Y"), + babl_component ("A"), + NULL); + const Babl *yAF_linear = babl_format_new ( + babl_model ("YaA"), + babl_type ("float"), + babl_component ("Ya"), + babl_component ("A"), + NULL); + const Babl *yaF_nonlinear = babl_format_new ( + babl_model ("Y'A"), + babl_type ("float"), + babl_component ("Y'"), + babl_component ("A"), + NULL); + const Babl *rgbaF_linear = babl_format_new ( + babl_model ("RGBA"), + babl_type ("float"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + babl_component ("A"), + NULL); + const Babl *rgbAF_linear = babl_format_new ( + babl_model ("RaGaBaA"), + babl_type ("float"), + babl_component ("Ra"), + babl_component ("Ga"), + babl_component ("Ba"), + babl_component ("A"), + NULL); + const Babl *rgbaF_nonlinear = babl_format_new ( + babl_model ("R'G'B'A"), + babl_type ("float"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + babl_component ("A"), + NULL); + const Babl *rgbaF_perceptual = babl_format_new ( + babl_model ("R~G~B~A"), + babl_type ("float"), + babl_component ("R~"), + babl_component ("G~"), + babl_component ("B~"), + babl_component ("A"), + NULL); + const Babl *yAF_nonlinear = babl_format_new ( + babl_model ("Y'aA"), + babl_type ("float"), + babl_component ("Y'a"), + babl_component ("A"), + NULL); + const Babl *rgbAF_nonlinear = babl_format_new ( + babl_model ("R'aG'aB'aA"), + babl_type ("float"), + babl_component ("R'a"), + babl_component ("G'a"), + babl_component ("B'a"), + babl_component ("A"), + NULL); + const Babl *rgbAF_perceptual = babl_format_new ( + babl_model ("R~aG~aB~aA"), + babl_type ("float"), + babl_component ("R~a"), + babl_component ("G~a"), + babl_component ("B~a"), + babl_component ("A"), + NULL); + const Babl *yF_linear = babl_format_new ( + babl_model ("Y"), + babl_type ("float"), + babl_component ("Y"), + NULL); + const Babl *yF_nonlinear = babl_format_new ( + babl_model ("Y'"), + babl_type ("float"), + babl_component ("Y'"), + NULL); + const Babl *rgbF_linear = babl_format_new ( + babl_model ("RGB"), + babl_type ("float"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + NULL); + const Babl *rgbF_nonlinear = babl_format_new ( + babl_model ("R'G'B'"), + babl_type ("float"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + NULL); + const Babl *rgbF_perceptual = babl_format_new ( + babl_model ("R~G~B~"), + babl_type ("float"), + babl_component ("R~"), + babl_component ("G~"), + babl_component ("B~"), + NULL); + trc_srgb = babl_trc("sRGB"); + + o (rgbAF_linear, rgbAF_nonlinear); + o (rgbaF_linear, rgbAF_nonlinear); + o (rgbaF_linear, rgbaF_nonlinear); + o (rgbaF_nonlinear, rgbaF_linear); + o (rgbF_linear, rgbF_nonlinear); + o (rgbF_nonlinear, rgbF_linear); + + + o (yaF_linear, yAF_linear); + o (yAF_linear, yaF_linear); + o (yAF_linear, yAF_nonlinear); + o (yaF_linear, yAF_nonlinear); + o (yaF_linear, yaF_nonlinear); + o (yaF_nonlinear, yaF_linear); + o (yF_linear, yF_nonlinear); + o (yF_nonlinear, yF_linear); + + o (rgbAF_linear, rgbAF_perceptual); + o (rgbaF_linear, rgbAF_perceptual); + o (rgbaF_linear, rgbaF_perceptual); + o (rgbaF_perceptual, rgbaF_linear); + o (rgbF_linear, rgbF_perceptual); + o (rgbF_perceptual, rgbF_linear); + + return 0; +} + diff --git a/extensions/gegl-fixups.c b/extensions/gegl-fixups.c new file mode 100644 index 0000000..45888ce --- /dev/null +++ b/extensions/gegl-fixups.c @@ -0,0 +1,625 @@ +/* + * This file was part of gggl, it implements a variety of pixel conversion + * functions that are usable with babl, the file needs more cleanup, but the + * conversion functions that are usable gets used by babl. + * + * GGGL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GGGL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GGGL; if not, see . + * + * Rights are granted to use this shared object in libraries covered by + * LGPL. (exception added, during import into babl CVS.) + * + * Copyright 2003, 2004, 2005, 2007 Øyvind Kolås + */ + +/* + * Implemented according to information read from: + * + * http://www.cinenet.net/~spitzak/conversion/sketches_0265.pdf + * + * initially ignoring any diffusion, to keep the implementation + * smaller, and interchangeable with the non optimized version. + * + * due to ability to be able to relicence gggl under a different + * licence than GPL, I avoided the temptation to look at the + * source files in the same location, in case I was going to + * need this piece of code for projects where GPL compatibility + * was a must. + * + * TODO: error diffusion, + */ + +#include +#include + +#include "config.h" +#include "babl.h" + +#include "base/util.h" +#include "extensions/util.h" + + +/* lookup tables used in conversion */ + +static float table_8_F[1 << 8]; +static float table_8g_F[1 << 8]; +static unsigned char table_F_8[1 << 17]; +static unsigned char table_F_8g[1 << 17]; + +static int table_inited = 0; + +static void +table_init (void) +{ + if (table_inited) + return; + table_inited = 1; + + /* fill tables for conversion from integer to float */ + { + int i; + for (i = 0; i < 1 << 8; i++) + { + float direct = i / 255.0; + table_8_F[i] = direct; + table_8g_F[i] = gamma_2_2_to_linear (direct); + } + } + /* fill tables for conversion from float to integer */ + { + union + { + float f; + uint32_t s; + } u; + u.f = 0.0; + + //u.s[0] = 0; + + for (u.s = 0; u.s < 4294900000U; u.s += 32768) + { + int c; + int cg; + + if (u.f <= 0.0) + { + c = 0; + cg = 0; + } + else + { + c = (u.f * 255.1619) + 0.5; + cg = (linear_to_gamma_2_2 (u.f) * 255.1619) + 0.5; + if (cg > 255) cg = 255; + if (c > 255) c = 255; + } + + table_F_8[(u.s >> 15) & ((1 << 17)-1)] = c; + table_F_8g[(u.s >> 15) & ((1 << 17)-1)] = cg; + } + } +#if 0 + /* fix tables to ensure 1:1 conversions back and forth */ + if (0) + { + int i; + for (i = 0; i < 256; i++) + { + float f; + unsigned short *hi = ((unsigned short *) (void *) &f); + unsigned short *lo = ((unsigned short *) (void *) &f); + + f = table_8_F[i]; + *lo = 0; + table_F_8[*hi] = i; + f = table_8g_F[i]; + *lo = 0; + table_F_8g[*hi] = i; + } + } +#endif +} + +/* function to find the index in table for a float */ +static inline unsigned int +gggl_float_to_index16 (float f) +{ + union + { + float f; + uint32_t s; + } u; + u.f = f; + return (u.s >> 15) & ((1 << 17)-1); +} + +static inline void +conv_F_8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + if (!table_inited) + table_init (); + while (n--) + { + register float f = (*(float *) src); + *(unsigned char *) dst = table_F_8[gggl_float_to_index16 (f)]; + dst += 1; + src += 4; + } +} + + +static inline void +conv_F_8g (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + if (!table_inited) + table_init (); + while (n--) + { + register float f = (*(float *) src); + *(unsigned char *) dst = table_F_8g[gggl_float_to_index16 (f)]; + dst += 1; + src += 4; + } +} + + +static inline void __attribute__((unused)) +conv_8_F (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + if (!table_inited) + table_init (); + while (n--) + { + (*(float *) dst) = table_8_F[*(unsigned char *) src]; + dst += 4; + src += 1; + } +} + + +static void +conv_rgbaF_rgb8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + register float f = (*(float *) src); + *(unsigned char *) dst = table_F_8g[gggl_float_to_index16 (f)]; + src += 4; + dst += 1; + + f = (*(float *) src); + *(unsigned char *) dst = table_F_8g[gggl_float_to_index16 (f)]; + src += 4; + dst += 1; + + f = (*(float *) src); + *(unsigned char *) dst = table_F_8g[gggl_float_to_index16 (f)]; + src += 4; + dst += 1; + + src += 4; + } +} + + +static void __attribute__((unused)) +conv_rgbaF_rgba8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + register float f = (*(float *) src); + *(unsigned char *) dst = table_F_8g[gggl_float_to_index16 (f)]; + src += 4; + dst += 1; + + f = (*(float *) src); + *(unsigned char *) dst = table_F_8g[gggl_float_to_index16 (f)]; + src += 4; + dst += 1; + + f = (*(float *) src); + *(unsigned char *) dst = table_F_8g[gggl_float_to_index16 (f)]; + src += 4; + dst += 1; + + f = (*(float *) src); + *(unsigned char *) dst = table_F_8[gggl_float_to_index16 (f)]; + src += 4; + dst += 1; + } +} + +#define conv_rgbaF_rgbP8 conv_rgbaF_rgba8 + +static void __attribute__((unused)) +conv_rgbF_rgb8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_F_8g (conversion, src, dst, samples * 3); +} + +static void __attribute__((unused)) +conv_gaF_ga8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_F_8 (conversion, src, dst, samples * 2); +} + +#define conv_rgbAF_rgbA8 conv_rgbaF_rgba8 +#define conv_gF_g8 conv_F_8 +#define conv_gAF_gA8 conv_gaF_ga8 + + +static void +conv_rgba8_rgbaF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + (*(float *) dst) = table_8g_F[*(unsigned char *) src]; + dst += 4; + src += 1; + + (*(float *) dst) = table_8g_F[*(unsigned char *) src]; + dst += 4; + src += 1; + + (*(float *) dst) = table_8g_F[*(unsigned char *) src]; + dst += 4; + src += 1; + + (*(float *) dst) = table_8_F[*(unsigned char *) src]; + dst += 4; + src += 1; + } +} + +static void +conv_ga8_rgbaF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + float gray = table_8g_F[*(unsigned char *) src]; + (*(float *) dst) = gray; + dst += 4; + src += 1; + + (*(float *) dst) = gray; + dst += 4; + + (*(float *) dst) = gray; + dst += 4; + + (*(float *) dst) = table_8_F[*(unsigned char *) src]; + dst += 4; + src += 1; + } +} + + +static void +conv_rgb8_rgbaF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + (*(float *) dst) = table_8g_F[*(unsigned char *) src]; + dst += 4; + src += 1; + + (*(float *) dst) = table_8g_F[*(unsigned char *) src]; + dst += 4; + src += 1; + + (*(float *) dst) = table_8g_F[*(unsigned char *) src]; + dst += 4; + src += 1; + + (*(float *) dst) = 1.0; + dst += 4; + } +} + +static void +conv_rgbAF_rgb8 (const Babl *conversion, + unsigned char *srcc, + unsigned char *dstc, + long samples) +{ + float *src = (void *) srcc; + unsigned char *dst = (void *) dstc; + long n = samples; + + while (n--) + { + float alpha = src[3]; + if (alpha == 0.0f) + { + dst[0] = 0.0f; + dst[1] = 0.0f; + dst[2] = 0.0f; + } + else + { + float alpha_recip = 1.0f / alpha; + dst[0] = table_F_8g[gggl_float_to_index16 (src[0] * alpha_recip)]; + dst[1] = table_F_8g[gggl_float_to_index16 (src[1] * alpha_recip)]; + dst[2] = table_F_8g[gggl_float_to_index16 (src[2] * alpha_recip)]; + } + src += 4; + dst += 3; + } +} + +static void +conv_bgrA8_rgba8 (const Babl *conversion, + unsigned char *srcc, + unsigned char *dstc, + long samples) +{ + unsigned char *src = (void *) srcc; + unsigned char *dst = (void *) dstc; + long n = samples; + + while (n--) + { + unsigned char alpha = src[3]; + dst[0] = alpha ? (src[2] * 255 / alpha) : 0; + dst[1] = alpha ? (src[1] * 255 / alpha) : 0; + dst[2] = alpha ? (src[0] * 255 / alpha) : 0; + dst[3] = alpha; + src += 4; + dst += 4; + } +} + +static void +conv_rgbaF_rgbAF (const Babl *conversion, + unsigned char *srcc, + unsigned char *dstc, + long samples) +{ + float *src = (void *) srcc; + float *dst = (void *) dstc; + long n = samples; + + while (n--) + { + float alpha = src[3]; + float used_alpha = babl_epsilon_for_zero_float (alpha); + dst[0] = src[0] * used_alpha; + dst[1] = src[1] * used_alpha; + dst[2] = src[2] * used_alpha; + dst[3] = alpha; + src += 4; + dst += 4; + } +} + +static void +conv_rgbAF_rgbaF (const Babl *conversion, + unsigned char *srcc, + unsigned char *dstc, + long samples) +{ + float *src = (void *) srcc; + float *dst = (void *) dstc; + long n = samples; + + while (n--) + { + float alpha = src[3]; + float used_alpha = babl_epsilon_for_zero_float (alpha); + float recip = 1.0f/used_alpha; + + dst[0] = src[0] * recip; + dst[1] = src[1] * recip; + dst[2] = src[2] * recip; + + dst[3] = alpha; + src += 4; + dst += 4; + } +} + + +static void +conv_rgbAF_lrgba8 (const Babl *conversion, + unsigned char *srcc, + unsigned char *dstc, + long samples) +{ + float *src = (void *) srcc; + unsigned char *dst = (void *) dstc; + long n = samples; + + while (n--) + { + float alpha = src[3]; + float used_alpha = babl_epsilon_for_zero_float (alpha); + float recip = (1.0f/used_alpha); + + dst[0] = table_F_8[gggl_float_to_index16 (src[0] * recip)]; + dst[1] = table_F_8[gggl_float_to_index16 (src[1] * recip)]; + dst[2] = table_F_8[gggl_float_to_index16 (src[2] * recip)]; + dst[3] = table_F_8[gggl_float_to_index16 (alpha)]; + src += 4; + dst += 4; + } +} + +static void +conv_rgba8_rgb8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples - 1; + + while (n--) + { + *(unsigned int *) dst = (*(unsigned int *) src); + src += 4; + dst += 3; + } + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; +} + +#define conv_rgb8_rgbAF conv_rgb8_rgbaF +#define conv_gamma_rgbaF_gamma_rgbAF conv_rgbaF_rgbAF +#define conv_gamma_rgbAF_gamma_rgbaF conv_rgbAF_rgbaF + +int init (void); + +int +init (void) +{ + const Babl *rgbaF = babl_format_new ( + babl_model ("RGBA"), + babl_type ("float"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + babl_component ("A"), + NULL); + const Babl *rgbAF = babl_format_new ( + babl_model ("RaGaBaA"), + babl_type ("float"), + babl_component ("Ra"), + babl_component ("Ga"), + babl_component ("Ba"), + babl_component ("A"), + NULL); + + const Babl *gamma_rgbaF = babl_format_new ( + babl_model ("R'G'B'A"), + babl_type ("float"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + babl_component ("A"), + NULL); + const Babl *gamma_rgbAF = babl_format_new ( + babl_model ("R'aG'aB'aA"), + babl_type ("float"), + babl_component ("R'a"), + babl_component ("G'a"), + babl_component ("B'a"), + babl_component ("A"), + NULL); + + const Babl *lrgba8 = babl_format_new ( + babl_model ("RGBA"), + babl_type ("u8"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + babl_component ("A"), + NULL); + + const Babl *rgba8 = babl_format_new ( + babl_model ("R'G'B'A"), + babl_type ("u8"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + babl_component ("A"), + NULL); + const Babl *bgrA8 = babl_format_new ( + "name", "B'aG'aR'aA u8", + babl_model ("R'aG'aB'aA"), + babl_type ("u8"), + babl_component ("B'a"), + babl_component ("G'a"), + babl_component ("R'a"), + babl_component ("A"), + NULL); + const Babl *rgb8 = babl_format_new ( + babl_model ("R'G'B'"), + babl_type ("u8"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + NULL); + const Babl *ga8 = babl_format_new ( + babl_model ("Y'A"), + babl_type ("u8"), + babl_component ("Y'"), + babl_component ("A"), + NULL); + + table_init (); + +#define o(src, dst) \ + babl_conversion_new (src, dst, "linear", conv_ ## src ## _ ## dst, NULL) + + o (rgbaF, rgbAF); + o (rgbAF, rgbaF); + o (gamma_rgbaF, gamma_rgbAF); + o (gamma_rgbAF, gamma_rgbaF); + o (rgbAF, lrgba8); + o (rgb8, rgbaF); + o (rgb8, rgbAF); + o (rgba8, rgbaF); + o (rgbaF, rgb8); + o (rgbAF, rgb8); + o (bgrA8, rgba8); + o (rgba8, rgb8); + o (ga8, rgbaF); + + return 0; +} diff --git a/extensions/gggl-lies.c b/extensions/gggl-lies.c new file mode 100644 index 0000000..09c4a90 --- /dev/null +++ b/extensions/gggl-lies.c @@ -0,0 +1,1017 @@ +/* + * This file was part of gggl, it implements a variety of pixel conversion + * functions that are usable with babl, the file needs more cleanup, and + * doesn't return the number of samples processed as a long, like it's + * supposed to. + * + * GGGL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GGGL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GGGL; if not, see . + * + * Rights are granted to use this shared object in libraries covered by + * LGPL. (exception added, during import into babl CVS.) + * + * Copyright 2003, 2004, 2005 Øyvind Kolås + */ + +#define _POSIX_C_SOURCE 200112L + +#include "config.h" +#include +#include + +#include "babl.h" +#include "extensions/util.h" + +/* + * Implemented according to information read from: + * + * http://www.cinenet.net/~spitzak/conversion/sketches_0265.pdf + * + * initially ignoring any diffusion, to keep the implementation + * smaller, and interchangeable with the non optimized version. + * + * due to ability to be able to relicence gggl under a different + * licence than GPL, I avoided the temptation to look at the + * source files in the same location, in case I was going to + * need this piece of code for projects where GPL compatibility + * was a must. + * + */ + +static void +conv_F_8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + float f = ((*(float *) src)); + if (f < 0.0) + { + *(unsigned char *) dst = 0; + } + else if (f > 1.0) + { + *(unsigned char *) dst = 255; + } + else + { + *(unsigned char *) dst = lrint (f * 255.0); + } + dst += 1; + src += 4; + } +} + +static void +conv_F_16 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + float f = ((*(float *) src)); + if (f < 0.0) + { + *(unsigned short *) dst = 0; + } + else if (f > 1.0) + { + *(unsigned short *) dst = 65535; + } + else + { + *(unsigned short *) dst = lrint (f * 65535.0); + } + dst += 2; + src += 4; + } +} + + + +static void +conv_8_F (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + (*(float *) dst) = (*(unsigned char *) src / 255.0); + dst += 4; + src += 1; + } +} + +static void +conv_16_F (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + (*(float *) dst) = *(unsigned short *) src / 65535.0; + dst += 4; + src += 2; + } +} + +static void +conv_F_D (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + *(double *) dst = ((*(float *) src)); + dst += 8; + src += 4; + } +} + +static void +conv_D_F (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + *(float *) dst = ((*(double *) src)); + dst += 4; + src += 8; + } +} + +static void +conv_16_8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n>4) + { +#define div_257(a) ((((a)+128)-(((a)+128)>>8))>>8) + ((unsigned char *) dst)[0] = div_257 (((unsigned short *) src)[0]); + ((unsigned char *) dst)[1] = div_257 (((unsigned short *) src)[1]); + ((unsigned char *) dst)[2] = div_257 (((unsigned short *) src)[2]); + ((unsigned char *) dst)[3] = div_257 (((unsigned short *) src)[3]); + dst += 4; + src += 8; + n-=4; + } + + while (n--) + { + (*(unsigned char *) dst) = div_257 (*(unsigned short *) src); + dst += 1; + src += 2; + } +} + +static void +conv_8_16 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + (*(unsigned short *) dst) = ((*(unsigned char *) src) << 8) | *src; + dst += 2; + src += 1; + } +} + +/*********/ +static void +conv_rgbaF_rgba8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_F_8 (conversion, src, dst, samples * 4); +} + +#define conv_rgbaF_rgbP8 conv_rgbaF_rgba8 + +static void +conv_rgbF_rgb8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_F_8 (conversion, src, dst, samples * 3); +} + +static void +conv_gaF_ga8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_F_8 (conversion, src, dst, samples * 2); +} + +#define conv_rgbAF_rgbA8 conv_rgbaF_rgba8 +#define conv_gF_g8 conv_F_8 +#define conv_gAF_gA8 conv_gaF_ga8 + +static void +conv_rgbaF_rgba16 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_F_16 (conversion, src, dst, samples * 4); +} + +static void +conv_rgbaF_rgbaD (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_F_D (conversion, src, dst, samples * 4); +} + +static void +conv_rgbaD_rgbaF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_D_F (conversion, src, dst, samples * 4); +} + +static void +conv_rgbF_rgb16 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_F_16 (conversion, src, dst, samples * 3); +} + +static void +conv_gaF_ga16 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_F_16 (conversion, src, dst, samples * 2); +} + +#define conv_rgbAF_rgbAD conv_rgbaF_rgbaD +#define conv_rgbAD_rgbAF conv_rgbaD_rgbaF +#define conv_rgbAF_rgbA16 conv_rgbaF_rgba16 +#define conv_gF_g16 conv_F_16 +#define conv_gAF_gA16 conv_gaF_ga16 + +static void +conv_rgba8_rgbaF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_8_F (conversion, src, dst, samples * 4); +} + +static void +conv_rgb8_rgbF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_8_F (conversion, src, dst, samples * 3); +} + +static void +conv_ga8_gaF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_8_F (conversion, src, dst, samples * 2); +} + +#define conv_rgbA8_rgbAF conv_rgba8_rgbaF +#define conv_gA8_gAF conv_ga8_gaF +#define conv_g8_gF conv_8_F + +static void +conv_rgba16_rgbaF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_16_F (conversion, src, dst, samples * 4); +} + +static void +conv_rgb16_rgbF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_16_F (conversion, src, dst, samples * 3); +} + +static void +conv_ga16_gaF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_16_F (conversion, src, dst, samples * 2); +} + +#define conv_rgbA16_rgbAF conv_rgba16_rgbaF +#define conv_gA16_gAF conv_ga16_gaF +#define conv_g16_gF conv_16_F + +static void +conv_rgba16_rgba8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_16_8 (conversion, src, dst, samples * 4); +} + +static void +conv_rgb16_rgb8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_16_8 (conversion, src, dst, samples * 3); +} + +static void +conv_ga16_ga8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_16_8 (conversion, src, dst, samples * 2); +} + +#define conv_rgbA16_rgbA8 conv_rgba16_rgba8 +#define conv_gA16_gA8 conv_ga16_ga8 +#define conv_g16_g8 conv_16_8 + +static void +conv_rgba8_rgba16 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_8_16 (conversion, src, dst, samples * 4); +} + +static void +conv_rgb8_rgb16 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_8_16 (conversion, src, dst, samples * 3); +} + +static void +conv_ga8_ga16 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_8_16 (conversion, src, dst, samples * 2); +} + +#define conv_rgbA8_rgbA16 conv_rgba8_rgba16 +#define conv_gA8_gA16 conv_ga8_ga16 +#define conv_g8_g16 conv_8_16 + +/* alpha conversions */ + +static void +conv_gaF_gAF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + float alpha = (*(float *) (src + 4)); + + *(float *) dst = ((*(float *) src) * alpha); + dst += 4; + src += 4; + *(float *) dst = alpha; + dst += 4; + src += 4; + } +} + +static void +conv_gAF_gaF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + float alpha = (*(float *) (src + 4)); + + if (alpha == 0.0f) + *(float *) dst = 0.0f; + else + *(float *) dst = ((*(float *) src) / alpha); + dst += 4; + src += 4; + *(float *) dst = alpha; + dst += 4; + src += 4; + } +} + +/* alpha stripping and adding */ + +static void +conv_rgbaF_rgbF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + *(int *) dst = (*(int *) src); + dst += 4; + src += 4; + *(int *) dst = (*(int *) src); + dst += 4; + src += 4; + *(int *) dst = (*(int *) src); + dst += 4; + src += 4; + src += 4; + } +} + + +static void +conv_gF_rgbaF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + *(int *) dst = (*(int *) src); + dst += 4; + *(int *) dst = (*(int *) src); + dst += 4; + *(int *) dst = (*(int *) src); + dst += 4; + *(float *) dst = 1.0; + dst += 4; + src += 4; + } +} + +#define conv_gF_rgbAF conv_gF_rgbaF + +static void +conv_rgbF_rgbaF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + *(int *) dst = (*(int *) src); + dst += 4; + src += 4; + *(int *) dst = (*(int *) src); + dst += 4; + src += 4; + *(int *) dst = (*(int *) src); + dst += 4; + src += 4; + *(float *) dst = 1.0; + dst += 4; + } +} + +static void +conv_gaF_gF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + *(int *) dst = (*(int *) src); + dst += 4; + src += 4; + src += 4; + } +} + +static void +conv_gF_gaF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + *(int *) dst = (*(int *) src); + dst += 4; + src += 4; + *(float *) dst = 1.0; + dst += 4; + } +} + +#define conv_gF_gAF conv_gF_gaF + +#define conv_rgbF_rgbAF conv_rgbF_rgbaF + +/* colorchannel dropping and adding */ + +static void +conv_gF_rgbF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + int c; + + for (c = 0; c < 3; c++) + { + (*(int *) dst) = (*(int *) src); + dst += 4; + } + src += 4; + } +} + +static void +conv_gaF_rgbaF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + int c; + + for (c = 0; c < 3; c++) + { + (*(int *) dst) = (*(int *) src); + dst += 4; + } + src += 4; + (*(int *) dst) = (*(int *) src); + dst += 4; + src += 4; + } +} + +#define conv_gAF_rgbAF conv_gaF_rgbaF + +/* other conversions coded for some optimisation reason or sumthin */ + +static void +conv_rgbaF_rgbA8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + float alpha = (*(float *) (src + (4 * 3))); + int c; + + for (c = 0; c < 3; c++) + { + *(unsigned char *) dst = lrint (((*(float *) src) * alpha) * 255.0); + dst += 1; + src += 4; + } + *(unsigned char *) dst = lrint (alpha * 255.0); + dst++; + src += 4; + } +} + +static void +conv_rgbaF_rgb8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + int c; + + for (c = 0; c < 3; c++) + { + *(unsigned char *) dst = lrint ((*(float *) src) * 255.0); + dst += 1; + src += 4; + } + src += 4; + } +} + +static void +conv_rgbaF_rgb16 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + int c; + + for (c = 0; c < 3; c++) + { + *(unsigned short *) dst = lrint ((*(float *) src) * 65535.0); + dst += 2; + src += 4; + } + src += 4; + } +} + +static void +conv_rgba8_rgbA8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + if (src[3] == 255) + { + *(unsigned int *) dst = *(unsigned int *) src; + } + else if (src[3] == 0) + { + *(unsigned int *) dst = 0; + } + else + { +#define div_255(a) ((((a)+127)+(((a)+127)>>8))>>8) + dst[0] = div_255 (src[0] * src[3]); + dst[1] = div_255 (src[1] * src[3]); + dst[2] = div_255 (src[2] * src[3]); + dst[3] = src[3]; + } + dst += 4; + src += 4; + } +} + +static void +conv_rgbA8_rgba8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + if (src[3] == 255) + { + *(unsigned int *) dst = *(unsigned int *) src; + dst += 4; + } + else if (src[3] == 0) + { + *(unsigned int *) dst = 0; + dst += 4; + } + else + { + unsigned int aa = ((255 << 16) - 255) / src[3]; + *dst++ = (src[0] * aa + 0x8000) >> 16; + *dst++ = (src[1] * aa + 0x8000) >> 16; + *dst++ = (src[2] * aa + 0x8000) >> 16; + *dst++ = src[3]; + } + src += 4; + } +} + +static void +conv_rgb8_rgba8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = 255; + src += 3; + dst += 4; + } + +} + +#define conv_rgb8_rgbA8 conv_rgb8_rgba8 + +static void +conv_rgba8_rgb8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + src += 4; + dst += 3; + } +} + +int init (void); + +int +init (void) +{ + const Babl *rgbaF = babl_format_new ( + babl_model ("RGBA"), + babl_type ("float"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + babl_component ("A"), + NULL); + const Babl *rgba16 = babl_format_new ( + babl_model ("RGBA"), + babl_type ("u16"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + babl_component ("A"), + NULL); + const Babl *rgbaD = babl_format_new ( + babl_model ("RGBA"), + babl_type ("double"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + babl_component ("A"), + NULL); + const Babl *rgba8 = babl_format_new ( + babl_model ("RGBA"), + babl_type ("u8"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + babl_component ("A"), + NULL); + const Babl *rgbAF = babl_format_new ( + babl_model ("RaGaBaA"), + babl_type ("float"), + babl_component ("Ra"), + babl_component ("Ga"), + babl_component ("Ba"), + babl_component ("A"), + NULL); + const Babl *rgbAD = babl_format_new ( + babl_model ("RaGaBaA"), + babl_type ("double"), + babl_component ("Ra"), + babl_component ("Ga"), + babl_component ("Ba"), + babl_component ("A"), + NULL); + + const Babl *rgbA16 = babl_format_new ( + babl_model ("RaGaBaA"), + babl_type ("u16"), + babl_component ("Ra"), + babl_component ("Ga"), + babl_component ("Ba"), + babl_component ("A"), + NULL); + const Babl *rgbA8 = babl_format_new ( + babl_model ("RaGaBaA"), + babl_type ("u8"), + babl_component ("Ra"), + babl_component ("Ga"), + babl_component ("Ba"), + babl_component ("A"), + NULL); + const Babl *rgbF = babl_format_new ( + babl_model ("RGB"), + babl_type ("float"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + NULL); + const Babl *rgb16 = babl_format_new ( + babl_model ("RGB"), + babl_type ("u16"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + NULL); + const Babl *rgb8 = babl_format_new ( + babl_model ("RGB"), + babl_type ("u8"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + NULL); + const Babl *gaF = babl_format_new ( + babl_model ("YA"), + babl_type ("float"), + babl_component ("Y"), + babl_component ("A"), + NULL); + const Babl *gAF = babl_format_new ( + babl_model ("YaA"), + babl_type ("float"), + babl_component ("Ya"), + babl_component ("A"), + NULL); + const Babl *gF = babl_format_new ( + babl_model ("Y"), + babl_type ("float"), + babl_component ("Y"), + NULL); + const Babl *ga16 = babl_format_new ( + babl_model ("YA"), + babl_type ("u16"), + babl_component ("Y"), + babl_component ("A"), + NULL); + const Babl *gA16 = babl_format_new ( + babl_model ("YaA"), + babl_type ("u16"), + babl_component ("Ya"), + babl_component ("A"), + NULL); + const Babl *g16 = babl_format_new ( + babl_model ("Y"), + babl_type ("u16"), + babl_component ("Y"), + NULL); + const Babl *ga8 = babl_format_new ( + babl_model ("YA"), + babl_type ("u8"), + babl_component ("Y"), + babl_component ("A"), + NULL); + const Babl *gA8 = babl_format_new ( + babl_model ("YaA"), + babl_type ("u8"), + babl_component ("Ya"), + babl_component ("A"), + NULL); + const Babl *g8 = babl_format_new ( + babl_model ("Y"), + babl_type ("u8"), + babl_component ("Y"), + NULL); + +#define o(src, dst) \ + babl_conversion_new (src, dst, "linear", conv_ ## src ## _ ## dst, NULL) + + o (rgbaF, rgbaD); + o (rgbaD, rgbaF); + o (rgbAF, rgbAD); + o (rgbAD, rgbAF); + o (rgbaF, rgba8); + o (rgba8, rgbaF); + o (rgbaF, rgba16); + o (rgba16, rgbaF); + o (rgbAF, rgbA8); + o (rgbA8, rgbAF); + o (rgbAF, rgbA16); + o (rgbA16, rgbAF); + o (rgbF, rgb8); + o (rgb8, rgbF); + o (rgbF, rgb16); + o (rgb16, rgbF); + o (rgba8, rgba16); + o (rgba16, rgba8); + o (rgbA8, rgbA16); + o (rgbA16, rgbA8); + o (rgb8, rgb16); + o (rgb16, rgb8); + o (gaF, ga8); + o (gAF, gA8); + o (gF, g8); + o (gF, rgbAF); + o (gF, rgbaF); + o (ga8, gaF); + o (gA8, gAF); + o (g8, gF); + o (gaF, ga16); + o (gAF, gA16); + o (gF, g16); + o (ga16, gaF); + o (gA16, gAF); + o (g16, gF); + o (ga16, ga8); + o (g16, g8); + o (ga8, ga16); + o (gA8, gA16); + o (g8, g16); + o (gaF, gAF); + o (gAF, gaF); + o (rgbaF, rgbF); + o (gaF, gF); + o (rgbF, rgbaF); + o (rgbF, rgbAF); + o (gF, gaF); + o (gF, gAF); + o (gF, rgbF); + o (gaF, rgbaF); + o (gAF, rgbAF); + o (rgbaF, rgb8); + o (rgbA8, rgba8); + o (rgba8, rgbA8); + o (rgbaF, rgb16); + o (rgb8, rgba8); + o (rgb8, rgbA8); + o (rgba8, rgb8); + o (rgbaF, rgbA8); + + return 0; +} diff --git a/extensions/gggl-table-lies.c b/extensions/gggl-table-lies.c new file mode 100644 index 0000000..51ce57e --- /dev/null +++ b/extensions/gggl-table-lies.c @@ -0,0 +1,565 @@ +/* + * This file was part of gggl, it implements a variety of pixel conversion + * functions that are usable with babl, the file needs more cleanup, and + * doesn't return the number of samples processed as a long, like it's + * supposed to. + * + * GGGL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GGGL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GGGL; if not, see . + * + * Rights are granted to use this shared object in libraries covered by + * LGPL. (exception added, during import into babl CVS.) + * + * Copyright 2003, 2004, 2005 Øyvind Kolås + */ + +//#define _POSIX_C_SOURCE 200112L + +#include "config.h" +#include +#include + +#include "babl.h" +#include "base/util.h" +#include "extensions/util.h" + + +/* + * Implemented according to information read from: + * + * http://www.cinenet.net/~spitzak/conversion/sketches_0265.pdf + * + * initially ignoring any diffusion, to keep the implementation + * smaller, and interchangeable with the non optimized version. + * + * due to ability to be able to relicence gggl under a different + * licence than GPL, I avoided the temptation to look at the + * source files in the same location, in case I was going to + * need this piece of code for projects where GPL compatibility + * was a must. + * + * TODO: error diffusion, + * gamma correction (not really,. gamma correction belongs in seperate ops,. + */ + +/* lookup tables used in conversion */ + +static float table_8_F[1 << 8]; +static float table_16_F[1 << 16]; +static unsigned char table_F_8[1 << 16]; +static unsigned short table_F_16[1 << 16]; + + +static int table_inited = 0; + +static void +table_init (void) +{ + int i; + + if (table_inited) + return; + table_inited = 1; + + /* fill tables for conversion from integer to float */ + for (i = 0; i < 1 << 8; i++) + { + table_8_F[i] = (i * 1.0) / 255.0; + } + for (i = 0; i < 1 << 16; i++) + { + table_16_F[i] = (i * 1.0) / 65535.0; + } + /* fill tables for conversion from float to integer */ + { + union + { + float f; + unsigned short s[2]; + } u; + u.f = 0.0; + + u.s[0] = 0x8000; + + for (i = 0; i < 1 << 16; i++) + { + unsigned char c; + unsigned short s; + + u.s[1] = i; + + if (u.f <= 0.0) + { + c = 0; + s = 0; + } + else if (u.f >= 1.0) + { + c = 255; + s = 65535; + } + else + { + c = u.f * 255 + 0.5f; + s = u.f * 65535 + 0.5f; + } + + /*fprintf (stderr, "%2.3f=%03i %05i ", f, c, (*hi)); + / if (! ((*hi)%9)) + / fprintf (stderr, "\n"); */ + + table_F_8[u.s[1]] = c; + table_F_16[u.s[1]] = s; + } + } + /* fix tables to ensure 1:1 conversions back and forth */ + if (0) + { /*FIXME: probably not the right way to do it,.. must sit down and scribble on paper */ + int i; + for (i = 0; i < 256; i++) + { + float f = table_8_F[i]; + unsigned short *hi = ((unsigned short *) (void *) &f); + unsigned short *lo = ((unsigned short *) (void *) &f); + *lo = 0; + table_F_8[(*hi)] = i; + } + } +} + +/* function to find the index in table for a float */ +static unsigned int +gggl_float_to_index16 (float f) +{ + union + { + float f; + unsigned short s[2]; + } u; + u.f = f; + return u.s[1]; +} + + +static void +conv_F_8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + if (!table_inited) + table_init (); + while (n--) + { + register float f = (*(float *) src); + *(unsigned char *) dst = table_F_8[gggl_float_to_index16 (f)]; + dst += 1; + src += 4; + } +} + +static void +conv_F_16 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + if (!table_inited) + table_init (); + while (n--) + { + register float f = (*(float *) src); + *(unsigned short *) dst = table_F_16[gggl_float_to_index16 (f)]; + dst += 2; + src += 4; + } +} + +static void +conv_8_F (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + if (!table_inited) + table_init (); + while (n--) + { + (*(float *) dst) = table_8_F[*(unsigned char *) src]; + dst += 4; + src += 1; + } +} + +static void +conv_16_F (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + if (!table_inited) + table_init (); + while (n--) + { + (*(float *) dst) = table_16_F[*(unsigned short *) src]; + dst += 4; + src += 2; + } +} + +/*********/ +static void +conv_rgbaF_rgba8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_F_8 (conversion, src, dst, samples * 4); +} + +#define conv_rgbaF_rgbP8 conv_rgbaF_rgba8 + +static void +conv_rgbF_rgb8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_F_8 (conversion, src, dst, samples * 3); +} + +static void +conv_gaF_ga8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_F_8 (conversion, src, dst, samples * 2); +} + +#define conv_rgbAF_rgbA8 conv_rgbaF_rgba8 +#define conv_gF_g8 conv_F_8 +#define conv_gAF_gA8 conv_gaF_ga8 + +static void +conv_rgbaF_rgba16 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_F_16 (conversion, src, dst, samples * 4); +} + +static void +conv_rgbF_rgb16 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_F_16 (conversion, src, dst, samples * 3); +} + +static void +conv_gaF_ga16 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_F_16 (conversion, src, dst, samples * 2); +} + +#define conv_rgbAF_rgbA16 conv_rgbaF_rgba16 +#define conv_gF_g16 conv_F_16 +#define conv_gAF_gA16 conv_gaF_ga16 + +static void +conv_rgba8_rgbaF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_8_F (conversion, src, dst, samples * 4); +} + +static void +conv_rgb8_rgbF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_8_F (conversion, src, dst, samples * 3); +} + +static void +conv_ga8_gaF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_8_F (conversion, src, dst, samples * 2); +} + +#define conv_rgbA8_rgbAF conv_rgba8_rgbaF +#define conv_gA8_gAF conv_ga8_gaF +#define conv_g8_gF conv_8_F + +static void +conv_rgba16_rgbaF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_16_F (conversion, src, dst, samples * 4); +} + +static void +conv_rgb16_rgbF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_16_F (conversion, src, dst, samples * 3); +} + +static void +conv_ga16_gaF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_16_F (conversion, src, dst, samples * 2); +} + +#define conv_rgbA16_rgbAF conv_rgba16_rgbaF +#define conv_gA16_gAF conv_ga16_gaF +#define conv_g16_gF conv_16_F + +static void +conv_rgbafloat_linear_cairo32_le (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst, + long samples) +{ + long n = samples; + float *src = (float*)src_char; + + while (n--) + { + float alpha = src[3] * 255; + + if (alpha <= BABL_ALPHA_FLOOR) + { + *(int *)dst = 0; + } + else + { + if (alpha > 255) alpha = 255; +#define div_255(a) ((((a)+128)+(((a)+128)>>8))>>8) + dst[0] = src[2] * alpha + 0.5f; + dst[1] = src[1] * alpha + 0.5f; + dst[2] = src[0] * alpha + 0.5f; + dst[3] = alpha + 0.5f; + } + src += 4; + dst += 4; + } +} + + +int init (void); + +int +init (void) +{ + const Babl *rgbaF = babl_format_new ( + babl_model ("RGBA"), + babl_type ("float"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + babl_component ("A"), + NULL); + const Babl *rgba16 = babl_format_new ( + babl_model ("RGBA"), + babl_type ("u16"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + babl_component ("A"), + NULL); + const Babl *rgba8 = babl_format_new ( + babl_model ("RGBA"), + babl_type ("u8"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + babl_component ("A"), + NULL); + const Babl *rgbAF = babl_format_new ( + babl_model ("RaGaBaA"), + babl_type ("float"), + babl_component ("Ra"), + babl_component ("Ga"), + babl_component ("Ba"), + babl_component ("A"), + NULL); + const Babl *rgbA16 = babl_format_new ( + babl_model ("RaGaBaA"), + babl_type ("u16"), + babl_component ("Ra"), + babl_component ("Ga"), + babl_component ("Ba"), + babl_component ("A"), + NULL); + const Babl *rgbA8 = babl_format_new ( + babl_model ("RaGaBaA"), + babl_type ("u8"), + babl_component ("Ra"), + babl_component ("Ga"), + babl_component ("Ba"), + babl_component ("A"), + NULL); + const Babl *rgbF = babl_format_new ( + babl_model ("RGB"), + babl_type ("float"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + NULL); + const Babl *rgb16 = babl_format_new ( + babl_model ("RGB"), + babl_type ("u16"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + NULL); + const Babl *rgb8 = babl_format_new ( + babl_model ("RGB"), + babl_type ("u8"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + NULL); + const Babl *gaF = babl_format_new ( + babl_model ("YA"), + babl_type ("float"), + babl_component ("Y"), + babl_component ("A"), + NULL); + const Babl *gAF = babl_format_new ( + babl_model ("YaA"), + babl_type ("float"), + babl_component ("Ya"), + babl_component ("A"), + NULL); + const Babl *gF = babl_format_new ( + babl_model ("Y"), + babl_type ("float"), + babl_component ("Y"), + NULL); + const Babl *ga16 = babl_format_new ( + babl_model ("YA"), + babl_type ("u16"), + babl_component ("Y"), + babl_component ("A"), + NULL); + const Babl *gA16 = babl_format_new ( + babl_model ("YaA"), + babl_type ("u16"), + babl_component ("Ya"), + babl_component ("A"), + NULL); + const Babl *g16 = babl_format_new ( + babl_model ("Y"), + babl_type ("u16"), + babl_component ("Y"), + NULL); + const Babl *ga8 = babl_format_new ( + babl_model ("YA"), + babl_type ("u8"), + babl_component ("Y"), + babl_component ("A"), + NULL); + const Babl *gA8 = babl_format_new ( + babl_model ("YaA"), + babl_type ("u8"), + babl_component ("Ya"), + babl_component ("A"), + NULL); + const Babl *g8 = babl_format_new ( + babl_model ("Y"), + babl_type ("u8"), + babl_component ("Y"), + NULL); + + int testint = 23; + char *testchar = (char*) &testint; + int littleendian = (testchar[0] == 23); + + if (littleendian) + { + const Babl *f32 = babl_format_new ( + "name", "cairo-ARGB32", + babl_model ("R'aG'aB'aA"), + babl_type ("u8"), + babl_component ("B'a"), + babl_component ("G'a"), + babl_component ("R'a"), + babl_component ("A"), + NULL + ); + babl_conversion_new (babl_format ("RGBA float"), f32, "linear", + conv_rgbafloat_linear_cairo32_le, NULL); + } + +#define o(src, dst) \ + babl_conversion_new (src, dst, "linear", conv_ ## src ## _ ## dst, NULL) + + o (rgbaF, rgba8); + o (rgba8, rgbaF); + o (rgbaF, rgba16); + o (rgba16, rgbaF); + o (rgbAF, rgbA8); + o (rgbA8, rgbAF); + o (rgbAF, rgbA16); + o (rgbA16, rgbAF); + o (rgbF, rgb8); + o (rgb8, rgbF); + o (rgbF, rgb16); + o (rgb16, rgbF); + o (gaF, ga8); + o (gAF, gA8); + o (gF, g8); + o (ga8, gaF); + o (gA8, gAF); + o (g8, gF); + o (gaF, ga16); + o (gAF, gA16); + o (gF, g16); + o (ga16, gaF); + o (gA16, gAF); + o (g16, gF); + + if (!table_inited) + table_init (); + + return 0; +} diff --git a/extensions/gggl-table.c b/extensions/gggl-table.c new file mode 100644 index 0000000..60c4420 --- /dev/null +++ b/extensions/gggl-table.c @@ -0,0 +1,563 @@ +/* + * This file was part of gggl, it implements a variety of pixel conversion + * functions that are usable with babl, the file needs more cleanup. + * + * GGGL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GGGL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GGGL; if not, see . + * + * Rights are granted to use this shared object in libraries covered by + * LGPL. (exception added, during import into babl CVS.) + * + * Copyright 2003, 2004, 2005 Øyvind Kolås + */ + +#define _POSIX_C_SOURCE 200112L + +#include "config.h" +#include +#include +#include + +#include "babl.h" +#include "extensions/util.h" + +/* + * Implemented according to information read from: + * + * http://www.cinenet.net/~spitzak/conversion/sketches_0265.pdf + * + * due to ability to be able to relicence gggl under a different + * licence than GPL, I avoided the temptation to look at the + * source files in the same location, in case I was going to + * need this piece of code for projects where GPL compatibility + * was a must. + * + */ + +/* lookup tables used in conversion */ + +static float table_8_F[1 << 8]; +static float table_16_F[1 << 16]; +static unsigned char table_F_8[1 << 16]; +static unsigned short table_F_16[1 << 16]; + +static uint32_t *table_8_F_int = NULL; + +static int table_inited = 0; + +static void +table_init (void) +{ + if (table_inited) + return; + + table_8_F_int = (void*)(table_8_F); + + table_inited = 1; + + /* fill tables for conversion from integer to float */ + { + int i; + for (i = 0; i < 1 << 8; i++) + { + table_8_F[i] = (i * 1.0) / 255.0; + } + for (i = 0; i < 1 << 16; i++) + table_16_F[i] = (i * 1.0) / 65535.0; + } + /* fill tables for conversion from float to integer */ + { + union + { + float f; + unsigned short s[2]; + } u; + u.f = 0.0; + + u.s[0] = 0x8000; + + for (u.s[1] = 0; u.s[1] < 65535; u.s[1] += 1) + { + unsigned char c; + unsigned short s; + + if (u.f <= 0.0) + { + c = 0; + s = 0; + } + else if (u.f >= 1.0) + { + c = 255; + s = 65535; + } + else + { + c = u.f * 255 + 0.5f; + s = u.f * 65535 + 0.5f; + } + + /*fprintf (stderr, "%2.3f=%03i %05i ", f, c, (*hi)); + / if (! ((*hi)%9)) + / fprintf (stderr, "\n"); */ + + table_F_8[u.s[1]] = c; + table_F_16[u.s[1]] = s; + } + } + /* patch tables to ensure 1:1 conversions back and forth */ + if (0) + { /*FIXME: probably not the right way to do it,.. must sit down and scribble on paper */ + int i; + for (i = 0; i < 256; i++) + { + float f = table_8_F[i]; + unsigned short *hi = ((unsigned short *) (void *) &f); + unsigned short *lo = ((unsigned short *) (void *) &f); + *lo = 0; + table_F_8[(*hi)] = i; + } + } +} + +/* function to find the index in table for a float */ +static unsigned int +gggl_float_to_index16 (float f) +{ + union + { + float f; + unsigned short s[2]; + } u; + u.f = f; + return u.s[1]; +} + +static void +conv_F_8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + if (!table_inited) + table_init (); + while (n--) + { + register float f = (*(float *) src); + *(unsigned char *) dst = table_F_8[gggl_float_to_index16 (f)]; + dst += 1; + src += 4; + } +} + + +static void +conv_F_16 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + if (!table_inited) + table_init (); + while (n--) + { + register float f = (*(float *) src); + *(unsigned short *) dst = table_F_16[gggl_float_to_index16 (f)]; + dst += 2; + src += 4; + } +} + +static void +conv_8_F (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + if (!table_inited) + table_init (); + while (n--) + { + (*(uint32_t *) dst) = table_8_F_int[*(unsigned char *) src]; + dst += 4; + src += 1; + } +} + +static void +conv_rgb8_rgbaF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + if (!table_inited) + table_init (); + while (n--) + { + (*(uint32_t *) dst) = table_8_F_int[*(unsigned char *) src]; + dst += 4; + src += 1; + (*(uint32_t *) dst) = table_8_F_int[*(unsigned char *) src]; + dst += 4; + src += 1; + (*(uint32_t *) dst) = table_8_F_int[*(unsigned char *) src]; + dst += 4; + src += 1; + (*(float *) dst) = 1.0; + dst += 4; + } +} + +static void +conv_16_F (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + if (!table_inited) + table_init (); + while (n--) + { + (*(float *) dst) = table_16_F[*(unsigned short *) src]; + dst += 4; + src += 2; + } +} + +static void +conv_rgbaF_rgb8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + register float f = (*(float *) src); + *(unsigned char *) dst = table_F_8[gggl_float_to_index16 (f)]; + src += 4; + dst += 1; + + f = (*(float *) src); + *(unsigned char *) dst = table_F_8[gggl_float_to_index16 (f)]; + src += 4; + dst += 1; + + f = (*(float *) src); + *(unsigned char *) dst = table_F_8[gggl_float_to_index16 (f)]; + src += 4; + dst += 1; + + src += 4; + } +} + + +/*********/ +static void +conv_rgbaF_rgba8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_F_8 (conversion, src, dst, samples * 4); +} + +static void +conv_rgbF_rgb8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_F_8 (conversion, src, dst, samples * 3); +} + +static void +conv_gaF_ga8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_F_8 (conversion, src, dst, samples * 2); +} + +#define conv_rgbAF_rgbA8 conv_rgbaF_rgba8 +#define conv_gF_g8 conv_F_8 +#define conv_gAF_gA8 conv_gaF_ga8 + +static void +conv_rgbaF_rgba16 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_F_16 (conversion, src, dst, samples * 4); +} + +static void +conv_rgbF_rgb16 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_F_16 (conversion, src, dst, samples * 3); +} + +static void +conv_gaF_ga16 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_F_16 (conversion, src, dst, samples * 2); +} + +#define conv_rgbAF_rgbA16 conv_rgbaF_rgba16 +#define conv_gF_g16 conv_F_16 +#define conv_gAF_gA16 conv_gaF_ga16 + +static void +conv_rgba8_rgbaF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_8_F (conversion, src, dst, samples * 4); +} + + +static void +conv_rgb8_rgbF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_8_F (conversion, src, dst, samples * 3); +} + +static void +conv_ga8_gaF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_8_F (conversion, src, dst, samples * 2); +} + +#define conv_rgbA8_rgbAF conv_rgba8_rgbaF +#define conv_gA8_gAF conv_ga8_gaF +#define conv_g8_gF conv_8_F + +static void +conv_rgba16_rgbaF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_16_F (conversion, src, dst, samples * 4); +} + +static void +conv_rgb16_rgbF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_16_F (conversion, src, dst, samples * 3); +} + +static void +conv_ga16_gaF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_16_F (conversion, src, dst, samples * 2); +} + +#define conv_rgbA16_rgbAF conv_rgba16_rgbaF +#define conv_gA16_gAF conv_ga16_gaF +#define conv_g16_gF conv_16_F + +int init (void); + +int +init (void) +{ + const Babl *rgbaF = babl_format_new ( + babl_model ("R'G'B'A"), + babl_type ("float"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + babl_component ("A"), + NULL); + const Babl *rgba16 = babl_format_new ( + babl_model ("R'G'B'A"), + babl_type ("u16"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + babl_component ("A"), + NULL); + const Babl *rgba8 = babl_format_new ( + babl_model ("R'G'B'A"), + babl_type ("u8"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + babl_component ("A"), + NULL); + const Babl *rgbAF = babl_format_new ( + babl_model ("R'aG'aB'aA"), + babl_type ("float"), + babl_component ("R'a"), + babl_component ("G'a"), + babl_component ("B'a"), + babl_component ("A"), + NULL); + const Babl *rgbA16 = babl_format_new ( + babl_model ("R'aG'aB'aA"), + babl_type ("u16"), + babl_component ("R'a"), + babl_component ("G'a"), + babl_component ("B'a"), + babl_component ("A"), + NULL); + const Babl *rgbA8 = babl_format_new ( + babl_model ("R'aG'aB'aA"), + babl_type ("u8"), + babl_component ("R'a"), + babl_component ("G'a"), + babl_component ("B'a"), + babl_component ("A"), + NULL); + const Babl *rgbF = babl_format_new ( + babl_model ("R'G'B'"), + babl_type ("float"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + NULL); + const Babl *rgb16 = babl_format_new ( + babl_model ("R'G'B'"), + babl_type ("u16"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + NULL); + const Babl *rgb8 = babl_format_new ( + babl_model ("R'G'B'"), + babl_type ("u8"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + NULL); + const Babl *gaF = babl_format_new ( + babl_model ("Y'A"), + babl_type ("float"), + babl_component ("Y'"), + babl_component ("A"), + NULL); + const Babl *gAF = babl_format_new ( + babl_model ("Y'aA"), + babl_type ("float"), + babl_component ("Y'a"), + babl_component ("A"), + NULL); + const Babl *gF = babl_format_new ( + babl_model ("Y'"), + babl_type ("float"), + babl_component ("Y'"), + NULL); + const Babl *ga16 = babl_format_new ( + babl_model ("Y'A"), + babl_type ("u16"), + babl_component ("Y'"), + babl_component ("A"), + NULL); + const Babl *gA16 = babl_format_new ( + babl_model ("Y'aA"), + babl_type ("u16"), + babl_component ("Y'a"), + babl_component ("A"), + NULL); + const Babl *g16 = babl_format_new ( + babl_model ("Y'"), + babl_type ("u16"), + babl_component ("Y'"), + NULL); + const Babl *ga8 = babl_format_new ( + babl_model ("Y'A"), + babl_type ("u8"), + babl_component ("Y'"), + babl_component ("A"), + NULL); + const Babl *gA8 = babl_format_new ( + babl_model ("Y'aA"), + babl_type ("u8"), + babl_component ("Y'a"), + babl_component ("A"), + NULL); + const Babl *g8 = babl_format_new ( + babl_model ("Y'"), + babl_type ("u8"), + babl_component ("Y'"), + NULL); + +#define o(src, dst) \ + babl_conversion_new (src, dst, "linear", conv_ ## src ## _ ## dst, NULL) + + o (rgbaF, rgba8); + o (rgba8, rgbaF); + o (rgbaF, rgba16); + o (rgba16, rgbaF); + o (rgbAF, rgbA8); + o (rgbA8, rgbAF); + o (rgbAF, rgbA16); + o (rgbA16, rgbAF); + o (rgbF, rgb8); + o (rgb8, rgbF); + o (rgbF, rgb16); + o (rgb16, rgbF); + o (gaF, ga8); + o (gAF, gA8); + o (gF, g8); + o (ga8, gaF); + o (gA8, gAF); + o (g8, gF); + o (gaF, ga16); + o (gAF, gA16); + o (gF, g16); + o (ga16, gaF); + o (gA16, gAF); + o (g16, gF); + o (rgbaF, rgb8); + o (rgb8, rgbaF); + + if (!table_inited) + table_init (); + + return 0; +} diff --git a/extensions/gggl.c b/extensions/gggl.c new file mode 100644 index 0000000..34068f1 --- /dev/null +++ b/extensions/gggl.c @@ -0,0 +1,1302 @@ +/* + * This file was part of gggl, it implements a variety of pixel conversion + * functions that are usable with babl, the file needs more cleanup. + * + * GGGL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GGGL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GGGL; if not, see . + * + * Rights are granted to use this shared object in libraries covered by + * LGPL. (exception added, during import into babl CVS.) + * + * Copyright 2003, 2004, 2005 Øyvind Kolås + */ + +#define _POSIX_C_SOURCE 200112L + +#include "config.h" +#include +#include +#include + +#include "babl.h" +#include "extensions/util.h" + +/* + * Implemented according to information read from: + * + * http://www.cinenet.net/~spitzak/conversion/sketches_0265.pdf + * + * initially ignoring any diffusion, to keep the implementation + * smaller, and interchangeable with the non optimized version. + * + * due to ability to be able to relicence gggl under a different + * licence than GPL, I avoided the temptation to look at the + * source files in the same location, in case I was going to + * need this piece of code for projects where GPL compatibility + * was a must. + * + * TODO: error diffusion, + * gamma correction (not really,. gamma correction belongs in seperate ops,. + */ + +static void +conv_F_8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + float f = ((*(float *) src)); + int uval = lrint (f * 255.0); + + if (uval < 0) uval = 0; + if (uval > 255) uval = 255; + *(unsigned char *) dst = uval; + + dst += 1; + src += 4; + } +} + +static void +conv_F_16 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + float f = ((*(float *) src)); + if (f < 0.0) + { + *(unsigned short *) dst = 0; + } + else if (f > 1.0) + { + *(unsigned short *) dst = 65535; + } + else + { + *(unsigned short *) dst = lrint (f * 65535.0); + } + dst += 2; + src += 4; + } +} + +static void +conv_8_F (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + (*(float *) dst) = ((*(unsigned char *) src) / 255.0); + dst += 4; + src += 1; + } +} + +static void +conv_16_F (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + (*(float *) dst) = *(unsigned short *) src / 65535.0; + dst += 4; + src += 2; + } +} + +static void +conv_rgbaF_rgb8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + int c; + + for (c = 0; c < 3; c++) + { + int val = rint ((*(float *) src) * 255.0); + if (val < 0) + *(unsigned char *) dst = 0; + else if (val > 255) + *(unsigned char *) dst = 255; + else + *(unsigned char *) dst = val; + dst += 1; + src += 4; + } + src += 4; + } +} + +static void +conv_F_D (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + *(double *) dst = ((*(float *) src)); + dst += 8; + src += 4; + } +} + +static void +conv_D_F (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + *(float *) dst = ((*(double *) src)); + dst += 4; + src += 8; + } +} + +static void +conv_16_8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n>4) + { +#define div_257(a) ((((a)+128)-(((a)+128)>>8))>>8) + ((unsigned char *) dst)[0] = div_257 (((unsigned short *) src)[0]); + ((unsigned char *) dst)[1] = div_257 (((unsigned short *) src)[1]); + ((unsigned char *) dst)[2] = div_257 (((unsigned short *) src)[2]); + ((unsigned char *) dst)[3] = div_257 (((unsigned short *) src)[3]); + dst += 4; + src += 8; + n-=4; + } + + while (n--) + { + (*(unsigned char *) dst) = div_257 (*(unsigned short *) src); + dst += 1; + src += 2; + } +} + +static inline void +conv_8_16 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + while (n--) + { + (*(unsigned short *) dst) = *src << 8 | *src; + dst += 2; + src += 1; + } +} + + +/*********/ +static void +conv_rgbaF_rgba8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_F_8 (conversion, src, dst, samples * 4); +} + +static void +conv_rgbF_rgb8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_F_8 (conversion, src, dst, samples * 3); +} + +static void +conv_gaF_ga8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_F_8 (conversion, src, dst, samples * 2); +} + +#define conv_rgbAF_rgbA8 conv_rgbaF_rgba8 +#define conv_gF_g8 conv_F_8 +#define conv_gAF_gA8 conv_gaF_ga8 + +static void +conv_rgbaF_rgba16 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_F_16 (conversion, src, dst, samples * 4); +} + +static void +conv_rgbF_rgb16 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_F_16 (conversion, src, dst, samples * 3); +} + +static void +conv_gaF_ga16 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_F_16 (conversion, src, dst, samples * 2); +} + +#define conv_rgbAF_rgbA16 conv_rgbaF_rgba16 +#define conv_gF_g16 conv_F_16 +#define conv_gAF_gA16 conv_gaF_ga16 + +static void +conv_rgba8_rgbaF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_8_F (conversion, src, dst, samples * 4); +} + + +static void +conv_rgb8_rgbF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_8_F (conversion, src, dst, samples * 3); +} + +static void +conv_ga8_gaF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_8_F (conversion, src, dst, samples * 2); +} + +#define conv_rgbA8_rgbAF conv_rgba8_rgbaF +#define conv_gA8_gAF conv_ga8_gaF +#define conv_g8_gF conv_8_F + +static void +conv_rgbaF_rgbaD (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_F_D (conversion, src, dst, samples * 4); +} + +static void +conv_rgbaD_rgbaF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_D_F (conversion, src, dst, samples * 4); +} + +static void +conv_rgba16_rgbaF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_16_F (conversion, src, dst, samples * 4); +} + +static void +conv_rgb16_rgbF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_16_F (conversion, src, dst, samples * 3); +} + +static void +conv_ga16_gaF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_16_F (conversion, src, dst, samples * 2); +} + +#define conv_rgbA16_rgbAF conv_rgba16_rgbaF +#define conv_gA16_gAF conv_ga16_gaF +#define conv_g16_gF conv_16_F + +static void +conv_rgba16_rgba8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_16_8 (conversion, src, dst, samples * 4); +} + +static void +conv_rgb16_rgb8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_16_8 (conversion, src, dst, samples * 3); +} + +static void +conv_ga16_ga8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_16_8 (conversion, src, dst, samples * 2); +} + +#define conv_rgbA16_rgbA8 conv_rgba16_rgba8 +#define conv_gA16_gA8 conv_ga16_ga8 +#define conv_g16_g8 conv_16_8 + +static void +conv_rgba8_rgba16 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_8_16 (conversion, src, dst, samples * 4); +} + +static void +conv_rgb8_rgb16 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_8_16 (conversion, src, dst, samples * 3); +} + +static void +conv_ga8_ga16 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + conv_8_16 (conversion, src, dst, samples * 2); +} + +#define conv_rgbA8_rgbA16 conv_rgba8_rgba16 +#define conv_gA8_gA16 conv_ga8_ga16 +#define conv_g8_g16 conv_8_16 + +/* alpha conversions */ + +static void +conv_gaF_gAF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + float alpha = (*(float *) (src + 4)); + + *(float *) dst = ((*(float *) src) * alpha); + dst += 4; + src += 4; + *(float *) dst = alpha; + dst += 4; + src += 4; + } +} + +static void +conv_gAF_gaF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + float alpha = (*(float *) (src + 4)); + + if (alpha == 0.0f) + *(float *) dst = 0.0f; + else + *(float *) dst = ((*(float *) src) / alpha); + dst += 4; + src += 4; + *(float *) dst = alpha; + dst += 4; + src += 4; + } +} + +/* alpha stripping and adding */ + +static void +conv_rgbaF_rgbF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + *(uint32_t *) dst = (*(uint32_t *) src); + dst += 4; + src += 4; + *(uint32_t *) dst = (*(uint32_t *) src); + dst += 4; + src += 4; + *(uint32_t *) dst = (*(uint32_t *) src); + dst += 4; + src += 4; + src += 4; + } +} + +static void +conv_rgbF_rgbaF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + float *fsrc = (void*) src; + float *fdst = (void*) dst; + + while (n--) + { + *fdst++ = *fsrc++; + *fdst++ = *fsrc++; + *fdst++ = *fsrc++; + *fdst++ = 1.0f; + } +} + +#define conv_rgbF_rgbAF conv_rgbF_rgbaF + + +static void +conv_gaF_gF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + *(int *) dst = (*(int *) src); + dst += 4; + src += 4; + src += 4; + } +} + +static void +conv_gF_gaF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + *(float *) dst = (*(float *) src); + dst += 4; + src += 4; + *(float *) dst = 1.0; + dst += 4; + } +} + +#define conv_gF_gAF conv_gF_gaF + +#define conv_rgbF_rgbAF conv_rgbF_rgbaF + +/* colorchannel dropping and adding */ + +static void +conv_gF_rgbF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + int c; + + for (c = 0; c < 3; c++) + { + (*(float *) dst) = (*(float *) src); + dst += 4; + } + src += 4; + } +} + +static void +conv_g8_rgb8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + dst[0]=*src; + dst[1]=*src; + dst[2]=*src; + dst += 3; + src += 1; + } +} +#define conv_g8_rgbA8 conv_g8_rgba8 +static void +conv_g8_rgba8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + dst[0]=*src; + dst[1]=*src; + dst[2]=*src; + dst[3]=255; + dst += 4; + src += 1; + } +} + +static void +conv_gaF_rgbaF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + int c; + + for (c = 0; c < 3; c++) + { + (*(int *) dst) = (*(int *) src); + dst += 4; + } + src += 4; + (*(int *) dst) = (*(int *) src); + dst += 4; + src += 4; + } +} + +#define conv_gAF_rgbAF conv_gaF_rgbaF + +/* other conversions coded for some optimisation reason or sumthin */ + + +static void +conv_rgbaF_rgbA8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + float alpha = (*(float *) (src + (4 * 3))); + int c; + + for (c = 0; c < 3; c++) + { + *(unsigned char *) dst = lrint (((*(float *) src) * alpha) * 255.0); + dst += 1; + src += 4; + } + *(unsigned char *) dst = lrint (alpha * 255.0); + dst++; + src += 4; + } +} + +static void +conv_rgbaF_rgb16 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + int c; + + for (c = 0; c < 3; c++) + { + if ((*(float *) src) >= 1.0) + *(unsigned short *) dst = 65535; + else if ((*(float *) src) <=0) + *(unsigned short *) dst = 0; + else + *(unsigned short *) dst = lrint ((*(float *) src) * 65535.0); + dst += 2; + src += 4; + } + src += 4; + } +} + +static void +conv_rgbA16_rgbaF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + float alpha = (((unsigned short *) src)[3]) / 65535.0; + int c; + float recip_alpha; + + if (alpha == 0.0f) + recip_alpha = 10000.0; + else + recip_alpha = 1.0/alpha; + + for (c = 0; c < 3; c++) + { + (*(float *) dst) = (*(unsigned short *) src / 65535.0) * recip_alpha; + dst += 4; + src += 2; + } + *(float *) dst = alpha; + dst += 4; + src += 2; + } +} + +static void +conv_gF_rgbaF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + *(int *) dst = (*(int *) src); + dst += 4; + *(int *) dst = (*(int *) src); + dst += 4; + *(int *) dst = (*(int *) src); + dst += 4; + *(float *) dst = 1.0; + dst += 4; + src += 4; + } +} + +#define conv_gF_rgbAF conv_gF_rgbaF + +/* + static void + conv_rgb8_rgbaF (unsigned char *src, + unsigned char *dst, + int samples) + { + long n=samples; + while (n--) { + int c; + + for (c = 0; c < 3; c++) { + (*(float *) dst) = *(unsigned char *) src / 255.0; + dst += 4; + src += 1; + } + (*(float *) dst) = 1.0; + dst += 4; + } + } + + static void + conv_g8_rgbaF (unsigned char *src, + unsigned char *dst, + int samples) + { + long n=samples; + while (n--) { + int c; + + for (c = 0; c < 3; c++) { + (*(float *) dst) = *(unsigned char *) src / 255.0; + dst += 4; + } + src += 1; + (*(float *) dst) = 1.0; + dst += 4; + } + } + + static void + conv_rgb16_rgbaF (unsigned char *src, + unsigned char *dst, + int samples) + { + long n=samples; + while (n--) { + int c; + + for (c = 0; c < 3; c++) { + *(float *) dst = (*(unsigned short *) src) / 65535.0; + src += 2; + dst += 4; + } + *(float *) dst = 1.0; + src += 2; + dst += 4; + } + } + + static void + conv_gF_rgbaF (unsigned char *src, + unsigned char *dst, + int samples) + { + long n=samples; + while (n--) { + (*(float *) dst) = (*(float *) src); + dst += 4; + (*(float *) dst) = (*(float *) src); + dst += 4; + (*(float *) dst) = (*(float *) src); + dst += 4; + (*(float *) dst) = 1.0; + dst += 4; + src += 4; + + } + } + */ +static void +conv_rgba8_rgbA8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + if (src[3] == 255) + { + *(unsigned int *) dst = *(unsigned int *) src; + } + else if (src[3] == 0) + { + *(unsigned int *) dst = 0; + } + else + { +#define div_255(a) ((((a)+127)+(((a)+127)>>8))>>8) + dst[0] = div_255 (src[0] * src[3]); + dst[1] = div_255 (src[1] * src[3]); + dst[2] = div_255 (src[2] * src[3]); + dst[3] = src[3]; + } + dst += 4; + src += 4; + } +} + +static void +conv_rgbA8_rgba8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + if (src[3] == 255) + { + *(unsigned int *) dst = *(unsigned int *) src; + dst += 4; + } + else if (src[3] == 0) + { + *(unsigned int *) dst = 0; + dst += 4; + } + else + { + float alpha = src[3]/255.0; + float ralpha = 1.0/alpha; + //unsigned aa = ((255 << 16)) / src[3]; + unsigned aa = ((1 << 10)) * ralpha; + *dst++ = (src[0] * aa + .5) / 1024.0 + 0.5; + *dst++ = (src[1] * aa +.5) / 1024.0 + 0.5; + *dst++ = (src[2] * aa +.5) / 1024.0 + 0.5; + *dst++ = src[3]; + } + src += 4; + } +} + +static void +conv_rgb8_rgba8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples-1; + while (n--) + { + *(unsigned int *) dst = (*(unsigned int *) src) | (255UL << 24); + src += 3; + dst += 4; + } + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst[3] = 255; +} + +#define conv_rgb8_rgbA8 conv_rgb8_rgba8 + +static void +conv_rgba8_rgb8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + src += 4; + dst += 3; + } +} + +static void +conv_rgbA8_rgb8 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + int alpha = src[3]; + if (alpha == 255) + { + *dst++ = src[0]; + *dst++ = src[1]; + *dst++ = src[2]; + } + else if (alpha == 0) + { + *dst++ = 0; + *dst++ = 0; + *dst++ = 0; + } + else + { + unsigned int aa = ((255 << 16) + (alpha >> 1)) / alpha; + *dst++ = (src[0] * aa + 0x8000) >> 16; + *dst++ = (src[1] * aa + 0x8000) >> 16; + *dst++ = (src[2] * aa + 0x8000) >> 16; + } + src += 4; + } +} + +#ifndef byteclamp +#define byteclamp(j) do { if (j < 0) j = 0;else if (j > 255) j = 255; } while (0) +#endif + +#define YUV82RGB8(Y, U, V, R, G, B) do { \ + R = ((Y << 15) + 37355 * (V - 128)) >> 15; \ + G = ((Y << 15) - 12911 * (U - 128) - 19038 * (V - 128)) >> 15; \ + B = ((Y << 15) + 66454 * (U - 128)) >> 15; \ + byteclamp (R); \ + byteclamp (G); \ + byteclamp (B); \ + } while (0) + +#define RGB82YUV8(R, G, B, Y, U, V) do { \ + Y = ((9798 * R + 19234 * G + 3736 * B) >> 15) + 000; \ + U = ((-4817 * R - 9470 * G + 14320 * B) >> 15) + 128; \ + V = ((20152 * R - 16875 * G - 3277 * B) >> 15) + 128; \ + byteclamp (Y); \ + byteclamp (U); \ + byteclamp (V); \ + } while (0) + + + + static void +conv_yuvaF_rgbaF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + float *src_f = (float *) src; + float *dst_f = (float *) dst; + long n = samples; + + while (n--) + { + float Y, U, V; + float R, G, B; + + Y = src_f[0]; + U = src_f[1]; + V = src_f[2]; + + R = Y + 1.40200 * (V /*-0.5*/); + G = Y - 0.34414 * (U /*-0.5*/) -0.71414 * (V /*-0.5*/); + B = Y + 1.77200 * (U /*-0.5*/); + + dst_f[0] = R; + dst_f[1] = G; + dst_f[2] = B; + dst_f[3] = src_f[3]; + + dst_f += 4; + src_f += 4; + } +} + + +static void +conv_yuvF_rgbF (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + float *src_f = (float *) src; + float *dst_f = (float *) dst; + long n = samples; + + while (n--) + { + float Y, U, V; + float R, G, B; + + Y = src_f[0]; + U = src_f[1]; + V = src_f[2]; + + R = Y + 1.40200 * (V /*-0.5*/); + G = Y - 0.34414 * (U /*-0.5*/) -0.71414 * (V /*-0.5*/); + B = Y + 1.77200 * (U /*-0.5*/); + + dst_f[0] = R; + dst_f[1] = G; + dst_f[2] = B; + + dst_f += 3; + src_f += 3; + } +} + +int init (void); + +int +init (void) +{ + const Babl *rgbaD = babl_format_new ( + babl_model ("R'G'B'A"), + babl_type ("double"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + babl_component ("A"), + NULL); + const Babl *rgbaF = babl_format_new ( + babl_model ("R'G'B'A"), + babl_type ("float"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + babl_component ("A"), + NULL); + const Babl *rgba16 = babl_format_new ( + babl_model ("R'G'B'A"), + babl_type ("u16"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + babl_component ("A"), + NULL); + const Babl *rgba8 = babl_format_new ( + babl_model ("R'G'B'A"), + babl_type ("u8"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + babl_component ("A"), + NULL); + const Babl *rgbAF = babl_format_new ( + babl_model ("R'aG'aB'aA"), + babl_type ("float"), + babl_component ("R'a"), + babl_component ("G'a"), + babl_component ("B'a"), + babl_component ("A"), + NULL); + const Babl *rgbA16 = babl_format_new ( + babl_model ("R'aG'aB'aA"), + babl_type ("u16"), + babl_component ("R'a"), + babl_component ("G'a"), + babl_component ("B'a"), + babl_component ("A"), + NULL); + const Babl *rgbA8 = babl_format_new ( + babl_model ("R'aG'aB'aA"), + babl_type ("u8"), + babl_component ("R'a"), + babl_component ("G'a"), + babl_component ("B'a"), + babl_component ("A"), + NULL); + const Babl *rgbF = babl_format_new ( + babl_model ("R'G'B'"), + babl_type ("float"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + NULL); + const Babl *rgb16 = babl_format_new ( + babl_model ("R'G'B'"), + babl_type ("u16"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + NULL); + const Babl *rgb8 = babl_format_new ( + babl_model ("R'G'B'"), + babl_type ("u8"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + NULL); + const Babl *gaF = babl_format_new ( + babl_model ("Y'A"), + babl_type ("float"), + babl_component ("Y'"), + babl_component ("A"), + NULL); + const Babl *gAF = babl_format_new ( + babl_model ("Y'aA"), + babl_type ("float"), + babl_component ("Y'a"), + babl_component ("A"), + NULL); + const Babl *gF = babl_format_new ( + babl_model ("Y'"), + babl_type ("float"), + babl_component ("Y'"), + NULL); + const Babl *ga16 = babl_format_new ( + babl_model ("Y'A"), + babl_type ("u16"), + babl_component ("Y'"), + babl_component ("A"), + NULL); + const Babl *gA16 = babl_format_new ( + babl_model ("Y'aA"), + babl_type ("u16"), + babl_component ("Y'a"), + babl_component ("A"), + NULL); + const Babl *g16 = babl_format_new ( + babl_model ("Y'"), + babl_type ("u16"), + babl_component ("Y'"), + NULL); + const Babl *ga8 = babl_format_new ( + babl_model ("Y'A"), + babl_type ("u8"), + babl_component ("Y'"), + babl_component ("A"), + NULL); + const Babl *gA8 = babl_format_new ( + babl_model ("Y'aA"), + babl_type ("u8"), + babl_component ("Y'a"), + babl_component ("A"), + NULL); + const Babl *g8 = babl_format_new ( + babl_model ("Y'"), + babl_type ("u8"), + babl_component ("Y'"), + NULL); + const Babl *yuvF = babl_format_new ( + babl_model ("Y'CbCr"), + babl_type ("float"), + babl_component ("Y'"), + babl_type ("float"), + babl_component ("Cb"), + babl_component ("Cr"), + NULL); + const Babl *yuvaF = babl_format_new ( + babl_model ("Y'CbCrA"), + babl_type ("float"), + babl_component ("Y'"), + babl_type ("float"), + babl_component ("Cb"), + babl_component ("Cr"), + babl_component ("A"), + NULL); + +#define o(src, dst) \ + babl_conversion_new (src, dst, "linear", conv_ ## src ## _ ## dst, NULL) + + o (rgbaF, rgba8); + o (rgba8, rgbaF); + o (rgbaF, rgba16); + o (rgba16, rgbaF); + o (rgbAF, rgbA8); + o (rgbA8, rgbAF); + o (rgbAF, rgbA16); + o (rgbA16, rgbAF); + o (rgbF, rgb8); + o (rgb8, rgbF); + o (rgbF, rgb16); + o (rgb16, rgbF); + o (rgba8, rgba16); + o (rgba16, rgba8); + o (rgbA8, rgbA16); + o (rgbA16, rgbA8); + o (rgb8, rgb16); + o (rgb16, rgb8); + o (gaF, ga8); + o (gAF, gA8); + o (gF, g8); + o (ga8, gaF); + o (gA8, gAF); + o (g8, gF); + o (g8, rgb8); + o (g8, rgba8); + o (g8, rgbA8); + o (gaF, ga16); + o (gAF, gA16); + o (gF, g16); + o (ga16, gaF); + o (gA16, gAF); + o (g16, gF); + o (ga16, ga8); + o (g16, g8); + o (yuvF, rgbF); + o (yuvaF, rgbaF); + o (ga8, ga16); + o (gA8, gA16); + o (g8, g16); + o (gaF, gAF); + o (gAF, gaF); + o (rgbaF, rgbF); + o (gaF, gF); + o (rgbF, rgbaF); + o (rgbF, rgbAF); + o (gF, gaF); + o (gF, gAF); + o (gF, rgbF); + o (gF, rgbaF); + o (gF, rgbAF); + o (gaF, rgbaF); + o (gAF, rgbAF); + o (rgbaF, rgb8); + o (rgbA8, rgba8); + o (rgba8, rgbA8); + o (rgbaF, rgb16); + o (rgb8, rgba8); + o (rgb8, rgbA8); + o (rgbA8, rgb8); + o (rgba8, rgb8); + o (rgbaF, rgbA8); + o (rgbA16, rgbaF); + o (rgbaF, rgbaD); + o (rgbaD, rgbaF); + + return 0; +} diff --git a/extensions/gimp-8bit.c b/extensions/gimp-8bit.c new file mode 100644 index 0000000..326058d --- /dev/null +++ b/extensions/gimp-8bit.c @@ -0,0 +1,531 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * Optimized 8bit conversion routines as used by legacy GIMP code. + * Copyright (C) 2008 Sven Neumann + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include + +#include "babl-internal.h" + +#include "base/util.h" +#include "extensions/util.h" + + +/* lookup tables used in conversion */ + +#define MAX_SPACES 32 +static const Babl *spaces[MAX_SPACES]={NULL,}; + +static float lut_linear[1 << 8]; +static float lut_gamma_2_2[MAX_SPACES][1 << 8]; + + +static int +tables_init (const Babl *space) +{ + int i, j; + + for (j = 0; spaces[j]; j++) + { + if (spaces[j] == space) + return j; + } + spaces[j] = space; + + /* fill tables for conversion from 8 bit integer to float */ + if (j == 0) + for (i = 0; i < 1 << 8; i++) + { + double value = i / 255.0; + lut_linear[i] = value; + } + + /* fill tables for conversion from 8 bit integer to float */ + for (i = 0; i < 1 << 8; i++) + { + double value = i / 255.0; + lut_gamma_2_2[j][i] = babl_trc_to_linear (space->space.trc[0], value); + } + + return j; +} + +static inline void +u8_linear_to_float_linear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + float *d = (float *) dst; + long n = samples; + + while (n--) + *d++ = lut_linear[*src++]; +} + + +static void +u8_linear_to_float_linear_assoc (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + float *d = (float *) dst; + long n = samples; + + while (n--) + { + float alpha = lut_linear[src[3]]; + d[0] = lut_linear[src[0]] * alpha; + d[1] = lut_linear[src[1]] * alpha; + d[2] = lut_linear[src[2]] * alpha; + d[3] = alpha; + src += 4; + d += 4; + } +} + +static inline void +u8_gamma_2_2_to_float_linear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + int space_no = tables_init (conversion->conversion.source->format.space); + float *d = (float *) dst; + long n = samples; + + while (n--) + *d++ = lut_gamma_2_2[space_no][*src++]; +} + +static void +conv_rgba8_linear_rgbaF_linear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + u8_linear_to_float_linear (conversion, src, dst, samples * 4); +} + +static void +conv_rgba8_linear_ragabaaF_linear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + u8_linear_to_float_linear_assoc (conversion, src, dst, samples); +} + + +static void +conv_rgba8_gamma_2_2_rgbaF_linear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + int space_no = tables_init (conversion->conversion.source->format.space); + float *d = (float *) dst; + long n = samples; + + while (n--) + { + *d++ = lut_gamma_2_2[space_no][*src++]; + *d++ = lut_gamma_2_2[space_no][*src++]; + *d++ = lut_gamma_2_2[space_no][*src++]; + *d++ = lut_linear[*src++]; + } +} + +static void +conv_rgb8_linear_rgbF_linear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + u8_linear_to_float_linear (conversion, src, dst, samples * 3); +} + +static void +conv_rgb8_gamma_2_2_rgbF_linear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + u8_gamma_2_2_to_float_linear (conversion, src, dst, samples * 3); +} + +static void +conv_rgb8_linear_rgbaF_linear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + float *d = (float *) dst; + long n = samples; + + while (n--) + { + *d++ = lut_linear[*src++]; + *d++ = lut_linear[*src++]; + *d++ = lut_linear[*src++]; + *d++ = 1.0; + } +} + +#define conv_rgb8_linear_ragabaaF_linear conv_rgb8_linear_rgbaF_linear + +static void +conv_rgb8_gamma_2_2_rgbaF_linear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + int space_no = tables_init (conversion->conversion.source->format.space); + float *d = (float *) dst; + long n = samples; + + while (n--) + { + *d++ = lut_gamma_2_2[space_no][*src++]; + *d++ = lut_gamma_2_2[space_no][*src++]; + *d++ = lut_gamma_2_2[space_no][*src++]; + *d++ = 1.0; + } +} + +static void +conv_ga8_linear_gaF_linear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + u8_linear_to_float_linear (conversion, src, dst, samples * 2); +} + +static void +conv_ga8_gamma_2_2_gaF_linear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + int space_no = tables_init (conversion->conversion.source->format.space); + float *d = (float *) dst; + long n = samples; + + while (n--) + { + *d++ = lut_gamma_2_2[space_no][*src++]; + *d++ = lut_linear[*src++]; + } +} + +static void +conv_ga8_gamma_2_2_rgba8_gamma_2_2 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + long n = samples; + + while (n--) + { + *dst++ = *src; + *dst++ = *src; + *dst++ = *src++; + *dst++ = *src++; + } +} + +static void +conv_ga8_linear_rgbaF_linear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + float *d = (float *) dst; + long n = samples; + + while (n--) + { + float value = lut_linear[*src++]; + + *d++ = value; + *d++ = value; + *d++ = value; + *d++ = lut_linear[*src++]; + } +} + +static void +conv_ga8_gamma_2_2_rgbaF_linear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + int space_no = tables_init (conversion->conversion.source->format.space); + float *d = (float *) dst; + long n = samples; + + while (n--) + { + float value = lut_gamma_2_2[space_no][*src++]; + + *d++ = value; + *d++ = value; + *d++ = value; + *d++ = lut_linear[*src++]; + } +} + +static void +conv_g8_linear_gF_linear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + u8_linear_to_float_linear (conversion, src, dst, samples); +} + +static void +conv_g8_gamma_2_2_gF_linear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + u8_gamma_2_2_to_float_linear (conversion, src, dst, samples); +} + +static void +conv_g8_linear_rgbaF_linear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + float *d = (float *) dst; + long n = samples; + + while (n--) + { + float value = lut_linear[*src++]; + + *d++ = value; + *d++ = value; + *d++ = value; + *d++ = 1.0; + } +} + +static void +conv_g8_gamma_2_2_rgbaF_linear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + int space_no = tables_init (conversion->conversion.source->format.space); + float *d = (float *) dst; + long n = samples; + + while (n--) + { + float value = lut_gamma_2_2[space_no][*src++]; + + *d++ = value; + *d++ = value; + *d++ = value; + *d++ = 1.0; + } +} + +static void +conv_rgbaF_linear_rgb8_linear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + float *fsrc = (float *) src; + long n = samples; + long int v; + + while (n--) + { + v = rint (*fsrc++ * 255.0); + *dst++ = (v < 0) ? 0 : ((v > 255) ? 255 : v); + + v = rint (*fsrc++ * 255.0); + *dst++ = (v < 0) ? 0 : ((v > 255) ? 255 : v); + + v = rint (*fsrc++ * 255.0); + *dst++ = (v < 0) ? 0 : ((v > 255) ? 255 : v); + + fsrc++; + } +} + +static void +conv_rgbaF_linear_rgba8_linear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + float *fsrc = (float *) src; + long n = samples; + long int v; + + while (n--) + { + v = rint (*fsrc++ * 255.0); + *dst++ = (v < 0) ? 0 : ((v > 255) ? 255 : v); + + v = rint (*fsrc++ * 255.0); + *dst++ = (v < 0) ? 0 : ((v > 255) ? 255 : v); + + v = rint (*fsrc++ * 255.0); + *dst++ = (v < 0) ? 0 : ((v > 255) ? 255 : v); + + v = rint (*fsrc++ * 255.0); + *dst++ = (v < 0) ? 0 : ((v > 255) ? 255 : v); + } +} + +int init (void); + +int +init (void) +{ + const Babl *ragabaaF_linear = babl_format_new ( + babl_model ("RaGaBaA"), + babl_type ("float"), + babl_component ("Ra"), + babl_component ("Ga"), + babl_component ("Ba"), + babl_component ("A"), + NULL); + const Babl *rgbaF_linear = babl_format_new ( + babl_model ("RGBA"), + babl_type ("float"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + babl_component ("A"), + NULL); + const Babl *rgba8_linear = babl_format_new ( + babl_model ("RGBA"), + babl_type ("u8"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + babl_component ("A"), + NULL); + const Babl *rgba8_gamma_2_2 = babl_format_new ( + babl_model ("R'G'B'A"), + babl_type ("u8"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + babl_component ("A"), + NULL); + const Babl *rgbF_linear = babl_format_new ( + babl_model ("RGB"), + babl_type ("float"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + NULL); + const Babl *rgb8_linear = babl_format_new ( + babl_model ("RGB"), + babl_type ("u8"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + NULL); + const Babl *rgb8_gamma_2_2 = babl_format_new ( + babl_model ("R'G'B'"), + babl_type ("u8"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + NULL); + const Babl *gaF_linear = babl_format_new ( + babl_model ("YA"), + babl_type ("float"), + babl_component ("Y"), + babl_component ("A"), + NULL); + const Babl *ga8_linear = babl_format_new ( + babl_model ("YA"), + babl_type ("u8"), + babl_component ("Y"), + babl_component ("A"), + NULL); + const Babl *ga8_gamma_2_2 = babl_format_new ( + babl_model ("Y'A"), + babl_type ("u8"), + babl_component ("Y'"), + babl_component ("A"), + NULL); + const Babl *gF_linear = babl_format_new ( + babl_model ("Y"), + babl_type ("float"), + babl_component ("Y"), + NULL); + const Babl *g8_linear = babl_format_new ( + babl_model ("Y"), + babl_type ("u8"), + babl_component ("Y"), + NULL); + const Babl *g8_gamma_2_2 = babl_format_new ( + babl_model ("Y'"), + babl_type ("u8"), + babl_component ("Y'"), + NULL); + + tables_init (babl_space("sRGB")); + +#define o(src, dst) \ + babl_conversion_new (src, dst, "linear", conv_ ## src ## _ ## dst, NULL) + + o (rgba8_linear, ragabaaF_linear); + o (rgba8_linear, rgbaF_linear); + o (rgba8_gamma_2_2, rgbaF_linear); + + o (rgb8_linear, rgbF_linear); + o (rgb8_gamma_2_2, rgbF_linear); + o (rgb8_linear, rgbaF_linear); + o (rgb8_linear, ragabaaF_linear); + o (rgb8_gamma_2_2, rgbaF_linear); + + o (ga8_linear, gaF_linear); + o (ga8_gamma_2_2, gaF_linear); + o (ga8_linear, rgbaF_linear); + o (ga8_gamma_2_2, rgbaF_linear); + + o (ga8_gamma_2_2, rgba8_gamma_2_2); + + o (g8_linear, gF_linear); + o (g8_gamma_2_2, gF_linear); + o (g8_linear, rgbaF_linear); + o (g8_gamma_2_2, rgbaF_linear); + + o (rgbaF_linear, rgb8_linear); + o (rgbaF_linear, rgba8_linear); + + return 0; +} diff --git a/extensions/grey.c b/extensions/grey.c new file mode 100644 index 0000000..3f20842 --- /dev/null +++ b/extensions/grey.c @@ -0,0 +1,175 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2013, Daniel Sabo + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include + +#include "babl-internal.h" + +#include "base/util.h" +#include "extensions/util.h" + +static void +conv_rgbaF_linear_y8_linear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + const double *rgbtoxyz = babl_space_get_rgbtoxyz (space); + const float RGB_LUMINANCE_RED_FLOAT = rgbtoxyz[3]; + const float RGB_LUMINANCE_GREEN_FLOAT = rgbtoxyz[4]; + const float RGB_LUMINANCE_BLUE_FLOAT = rgbtoxyz[5]; + + float *s = (float *) src; + long n = samples; + + while (n--) + { + float value; + long int v; + value = *s++ * RGB_LUMINANCE_RED_FLOAT; + value += *s++ * RGB_LUMINANCE_GREEN_FLOAT; + value += *s++ * RGB_LUMINANCE_BLUE_FLOAT; + s++; + + v = rint (value * 255.0); + *dst++ = (v < 0) ? 0 : ((v > 255) ? 255 : v); + } +} + +static void +conv_rgbaF_linear_yF_linear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + const double *rgbtoxyz = babl_space_get_rgbtoxyz (space); + const float RGB_LUMINANCE_RED_FLOAT = rgbtoxyz[3]; + const float RGB_LUMINANCE_GREEN_FLOAT = rgbtoxyz[4]; + const float RGB_LUMINANCE_BLUE_FLOAT = rgbtoxyz[5]; + + float *s = (float *) src; + float *d = (float *) dst; + long n = samples; + + while (n--) + { + float value; + value = *s++ * RGB_LUMINANCE_RED_FLOAT; + value += *s++ * RGB_LUMINANCE_GREEN_FLOAT; + value += *s++ * RGB_LUMINANCE_BLUE_FLOAT; + s++; + *d++ = value; + } +} + +static void +conv_rgbaF_linear_yaF_linear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + const Babl *space = babl_conversion_get_source_space (conversion); + const double *rgbtoxyz = babl_space_get_rgbtoxyz (space); + const float RGB_LUMINANCE_RED_FLOAT = rgbtoxyz[3]; + const float RGB_LUMINANCE_GREEN_FLOAT = rgbtoxyz[4]; + const float RGB_LUMINANCE_BLUE_FLOAT = rgbtoxyz[5]; + + float *s = (float *) src; + float *d = (float *) dst; + long n = samples; + + while (n--) + { + float value; + value = *s++ * RGB_LUMINANCE_RED_FLOAT; + value += *s++ * RGB_LUMINANCE_GREEN_FLOAT; + value += *s++ * RGB_LUMINANCE_BLUE_FLOAT; + *d++ = value; + *d++ = *s++; /* alpha */ + } +} + +static void +conv_yaF_linear_rgbaF_linear (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + float *s = (float *) src; + float *d = (float *) dst; + long n = samples; + + while (n--) + { + float value; + value = *s++; + *d++ = value; + *d++ = value; + *d++ = value; + *d++ = *s++; /* alpha */ + } +} + + +int init (void); + +int +init (void) +{ + babl_conversion_new (babl_format ("RGBA float"), + babl_format ("Y u8"), + "linear", + conv_rgbaF_linear_y8_linear, + NULL); + + babl_conversion_new (babl_format ("RGBA float"), + babl_format ("Y float"), + "linear", + conv_rgbaF_linear_yF_linear, + NULL); + + babl_conversion_new (babl_format ("RGBA float"), + babl_format ("YA float"), + "linear", + conv_rgbaF_linear_yaF_linear, + NULL); + + + babl_conversion_new (babl_format ("YA float"), + babl_format ("RGBA float"), + "linear", + conv_yaF_linear_rgbaF_linear, + NULL); + + babl_conversion_new (babl_format ("YaA float"), + babl_format ("RaGaBaA float"), + "linear", + conv_yaF_linear_rgbaF_linear, + NULL); + + babl_conversion_new (babl_format ("Y'A float"), + babl_format ("R'G'B'A float"), + "linear", + conv_yaF_linear_rgbaF_linear, + NULL); + + return 0; +} diff --git a/extensions/half.c b/extensions/half.c new file mode 100644 index 0000000..f308e03 --- /dev/null +++ b/extensions/half.c @@ -0,0 +1,621 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2015 Daniel Sabo + * 2016 Øyvind Kolås + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +/* Copyright: (c) 2009 by James Tursa, All Rights Reserved + * + * This code uses the BSD License: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the distribution + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * halfprecision converts the input argument to/from a half precision floating + * point bit pattern corresponding to IEEE 754r. The bit pattern is stored in a + * uint16 class variable. Please note that halfprecision is *not* a class. That + * is, you cannot do any arithmetic with the half precision bit patterns. + * halfprecision is simply a function that converts the IEEE 754r half precision + * bit pattern to/from other numeric MATLAB variables. You can, however, take + * the half precision bit patterns, convert them to single or double, do the + * operation, and then convert the result back manually. + * + * 1 bit sign bit + * 5 bits exponent, biased by 15 + * 10 bits mantissa, hidden leading bit, normalized to 1.0 + * + * Special floating point bit patterns recognized and supported: + * + * All exponent bits zero: + * - If all mantissa bits are zero, then number is zero (possibly signed) + * - Otherwise, number is a denormalized bit pattern + * + * All exponent bits set to 1: + * - If all mantissa bits are zero, then number is +Infinity or -Infinity + * - Otherwise, number is NaN (Not a Number) + */ + +#include "config.h" + +#include +#include + +#include "babl.h" +#include "extensions/util.h" + +static void +halfp2singles_fun(void *target, + const void *source, + long numel) +{ + uint16_t *hp = (uint16_t *) source; // Type pun input as an unsigned 16-bit int + uint32_t *xp = (uint32_t *) target; // Type pun output as an unsigned 32-bit int + uint16_t h, hs, he, hm; + uint32_t xs, xe, xm; + int32_t xes; + int e; + + if( source == NULL || target == NULL ) // Nothing to convert (e.g., imag part of pure real) + return; + while( numel-- ) { + h = *hp++; + if( (h & 0x7FFFu) == 0 ) { // Signed zero + *xp++ = ((uint32_t) h) << 16; // Return the signed zero + } else { // Not zero + hs = h & 0x8000u; // Pick off sign bit + he = h & 0x7C00u; // Pick off exponent bits + hm = h & 0x03FFu; // Pick off mantissa bits + if( he == 0 ) { // Denormal will convert to normalized + e = -1; // The following loop figures out how much extra to adjust the exponent + do { + e++; + hm <<= 1; + } while( (hm & 0x0400u) == 0 ); // Shift until leading bit overflows into exponent bit + xs = ((uint32_t) hs) << 16; // Sign bit + xes = ((int32_t) (he >> 10)) - 15 + 127 - e; // Exponent unbias the halfp, then bias the single + xe = (uint32_t) (xes << 23); // Exponent + xm = ((uint32_t) (hm & 0x03FFu)) << 13; // Mantissa + *xp++ = (xs | xe | xm); // Combine sign bit, exponent bits, and mantissa bits + } else if( he == 0x7C00u ) { // Inf or NaN (all the exponent bits are set) + if( hm == 0 ) { // If mantissa is zero ... + *xp++ = (((uint32_t) hs) << 16) | ((uint32_t) 0x7F800000u); // Signed Inf + } else { + *xp++ = (uint32_t) 0xFFC00000u; // NaN, only 1st mantissa bit set + } + } else { // Normalized number + xs = ((uint32_t) hs) << 16; // Sign bit + xes = ((int32_t) (he >> 10)) - 15 + 127; // Exponent unbias the halfp, then bias the single + xe = (uint32_t) (xes << 23); // Exponent + xm = ((uint32_t) hm) << 13; // Mantissa + *xp++ = (xs | xe | xm); // Combine sign bit, exponent bits, and mantissa bits + } + } + } +} + +static float half_float_table[65536]; + +static void +halfp2singles(void *target, + const void *source, + long numel) +{ + uint16_t *src = (uint16_t *) source; + float *dst = (float *) target; + int i; + for (i = 0; i < numel; i++) + { + dst[i] = half_float_table[src[i]]; + } +} + +/* from table based approach from qcms/blink/webkit */ + +const unsigned short half_float_base_table[512] = { +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,1,2,4,8,16,32,64,128,256, +512,1024,2048,3072,4096,5120,6144,7168,8192,9216,10240,11264,12288,13312,14336,15360, +16384,17408,18432,19456,20480,21504,22528,23552,24576,25600,26624,27648,28672,29696,30720,31744, +31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744, +31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744, +31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744, +31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744, +31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744, +31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744, +31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744,31744, +32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768, +32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768, +32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768, +32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768, +32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768, +32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768,32768, +32768,32768,32768,32768,32768,32768,32768,32769,32770,32772,32776,32784,32800,32832,32896,33024, +33280,33792,34816,35840,36864,37888,38912,39936,40960,41984,43008,44032,45056,46080,47104,48128, +49152,50176,51200,52224,53248,54272,55296,56320,57344,58368,59392,60416,61440,62464,63488,64512, +64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512, +64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512, +64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512, +64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512, +64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512, +64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512, +64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512,64512 +}; + +const unsigned char half_float_shift_table[512] = { +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,23,22,21,20,19,18,17,16,15, +14,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, +13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,13, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,23,22,21,20,19,18,17,16,15, +14,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, +13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,13 +}; + +static inline unsigned short +float_to_half_float(float f) +{ + // See Blink::Source/platform/graphics/gpu/WebGLImageConversion.cpp::convertFloatToHalfFloat() and http://crbug.com/491784 + union { + float f; + uint32_t u; + } u; + unsigned int temp; + unsigned int signexp; + u.f = f; + temp = u.u; + signexp = (temp >> 23) & 0x1ff; + return half_float_base_table[signexp] + ((temp & 0x007fffff) >> half_float_shift_table[signexp]); +} + +static void +singles2halfp(void *target, + const void *source, + long numel) +{ + const float *src = source; + uint16_t *dst = target; + int i; + for (i = 0; i < numel; i++) + dst[i] = float_to_half_float (src[i]); +} + +static inline void +conv_yHalf_yF (const Babl *conversion, + const uint16_t *src, + float *dst, + long samples) +{ + halfp2singles(dst, src, samples); +} + +static void +conv_yaHalf_yaF (const Babl *conversion, + const uint16_t *src, + float *dst, + long samples) +{ + conv_yHalf_yF (conversion, src, dst, samples * 2); +} + +static void +conv_rgbHalf_rgbF (const Babl *conversion, + const uint16_t *src, + float *dst, + long samples) +{ + conv_yHalf_yF (conversion, src, dst, samples * 3); +} + +static void +conv_rgbaHalf_rgbaF (const Babl *conversion, + const uint16_t *src, + float *dst, + long samples) +{ + conv_yHalf_yF (conversion, src, dst, samples * 4); +} + +#define conv_rgbAHalf_rgbAF conv_rgbaHalf_rgbaF + +static void +conv_yF_yHalf (const Babl *conversion, + const float *src, + uint16_t *dst, + long samples) +{ + singles2halfp (dst, src, samples); +} + +static void +conv_yaF_yaHalf (const Babl *conversion, + const float *src, + uint16_t *dst, + long samples) +{ + conv_yF_yHalf (conversion, src, dst, samples * 2); +} + +static void +conv_rgbF_rgbHalf (const Babl *conversion, + const float *src, + uint16_t *dst, + long samples) +{ + conv_yF_yHalf (conversion, src, dst, samples * 3); +} + +static void +conv_rgbaF_rgbaHalf (const Babl *conversion, + const float *src, + uint16_t *dst, + long samples) +{ + conv_yF_yHalf (conversion, src, dst, samples * 4); +} + +#define conv_rgbAF_rgbAHalf conv_rgbaF_rgbaHalf + +static void +singles2halfp2(void *target, + const void *source, + long numel) +{ + uint16_t *hp = (uint16_t *) target; // Type pun output as an unsigned 16-bit int + uint32_t *xp = (uint32_t *) source; // Type pun input as an unsigned 32-bit int + uint16_t hs, he, hm; + uint32_t x, xs, xe, xm; + int hes; + + if( source == NULL || target == NULL ) { // Nothing to convert (e.g., imag part of pure real) + return; + } + while( numel-- ) { + x = *xp++; + if( (x & 0x7FFFFFFFu) == 0 ) { // Signed zero + *hp++ = (uint16_t) (x >> 16); // Return the signed zero + } else { // Not zero + xs = x & 0x80000000u; // Pick off sign bit + xe = x & 0x7F800000u; // Pick off exponent bits + xm = x & 0x007FFFFFu; // Pick off mantissa bits + if( xe == 0 ) { // Denormal will underflow, return a signed zero + *hp++ = (uint16_t) (xs >> 16); + } else if( xe == 0x7F800000u ) { // Inf or NaN (all the exponent bits are set) + if( xm == 0 ) { // If mantissa is zero ... + *hp++ = (uint16_t) ((xs >> 16) | 0x7C00u); // Signed Inf + } else { + *hp++ = (uint16_t) 0xFE00u; // NaN, only 1st mantissa bit set + } + } else { // Normalized number + hs = (uint16_t) (xs >> 16); // Sign bit + hes = ((int)(xe >> 23)) - 127 + 15; // Exponent unbias the single, then bias the halfp + if( hes >= 0x1F ) { // Overflow + *hp++ = (uint16_t) ((xs >> 16) | 0x7C00u); // Signed Inf + } else if( hes <= 0 ) { // Underflow + if( (14 - hes) > 24 ) { // Mantissa shifted all the way off & no rounding possibility + hm = (uint16_t) 0u; // Set mantissa to zero + } else { + xm |= 0x00800000u; // Add the hidden leading bit + hm = (uint16_t) (xm >> (14 - hes)); // Mantissa + if( (xm >> (13 - hes)) & 0x00000001u ) // Check for rounding + hm += (uint16_t) 1u; // Round, might overflow into exp bit, but this is OK + } + *hp++ = (hs | hm); // Combine sign bit and mantissa bits, biased exponent is zero + } else { + he = (uint16_t) (hes << 10); // Exponent + hm = (uint16_t) (xm >> 13); // Mantissa + if( xm & 0x00001000u ) // Check for rounding + *hp++ = (hs | he | hm) + (uint16_t) 1u; // Round, might overflow to inf, this is OK + else + *hp++ = (hs | he | hm); // No rounding + } + } + } + } +} + +static void +conv2_yF_yHalf (const Babl *conversion, + const float *src, + uint16_t *dst, + long samples) +{ + singles2halfp2 (dst, src, samples); +} + +static void +conv2_yaF_yaHalf (const Babl *conversion, + const float *src, + uint16_t *dst, + long samples) +{ + conv2_yF_yHalf (conversion, src, dst, samples * 2); +} + +static void +conv2_rgbF_rgbHalf (const Babl *conversion, + const float *src, + uint16_t *dst, + long samples) +{ + conv2_yF_yHalf (conversion, src, dst, samples * 3); +} + +static void +conv2_rgbaF_rgbaHalf (const Babl *conversion, + const float *src, + uint16_t *dst, + long samples) +{ + conv2_yF_yHalf (conversion, src, dst, samples * 4); +} + +#define conv_yAF_yAHalf conv_yaF_yaHalf +#define conv_yAHalf_yAF conv_yaHalf_yaF + +int init (void); + +int +init (void) +{ + int i; + const Babl *rgbaF_linear = babl_format_new ( + babl_model ("RGBA"), + babl_type ("float"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + babl_component ("A"), + NULL); + const Babl *rgbAF_linear = babl_format_new ( + babl_model ("RaGaBaA"), + babl_type ("float"), + babl_component ("Ra"), + babl_component ("Ga"), + babl_component ("Ba"), + babl_component ("A"), + NULL); + const Babl *rgbAHalf_linear = babl_format_new ( + babl_model ("RaGaBaA"), + babl_type ("half"), + babl_component ("Ra"), + babl_component ("Ga"), + babl_component ("Ba"), + babl_component ("A"), + NULL); + const Babl *rgbAF_gamma = babl_format_new ( + babl_model ("R'aG'aB'aA"), + babl_type ("float"), + babl_component ("R'a"), + babl_component ("G'a"), + babl_component ("B'a"), + babl_component ("A"), + NULL); + const Babl *rgbAHalf_gamma = babl_format_new ( + babl_model ("R'aG'aB'aA"), + babl_type ("half"), + babl_component ("R'a"), + babl_component ("G'a"), + babl_component ("B'a"), + babl_component ("A"), + NULL); + + const Babl *rgbaHalf_linear = babl_format_new ( + babl_model ("RGBA"), + babl_type ("half"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + babl_component ("A"), + NULL); + const Babl *rgbaF_gamma = babl_format_new ( + babl_model ("R'G'B'A"), + babl_type ("float"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + babl_component ("A"), + NULL); + const Babl *rgbaHalf_gamma = babl_format_new ( + babl_model ("R'G'B'A"), + babl_type ("half"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + babl_component ("A"), + NULL); + const Babl *rgbF_linear = babl_format_new ( + babl_model ("RGB"), + babl_type ("float"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + NULL); + const Babl *rgbHalf_linear = babl_format_new ( + babl_model ("RGB"), + babl_type ("half"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + NULL); + const Babl *rgbF_gamma = babl_format_new ( + babl_model ("R'G'B'"), + babl_type ("float"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + NULL); + const Babl *rgbHalf_gamma = babl_format_new ( + babl_model ("R'G'B'"), + babl_type ("half"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + NULL); + const Babl *yaF_linear = babl_format_new ( + babl_model ("YA"), + babl_type ("float"), + babl_component ("Y"), + babl_component ("A"), + NULL); + const Babl *yAF_linear = babl_format_new ( + babl_model ("YaA"), + babl_type ("float"), + babl_component ("Ya"), + babl_component ("A"), + NULL); + const Babl *yaHalf_linear = babl_format_new ( + babl_model ("YA"), + babl_type ("half"), + babl_component ("Y"), + babl_component ("A"), + NULL); + const Babl *yAHalf_linear = babl_format_new ( + babl_model ("YaA"), + babl_type ("half"), + babl_component ("Ya"), + babl_component ("A"), + NULL); + const Babl *yaF_gamma = babl_format_new ( + babl_model ("Y'A"), + babl_type ("float"), + babl_component ("Y'"), + babl_component ("A"), + NULL); + const Babl *yAF_gamma = babl_format_new ( + babl_model ("Y'aA"), + babl_type ("float"), + babl_component ("Y'a"), + babl_component ("A"), + NULL); + const Babl *yaHalf_gamma = babl_format_new ( + babl_model ("Y'A"), + babl_type ("half"), + babl_component ("Y'"), + babl_component ("A"), + NULL); + const Babl *yAHalf_gamma = babl_format_new ( + babl_model ("Y'aA"), + babl_type ("half"), + babl_component ("Y'a"), + babl_component ("A"), + NULL); + const Babl *yF_linear = babl_format_new ( + babl_model ("Y"), + babl_type ("float"), + babl_component ("Y"), + NULL); + const Babl *yHalf_linear = babl_format_new ( + babl_model ("Y"), + babl_type ("half"), + babl_component ("Y"), + NULL); + const Babl *yF_gamma = babl_format_new ( + babl_model ("Y'"), + babl_type ("float"), + babl_component ("Y'"), + NULL); + const Babl *yHalf_gamma = babl_format_new ( + babl_model ("Y'"), + babl_type ("half"), + babl_component ("Y'"), + NULL); + + for (i = 0; i < 65536; i++) + { + uint16_t buf[2] = {i, i}; + float fbuf[2]; + halfp2singles_fun(fbuf, buf, 1); + half_float_table[i] = fbuf[0]; + } + +#define CONV(src, dst) \ +{ \ + babl_conversion_new (src ## _linear, dst ## _linear, "linear", conv_ ## src ## _ ## dst, NULL); \ + babl_conversion_new (src ## _gamma, dst ## _gamma, "linear", conv_ ## src ## _ ## dst, NULL); \ +} +#define CONV2(src, dst) \ +{ \ + babl_conversion_new (src ## _linear, dst ## _linear, "linear", conv2_ ## src ## _ ## dst, NULL); \ + babl_conversion_new (src ## _gamma, dst ## _gamma, "linear", conv2_ ## src ## _ ## dst, NULL); \ +} + + CONV(rgbAHalf, rgbAF); + CONV(rgbAF, rgbAHalf); + CONV(rgbaHalf, rgbaF); + CONV(rgbHalf, rgbF); + CONV(yaHalf, yaF); + CONV(yHalf, yF); + CONV(rgbaF, rgbaHalf); + CONV(rgbF, rgbHalf); + CONV(yaF, yaHalf); + CONV(yF, yHalf); + + CONV(yAF, yAHalf); + CONV(yAHalf, yAF); + + CONV2(rgbaF, rgbaHalf); + CONV2(rgbF, rgbHalf); + CONV2(yaF, yaHalf); + CONV2(yF, yHalf); + + return 0; +} diff --git a/extensions/meson.build b/extensions/meson.build new file mode 100644 index 0000000..850793f --- /dev/null +++ b/extensions/meson.build @@ -0,0 +1,69 @@ +babl_extensions_build_dir = meson.current_build_dir() + +no_cflags = [] + +# Dependencies +babl_ext_dep = [ + math, + thread, +] + +# Include directories +babl_ext_inc = [ + rootInclude, + bablInclude, +] + +# Linker arguments +babl_ext_link_args = [ +] +if platform_win32 + babl_ext_link_args += no_undefined +endif + + +extensions = [ + ['u16', no_cflags], + ['u32', no_cflags], + ['cairo', no_cflags], + ['CIE', sse2_cflags], + ['double', no_cflags], + ['fast-float', no_cflags], + ['half', no_cflags], + ['float', no_cflags], + ['gegl-fixups', no_cflags], + ['gggl-lies', no_cflags], + ['gggl-table-lies', no_cflags], + ['gggl-table', no_cflags], + ['gggl', no_cflags], + ['gimp-8bit', no_cflags], + ['grey', no_cflags], + ['HCY', no_cflags], + ['HSL', no_cflags], + ['HSV', no_cflags], + ['naive-CMYK', no_cflags], + ['simple', no_cflags], + ['sse-half', [sse4_1_cflags, f16c_cflags]], + ['sse2-float', sse2_cflags], + ['sse2-int16', sse2_cflags], + ['sse2-int8', sse2_cflags], + ['sse4-int8', sse4_1_cflags], + ['avx2-int8', avx2_cflags], + ['two-table', sse2_cflags], + ['ycbcr', sse2_cflags], +] + +foreach ext : extensions + library( + ext[0], + ext[0] + '.c', + c_args: ext[1], + include_directories: babl_ext_inc, + link_with: babl, + link_args: babl_ext_link_args, + dependencies: babl_ext_dep, + name_prefix: '', + install: true, + install_dir: babl_libdir / lib_name, + ) +endforeach diff --git a/extensions/naive-CMYK.c b/extensions/naive-CMYK.c new file mode 100644 index 0000000..de93fa8 --- /dev/null +++ b/extensions/naive-CMYK.c @@ -0,0 +1,42 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, 2018 Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + * + * this is an interim file, to keep babl from complaining about double + * registration of cmyk formats. + */ + +#include "config.h" +#include +#include + +#include "babl.h" +#include "base/util.h" + +int init (void); + +/* implement a hacky way to do cmyk with cairo */ +/* CMYKA */ +/* CMKA */ +/* CKYA */ + + +int +init (void) +{ + return 0; +} + diff --git a/extensions/simple.c b/extensions/simple.c new file mode 100644 index 0000000..627247a --- /dev/null +++ b/extensions/simple.c @@ -0,0 +1,830 @@ +#include +#include +#include "babl.h" + +int init (void); + + +static inline void +float_to_u8_x1 (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst, + long samples) +{ + float *src = (float *)src_char; + long n = samples; + while (n--) + { + float r = src[0]; + dst[0] = (r >= 1.0f) ? 0xFF : ((r <= 0.0f) ? 0x0 : 0xFF * r + 0.5f); + dst += 1; + src += 1; + } +} + +static inline void +float_to_u8_x4 (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst, + long samples) +{ + float_to_u8_x1 (conversion, src_char, dst, samples * 4); +} + +static inline void +float_to_u8_x3 (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst, + long samples) +{ + float_to_u8_x1 (conversion, src_char, dst, samples * 3); +} + +static inline void +float_to_u8_x2 (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst, + long samples) +{ + float_to_u8_x1 (conversion, src_char, dst, samples * 2); +} + + + +static inline void +float_pre_to_u8_pre (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst, + long samples) +{ + float *src = (float *)src_char; + long n = samples; + while (n--) + { + float r = src[0]; + float g = src[1]; + float b = src[2]; + float a = src[3]; + + if (a > 1.0f) { + r /= a; + g /= a; + b /= a; + a /= a; + } + + dst[0] = (r >= 1.0f) ? 0xFF : ((r <= 0.0f) ? 0x0 : 0xFF * r + 0.5f); + dst[1] = (g >= 1.0f) ? 0xFF : ((g <= 0.0f) ? 0x0 : 0xFF * g + 0.5f); + dst[2] = (b >= 1.0f) ? 0xFF : ((b <= 0.0f) ? 0x0 : 0xFF * b + 0.5f); + dst[3] = (a >= 1.0f) ? 0xFF : ((a <= 0.0f) ? 0x0 : 0xFF * a + 0.5f); + + dst += 4; + src += 4; + + } +} + +static inline void +float_to_u16_x1 (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples) +{ + float *src = (float *)src_char; + uint16_t *dst = (uint16_t *)dst_char; + long n = samples; + while (n--) + { + float r = src[0]; + dst[0] = (r >= 1.0f) ? 0xFFFF : ((r <= 0.0f) ? 0x0 : 0xFFFF * r + 0.5f); + dst += 1; + src += 1; + } +} +static inline void +float_to_u16_x2 (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples) +{ + float_to_u16_x1 (conversion, src_char, dst_char, samples * 2); +} +static inline void +float_to_u16_x3 (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples) +{ + float_to_u16_x1 (conversion, src_char, dst_char, samples * 3); +} +static inline void +float_to_u16_x4 (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples) +{ + float_to_u16_x1 (conversion, src_char, dst_char, samples * 4); +} + +static inline void +float_pre_to_u16_pre (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples) +{ + float *src = (float *)src_char; + uint16_t *dst = (uint16_t *)dst_char; + long n = samples; + while (n--) + { + float r = src[0]; + float g = src[1]; + float b = src[2]; + float a = src[3]; + + dst[0] = (r >= 1.0f) ? 0xFFFF : ((r <= 0.0f) ? 0x0 : 0xFFFF * r + 0.5f); + dst[1] = (g >= 1.0f) ? 0xFFFF : ((g <= 0.0f) ? 0x0 : 0xFFFF * g + 0.5f); + dst[2] = (b >= 1.0f) ? 0xFFFF : ((b <= 0.0f) ? 0x0 : 0xFFFF * b + 0.5f); + dst[3] = (a >= 1.0f) ? 0xFFFF : ((a <= 0.0f) ? 0x0 : 0xFFFF * a + 0.5f); + + dst += 4; + src += 4; + } +} + +static inline void +float_pre_to_u32_pre (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples) +{ + float *src = (float *)src_char; + uint32_t *dst = (uint32_t *)dst_char; + long n = samples; + while (n--) + { + float r = src[0]; + float g = src[1]; + float b = src[2]; + float a = src[3]; + + dst[0] = (r >= 1.0f) ? 0xFFFFFFFF : ((r <= 0.0f) ? 0x0 : 0xFFFFFFFF * r + 0.5f); + dst[1] = (g >= 1.0f) ? 0xFFFFFFFF : ((g <= 0.0f) ? 0x0 : 0xFFFFFFFF * g + 0.5f); + dst[2] = (b >= 1.0f) ? 0xFFFFFFFF : ((b <= 0.0f) ? 0x0 : 0xFFFFFFFF * b + 0.5f); + dst[3] = (a >= 1.0f) ? 0xFFFFFFFF : ((a <= 0.0f) ? 0x0 : 0xFFFFFFFF * a + 0.5f); + + dst += 4; + src += 4; + } +} + + +static inline void +float_to_u32_x1 (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples) +{ + float *src = (float *)src_char; + uint32_t *dst = (uint32_t *)dst_char; + long n = samples; + while (n--) + { + double r = src[0]; + + dst[0] = (r >= 1.0f) ? 0xFFFFFFFF : ((r <= 0.0f) ? 0x0 : 0xFFFFFFFF * r + 0.5f); + + dst += 1; + src += 1; + } +} +static void +float_to_u32_x2 (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples) +{ + float_to_u32_x1 (conversion, src_char, dst_char, samples * 2); +} +static void +float_to_u32_x3 (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples) +{ + float_to_u32_x1 (conversion, src_char, dst_char, samples * 3); +} +static void +float_to_u32_x4 (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples) +{ + float_to_u32_x1 (conversion, src_char, dst_char, samples * 4); +} + + +static inline void +u32_to_float (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples) +{ + uint32_t *src = (uint32_t *)src_char; + float *dst = (float *)dst_char; + long n = samples; + while (n--) + { + dst[0] = src[0] / 4294967295.0; + dst ++; + src ++; + } +} + +static void +u32_to_float_x4 (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples) +{ + u32_to_float (conversion, src_char, dst_char, samples * 4); +} + +static void +u32_to_float_x3 (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples) +{ + u32_to_float (conversion, src_char, dst_char, samples * 3); +} + + +static void +u32_to_float_x2 (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples) +{ + u32_to_float (conversion, src_char, dst_char, samples * 2); +} + + +static inline void +u16_to_float (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples) +{ + uint16_t *src = (uint16_t *)src_char; + float *dst = (float *)dst_char; + long n = samples; + while (n--) + { + dst[0] = src[0] / 65535.0f; + dst ++; + src ++; + } +} + +static void +u16_to_float_x4 (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples) +{ + u16_to_float (conversion, src_char, dst_char, samples * 4); +} + +static void +u16_to_float_x3 (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples) +{ + u16_to_float (conversion, src_char, dst_char, samples * 3); +} + + +static void +u16_to_float_x2 (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples) +{ + u16_to_float (conversion, src_char, dst_char, samples * 2); +} + +static inline void +yau16_rgbaf (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples) +{ + uint16_t *src = (uint16_t *)src_char; + float *dst = (float *)dst_char; + long n = samples; + while (n--) + { + dst[0] = src[0] / 65535.0f; + dst[1] = src[0] / 65535.0f; + dst[2] = src[0] / 65535.0f; + dst[3] = src[1] / 65535.0f; + dst +=4; + src +=2; + } +} + + +static inline void +u8_to_float (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples) +{ + uint8_t *src = (uint8_t *)src_char; + float *dst = (float *)dst_char; + long n = samples; + while (n--) + { + dst[0] = src[0] / 255.0f; + dst ++; + src ++; + } +} + +static void +u8_to_float_x4 (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples) +{ + u8_to_float (conversion, src_char, dst_char, samples * 4); +} + +static void +u8_to_float_x3 (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples) +{ + u8_to_float (conversion, src_char, dst_char, samples * 3); +} + + +static void +u8_to_float_x2 (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples) +{ + u8_to_float (conversion, src_char, dst_char, samples * 2); +} + +static inline void +yau8_rgbaf (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples) +{ + uint8_t *src = (uint8_t *)src_char; + float *dst = (float *)dst_char; + long n = samples; + while (n--) + { + dst[0] = src[0] / 255.0f; + dst[1] = src[0] / 255.0f; + dst[2] = src[0] / 255.0f; + dst[3] = src[1] / 255.0f; + dst +=4; + src +=2; + } +} + + +static inline void +yu8_yau8 (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples) +{ + uint8_t *src = (uint8_t *)src_char; + uint8_t *dst = (uint8_t *)dst_char; + long n = samples; + while (n--) + { + dst[0] = src[0]; + dst[1] = 255; + dst += 2; + src += 1; + } +} + + +static inline void +yau8_yu8 (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples) +{ + uint8_t *src = (uint8_t *)src_char; + uint8_t *dst = (uint8_t *)dst_char; + long n = samples; + while (n--) + { + dst[0] = src[0]; + dst += 1; + src += 2; + } +} + + + +static inline void +yu16_yau16 (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples) +{ + uint16_t *src = (uint16_t *)src_char; + uint16_t *dst = (uint16_t *)dst_char; + long n = samples; + while (n--) + { + dst[0] = src[0]; + dst[1] = 65535; + dst += 2; + src += 1; + } +} + +static inline void +yau16_yu16 (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst_char, + long samples) +{ + uint16_t *src = (uint16_t *)src_char; + uint16_t *dst = (uint16_t *)dst_char; + long n = samples; + while (n--) + { + dst[0] = src[0]; + dst += 1; + src += 2; + } +} + + +int +init (void) +{ + /* float and u8 */ + babl_conversion_new (babl_format ("R'G'B'A float"), + babl_format ("R'G'B'A u8"), + "linear", + float_to_u8_x4, + NULL); + babl_conversion_new (babl_format ("RGBA float"), + babl_format ("RGBA u8"), + "linear", + float_to_u8_x4, + NULL); + babl_conversion_new (babl_format ("R'G'B' float"), + babl_format ("R'G'B' u8"), + "linear", + float_to_u8_x3, + NULL); + babl_conversion_new (babl_format ("RGB float"), + babl_format ("RGB u8"), + "linear", + float_to_u8_x3, + NULL); + babl_conversion_new (babl_format ("Y'A float"), + babl_format ("Y'A u8"), + "linear", + float_to_u8_x2, + NULL); + babl_conversion_new (babl_format ("YA float"), + babl_format ("YA u8"), + "linear", + float_to_u8_x2, + NULL); + babl_conversion_new (babl_format ("YA float"), + babl_format ("YA u8"), + "linear", + float_to_u8_x2, + NULL); + babl_conversion_new (babl_format ("Y' float"), + babl_format ("Y' u8"), + "linear", + float_to_u8_x1, + NULL); + babl_conversion_new (babl_format ("R'aG'aB'aA float"), + babl_format ("R'aG'aB'aA u8"), + "linear", + float_pre_to_u8_pre, + NULL); + babl_conversion_new (babl_format ("RaGaBaA float"), + babl_format ("RaGaBaA u8"), + "linear", + float_pre_to_u8_pre, + NULL); + + /* float and u16 */ + babl_conversion_new (babl_format ("R'G'B'A float"), + babl_format ("R'G'B'A u16"), + "linear", + float_to_u16_x4, + NULL); + babl_conversion_new (babl_format ("RGBA float"), + babl_format ("RGBA u16"), + "linear", + float_to_u16_x4, + NULL); + + babl_conversion_new (babl_format ("R'G'B' float"), + babl_format ("R'G'B' u16"), + "linear", + float_to_u16_x3, + NULL); + babl_conversion_new (babl_format ("RGB float"), + babl_format ("RGB u16"), + "linear", + float_to_u16_x3, + NULL); + babl_conversion_new (babl_format ("Y'A float"), + babl_format ("Y'A u16"), + "linear", + float_to_u16_x2, + NULL); + babl_conversion_new (babl_format ("YA float"), + babl_format ("YA u16"), + "linear", + float_to_u16_x2, + NULL); + babl_conversion_new (babl_format ("Y' float"), + babl_format ("Y' u16"), + "linear", + float_to_u16_x1, + NULL); + babl_conversion_new (babl_format ("Y float"), + babl_format ("Y u16"), + "linear", + float_to_u16_x1, + NULL); + babl_conversion_new (babl_format ("R'aG'aB'aA float"), + babl_format ("R'aG'aB'aA u16"), + "linear", + float_pre_to_u16_pre, + NULL); + babl_conversion_new (babl_format ("RaGaBaA float"), + babl_format ("RaGaBaA u16"), + "linear", + float_pre_to_u16_pre, + NULL); + + + /* float and u32 */ + babl_conversion_new (babl_format ("R'G'B'A float"), + babl_format ("R'G'B'A u32"), + "linear", + float_to_u32_x4, + NULL); + babl_conversion_new (babl_format ("RGBA float"), + babl_format ("RGBA u32"), + "linear", + float_to_u32_x4, + NULL); + babl_conversion_new (babl_format ("R'G'B' float"), + babl_format ("R'G'B' u32"), + "linear", + float_to_u32_x3, + NULL); + babl_conversion_new (babl_format ("RGB float"), + babl_format ("RGB u32"), + "linear", + float_to_u32_x3, + NULL); + babl_conversion_new (babl_format ("Y'A float"), + babl_format ("Y'A u32"), + "linear", + float_to_u32_x2, + NULL); + babl_conversion_new (babl_format ("YA float"), + babl_format ("YA u32"), + "linear", + float_to_u32_x2, + NULL); + babl_conversion_new (babl_format ("Y' float"), + babl_format ("Y' u32"), + "linear", + float_to_u32_x1, + NULL); + babl_conversion_new (babl_format ("Y float"), + babl_format ("Y u32"), + "linear", + float_to_u32_x1, + NULL); + babl_conversion_new (babl_format ("R'aG'aB'aA float"), + babl_format ("R'aG'aB'aA u32"), + "linear", + float_pre_to_u32_pre, + NULL); + babl_conversion_new (babl_format ("RaGaBaA float"), + babl_format ("RaGaBaA u32"), + "linear", + float_pre_to_u32_pre, + NULL); + babl_conversion_new (babl_format ("YA u32"), + babl_format ("YA float"), + "linear", + u32_to_float_x2, + NULL); + babl_conversion_new (babl_format ("Y'A u32"), + babl_format ("Y'A float"), + "linear", + u32_to_float_x2, + NULL); + babl_conversion_new (babl_format ("Y u32"), + babl_format ("Y float"), + "linear", + u32_to_float, + NULL); + babl_conversion_new (babl_format ("Y' u32"), + babl_format ("Y' float"), + "linear", + u32_to_float, + NULL); + babl_conversion_new (babl_format ("RGBA u32"), + babl_format ("RGBA float"), + "linear", + u32_to_float_x4, + NULL); + babl_conversion_new (babl_format ("R'G'B'A u32"), + babl_format ("R'G'B'A float"), + "linear", + u32_to_float_x4, + NULL); + + babl_conversion_new (babl_format ("RGB u32"), + babl_format ("RGB float"), + "linear", + u32_to_float_x3, + NULL); + babl_conversion_new (babl_format ("R'G'B' u32"), + babl_format ("R'G'B' float"), + "linear", + u32_to_float_x3, + NULL); + + + + babl_conversion_new (babl_format ("YA u16"), + babl_format ("YA float"), + "linear", + u16_to_float_x2, + NULL); + babl_conversion_new (babl_format ("Y'A u16"), + babl_format ("Y'A float"), + "linear", + u16_to_float_x2, + NULL); + babl_conversion_new (babl_format ("Y u16"), + babl_format ("Y float"), + "linear", + u16_to_float, + NULL); + babl_conversion_new (babl_format ("Y' u16"), + babl_format ("Y' float"), + "linear", + u16_to_float, + NULL); + babl_conversion_new (babl_format ("RGBA u16"), + babl_format ("RGBA float"), + "linear", + u16_to_float_x4, + NULL); + babl_conversion_new (babl_format ("R'G'B'A u16"), + babl_format ("R'G'B'A float"), + "linear", + u16_to_float_x4, + NULL); + + babl_conversion_new (babl_format ("RGB u16"), + babl_format ("RGB float"), + "linear", + u16_to_float_x3, + NULL); + babl_conversion_new (babl_format ("R'G'B' u16"), + babl_format ("R'G'B' float"), + "linear", + u16_to_float_x3, + NULL); + babl_conversion_new (babl_format ("Y'A u16"), + babl_format ("R'G'B'A float"), + "linear", + yau16_rgbaf, + NULL); + + + babl_conversion_new (babl_format ("YA u8"), + babl_format ("YA float"), + "linear", + u8_to_float_x2, + NULL); + babl_conversion_new (babl_format ("Y'A u8"), + babl_format ("Y'A float"), + "linear", + u8_to_float_x2, + NULL); + babl_conversion_new (babl_format ("Y u8"), + babl_format ("Y float"), + "linear", + u8_to_float, + NULL); + babl_conversion_new (babl_format ("Y' u8"), + babl_format ("Y' float"), + "linear", + u8_to_float, + NULL); + babl_conversion_new (babl_format ("RGBA u8"), + babl_format ("RGBA float"), + "linear", + u8_to_float_x4, + NULL); + babl_conversion_new (babl_format ("R'G'B'A u8"), + babl_format ("R'G'B'A float"), + "linear", + u8_to_float_x4, + NULL); + + babl_conversion_new (babl_format ("RGB u8"), + babl_format ("RGB float"), + "linear", + u8_to_float_x3, + NULL); + babl_conversion_new (babl_format ("R'G'B' u8"), + babl_format ("R'G'B' float"), + "linear", + u8_to_float_x3, + NULL); + babl_conversion_new (babl_format ("Y'A u8"), + babl_format ("R'G'B'A float"), + "linear", + yau8_rgbaf, + NULL); + + + babl_conversion_new (babl_format ("Y' u8"), + babl_format ("Y'A u8"), + "linear", + yu8_yau8, + NULL); + + babl_conversion_new (babl_format ("Y u8"), + babl_format ("YA u8"), + "linear", + yu8_yau8, + NULL); + + babl_conversion_new (babl_format ("Y' u16"), + babl_format ("Y'A u16"), + "linear", + yu16_yau16, + NULL); + + babl_conversion_new (babl_format ("Y u16"), + babl_format ("YA u16"), + "linear", + yu16_yau16, + NULL); + + + babl_conversion_new (babl_format ("Y'A u8"), + babl_format ("Y' u8"), + "linear", + yau8_yu8, + NULL); + + babl_conversion_new (babl_format ("YA u8"), + babl_format ("Y u8"), + "linear", + yau8_yu8, + NULL); + + babl_conversion_new (babl_format ("Y'A u16"), + babl_format ("Y' u16"), + "linear", + yau16_yu16, + NULL); + + babl_conversion_new (babl_format ("YA u16"), + babl_format ("Y u16"), + "linear", + yau16_yu16, + NULL); + + + return 0; +} diff --git a/extensions/sse-half.c b/extensions/sse-half.c new file mode 100644 index 0000000..cee3975 --- /dev/null +++ b/extensions/sse-half.c @@ -0,0 +1,319 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2015 Daniel Sabo + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" + +#if defined(USE_SSE4_1) && defined(USE_F16C) && defined(ARCH_X86_64) + +#include + +#include +#include + +#include "babl.h" +#include "babl-cpuaccel.h" +#include "extensions/util.h" + +static inline void +conv_yHalf_yF (const Babl *conversion, + const uint16_t *src, + float *dst, + long samples) +{ + const uint64_t *s_vec; + __v4sf *d_vec; + + long n = samples; + + s_vec = (const uint64_t *)src; + d_vec = (__v4sf *)dst; + + while (n >= 4) + { + __m128i in_val = _mm_insert_epi64((__m128i)_mm_setzero_ps(), *s_vec++, 0); + __v4sf out_val = (__v4sf)_mm_cvtph_ps(in_val); + _mm_storeu_ps((float *)d_vec++, out_val); + n -= 4; + } + + src = (const uint16_t *)s_vec; + dst = (float *)d_vec; + + while (n) + { + __m128i in_val = _mm_insert_epi16((__m128i)_mm_setzero_ps(), *src++, 0); + __v4sf out_val = (__v4sf)_mm_cvtph_ps(in_val); + _mm_store_ss(dst++, out_val); + n -= 1; + } +} + +static void +conv_yaHalf_yaF (const Babl *conversion, + const uint16_t *src, + float *dst, + long samples) +{ + conv_yHalf_yF (conversion, src, dst, samples * 2); +} + +static void +conv_rgbHalf_rgbF (const Babl *conversion, + const uint16_t *src, + float *dst, + long samples) +{ + conv_yHalf_yF (conversion, src, dst, samples * 3); +} + +static void +conv_rgbaHalf_rgbaF (const Babl *conversion, + const uint16_t *src, + float *dst, + long samples) +{ + conv_yHalf_yF (conversion, src, dst, samples * 4); +} + +static inline void +conv_yF_yHalf (const Babl *conversion, + const float *src, + uint16_t *dst, + long samples) +{ + const __v4sf *s_vec; + uint64_t *d_vec; + + long n = samples; + + s_vec = (const __v4sf *)src; + d_vec = (uint64_t *)dst; + + while (n >= 4) + { + __m128 in_val = _mm_loadu_ps((float *)s_vec++); + __m128i out_val = _mm_cvtps_ph(in_val, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + _mm_storel_epi64((__m128i *)d_vec++, out_val); + n -= 4; + } + + src = (const float *)s_vec; + dst = (uint16_t *)d_vec; + + while (n) + { + __m128 in_val = _mm_load_ss(src++); + __m128i out_val = _mm_cvtps_ph(in_val, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + *dst++ = _mm_extract_epi16(out_val, 0); + n -= 1; + } +} + +static void +conv_yaF_yaHalf (const Babl *conversion, + const float *src, + uint16_t *dst, + long samples) +{ + conv_yF_yHalf (conversion, src, dst, samples * 2); +} + +#define conv_yAF_yAHalf conv_yaF_yaHalf +#define conv_yAHalf_yAF conv_yaHalf_yaF + +static void +conv_rgbF_rgbHalf (const Babl *conversion, + const float *src, + uint16_t *dst, + long samples) +{ + conv_yF_yHalf (conversion, src, dst, samples * 3); +} + +static void +conv_rgbaF_rgbaHalf (const Babl *conversion, + const float *src, + uint16_t *dst, + long samples) +{ + conv_yF_yHalf (conversion, src, dst, samples * 4); +} + +#endif /* defined(USE_SSE4_1) && defined(USE_F16C) && defined(ARCH_X86_64) */ + +int init (void); + +int +init (void) +{ +#if defined(USE_SSE4_1) && defined(USE_F16C) && defined(ARCH_X86_64) + const Babl *rgbaF_linear = babl_format_new ( + babl_model ("RGBA"), + babl_type ("float"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + babl_component ("A"), + NULL); + const Babl *rgbaHalf_linear = babl_format_new ( + babl_model ("RGBA"), + babl_type ("half"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + babl_component ("A"), + NULL); + const Babl *rgbaF_gamma = babl_format_new ( + babl_model ("R'G'B'A"), + babl_type ("float"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + babl_component ("A"), + NULL); + const Babl *rgbaHalf_gamma = babl_format_new ( + babl_model ("R'G'B'A"), + babl_type ("half"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + babl_component ("A"), + NULL); + const Babl *rgbF_linear = babl_format_new ( + babl_model ("RGB"), + babl_type ("float"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + NULL); + const Babl *rgbHalf_linear = babl_format_new ( + babl_model ("RGB"), + babl_type ("half"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + NULL); + const Babl *rgbF_gamma = babl_format_new ( + babl_model ("R'G'B'"), + babl_type ("float"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + NULL); + const Babl *rgbHalf_gamma = babl_format_new ( + babl_model ("R'G'B'"), + babl_type ("half"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + NULL); + const Babl *yaF_linear = babl_format_new ( + babl_model ("YA"), + babl_type ("float"), + babl_component ("Y"), + babl_component ("A"), + NULL); + const Babl *yaHalf_linear = babl_format_new ( + babl_model ("YA"), + babl_type ("half"), + babl_component ("Y"), + babl_component ("A"), + NULL); + const Babl *yaF_gamma = babl_format_new ( + babl_model ("Y'A"), + babl_type ("float"), + babl_component ("Y'"), + babl_component ("A"), + NULL); + const Babl *yaHalf_gamma = babl_format_new ( + babl_model ("Y'A"), + babl_type ("half"), + babl_component ("Y'"), + babl_component ("A"), + NULL); + const Babl *yAF_linear = babl_format_new ( + babl_model ("YaA"), + babl_type ("float"), + babl_component ("Ya"), + babl_component ("A"), + NULL); + const Babl *yAHalf_linear = babl_format_new ( + babl_model ("YaA"), + babl_type ("half"), + babl_component ("Ya"), + babl_component ("A"), + NULL); + const Babl *yAF_gamma = babl_format_new ( + babl_model ("Y'aA"), + babl_type ("float"), + babl_component ("Y'a"), + babl_component ("A"), + NULL); + const Babl *yAHalf_gamma = babl_format_new ( + babl_model ("Y'aA"), + babl_type ("half"), + babl_component ("Y'a"), + babl_component ("A"), + NULL); + const Babl *yF_linear = babl_format_new ( + babl_model ("Y"), + babl_type ("float"), + babl_component ("Y"), + NULL); + const Babl *yHalf_linear = babl_format_new ( + babl_model ("Y"), + babl_type ("half"), + babl_component ("Y"), + NULL); + const Babl *yF_gamma = babl_format_new ( + babl_model ("Y'"), + babl_type ("float"), + babl_component ("Y'"), + NULL); + const Babl *yHalf_gamma = babl_format_new ( + babl_model ("Y'"), + babl_type ("half"), + babl_component ("Y'"), + NULL); + +#define CONV(src, dst) \ +{ \ + babl_conversion_new (src ## _linear, dst ## _linear, "linear", conv_ ## src ## _ ## dst, NULL); \ + babl_conversion_new (src ## _gamma, dst ## _gamma, "linear", conv_ ## src ## _ ## dst, NULL); \ +} + + if ((babl_cpu_accel_get_support () & BABL_CPU_ACCEL_X86_SSE4_1) && + (babl_cpu_accel_get_support () & BABL_CPU_ACCEL_X86_F16C)) + { + CONV(rgbaHalf, rgbaF); + CONV(rgbHalf, rgbF); + CONV(yaHalf, yaF); + CONV(yAHalf, yAF); + CONV(yHalf, yF); + CONV(rgbaF, rgbaHalf); + CONV(rgbF, rgbHalf); + CONV(yaF, yaHalf); + CONV(yAF, yAHalf); + CONV(yF, yHalf); + } + +#endif /* defined(USE_SSE4_1) && defined(USE_F16C) && defined(ARCH_X86_64) */ + + return 0; +} + diff --git a/extensions/sse2-float.c b/extensions/sse2-float.c new file mode 100644 index 0000000..3757ffe --- /dev/null +++ b/extensions/sse2-float.c @@ -0,0 +1,742 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2013 Massimo Valentini + * Copyright (C) 2013 Daniel Sabo + * Copyright (C) 2013 Loren Merritt + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" + +#if defined(USE_SSE2) + +/* SSE 2 */ +#include + +#include +#include + +#include "babl.h" +#include "babl-cpuaccel.h" +#include "base/util.h" +#include "extensions/util.h" + +#define Q(a) { a, a, a, a } + +static const float BABL_ALPHA_FLOOR_FLOAT = (float)BABL_ALPHA_FLOOR; + +static void +conv_rgbaF_linear_rgbAF_linear (const Babl *conversion, + const float *src, + float *dst, + long samples) +{ + long i = 0; + long remainder; + + if (((uintptr_t)src % 16) + ((uintptr_t)dst % 16) == 0) + { + const long n = (samples / 2) * 2; + const __v4sf *s = (const __v4sf*) src; + __v4sf *d = (__v4sf*)dst; + + for ( ; i < n; i += 2) + { + float alpha0 = ((float *)s)[3]; + float alpha1 = ((float *)s)[7]; + float used_alpha0 = babl_epsilon_for_zero_float (alpha0); + float used_alpha1 = babl_epsilon_for_zero_float (alpha1); + + { + __v4sf rbaa0, rbaa1; + + __v4sf rgba0 = *s++; + __v4sf rgba1 = *s++; + + + /* Expand alpha */ + __v4sf aaaa0 = (__v4sf)_mm_set1_ps(used_alpha0); + __v4sf aaaa1 = (__v4sf)_mm_set1_ps(used_alpha1); + + /* Premultiply */ + rgba0 = rgba0 * aaaa0; + rgba1 = rgba1 * aaaa1; + + aaaa0 = (__v4sf)_mm_set1_ps(alpha0); + aaaa1 = (__v4sf)_mm_set1_ps(alpha1); + + /* Shuffle the original alpha value back in */ + rbaa0 = _mm_shuffle_ps(rgba0, aaaa0, _MM_SHUFFLE(0, 0, 2, 0)); + rbaa1 = _mm_shuffle_ps(rgba1, aaaa1, _MM_SHUFFLE(0, 0, 2, 0)); + + rgba0 = _mm_shuffle_ps(rgba0, rbaa0, _MM_SHUFFLE(2, 1, 1, 0)); + rgba1 = _mm_shuffle_ps(rgba1, rbaa1, _MM_SHUFFLE(2, 1, 1, 0)); + + *d++ = rgba0; + *d++ = rgba1; + } + } + _mm_empty (); + } + + dst += i * 4; + src += i * 4; + remainder = samples - i; + while (remainder--) + { + float a = src[3]; + float used_alpha = babl_epsilon_for_zero_float (a); + dst[0] = src[0] * used_alpha; + dst[1] = src[1] * used_alpha; + dst[2] = src[2] * used_alpha; + dst[3] = a; + + src += 4; + dst += 4; + } +} + +static void +conv_rgbAF_linear_rgbaF_linear_shuffle (const Babl *conversion, + const float *src, + float *dst, + long samples) +{ + long i = 0; + long remainder; + + if (((uintptr_t)src % 16) + ((uintptr_t)dst % 16) == 0) + { + const long n = samples; + const __v4sf *s = (const __v4sf*) src; + __v4sf *d = (__v4sf*)dst; + + for ( ; i < n; i += 1) + { + __v4sf pre_rgba0, rgba0, rbaa0, raaaa0; + + float alpha0 = ((float *)s)[3]; + float used_alpha0 = babl_epsilon_for_zero_float (alpha0); + pre_rgba0 = *s; + + { + float recip0 = 1.0f/used_alpha0; + + /* Expand reciprocal */ + raaaa0 = _mm_load1_ps(&recip0); + + /* Un-Premultiply */ + rgba0 = pre_rgba0 * raaaa0; + } + + /* Shuffle the original alpha value back in */ + rbaa0 = _mm_shuffle_ps(rgba0, pre_rgba0, _MM_SHUFFLE(3, 3, 2, 0)); + rgba0 = _mm_shuffle_ps(rgba0, rbaa0, _MM_SHUFFLE(2, 1, 1, 0)); + + s++; + *d++ = rgba0; + } + _mm_empty (); + } + + dst += i * 4; + src += i * 4; + remainder = samples - i; + while (remainder--) + { + float alpha = src[3]; + float recip; + if (alpha <= 0.0f) + recip = 0.0f; + else + recip = 1.0f/alpha; + dst[0] = src[0] * recip; + dst[1] = src[1] * recip; + dst[2] = src[2] * recip; + dst[3] = alpha; + + src += 4; + dst += 4; + } +} + +static void +conv_rgbAF_linear_rgbaF_linear_spin (const Babl *conversion, + const float *src, + float *dst, + long samples) +{ + long i = 0; + long remainder; + // XXX : not ported to zero preserving alpha transforms + if (((uintptr_t)src % 16) + ((uintptr_t)dst % 16) == 0) + { + const long n = samples; + const __v4sf *s = (const __v4sf*) src; + __v4sf *d = (__v4sf*)dst; + const __v4sf zero = _mm_set_ss (BABL_ALPHA_FLOOR_FLOAT); + const __v4sf one = _mm_set_ss(1.0f); + + for ( ; i < n; i += 1) + { + __v4sf pre_abgr0, abgr0, rgba0, raaaa0; + + + rgba0 = *s; + /* Rotate to ABGR */ + pre_abgr0 = (__v4sf)_mm_shuffle_epi32((__m128i)rgba0, _MM_SHUFFLE(0, 1, 2, 3)); + + if (_mm_ucomile_ss(pre_abgr0, zero)) + { + /* Zero RGB */ + abgr0 = zero; + } + else + { + /* Un-Premultiply */ + raaaa0 = _mm_div_ss(one, pre_abgr0); + + /* Expand reciprocal */ + raaaa0 = (__v4sf)_mm_shuffle_epi32((__m128i)raaaa0, _MM_SHUFFLE(0, 0, 0, 0)); + + /* Un-Premultiply */ + abgr0 = pre_abgr0 * raaaa0; + } + + /* Move the original alpha value back in */ + abgr0 = _mm_move_ss(abgr0, pre_abgr0); + + /* Rotate to ABGR */ + rgba0 = (__v4sf)_mm_shuffle_epi32((__m128i)abgr0, _MM_SHUFFLE(0, 1, 2, 3)); + + *d++ = rgba0; + s++; + } + _mm_empty (); + } + + dst += i * 4; + src += i * 4; + remainder = samples - i; + while (remainder--) + { + float alpha = src[3]; + float recip; + if (alpha <= 0.0f) + recip = 0.0f; + else + recip = 1.0f/alpha; + dst[0] = src[0] * recip; + dst[1] = src[1] * recip; + dst[2] = src[2] * recip; + dst[3] = alpha; + + src += 4; + dst += 4; + } +} + +#define splat4f(x) ((__v4sf){x,x,x,x}) +#define splat4i(x) ((__v4si){x,x,x,x}) +#define FLT_ONE 0x3f800000 // ((union {float f; int i;}){1.0f}).i +#define FLT_MANTISSA (1<<23) + +static inline float +sse_max_component (__v4sf x) { + __v4sf s; + __v4sf m; + + /* m = [max (x[3], x[1]), max (x[2], x[0])] */ + s = (__v4sf) _mm_shuffle_epi32 ((__m128i) x, _MM_SHUFFLE(0, 0, 3, 2)); + m = _mm_max_ps (x, s); + + /* m = [max (m[1], m[0])] = [max (max (x[3], x[1]), max (x[2], x[0]))] */ + s = (__v4sf) _mm_shuffle_epi32 ((__m128i) m, _MM_SHUFFLE(0, 0, 0, 1)); + m = _mm_max_ps (m, s); + + return m[0]; +} + +static inline __v4sf +sse_init_newton (__v4sf x, double exponent, double c0, double c1, double c2) +{ + double norm = exponent*M_LN2/FLT_MANTISSA; + __v4sf y = _mm_cvtepi32_ps((__m128i)((__v4si)x - splat4i(FLT_ONE))); + return splat4f(c0) + splat4f(c1*norm)*y + splat4f(c2*norm*norm)*y*y; +} + +static inline __v4sf +sse_pow_1_24 (__v4sf x) +{ + __v4sf y, z; + if (sse_max_component (x) > 1024.0f) { + /* for large values, fall back to a slower but more accurate version */ + return _mm_set_ps (expf (logf (x[3]) * (1.0f / 2.4f)), + expf (logf (x[2]) * (1.0f / 2.4f)), + expf (logf (x[1]) * (1.0f / 2.4f)), + expf (logf (x[0]) * (1.0f / 2.4f))); + } + y = sse_init_newton (x, -1./12, 0.9976800269, 0.9885126933, 0.5908575383); + x = _mm_sqrt_ps (x); + /* newton's method for x^(-1/6) */ + z = splat4f (1.f/6.f) * x; + y = splat4f (7.f/6.f) * y - z * ((y*y)*(y*y)*(y*y*y)); + y = splat4f (7.f/6.f) * y - z * ((y*y)*(y*y)*(y*y*y)); + return x*y; +} + +static inline __v4sf +sse_pow_24 (__v4sf x) +{ + __v4sf y, z; + if (sse_max_component (x) > 16.0f) { + /* for large values, fall back to a slower but more accurate version */ + return _mm_set_ps (expf (logf (x[3]) * 2.4f), + expf (logf (x[2]) * 2.4f), + expf (logf (x[1]) * 2.4f), + expf (logf (x[0]) * 2.4f)); + } + y = sse_init_newton (x, -1./5, 0.9953189663, 0.9594345146, 0.6742970332); + /* newton's method for x^(-1/5) */ + z = splat4f (1.f/5.f) * x; + y = splat4f (6.f/5.f) * y - z * ((y*y*y)*(y*y*y)); + y = splat4f (6.f/5.f) * y - z * ((y*y*y)*(y*y*y)); + x *= y; + return x*x*x; +} + +static inline __v4sf +linear_to_gamma_2_2_sse2 (__v4sf x) +{ + __v4sf curve = sse_pow_1_24 (x) * splat4f (1.055f) - + splat4f (0.055f - + 3.0f / (float) (1 << 24)); + /* ^ offset the result such that 1 maps to 1 */ + __v4sf line = x * splat4f (12.92f); + __v4sf mask = _mm_cmpgt_ps (x, splat4f (0.003130804954f)); + return _mm_or_ps (_mm_and_ps (mask, curve), _mm_andnot_ps (mask, line)); +} + +static inline __v4sf +gamma_2_2_to_linear_sse2 (__v4sf x) +{ + __v4sf curve = sse_pow_24 ((x + splat4f (0.055f)) * splat4f (1/1.055f)); + __v4sf line = x * splat4f (1/12.92f); + __v4sf mask = _mm_cmpgt_ps (x, splat4f (0.04045f)); + return _mm_or_ps (_mm_and_ps (mask, curve), _mm_andnot_ps (mask, line)); +} + +#define GAMMA_RGBA(func, munge) \ +static inline void \ +func (const Babl *conversion,const float *src, float *dst, long samples)\ +{\ + int i = samples;\ + if (((uintptr_t)src % 16) + ((uintptr_t)dst % 16) == 0)\ + {\ + for (; i > 3; i -= 4, src += 16, dst += 16)\ + {\ + /* Pack the rgb components from 4 pixels into 3 vectors, gammafy, unpack. */\ + __v4sf x0 = _mm_load_ps (src);\ + __v4sf x1 = _mm_load_ps (src+4);\ + __v4sf x2 = _mm_load_ps (src+8);\ + __v4sf x3 = _mm_load_ps (src+12);\ + __v4sf y0 = _mm_movelh_ps (x0, x1);\ + __v4sf y1 = _mm_movelh_ps (x2, x3);\ + __v4sf z0 = _mm_unpackhi_ps (x0, x1);\ + __v4sf z1 = _mm_unpackhi_ps (x2, x3);\ + __v4sf y2 = _mm_movelh_ps (z0, z1);\ + __v4sf y3 = _mm_movehl_ps (z1, z0);\ + y0 = munge (y0);\ + _mm_storel_pi ((__m64*)(dst), y0);\ + _mm_storeh_pi ((__m64*)(dst+4), y0);\ + y1 = munge (y1);\ + _mm_storel_pi ((__m64*)(dst+8), y1);\ + _mm_storeh_pi ((__m64*)(dst+12), y1);\ + y2 = munge (y2);\ + z0 = _mm_unpacklo_ps (y2, y3);\ + z1 = _mm_unpackhi_ps (y2, y3);\ + _mm_storel_pi ((__m64*)(dst+2), z0);\ + _mm_storeh_pi ((__m64*)(dst+6), z0);\ + _mm_storel_pi ((__m64*)(dst+10), z1);\ + _mm_storeh_pi ((__m64*)(dst+14), z1);\ + }\ + for (; i > 0; i--, src += 4, dst += 4)\ + {\ + __v4sf x = munge (_mm_load_ps (src));\ + float a = src[3];\ + _mm_store_ps (dst, x);\ + dst[3] = a;\ + }\ + }\ + else\ + {\ + for (; i > 0; i--, src += 4, dst += 4)\ + {\ + __v4sf x = munge (_mm_loadu_ps (src));\ + float a = src[3];\ + _mm_storeu_ps (dst, x);\ + dst[3] = a;\ + }\ + }\ +} + +GAMMA_RGBA(conv_rgbaF_linear_rgbaF_gamma, linear_to_gamma_2_2_sse2) +GAMMA_RGBA(conv_rgbaF_gamma_rgbaF_linear, gamma_2_2_to_linear_sse2) + +static void conv_rgbaF_linear_rgbAF_gamma (const Babl *conversion, + const float *src, + float *dst, + long samples) +{ + float *tmp = alloca (sizeof(float)*4*samples); + conv_rgbaF_linear_rgbaF_gamma (conversion, src, tmp, samples); + conv_rgbaF_linear_rgbAF_linear (conversion, tmp, dst, samples); +} + +#define YA_APPLY(load, store, convert) \ +{ \ + __v4sf yyaa0, yyaa1; \ + __v4sf yaya0 = load ((float *)s++); \ + __v4sf yaya1 = load ((float *)s++); \ + __v4sf yyyy01 = _mm_shuffle_ps (yaya0, yaya1, _MM_SHUFFLE(0, 2, 0, 2)); \ +\ + yyyy01 = convert (yyyy01); \ +\ + yyaa0 = _mm_shuffle_ps (yyyy01, yaya0, _MM_SHUFFLE(3, 1, 0, 1)); \ + yaya0 = (__v4sf)_mm_shuffle_epi32((__m128i)yyaa0, _MM_SHUFFLE(3, 1, 2, 0)); \ + yyaa1 = _mm_shuffle_ps (yyyy01, yaya1, _MM_SHUFFLE(3, 1, 2, 3)); \ + yaya1 = (__v4sf)_mm_shuffle_epi32((__m128i)yyaa1, _MM_SHUFFLE(3, 1, 2, 0)); \ +\ + store ((float *)d++, yaya0); \ + store ((float *)d++, yaya1); \ +}\ + +static void +conv_yaF_linear_yaF_gamma (const Babl *conversion, + const float *src, + float *dst, + long samples) +{ + const __v4sf *s = (const __v4sf*)src; + __v4sf *d = (__v4sf*)dst; + + if (((uintptr_t)src % 16) + ((uintptr_t)dst % 16) == 0) + { + while (samples > 4) + { + YA_APPLY (_mm_load_ps, _mm_store_ps, linear_to_gamma_2_2_sse2); + samples -= 4; + } + } + else + { + while (samples > 4) + { + YA_APPLY (_mm_loadu_ps, _mm_storeu_ps, linear_to_gamma_2_2_sse2); + samples -= 4; + } + } + + src = (const float *)s; + dst = (float *)d; + + while (samples--) + { + float y = *src++; + *dst++ = linear_to_gamma_2_2_sse2 (splat4f (y))[0]; + *dst++ = *src++; + } +} + + +static void +conv_yaF_gamma_yaF_linear (const Babl *conversion, + const float *src, + float *dst, + long samples) +{ + const __v4sf *s = (const __v4sf*)src; + __v4sf *d = (__v4sf*)dst; + + if (((uintptr_t)src % 16) + ((uintptr_t)dst % 16) == 0) + { + while (samples > 4) + { + YA_APPLY (_mm_load_ps, _mm_store_ps, gamma_2_2_to_linear_sse2); + samples -= 4; + } + } + else + { + while (samples > 4) + { + YA_APPLY (_mm_loadu_ps, _mm_storeu_ps, gamma_2_2_to_linear_sse2); + samples -= 4; + } + } + + src = (const float *)s; + dst = (float *)d; + + while (samples--) + { + float y = *src++; + *dst++ = gamma_2_2_to_linear_sse2 (splat4f (y))[0]; + *dst++ = *src++; + } +} + +static inline void +conv_yF_linear_yF_gamma (const Babl *conversion, + const float *src, + float *dst, + long samples) +{ + const __v4sf *s = (const __v4sf*)src; + __v4sf *d = (__v4sf*)dst; + + if (((uintptr_t)src % 16) + ((uintptr_t)dst % 16) == 0) + { + while (samples > 4) + { + __v4sf rgba0 = _mm_load_ps ((float *)s++); + rgba0 = linear_to_gamma_2_2_sse2 (rgba0); + _mm_store_ps ((float *)d++, rgba0); + samples -= 4; + } + } + else + { + while (samples > 4) + { + __v4sf rgba0 = _mm_loadu_ps ((float *)s++); + rgba0 = linear_to_gamma_2_2_sse2 (rgba0); + _mm_storeu_ps ((float *)d++, rgba0); + samples -= 4; + } + } + + src = (const float *)s; + dst = (float *)d; + + while (samples--) + { + float y = *src++; + *dst++ = linear_to_gamma_2_2_sse2 (splat4f (y))[0]; + } +} + +static inline void +conv_yF_gamma_yF_linear (const Babl *conversion, + const float *src, + float *dst, + long samples) +{ + const __v4sf *s = (const __v4sf*)src; + __v4sf *d = (__v4sf*)dst; + + if (((uintptr_t)src % 16) + ((uintptr_t)dst % 16) == 0) + { + while (samples > 4) + { + __v4sf rgba0 = _mm_load_ps ((float *)s++); + rgba0 = gamma_2_2_to_linear_sse2 (rgba0); + _mm_store_ps ((float *)d++, rgba0); + samples -= 4; + } + } + else + { + while (samples > 4) + { + __v4sf rgba0 = _mm_loadu_ps ((float *)s++); + rgba0 = gamma_2_2_to_linear_sse2 (rgba0); + _mm_storeu_ps ((float *)d++, rgba0); + samples -= 4; + } + } + + src = (const float *)s; + dst = (float *)d; + + while (samples--) + { + float y = *src++; + *dst++ = gamma_2_2_to_linear_sse2 (splat4f (y))[0]; + } +} + + +static void +conv_rgbF_linear_rgbF_gamma (const Babl *conversion, + const float *src, + float *dst, + long samples) +{ + conv_yF_linear_yF_gamma (conversion, src, dst, samples * 3); +} + + +static void +conv_rgbF_gamma_rgbF_linear (const Babl *conversion, + const float *src, + float *dst, + long samples) +{ + conv_yF_gamma_yF_linear (conversion, src, dst, samples * 3); +} + +#endif /* defined(USE_SSE2) */ + +#define o(src, dst) \ + babl_conversion_new (src, dst, "linear", conv_ ## src ## _ ## dst, NULL) + +int init (void); + +int +init (void) +{ +#if defined(USE_SSE2) + + const Babl *rgbaF_linear = babl_format_new ( + babl_model ("RGBA"), + babl_type ("float"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + babl_component ("A"), + NULL); + const Babl *rgbAF_linear = babl_format_new ( + babl_model ("RaGaBaA"), + babl_type ("float"), + babl_component ("Ra"), + babl_component ("Ga"), + babl_component ("Ba"), + babl_component ("A"), + NULL); + const Babl *rgbAF_gamma = babl_format_new ( + babl_model ("R'aG'aB'aA"), + babl_type ("float"), + babl_component ("R'a"), + babl_component ("G'a"), + babl_component ("B'a"), + babl_component ("A"), + NULL); + const Babl *rgbaF_gamma = babl_format_new ( + babl_model ("R'G'B'A"), + babl_type ("float"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + babl_component ("A"), + NULL); + const Babl *rgbF_linear = babl_format_new ( + babl_model ("RGB"), + babl_type ("float"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + NULL); + const Babl *rgbF_gamma = babl_format_new ( + babl_model ("R'G'B'"), + babl_type ("float"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + NULL); + const Babl *yaF_linear = babl_format_new ( + babl_model ("YA"), + babl_type ("float"), + babl_component ("Y"), + babl_component ("A"), + NULL); + const Babl *yaF_gamma = babl_format_new ( + babl_model ("Y'A"), + babl_type ("float"), + babl_component ("Y'"), + babl_component ("A"), + NULL); + const Babl *yF_linear = babl_format_new ( + babl_model ("Y"), + babl_type ("float"), + babl_component ("Y"), + NULL); + const Babl *yF_gamma = babl_format_new ( + babl_model ("Y'"), + babl_type ("float"), + babl_component ("Y'"), + NULL); + + if ((babl_cpu_accel_get_support () & BABL_CPU_ACCEL_X86_SSE) && + (babl_cpu_accel_get_support () & BABL_CPU_ACCEL_X86_SSE2)) + + { + babl_conversion_new(rgbaF_linear, + rgbAF_linear, + "linear", + conv_rgbaF_linear_rgbAF_linear, + NULL); + + babl_conversion_new(rgbaF_gamma, + rgbAF_gamma, + "linear", + conv_rgbaF_linear_rgbAF_linear, + NULL); + + babl_conversion_new(rgbaF_linear, + rgbAF_gamma, + "linear", + conv_rgbaF_linear_rgbAF_gamma, + NULL); + + /* Which of these is faster varies by CPU, and the difference + * is big enough that it's worthwhile to include both and + * let them fight it out in the babl benchmarks. + */ + babl_conversion_new(rgbAF_linear, + rgbaF_linear, + "linear", + conv_rgbAF_linear_rgbaF_linear_shuffle, + NULL); + babl_conversion_new(rgbAF_gamma, + rgbaF_gamma, + "linear", + conv_rgbAF_linear_rgbaF_linear_shuffle, + NULL); + + babl_conversion_new(rgbAF_linear, + rgbaF_linear, + "linear", + conv_rgbAF_linear_rgbaF_linear_spin, + NULL); + + o (yF_linear, yF_gamma); + o (yF_gamma, yF_linear); + + o (yaF_linear, yaF_gamma); + o (yaF_gamma, yaF_linear); + + o (rgbF_linear, rgbF_gamma); + o (rgbF_gamma, rgbF_linear); + + o (rgbaF_linear, rgbaF_gamma); + o (rgbaF_gamma, rgbaF_linear); + } + +#endif /* defined(USE_SSE2) */ + + return 0; +} + diff --git a/extensions/sse2-int16.c b/extensions/sse2-int16.c new file mode 100644 index 0000000..52ca014 --- /dev/null +++ b/extensions/sse2-int16.c @@ -0,0 +1,216 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2013 Massimo Valentini + * Copyright (C) 2013 Daniel Sabo + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" + +#if defined(USE_SSE2) + +/* SSE 2 */ +#include + +#include +#include + +#include "babl.h" +#include "babl-cpuaccel.h" +#include "extensions/util.h" + +#define Q(a) { a, a, a, a } +static const __v4sf u16_float = Q (1.f / 65535); + +static void +conv_rgba16_rgbaF (const Babl *conversion, + const uint16_t *src, + float *dst, + long samples) +{ + long i = 0; + + if (((uintptr_t)src % 16) + ((uintptr_t)dst % 16) == 0) + { + long n = (samples / 2) * 2; + const __m128i *s = (const __m128i*) src; + __v4sf *d = (__v4sf*) dst; + + for (; i < n / 2; i++) + { + /* Expand shorts to ints by loading zero in the high bits */ + const __m128i t0 = _mm_unpacklo_epi16 (s[i + 0], (__m128i)_mm_setzero_ps()); + const __m128i t1 = _mm_unpackhi_epi16 (s[i + 0], (__m128i)_mm_setzero_ps()); + + /* Convert to float */ + const __m128 u0 = _mm_cvtepi32_ps (t0); + const __m128 u1 = _mm_cvtepi32_ps (t1); + + const __v4sf rgba0 = u0 * u16_float; + const __v4sf rgba1 = u1 * u16_float; + + d[2 * i + 0] = rgba0; + d[2 * i + 1] = rgba1; + } + _mm_empty(); + } + + for (i *= 2 * 4; i != 4 * samples; i++) + dst[i] = src[i] * (1.f / 65535); +} + +static void +conv_rgba16_rgbAF (const Babl *conversion, + const uint16_t *src, + float *dst, + long samples) +{ + long i = 0; + long remainder; + + if (((uintptr_t)src % 16) + ((uintptr_t)dst % 16) == 0) + { + long n = (samples / 2) * 2; + const __m128i *s = (const __m128i*) src; + __v4sf *d = (__v4sf*) dst; + + const __v4sf max_mask = { 0.0f, 0.0f, 0.0f, 1.0f }; + + for (; i < n / 2; i++) + { + /* Expand shorts to ints by loading zero in the high bits */ + const __m128i t0 = _mm_unpacklo_epi16 (s[i + 0], (__m128i)_mm_setzero_ps()); + const __m128i t1 = _mm_unpackhi_epi16 (s[i + 0], (__m128i)_mm_setzero_ps()); + + /* Convert to float */ + const __m128 u0 = _mm_cvtepi32_ps (t0); + const __m128 u1 = _mm_cvtepi32_ps (t1); + + /* Multiply by 1 / 65535 */ + __v4sf rgba0 = u0 * u16_float; + __v4sf rgba1 = u1 * u16_float; + + /* Expand alpha */ + __v4sf aaaa0 = (__v4sf)_mm_shuffle_epi32((__m128i)rgba0, _MM_SHUFFLE(3, 3, 3, 3)); + __v4sf aaaa1 = (__v4sf)_mm_shuffle_epi32((__m128i)rgba1, _MM_SHUFFLE(3, 3, 3, 3)); + + /* Set the value in the alpha slot to 1.0, we know max is sufficent because alpha was a short */ + aaaa0 = _mm_max_ps(aaaa0, max_mask); + aaaa1 = _mm_max_ps(aaaa1, max_mask); + + /* Premultiply */ + rgba0 = rgba0 * aaaa0; + rgba1 = rgba1 * aaaa1; + + d[2 * i + 0] = rgba0; + d[2 * i + 1] = rgba1; + } + _mm_empty(); + } + + dst += i * 2 * 4; + src += i * 2 * 4; + remainder = samples - (i * 2); + while (remainder--) + { + const float a = src[3] / 65535.0f; + const float a_term = a / 65535.0f; + dst[0] = src[0] * a_term; + dst[1] = src[1] * a_term; + dst[2] = src[2] * a_term; + dst[3] = a; + + src += 4; + dst += 4; + } +} + +#endif /* defined(USE_SSE2) */ + +int init (void); + +int +init (void) +{ +#if defined(USE_SSE2) + + const Babl *rgbaF_linear = babl_format_new ( + babl_model ("RGBA"), + babl_type ("float"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + babl_component ("A"), + NULL); + const Babl *rgbAF_linear = babl_format_new ( + babl_model ("RaGaBaA"), + babl_type ("float"), + babl_component ("Ra"), + babl_component ("Ga"), + babl_component ("Ba"), + babl_component ("A"), + NULL); + const Babl *rgba16_linear = babl_format_new ( + babl_model ("RGBA"), + babl_type ("u16"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + babl_component ("A"), + NULL); + + const Babl *rgbaF_gamma = babl_format_new ( + babl_model ("R'G'B'A"), + babl_type ("float"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + babl_component ("A"), + NULL); + const Babl *rgbAF_gamma = babl_format_new ( + babl_model ("R'aG'aB'aA"), + babl_type ("float"), + babl_component ("R'a"), + babl_component ("G'a"), + babl_component ("B'a"), + babl_component ("A"), + NULL); + const Babl *rgba16_gamma = babl_format_new ( + babl_model ("R'G'B'A"), + babl_type ("u16"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + babl_component ("A"), + NULL); + +#define CONV(src, dst) \ +{ \ + babl_conversion_new (src ## _linear, dst ## _linear, "linear", conv_ ## src ## _ ## dst, NULL); \ + babl_conversion_new (src ## _gamma, dst ## _gamma, "linear", conv_ ## src ## _ ## dst, NULL); \ +} + + if ((babl_cpu_accel_get_support () & BABL_CPU_ACCEL_X86_SSE) && + (babl_cpu_accel_get_support () & BABL_CPU_ACCEL_X86_SSE2)) + { + CONV (rgba16, rgbaF); + CONV (rgba16, rgbAF); + } + +#endif /* defined(USE_SSE2) */ + + return 0; +} + diff --git a/extensions/sse2-int8.c b/extensions/sse2-int8.c new file mode 100644 index 0000000..6da1b5b --- /dev/null +++ b/extensions/sse2-int8.c @@ -0,0 +1,334 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2013 Daniel Sabo + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" + +#if defined(USE_SSE2) + +/* SSE 2 */ +#include + +#include +#include + +#include "babl.h" +#include "babl-cpuaccel.h" +#include "extensions/util.h" + +static inline void +conv_yF_y8 (const Babl *conversion, + const float *src, + uint8_t *dst, + long samples) +{ + const __v4sf *s_vec; + __m128i *d_vec; + uint32_t *d_int; + + long n = samples; + + const __v4sf byte_fill = _mm_set_ps1(255.0f); + const __v4sf half = _mm_set_ps1(0.5); + + while (((uintptr_t)src % 16) && n > 0) + { + /* Work through the unaligned floats */ + float y = *src++; + *dst++ = (y >= 1.0f) ? 0xFF : ((y <= 0.0f) ? 0x0 : 0xFF * y + 0.5f); + + n -= 1; + } + + s_vec = (__v4sf *)src; + d_vec = (__m128i *)dst; + + /* Aligned chunks */ + + while (n > 16) + { + __v4sf yyyy0, yyyy1, yyyy2, yyyy3; + __m128i i32_0, i32_1, i32_2, i32_3; + __m128i i16_01, i16_23; + __m128i mm_ints; + + /* Add 0.5 and truncate, to match C rounding behavior. + * + * The _mm_min_ps is needed because _mm_packs_epi32 uses + * signed saturation, the unsigned version wasn't added + * until SSE4. + */ + yyyy0 = *s_vec++ * byte_fill + half; + yyyy0 = _mm_min_ps(yyyy0, byte_fill); + i32_0 = _mm_cvttps_epi32 ((__m128)yyyy0); + + yyyy1 = *s_vec++ * byte_fill + half; + yyyy1 = _mm_min_ps(yyyy1, byte_fill); + i32_1 = _mm_cvttps_epi32 ((__m128)yyyy1); + + i16_01 = _mm_packs_epi32 (i32_0, i32_1); + + yyyy2 = *s_vec++ * byte_fill + half; + yyyy2 = _mm_min_ps(yyyy2, byte_fill); + i32_2 = _mm_cvttps_epi32 ((__m128)yyyy2); + + yyyy3 = *s_vec++ * byte_fill + half; + yyyy3 = _mm_min_ps(yyyy3, byte_fill); + i32_3 = _mm_cvttps_epi32 ((__m128)yyyy3); + + i16_23 = _mm_packs_epi32 (i32_2, i32_3); + + mm_ints = _mm_packus_epi16 (i16_01, i16_23); + + _mm_storeu_si128 (d_vec++, mm_ints); + + n -= 16; + } + + d_int = (uint32_t *)d_vec; + + while (n > 4) + { + __v4sf yyyy0; + __m128i mm_ints; + + yyyy0 = *s_vec++ * byte_fill + half; + yyyy0 = _mm_min_ps(yyyy0, byte_fill); + mm_ints = _mm_cvttps_epi32 ((__m128)yyyy0); + mm_ints = _mm_packs_epi32 (mm_ints, mm_ints); + mm_ints = _mm_packus_epi16 (mm_ints, mm_ints); + _mm_store_ss ((float *)d_int++, (__v4sf)mm_ints); + + n -= 4; + } + + src = (float *)s_vec; + dst = (uint8_t *)d_int; + + while (n > 0) + { + float y = *src++; + *dst++ = (y >= 1.0f) ? 0xFF : ((y <= 0.0f) ? 0x0 : 0xFF * y + 0.5f); + + n -= 1; + } +} + +static void +conv_yaF_ya8 (const Babl *conversion, + const float *src, + uint8_t *dst, + long samples) +{ + conv_yF_y8 (conversion, src, dst, samples * 2); +} + + +static void +conv_rgbF_rgb8 (const Babl *conversion, + const float *src, + uint8_t *dst, + long samples) +{ + conv_yF_y8 (conversion, src, dst, samples * 3); +} + +static void +conv_rgbaF_rgba8 (const Babl *conversion, + const float *src, + uint8_t *dst, + long samples) +{ + conv_yF_y8 (conversion, src, dst, samples * 4); +} + +static void +conv_rgbAF_rgbA8 (const Babl *conversion, + const float *src, + uint8_t *dst, + long samples) +{ + conv_yF_y8 (conversion, src, dst, samples * 4); +} + +#endif + +int init (void); + +int +init (void) +{ +#if defined(USE_SSE2) + + const Babl *rgbAF_linear = babl_format_new ( + babl_model ("RaGaBaA"), + babl_type ("float"), + babl_component ("Ra"), + babl_component ("Ga"), + babl_component ("Ba"), + babl_component ("A"), + NULL); + const Babl *rgbA8_linear = babl_format_new ( + babl_model ("RaGaBaA"), + babl_type ("u8"), + babl_component ("Ra"), + babl_component ("Ga"), + babl_component ("Ba"), + babl_component ("A"), + NULL); + const Babl *rgbAF_gamma = babl_format_new ( + babl_model ("R'aG'aB'aA"), + babl_type ("float"), + babl_component ("R'a"), + babl_component ("G'a"), + babl_component ("B'a"), + babl_component ("A"), + NULL); + const Babl *rgbA8_gamma = babl_format_new ( + babl_model ("R'aG'aB'aA"), + babl_type ("u8"), + babl_component ("R'a"), + babl_component ("G'a"), + babl_component ("B'a"), + babl_component ("A"), + NULL); + + const Babl *rgbaF_linear = babl_format_new ( + babl_model ("RGBA"), + babl_type ("float"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + babl_component ("A"), + NULL); + const Babl *rgba8_linear = babl_format_new ( + babl_model ("RGBA"), + babl_type ("u8"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + babl_component ("A"), + NULL); + const Babl *rgbaF_gamma = babl_format_new ( + babl_model ("R'G'B'A"), + babl_type ("float"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + babl_component ("A"), + NULL); + const Babl *rgba8_gamma = babl_format_new ( + babl_model ("R'G'B'A"), + babl_type ("u8"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + babl_component ("A"), + NULL); + const Babl *rgbF_linear = babl_format_new ( + babl_model ("RGB"), + babl_type ("float"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + NULL); + const Babl *rgb8_linear = babl_format_new ( + babl_model ("RGB"), + babl_type ("u8"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + NULL); + const Babl *rgbF_gamma = babl_format_new ( + babl_model ("R'G'B'"), + babl_type ("float"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + NULL); + const Babl *rgb8_gamma = babl_format_new ( + babl_model ("R'G'B'"), + babl_type ("u8"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + NULL); + const Babl *yaF_linear = babl_format_new ( + babl_model ("YA"), + babl_type ("float"), + babl_component ("Y"), + babl_component ("A"), + NULL); + const Babl *ya8_linear = babl_format_new ( + babl_model ("YA"), + babl_type ("u8"), + babl_component ("Y"), + babl_component ("A"), + NULL); + const Babl *yaF_gamma = babl_format_new ( + babl_model ("Y'A"), + babl_type ("float"), + babl_component ("Y'"), + babl_component ("A"), + NULL); + const Babl *ya8_gamma = babl_format_new ( + babl_model ("Y'A"), + babl_type ("u8"), + babl_component ("Y'"), + babl_component ("A"), + NULL); + const Babl *yF_linear = babl_format_new ( + babl_model ("Y"), + babl_type ("float"), + babl_component ("Y"), + NULL); + const Babl *y8_linear = babl_format_new ( + babl_model ("Y"), + babl_type ("u8"), + babl_component ("Y"), + NULL); + const Babl *yF_gamma = babl_format_new ( + babl_model ("Y'"), + babl_type ("float"), + babl_component ("Y'"), + NULL); + const Babl *y8_gamma = babl_format_new ( + babl_model ("Y'"), + babl_type ("u8"), + babl_component ("Y'"), + NULL); + +#define CONV(src, dst) \ +{ \ + babl_conversion_new (src ## _linear, dst ## _linear, "linear", conv_ ## src ## _ ## dst, NULL); \ + babl_conversion_new (src ## _gamma, dst ## _gamma, "linear", conv_ ## src ## _ ## dst, NULL); \ +} + + if ((babl_cpu_accel_get_support () & BABL_CPU_ACCEL_X86_SSE2)) + { + CONV(rgbaF, rgba8); + CONV(rgbAF, rgbA8); + CONV(rgbF, rgb8); + CONV(yaF, ya8); + CONV(yF, y8); + } + +#endif + + return 0; +} + diff --git a/extensions/sse4-int8.c b/extensions/sse4-int8.c new file mode 100644 index 0000000..d505fe5 --- /dev/null +++ b/extensions/sse4-int8.c @@ -0,0 +1,228 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2013 Daniel Sabo + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" + +#if defined(USE_SSE4_1) + +/* SSE 4 */ +#include + +#include +#include + +#include "babl.h" +#include "babl-cpuaccel.h" +#include "extensions/util.h" + +static inline void +conv_y8_yF (const Babl *conversion, + const uint8_t *src, + float *dst, + long samples) +{ + const float factor = 1.0f / 255.0f; + const __v4sf factor_vec = {1.0f / 255.0f, 1.0f / 255.0f, 1.0f / 255.0f, 1.0f / 255.0f}; + const uint32_t *s_vec; + __v4sf *d_vec; + + long n = samples; + + s_vec = (const uint32_t *)src; + d_vec = (__v4sf *)dst; + + while (n >= 4) + { + __m128i in_val; + __v4sf out_val; + in_val = _mm_insert_epi32 ((__m128i)_mm_setzero_ps(), *s_vec++, 0); + in_val = _mm_cvtepu8_epi32 (in_val); + out_val = _mm_cvtepi32_ps (in_val) * factor_vec; + _mm_storeu_ps ((float *)d_vec++, out_val); + n -= 4; + } + + src = (const uint8_t *)s_vec; + dst = (float *)d_vec; + + while (n) + { + *dst++ = (float)(*src++) * factor; + n -= 1; + } +} + +static void +conv_ya8_yaF (const Babl *conversion, + const uint8_t *src, + float *dst, + long samples) +{ + conv_y8_yF (conversion, src, dst, samples * 2); +} + +static void +conv_rgb8_rgbF (const Babl *conversion, + const uint8_t *src, + float *dst, + long samples) +{ + conv_y8_yF (conversion, src, dst, samples * 3); +} + +static void +conv_rgba8_rgbaF (const Babl *conversion, + const uint8_t *src, + float *dst, + long samples) +{ + conv_y8_yF (conversion, src, dst, samples * 4); +} + +#endif + +int init (void); + +int +init (void) +{ +#if defined(USE_SSE4_1) + const Babl *rgbaF_linear = babl_format_new ( + babl_model ("RGBA"), + babl_type ("float"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + babl_component ("A"), + NULL); + const Babl *rgba8_linear = babl_format_new ( + babl_model ("RGBA"), + babl_type ("u8"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + babl_component ("A"), + NULL); + const Babl *rgbaF_gamma = babl_format_new ( + babl_model ("R'G'B'A"), + babl_type ("float"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + babl_component ("A"), + NULL); + const Babl *rgba8_gamma = babl_format_new ( + babl_model ("R'G'B'A"), + babl_type ("u8"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + babl_component ("A"), + NULL); + const Babl *rgbF_linear = babl_format_new ( + babl_model ("RGB"), + babl_type ("float"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + NULL); + const Babl *rgb8_linear = babl_format_new ( + babl_model ("RGB"), + babl_type ("u8"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + NULL); + const Babl *rgbF_gamma = babl_format_new ( + babl_model ("R'G'B'"), + babl_type ("float"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + NULL); + const Babl *rgb8_gamma = babl_format_new ( + babl_model ("R'G'B'"), + babl_type ("u8"), + babl_component ("R'"), + babl_component ("G'"), + babl_component ("B'"), + NULL); + const Babl *yaF_linear = babl_format_new ( + babl_model ("YA"), + babl_type ("float"), + babl_component ("Y"), + babl_component ("A"), + NULL); + const Babl *ya8_linear = babl_format_new ( + babl_model ("YA"), + babl_type ("u8"), + babl_component ("Y"), + babl_component ("A"), + NULL); + const Babl *yaF_gamma = babl_format_new ( + babl_model ("Y'A"), + babl_type ("float"), + babl_component ("Y'"), + babl_component ("A"), + NULL); + const Babl *ya8_gamma = babl_format_new ( + babl_model ("Y'A"), + babl_type ("u8"), + babl_component ("Y'"), + babl_component ("A"), + NULL); + const Babl *yF_linear = babl_format_new ( + babl_model ("Y"), + babl_type ("float"), + babl_component ("Y"), + NULL); + const Babl *y8_linear = babl_format_new ( + babl_model ("Y"), + babl_type ("u8"), + babl_component ("Y"), + NULL); + const Babl *yF_gamma = babl_format_new ( + babl_model ("Y'"), + babl_type ("float"), + babl_component ("Y'"), + NULL); + const Babl *y8_gamma = babl_format_new ( + babl_model ("Y'"), + babl_type ("u8"), + babl_component ("Y'"), + NULL); + +#define CONV(src, dst) \ +{ \ + babl_conversion_new (src ## _linear, dst ## _linear, "linear", conv_ ## src ## _ ## dst, NULL); \ + babl_conversion_new (src ## _gamma, dst ## _gamma, "linear", conv_ ## src ## _ ## dst, NULL); \ +} + + if ((babl_cpu_accel_get_support () & BABL_CPU_ACCEL_X86_SSE4_1)) + { + CONV(rgba8, rgbaF); + CONV(rgb8, rgbF); + CONV(ya8, yaF); + CONV(y8, yF); + } + +#endif + + return 0; +} + diff --git a/extensions/two-table-tables.h b/extensions/two-table-tables.h new file mode 100644 index 0000000..528d3f6 --- /dev/null +++ b/extensions/two-table-tables.h @@ -0,0 +1,3444 @@ +/* Gamma table generated from a babl conversion of Y to Y' */ +static const unsigned char linear_to_gamma[65536] = +{ +0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2, +2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4, +4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6, +6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8, +8,8,8,8,8,8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,10,10,10,10, +10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, +12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, +13,13,13,13,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14, +14,14,14,14,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, +15,15,15,15,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, +16,16,16,16,16,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, +17,17,17,17,17,17,17,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, +18,18,18,18,18,18,18,18,18,18,18,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, +19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,20,20,20,20,20,20,20,20,20,20, +20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,21,21,21,21, +21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21, +21,21,21,21,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, +22,22,22,22,22,22,22,22,22,22,22,22,22,23,23,23,23,23,23,23,23,23,23,23,23,23, +23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,24,24,24, +24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, +24,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25, +25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,26,26,26,26, +26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26, +26,26,26,26,26,26,26,26,26,26,26,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27, +27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27, +27,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28, +28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,29,29,29,29,29,29,29,29, +29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, +29,29,29,29,29,29,29,29,29,29,29,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, +30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30, +30,30,30,30,30,30,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31, +31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31, +31,31,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,33, +33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33, +33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,34,34, +34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34, +34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,35,35, +35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35, +35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36, +36,36,36,36,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, +37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, +37,37,37,37,37,37,37,37,37,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38, +38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38, +38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,39,39,39,39,39,39,39,39,39,39,39, +39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39, +39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,40,40,40, +40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40, +40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40, +40,40,40,40,40,40,40,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41, +41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41, +41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,42,42,42,42,42,42,42, +42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42, +42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42, +42,42,42,42,42,42,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, +43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,44,44,44,44,44,44, +44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44, +44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44, +44,44,44,44,44,44,44,44,44,44,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45, +45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45, +45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45, +45,45,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, +46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,47,47,47,47, +47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47, +47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47, +47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,48,48,48,48,48,48,48,48,48, +48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48, +48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48, +48,48,48,48,48,48,48,48,48,48,48,48,48,48,49,49,49,49,49,49,49,49,49,49,49,49, +49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49, +49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49, +49,49,49,49,49,49,49,49,49,49,49,49,49,50,50,50,50,50,50,50,50,50,50,50,50,50, +50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, +50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, +50,50,50,50,50,50,50,50,50,50,50,50,50,51,51,51,51,51,51,51,51,51,51,51,51,51, +51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51, +51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51, +51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,52,52,52,52,52,52,52,52,52,52,52, +52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52, +52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52, +52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,53,53,53,53,53,53,53, +53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53, +53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53, +53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,54, +54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54, +54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54, +54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54, +54,54,54,54,54,54,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55, +55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55, +55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55, +55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,56,56,56,56,56,56,56,56,56,56,56, +56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56, +56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56, +56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56, +57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, +57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, +57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57, +57,57,57,57,57,57,57,57,57,57,57,57,58,58,58,58,58,58,58,58,58,58,58,58,58,58, +58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58, +58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58, +58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58, +58,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59, +59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59, +59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59, +59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,60,60,60,60,60,60,60,60,60, +60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60, +60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60, +60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60, +60,60,60,60,60,60,60,60,60,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, +61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, +61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, +61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, +61,61,61,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62, +62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62, +62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62, +62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,63,63, +63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63, +63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63, +63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63, +63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,64,64,64,64, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,65,65,65,65,65, +65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65, +65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65, +65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65, +65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,66,66,66, +66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66, +66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66, +66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66, +66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66, +67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, +67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, +67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, +67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, +67,67,67,67,67,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68, +68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68, +68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68, +68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68, +68,68,68,68,68,68,68,68,68,68,68,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69, +69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69, +69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69, +69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69, +69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69,70,70,70,70,70,70, +70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70, +70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70, +70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70, +70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70, +70,70,70,70,70,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71, +71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71, +71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71, +71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71, +71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,72,72,72,72,72,72,72,72,72, +72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72, +72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72, +72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72, +72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72, +72,72,72,72,72,72,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73, +73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73, +73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73, +73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73, +73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,74,74,74,74, +74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74, +74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74, +74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74, +74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74, +74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,75,75,75,75,75,75,75,75,75,75,75, +75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75, +75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75, +75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75, +75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75, +75,75,75,75,75,75,75,75,75,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, +76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, +76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, +76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, +76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, +76,76,76,76,76,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77, +77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77, +77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77, +77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77, +77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77, +77,77,77,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78, +78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78, +78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78, +78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78, +78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78, +78,78,78,78,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79, +79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79, +79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79, +79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79, +79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79, +79,79,79,79,79,79,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80, +80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80, +80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80, +80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80, +80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80, +80,80,80,80,80,80,80,80,80,80,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81, +81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81, +81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81, +81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81, +81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81, +81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,82,82,82,82,82,82,82,82,82,82, +82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82, +82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82, +82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82, +82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82, +82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,83,83, +83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83, +83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83, +83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83, +83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83, +83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,83, +83,83,83,83,83,83,83,83,83,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, +84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, +84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, +84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, +84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, +84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,85,85,85,85,85, +85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, +85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, +85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, +85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, +85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, +85,85,85,85,85,85,85,85,85,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86, +86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86, +86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86, +86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86, +86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86, +86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86, +87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87, +87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87, +87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87, +87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87, +87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87, +87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,87,88,88,88,88,88,88,88,88, +88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88, +88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88, +88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88, +88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88, +88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88,88, +88,88,88,88,88,88,88,88,88,88,88,88,89,89,89,89,89,89,89,89,89,89,89,89,89,89, +89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89, +89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89, +89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89, +89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89, +89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89,89, +89,89,89,89,89,89,89,89,89,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90, +90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90, +90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90, +90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90, +90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90, +90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90,90, +90,90,90,90,90,90,90,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91, +91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91, +91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91, +91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91, +91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91, +91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91,91, +91,91,91,91,91,91,91,91,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, +92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, +92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, +92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, +92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, +92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92, +92,92,92,92,92,92,92,92,92,92,92,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93, +93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93, +93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93, +93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93, +93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93, +93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93, +93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,93,94,94,94,94,94,94,94,94,94,94, +94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94, +94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94, +94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94, +94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94, +94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94, +94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,94,95,95,95, +95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95, +95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95, +95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95, +95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95, +95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95, +95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95,95, +95,95,95,95,95,95,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96, +96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96, +96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96, +96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96, +96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96, +96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96, +96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,96,97,97,97,97,97,97,97,97,97, +97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97, +97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97, +97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97, +97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97, +97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97, +97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97,97, +97,97,97,97,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98, +98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98, +98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98, +98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98, +98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98, +98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98, +98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,98,99,99,99,99,99,99, +99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, +99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, +99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, +99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, +99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, +99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99, +99,99,99,99,99,99,99,99,99,99,99,99,100,100,100,100,100,100,100,100,100,100,100, +100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, +100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, +100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, +100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, +100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, +100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, +100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, +100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, +100,100,100,100,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101, +101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101, +101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101, +101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101, +101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101, +101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101, +101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101, +101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101, +101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101,101, +101,101,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, +102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, +102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, +102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, +102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, +102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, +102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, +102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, +102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, +102,102,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103, +103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103, +103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103, +103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103, +103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103, +103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103, +103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103, +103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103, +103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103, +103,103,103,103,103,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104, +104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104, +104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104, +104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104, +104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104, +104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104, +104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104, +104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104, +104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104,104, +104,104,104,104,104,104,104,104,104,105,105,105,105,105,105,105,105,105,105,105, +105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, +105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, +105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, +105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, +105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, +105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, +105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, +105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, +105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,106,106,106,106, +106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106, +106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106, +106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106, +106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106, +106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106, +106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106, +106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106, +106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106, +106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106,106, +106,106,106,106,106,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107, +107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107, +107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107, +107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107, +107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107, +107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107, +107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107, +107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107, +107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107, +107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,108,108,108,108, +108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108, +108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108, +108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108, +108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108, +108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108, +108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108, +108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108, +108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108, +108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108, +108,108,108,108,108,108,108,108,108,109,109,109,109,109,109,109,109,109,109,109, +109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109, +109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109, +109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109, +109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109, +109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109, +109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109, +109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109, +109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109, +109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109, +109,109,109,109,109,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110, +110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110, +110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110, +110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110, +110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110, +110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110, +110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110, +110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110, +110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110, +110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110,110, +110,110,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, +111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, +111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, +111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, +111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, +111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, +111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, +111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, +111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, +111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, +111,111,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112, +112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112, +112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112, +112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112, +112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112, +112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112, +112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112, +112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112, +112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112, +112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112,112, +112,112,112,112,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113, +113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113, +113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113, +113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113, +113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113, +113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113, +113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113, +113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113, +113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113, +113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113,113, +113,113,113,113,113,113,113,113,113,114,114,114,114,114,114,114,114,114,114,114, +114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, +114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, +114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, +114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, +114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, +114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, +114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, +114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, +114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114, +114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,114,115,115,115,115, +115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115, +115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115, +115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115, +115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115, +115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115, +115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115, +115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115, +115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115, +115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115, +115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115, +115,115,115,115,115,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116, +116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116, +116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116, +116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116, +116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116, +116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116, +116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116, +116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116, +116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116, +116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116, +116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,117,117,117,117, +117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117, +117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117, +117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117, +117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117, +117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117, +117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117, +117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117, +117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117, +117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117, +117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117,117, +117,117,117,117,117,117,117,117,117,118,118,118,118,118,118,118,118,118,118,118, +118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118, +118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118, +118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118, +118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118, +118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118, +118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118, +118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118, +118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118, +118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118, +118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118, +118,118,118,118,118,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119, +119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119, +119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119, +119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119, +119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119, +119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119, +119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119, +119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119, +119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119, +119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119, +119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119,119, +119,119,119,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120, +120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120, +120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120, +120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120, +120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120, +120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120, +120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120, +120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120, +120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120, +120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120, +120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120, +120,120,120,120,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121, +121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121, +121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121, +121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121, +121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121, +121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121, +121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121, +121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121, +121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121, +121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121, +121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121,121, +121,121,121,121,121,121,121,122,122,122,122,122,122,122,122,122,122,122,122,122, +122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122, +122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122, +122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122, +122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122, +122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122, +122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122, +122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122, +122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122, +122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122, +122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122,122, +122,122,122,122,122,122,122,122,122,122,122,122,123,123,123,123,123,123,123,123, +123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, +123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, +123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, +123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, +123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, +123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, +123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, +123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, +123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, +123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, +123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,124, +124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124, +124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124, +124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124, +124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124, +124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124, +124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124, +124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124, +124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124, +124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124, +124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124, +124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124, +124,124,124,124,124,124,124,124,124,125,125,125,125,125,125,125,125,125,125,125, +125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, +125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, +125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, +125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, +125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, +125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, +125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, +125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, +125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, +125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, +125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125,125, +125,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, +126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, +126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, +126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, +126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, +126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, +126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, +126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, +126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, +126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, +126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, +126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,127,127,127,127,127, +127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127, +127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127, +127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127, +127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127, +127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127, +127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127, +127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127, +127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127, +127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127, +127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127, +127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127,127, +127,127,127,127,127,127,127,127,127,127,127,127,128,128,128,128,128,128,128,128, +128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, +128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, +128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, +128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, +128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, +128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, +128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, +128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, +128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, +128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, +128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128,128, +128,128,128,128,128,128,128,128,128,128,128,129,129,129,129,129,129,129,129,129, +129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, +129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, +129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, +129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, +129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, +129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, +129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, +129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, +129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, +129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, +129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129,129, +129,129,129,129,129,129,129,129,129,129,129,129,130,130,130,130,130,130,130,130, +130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130, +130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130, +130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130, +130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130, +130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130, +130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130, +130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130, +130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130, +130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130, +130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130, +130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130, +130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,130,131,131,131,131, +131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131, +131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131, +131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131, +131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131, +131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131, +131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131, +131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131, +131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131, +131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131, +131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131, +131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131, +131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131, +131,131,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132, +132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132, +132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132, +132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132, +132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132, +132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132, +132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132, +132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132, +132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132, +132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132, +132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132, +132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132, +132,132,132,132,132,132,132,132,132,132,132,133,133,133,133,133,133,133,133,133, +133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133, +133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133, +133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133, +133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133, +133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133, +133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133, +133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133, +133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133, +133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133, +133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133, +133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133, +133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133, +133,133,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134, +134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134, +134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134, +134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134, +134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134, +134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134, +134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134, +134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134, +134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134, +134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134, +134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134, +134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,134, +134,134,134,134,134,134,134,134,134,134,134,134,134,134,134,135,135,135,135,135, +135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135, +135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135, +135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135, +135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135, +135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135, +135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135, +135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135, +135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135, +135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135, +135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135, +135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135, +135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135, +135,135,135,135,135,135,135,135,135,135,135,136,136,136,136,136,136,136,136,136, +136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136,136, +136,136,136,136,136,136,136,136,136,137,137,137,137,137,137,137,137,137,137,137, +137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137, +137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137, +137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137, +137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137, +137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137, +137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137, +137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137, +137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137, +137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137, +137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137, +137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137, +137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137, +137,137,137,137,137,137,137,137,137,138,138,138,138,138,138,138,138,138,138,138, +138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138, +138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138, +138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138, +138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138, +138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138, +138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138, +138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138, +138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138, +138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138, +138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138, +138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138, +138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138, +138,138,138,138,138,138,138,138,138,138,138,138,139,139,139,139,139,139,139,139, +139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, +139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, +139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, +139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, +139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, +139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, +139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, +139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, +139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, +139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, +139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, +139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, +139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,140,140, +140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140, +140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140, +140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140, +140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140, +140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140, +140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140, +140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140, +140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140, +140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140, +140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140, +140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140, +140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140, +140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140, +140,140,140,140,140,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, +141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, +141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, +141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, +141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, +141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, +141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, +141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, +141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, +141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, +141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, +141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, +141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141, +141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,141,142,142,142,142, +142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, +142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, +142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, +142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, +142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, +142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, +142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, +142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, +142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, +142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, +142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, +142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, +142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, +142,142,142,142,142,142,142,142,143,143,143,143,143,143,143,143,143,143,143,143, +143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143, +143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143, +143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143, +143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143, +143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143, +143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143, +143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143, +143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143, +143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143, +143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143, +143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143, +143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143, +143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143, +143,143,143,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144, +144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144, +144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144, +144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144, +144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144, +144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144, +144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144, +144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144, +144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144, +144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144, +144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144, +144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144, +144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144, +144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144,144, +144,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145, +145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145, +145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145, +145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145, +145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145, +145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145, +145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145, +145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145, +145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145, +145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145, +145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145, +145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145, +145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145, +145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145,145, +145,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, +146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, +146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, +146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, +146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, +146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, +146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, +146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, +146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, +146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, +146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, +146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, +146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, +146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, +146,146,146,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147, +147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147, +147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147, +147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147, +147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147, +147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147, +147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147, +147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147, +147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147, +147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147, +147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147, +147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147, +147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147, +147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147,147, +147,147,147,147,147,147,147,147,148,148,148,148,148,148,148,148,148,148,148,148, +148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148, +148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148, +148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148, +148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148, +148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148, +148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148, +148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148, +148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148, +148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148, +148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148, +148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148, +148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148, +148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148, +148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,149,149,149,149, +149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149, +149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149, +149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149, +149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149, +149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149, +149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149, +149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149, +149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149, +149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149, +149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149, +149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149, +149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149, +149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149, +149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149,149, +149,149,149,149,149,149,150,150,150,150,150,150,150,150,150,150,150,150,150,150, +150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150, +150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150, +150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150, +150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150, +150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150, +150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150, +150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150, +150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150, +150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150, +150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150, +150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150, +150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150, +150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150, +150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,151,151, +151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151, +151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151, +151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151, +151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151, +151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151, +151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151, +151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151, +151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151, +151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151, +151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151, +151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151, +151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151, +151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151, +151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151, +151,151,151,151,151,151,151,151,151,151,151,151,151,152,152,152,152,152,152,152, +152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152, +152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152, +152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152, +152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152, +152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152, +152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152, +152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152, +152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152, +152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152, +152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152, +152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152, +152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152, +152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152, +152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152, +152,152,152,152,152,152,152,152,152,152,152,153,153,153,153,153,153,153,153,153, +153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153, +153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153, +153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153, +153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153, +153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153, +153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153, +153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153, +153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153, +153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153, +153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153, +153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153, +153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153, +153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153, +153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153, +153,153,153,153,153,153,153,153,153,153,153,154,154,154,154,154,154,154,154,154, +154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154, +154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154, +154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154, +154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154, +154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154, +154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154, +154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154, +154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154, +154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154, +154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154, +154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154, +154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154, +154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154, +154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154, +154,154,154,154,154,154,154,154,154,154,154,154,154,155,155,155,155,155,155,155, +155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155, +155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155, +155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155, +155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155, +155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155, +155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155, +155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155, +155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155, +155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155, +155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155, +155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155, +155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155, +155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155, +155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155, +155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,155,156,156, +156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156, +156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156, +156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156, +156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156, +156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156, +156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156, +156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156, +156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156, +156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156, +156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156, +156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156, +156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156, +156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156, +156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156, +156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156, +156,156,156,156,156,156,157,157,157,157,157,157,157,157,157,157,157,157,157,157, +157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157, +157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157, +157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157, +157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157, +157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157, +157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157, +157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157, +157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157, +157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157, +157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157, +157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157, +157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157, +157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157, +157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157, +157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,157,158,158,158,158, +158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158, +158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158, +158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158, +158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158, +158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158, +158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158, +158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158, +158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158, +158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158, +158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158, +158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158, +158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158, +158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158, +158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158, +158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158,158, +158,158,158,158,158,158,158,158,159,159,159,159,159,159,159,159,159,159,159,159, +159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159, +159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159, +159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159, +159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159, +159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159, +159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159, +159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159, +159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159, +159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159, +159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159, +159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159, +159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159, +159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159, +159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159, +159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159,159, +159,159,159,159,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, +160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, +160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, +160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, +160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, +160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, +160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, +160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, +160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, +160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, +160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, +160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, +160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, +160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, +160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, +160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,160, +160,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, +161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, +161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, +161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, +161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, +161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, +161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, +161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, +161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, +161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, +161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, +161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, +161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, +161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, +161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, +161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161,161, +161,161,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162, +162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162, +162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162, +162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162, +162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162, +162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162, +162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162, +162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162, +162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162, +162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162, +162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162, +162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162, +162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162, +162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162, +162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162, +162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162,162, +162,162,162,162,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163, +163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163, +163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163, +163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163, +163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163, +163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163, +163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163, +163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163, +163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163, +163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163, +163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163, +163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163, +163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163, +163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163, +163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163, +163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163,163, +163,163,163,163,163,163,163,163,163,163,164,164,164,164,164,164,164,164,164,164, +164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164, +164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164, +164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164, +164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164, +164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164, +164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164, +164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164, +164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164, +164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164, +164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164, +164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164, +164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164, +164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164, +164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164, +164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164, +164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,165,165, +165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165, +165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165, +165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165, +165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165, +165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165, +165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165, +165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165, +165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165, +165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165, +165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165, +165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165, +165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165, +165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165, +165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165, +165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165, +165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165,165, +165,165,165,165,165,165,165,165,166,166,166,166,166,166,166,166,166,166,166,166, +166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166, +166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166, +166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166, +166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166, +166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166, +166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166, +166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166, +166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166, +166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166, +166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166, +166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166, +166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166, +166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166, +166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166, +166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166, +166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166,166, +166,166,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167, +167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167, +167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167, +167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167, +167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167, +167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167, +167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167, +167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167, +167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167, +167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167, +167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167, +167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167, +167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167, +167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167, +167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167, +167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167, +167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,167,168,168,168, +168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168, +168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168, +168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168, +168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168, +168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168, +168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168, +168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168, +168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168, +168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168, +168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168, +168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168, +168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168, +168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168, +168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168, +168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168, +168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168, +168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,168,169,169,169,169, +169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169, +169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169, +169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169, +169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169, +169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169, +169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169, +169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169, +169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169, +169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169, +169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169, +169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169, +169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169, +169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169, +169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169, +169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169, +169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169, +169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,169,170,170,170, +170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170, +170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170, +170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170, +170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170, +170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170, +170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170, +170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170, +170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170, +170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170, +170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170, +170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170, +170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170, +170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170, +170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170, +170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170, +170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170, +170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170,170, +171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171, +171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171, +171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171, +171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171, +171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171, +171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171, +171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171, +171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171, +171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171, +171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171, +171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171, +171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171, +171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171, +171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171, +171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171, +171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171, +171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171,171, +171,171,171,171,171,171,172,172,172,172,172,172,172,172,172,172,172,172,172,172, +172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172, +172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172, +172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172, +172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172, +172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172, +172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172, +172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172, +172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172, +172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172, +172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172, +172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172, +172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172, +172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172, +172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172, +172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172, +172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172, +172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,173,173,173,173,173, +173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173, +173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173, +173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173, +173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173, +173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173, +173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173, +173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173, +173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173, +173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173, +173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173, +173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173, +173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173, +173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173, +173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173, +173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173, +173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173, +173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173,173, +173,173,173,173,173,173,173,174,174,174,174,174,174,174,174,174,174,174,174,174, +174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174, +174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174, +174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174, +174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174, +174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174, +174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174, +174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174, +174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174, +174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174, +174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174, +174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174, +174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174, +174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174, +174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174, +174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174, +174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174, +174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174,174, +174,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175, +175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175, +175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175, +175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175, +175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175, +175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175, +175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175, +175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175, +175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175, +175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175, +175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175, +175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175, +175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175, +175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175, +175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175, +175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175, +175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175, +175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,175,176,176,176, +176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176, +176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176, +176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176, +176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176, +176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176, +176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176, +176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176, +176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176, +176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176, +176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176, +176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176, +176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176, +176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176, +176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176, +176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176, +176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176, +176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176, +176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,176,177,177,177, +177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,178, +178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178, +178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178, +178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178, +178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178, +178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178, +178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178, +178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178, +178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178, +178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178, +178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178, +178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178, +178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178, +178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178, +178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178, +178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178, +178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178, +178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178, +178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178, +178,178,178,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179, +179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179, +179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179, +179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179, +179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179, +179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179, +179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179, +179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179, +179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179, +179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179, +179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179, +179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179, +179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179, +179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179, +179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179, +179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179, +179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179, +179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179,179, +179,179,179,179,179,179,179,179,179,179,179,180,180,180,180,180,180,180,180,180, +180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180, +180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180, +180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180, +180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180, +180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180, +180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180, +180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180, +180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180, +180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180, +180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180, +180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180, +180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180, +180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180, +180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180, +180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180, +180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180, +180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180, +180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180, +180,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181, +181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181, +181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181, +181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181, +181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181, +181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181, +181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181, +181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181, +181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181, +181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181, +181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181, +181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181, +181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181, +181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181, +181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181, +181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181, +181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181, +181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181,181, +181,181,181,181,181,181,181,181,181,181,181,181,181,182,182,182,182,182,182,182, +182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182, +182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182, +182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182, +182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182, +182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182, +182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182, +182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182, +182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182, +182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182, +182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182, +182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182, +182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182, +182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182, +182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182, +182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182, +182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182, +182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182, +182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182,182, +182,182,182,182,182,182,182,182,182,183,183,183,183,183,183,183,183,183,183,183, +183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183, +183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183, +183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183, +183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183, +183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183, +183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183, +183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183, +183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183, +183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183, +183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183, +183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183, +183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183, +183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183, +183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183, +183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183, +183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183, +183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183, +183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183,183, +183,183,183,183,183,183,183,184,184,184,184,184,184,184,184,184,184,184,184,184, +184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184, +184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184, +184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184, +184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184, +184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184, +184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184, +184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184, +184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184, +184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184, +184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184, +184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184, +184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184, +184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184, +184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184, +184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184, +184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184, +184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184, +184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184,184, +184,184,184,184,184,184,184,185,185,185,185,185,185,185,185,185,185,185,185,185, +185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185, +185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185, +185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185, +185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185, +185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185, +185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185, +185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185, +185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185, +185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185, +185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185, +185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185, +185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185, +185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185, +185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185, +185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185, +185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185, +185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185, +185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185,185, +185,185,185,185,185,185,185,185,185,185,185,186,186,186,186,186,186,186,186,186, +186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186, +186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186, +186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186, +186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186, +186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186, +186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186, +186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186, +186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186, +186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186, +186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186, +186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186, +186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186, +186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186, +186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186, +186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186, +186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186, +186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186, +186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186, +186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,186,187,187,187, +187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187, +187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187, +187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187, +187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187, +187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187, +187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187, +187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187, +187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187, +187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187, +187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187, +187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187, +187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187, +187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187, +187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187, +187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187, +187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187, +187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187, +187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187, +187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187,187, +187,187,187,187,187,187,188,188,188,188,188,188,188,188,188,188,188,188,188,188, +188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188, +188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188, +188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188, +188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188, +188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188, +188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188, +188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188, +188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188, +188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188, +188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188, +188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188, +188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188, +188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188, +188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188, +188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188, +188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188, +188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188, +188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188, +188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,189,189,189, +189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189, +189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189, +189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189, +189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189, +189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189, +189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189, +189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189, +189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189, +189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189, +189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189, +189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189, +189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189, +189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189, +189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189, +189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189, +189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189, +189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189, +189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189, +189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189,189, +189,189,189,189,189,189,189,189,189,189,189,189,190,190,190,190,190,190,190,190, +190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190, +190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190, +190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190, +190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190, +190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190, +190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190, +190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190, +190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190, +190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190, +190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190, +190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190, +190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190, +190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190, +190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190, +190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190, +190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190, +190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190, +190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190, +190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190,190, +190,190,190,190,190,190,190,190,191,191,191,191,191,191,191,191,191,191,191,191, +191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191, +191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191, +191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191, +191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191, +191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191, +191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191, +191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191, +191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191, +191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191, +191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191, +191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191, +191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191, +191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191, +191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191, +191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191, +191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191, +191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191, +191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191, +191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191,191, +191,191,191,191,191,191,191,191,192,192,192,192,192,192,192,192,192,192,192,192, +192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, +192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, +192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, +192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, +192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, +192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, +192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, +192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, +192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, +192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, +192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, +192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, +192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, +192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, +192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, +192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, +192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, +192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, +192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192,192, +192,192,192,192,192,192,192,192,192,192,192,193,193,193,193,193,193,193,193,193, +193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193, +193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193, +193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193, +193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193, +193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193, +193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193, +193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193, +193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193, +193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193, +193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193, +193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193, +193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193, +193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193, +193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193, +193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193, +193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193, +193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193, +193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193, +193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193, +193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,193,194,194,194,194, +194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194, +194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194, +194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194, +194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194, +194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194, +194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194, +194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194, +194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194, +194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194, +194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194, +194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194, +194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194, +194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194, +194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194, +194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194, +194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194, +194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194, +194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194, +194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194, +194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194,194, +194,194,194,194,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195, +195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195, +195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195, +195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195, +195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195, +195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195, +195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195, +195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195, +195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195, +195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195, +195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195, +195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195, +195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195, +195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195, +195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195, +195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195, +195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195, +195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195, +195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195, +195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195,195, +195,195,195,195,195,195,195,195,195,195,195,195,195,195,196,196,196,196,196,196, +196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196, +196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196, +196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196, +196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196, +196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196, +196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196, +196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196, +196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196, +196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196, +196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196, +196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196, +196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196, +196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196, +196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196, +196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196, +196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196, +196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196, +196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196, +196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196, +196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196, +196,196,196,196,196,196,196,196,197,197,197,197,197,197,197,197,197,197,197,197, +197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197, +197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197, +197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197, +197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197, +197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197, +197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197, +197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197, +197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197, +197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197, +197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197, +197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197, +197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197, +197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197, +197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197, +197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197, +197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197, +197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197, +197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197, +197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197, +197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197,197, +197,197,197,197,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198, +198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198, +198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198, +198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198, +198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198, +198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198, +198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198, +198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198, +198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198, +198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198, +198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198, +198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198, +198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198, +198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198, +198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198, +198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198, +198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198, +198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198, +198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198, +198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198, +198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198,198, +198,198,198,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, +199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, +199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, +199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, +199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, +199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, +199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, +199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, +199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, +199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, +199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, +199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, +199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, +199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, +199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, +199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, +199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, +199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, +199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, +199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, +199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199,199, +199,199,199,199,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200, +200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200, +200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200, +200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200, +200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200, +200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200, +200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200, +200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200, +200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200, +200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200, +200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200, +200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200, +200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200, +200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200, +200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200, +200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200, +200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200, +200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200, +200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200, +200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200, +200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200,200, +200,200,200,200,200,200,200,200,200,201,201,201,201,201,201,201,201,201,201,201, +201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201, +201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201, +201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201, +201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201, +201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201, +201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201, +201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201, +201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201, +201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201, +201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201, +201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201, +201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201, +201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201, +201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201, +201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201, +201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201, +201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201, +201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201, +201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201, +201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201, +201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,201,202,202,202,202, +202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202, +202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202, +202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202, +202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202, +202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202, +202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202, +202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202, +202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202, +202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202, +202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202, +202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202, +202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202, +202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202, +202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202, +202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202, +202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202, +202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202, +202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202, +202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202, +202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202, +202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202, +202,202,202,202,202,202,203,203,203,203,203,203,203,203,203,203,203,203,203,203, +203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203, +203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203, +203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203, +203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203, +203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203, +203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203, +203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203, +203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203, +203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203, +203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203, +203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203, +203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203, +203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203, +203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203, +203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203, +203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203, +203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203, +203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203, +203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203, +203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203, +203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,203,204, +204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204, +204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204, +204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204, +204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204, +204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204, +204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204, +204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204, +204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204, +204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204, +204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204, +204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204, +204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204, +204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204, +204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204, +204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204, +204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204, +204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204, +204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204, +204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204, +204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204, +204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204, +204,204,204,204,204,204,204,204,204,204,204,204,204,204,205,205,205,205,205,205, +205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205, +205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205, +205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205, +205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205, +205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205, +205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205, +205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205, +205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205, +205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205, +205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205, +205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205, +205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205, +205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205, +205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205, +205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205, +205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205, +205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205, +205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205, +205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205, +205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205, +205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205,205, +205,205,205,205,205,205,205,205,205,205,205,205,205,206,206,206,206,206,206,206, +206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206, +206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206, +206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206, +206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206, +206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206, +206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206, +206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206, +206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206, +206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206, +206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206, +206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206, +206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206, +206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206, +206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206, +206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206, +206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206, +206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206, +206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206, +206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206, +206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206, +206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206,206, +206,206,206,206,206,206,206,206,206,206,206,206,206,206,207,207,207,207,207,207, +207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207, +207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207, +207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207, +207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207, +207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207, +207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207, +207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207, +207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207, +207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207, +207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207, +207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207, +207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207, +207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207, +207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207, +207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207, +207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207, +207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207, +207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207, +207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207, +207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207, +207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207, +207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,207,208,208, +208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, +208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, +208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, +208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, +208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, +208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, +208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, +208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, +208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, +208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, +208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, +208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, +208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, +208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, +208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, +208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, +208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, +208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, +208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, +208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, +208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, +208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208,208, +208,208,208,208,208,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209, +209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209, +209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209, +209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209, +209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209, +209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209, +209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209, +209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209, +209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209, +209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209, +209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209, +209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209, +209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209, +209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209, +209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209, +209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209, +209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209, +209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209, +209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209, +209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209, +209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209, +209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,209, +209,209,209,209,209,209,209,209,209,209,209,209,209,209,209,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210,210, +210,210,210,210,210,210,210,211,211,211,211,211,211,211,211,211,211,211,211,211, +211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211, +211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211, +211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211, +211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211, +211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211, +211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211, +211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211, +211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211, +211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211, +211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211, +211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211, +211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211, +211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211, +211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211, +211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211, +211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211, +211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211, +211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211, +211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211, +211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211, +211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211, +211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211,211, +211,211,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212, +212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212, +212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212, +212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212, +212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212, +212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212, +212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212, +212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212, +212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212, +212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212, +212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212, +212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212, +212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212, +212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212, +212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212, +212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212, +212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212, +212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212, +212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212, +212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212, +212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212, +212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212, +212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212, +212,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213, +213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213, +213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213, +213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213, +213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213, +213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213, +213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213, +213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213, +213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213, +213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213, +213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213, +213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213, +213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213, +213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213, +213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213, +213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213, +213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213, +213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213, +213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213, +213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213, +213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213, +213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213, +213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213,213, +213,213,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214, +214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214, +214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214, +214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214, +214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214, +214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214, +214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214, +214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214, +214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214, +214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214, +214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214, +214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214, +214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214, +214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214, +214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214, +214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214, +214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214, +214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214, +214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214, +214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214, +214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214, +214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214, +214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214,214, +214,214,214,214,214,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215, +215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215, +215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215, +215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215, +215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215, +215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215, +215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215, +215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215, +215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215, +215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215, +215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215, +215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215, +215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215, +215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215, +215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215, +215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215, +215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215, +215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215, +215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215, +215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215, +215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215, +215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215, +215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215,215, +215,215,215,215,215,215,215,215,215,215,215,215,216,216,216,216,216,216,216,216, +216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216, +216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216, +216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216, +216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216, +216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216, +216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216, +216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216, +216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216, +216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216, +216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216, +216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216, +216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216, +216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216, +216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216, +216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216, +216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216, +216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216, +216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216, +216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216, +216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216, +216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216, +216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216, +216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216,216, +216,216,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217, +217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217, +217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217, +217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217, +217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217, +217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217, +217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217, +217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217, +217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217, +217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217, +217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217, +217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217, +217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217, +217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217, +217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217, +217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217, +217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217, +217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217, +217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217, +217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217, +217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217, +217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217, +217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217,217, +217,217,217,217,217,217,217,217,217,217,217,217,217,217,218,218,218,218,218,218, +218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218, +218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218, +218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218, +218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218, +218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218, +218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218, +218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218, +218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218, +218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218, +218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218, +218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218, +218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218, +218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218, +218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218, +218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218, +218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218, +218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218, +218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218, +218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218, +218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218, +218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218, +218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218, +218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218,218, +218,218,218,218,218,218,218,218,218,219,219,219,219,219,219,219,219,219,219,219, +219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219, +219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219, +219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219, +219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219, +219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219, +219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219, +219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219, +219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219, +219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219, +219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219, +219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219, +219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219, +219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219, +219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219, +219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219, +219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219, +219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219, +219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219, +219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219, +219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219, +219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219, +219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219, +219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219, +219,219,219,219,219,219,219,220,220,220,220,220,220,220,220,220,220,220,220,220, +220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220, +220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220, +220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220, +220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220, +220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220, +220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220, +220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220, +220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220, +220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220, +220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220, +220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220, +220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220, +220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220, +220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220, +220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220, +220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220, +220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220, +220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220, +220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220, +220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220, +220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220, +220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220, +220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220, +220,220,220,220,220,220,220,220,221,221,221,221,221,221,221,221,221,221,221,221, +221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221, +221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221, +221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221, +221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221, +221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221, +221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221, +221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221, +221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221, +221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221, +221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221, +221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221, +221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221, +221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221, +221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221, +221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221, +221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221, +221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221, +221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221, +221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221, +221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221, +221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221, +221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221, +221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221,221, +221,221,221,221,221,221,221,221,221,221,221,221,222,222,222,222,222,222,222,222, +222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222, +222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222, +222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222, +222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222, +222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222, +222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222, +222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222, +222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222, +222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222, +222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222, +222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222, +222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222, +222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222, +222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222, +222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222, +222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222, +222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222, +222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222, +222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222, +222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222, +222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222, +222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222, +222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222, +222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,222,223, +223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223, +223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223, +223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223, +223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223, +223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223, +223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223, +223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223, +223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223, +223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223, +223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223, +223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223, +223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223, +223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223, +223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223, +223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223, +223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223, +223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223, +223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223, +223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223, +223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223, +223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223, +223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223, +223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223, +223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223,223, +223,223,223,223,223,223,223,223,223,224,224,224,224,224,224,224,224,224,224,224, +224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, +224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, +224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, +224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, +224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, +224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, +224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, +224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, +224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, +224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, +224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, +224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, +224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, +224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, +224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, +224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, +224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, +224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, +224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, +224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, +224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, +224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, +224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, +224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224,224, +224,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, +225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, +225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, +225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, +225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, +225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, +225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, +225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, +225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, +225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, +225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, +225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, +225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, +225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, +225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, +225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, +225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, +225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, +225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, +225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, +225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, +225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, +225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, +225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225, +225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,225,226,226,226, +226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226, +226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226, +226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226, +226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226, +226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226, +226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226, +226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226, +226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226, +226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226, +226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226, +226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226, +226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226, +226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226, +226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226, +226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226, +226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226, +226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226, +226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226, +226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226, +226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226, +226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226, +226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226, +226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226, +226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,226, +226,226,226,226,226,226,226,226,226,226,226,226,226,226,226,227,227,227,227,227, +227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227, +227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227, +227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227, +227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227, +227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227, +227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227, +227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227, +227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227, +227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227, +227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227, +227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227, +227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227, +227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227, +227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227, +227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227, +227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227, +227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227, +227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227, +227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227, +227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227, +227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227, +227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227, +227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227, +227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227, +227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,227,228,228,228,228, +228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228, +228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228, +228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228, +228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228, +228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228, +228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228, +228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228, +228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228, +228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228, +228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228, +228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228, +228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228, +228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228, +228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228, +228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228, +228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228, +228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228, +228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228, +228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228, +228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228, +228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228, +228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228, +228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228, +228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228, +228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228, +229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229, +229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229, +229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229, +229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229, +229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229, +229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229, +229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229, +229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229, +229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229, +229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229, +229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229, +229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229, +229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229, +229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229, +229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229, +229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229, +229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229, +229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229, +229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229, +229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229, +229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229, +229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229, +229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229, +229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229, +229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229,229, +229,229,229,229,229,229,229,229,230,230,230,230,230,230,230,230,230,230,230,230, +230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230, +230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230, +230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230, +230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230, +230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230, +230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230, +230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230, +230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230, +230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230, +230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230, +230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230, +230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230, +230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230, +230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230, +230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230, +230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230, +230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230, +230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230, +230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230, +230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230, +230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230, +230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230, +230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230, +230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230, +230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,230,231,231, +231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231, +231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231, +231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231, +231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231, +231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231, +231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231, +231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231, +231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231, +231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231, +231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231, +231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231, +231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231, +231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231, +231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231, +231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231, +231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231, +231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231, +231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231, +231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231, +231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231, +231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231, +231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231, +231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231, +231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231, +231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231, +231,231,231,231,231,231,231,231,231,231,231,232,232,232,232,232,232,232,232,232, +232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232, +232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232, +232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232, +232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232, +232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232, +232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232, +232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232, +232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232, +232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232, +232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232, +232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232, +232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232, +232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232, +232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232, +232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232, +232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232, +232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232, +232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232, +232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232, +232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232, +232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232, +232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232, +232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232, +232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232, +232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232,232, +232,232,232,232,232,232,233,233,233,233,233,233,233,233,233,233,233,233,233,233, +233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233, +233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233, +233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233, +233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233, +233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233, +233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233, +233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233, +233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233, +233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233, +233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233, +233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233, +233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233, +233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233, +233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233, +233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233, +233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233, +233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233, +233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233, +233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233, +233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233, +233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233, +233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233, +233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233, +233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233, +233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233,233, +233,233,233,233,233,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234, +234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234, +234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234, +234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234, +234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234, +234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234, +234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234, +234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234, +234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234, +234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234, +234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234, +234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234, +234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234, +234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234, +234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234, +234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234, +234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234, +234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234, +234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234, +234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234, +234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234, +234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234, +234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234, +234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234, +234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234, +234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234,234, +234,234,234,234,234,234,234,235,235,235,235,235,235,235,235,235,235,235,235,235, +235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, +235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, +235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, +235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, +235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, +235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, +235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, +235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, +235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, +235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, +235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, +235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, +235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, +235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, +235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, +235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, +235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, +235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, +235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, +235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, +235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, +235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, +235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, +235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, +235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235,235, +235,235,235,235,235,235,235,235,235,235,235,235,236,236,236,236,236,236,236,236, +236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236, +236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236, +236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236, +236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236, +236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236, +236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236, +236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236, +236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236, +236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236, +236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236, +236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236, +236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236, +236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236, +236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236, +236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236, +236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236, +236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236, +236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236, +236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236, +236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236, +236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236, +236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236, +236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236, +236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236, +236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236, +236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,237, +237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237, +237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237, +237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237, +237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237, +237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237, +237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237, +237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237, +237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237, +237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237, +237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237, +237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237, +237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237, +237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237, +237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237, +237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237, +237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237, +237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237, +237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237, +237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237, +237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237, +237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237, +237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237, +237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237, +237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237, +237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237, +237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237,237, +237,237,237,237,237,237,237,237,237,237,238,238,238,238,238,238,238,238,238,238, +238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238, +238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238, +238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238, +238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238, +238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238, +238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238, +238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238, +238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238, +238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238, +238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238, +238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238, +238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238, +238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238, +238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238, +238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238, +238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238, +238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238, +238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238, +238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238, +238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238, +238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238, +238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238, +238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238, +238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238, +238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238, +238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238,238, +238,238,238,238,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239, +239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239, +239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239, +239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239, +239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239, +239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239, +239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239, +239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239, +239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239, +239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239, +239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239, +239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239, +239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239, +239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239, +239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239, +239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239, +239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239, +239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239, +239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239, +239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239, +239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239, +239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239, +239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239, +239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239, +239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239, +239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239, +239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241, +241,241,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242, +242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242, +242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242, +242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242, +242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242, +242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242, +242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242, +242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242, +242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242, +242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242, +242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242, +242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242, +242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242, +242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242, +242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242, +242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242, +242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242, +242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242, +242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242, +242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242, +242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242, +242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242, +242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242, +242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242, +242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242, +242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242, +242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242, +242,242,242,242,242,242,242,242,243,243,243,243,243,243,243,243,243,243,243,243, +243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243, +243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243, +243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243, +243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243, +243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243, +243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243, +243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243, +243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243, +243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243, +243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243, +243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243, +243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243, +243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243, +243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243, +243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243, +243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243, +243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243, +243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243, +243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243, +243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243, +243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243, +243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243, +243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243, +243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243, +243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243, +243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243, +243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,244,244,244,244, +244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244, +244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244, +244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244, +244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244, +244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244, +244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244, +244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244, +244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244, +244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244, +244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244, +244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244, +244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244, +244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244, +244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244, +244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244, +244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244, +244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244, +244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244, +244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244, +244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244, +244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244, +244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244, +244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244, +244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244, +244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244, +244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244, +244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244, +244,244,244,244,244,244,244,244,245,245,245,245,245,245,245,245,245,245,245,245, +245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245, +245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245, +245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245, +245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245, +245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245, +245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245, +245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245, +245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245, +245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245, +245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245, +245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245, +245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245, +245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245, +245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245, +245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245, +245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245, +245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245, +245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245, +245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245, +245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245, +245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245, +245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245, +245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245, +245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245, +245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245, +245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245, +245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245, +245,245,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246, +246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246, +246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246, +246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246, +246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246, +246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246, +246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246, +246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246, +246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246, +246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246, +246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246, +246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246, +246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246, +246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246, +246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246, +246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246, +246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246, +246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246, +246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246, +246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246, +246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246, +246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246, +246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246, +246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246, +246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246, +246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246, +246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246, +246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,247, +247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247, +247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247, +247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247, +247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247, +247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247, +247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247, +247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247, +247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247, +247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247, +247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247, +247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247, +247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247, +247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247, +247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247, +247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247, +247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247, +247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247, +247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247, +247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247, +247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247, +247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247, +247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247, +247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247, +247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247, +247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247, +247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247, +247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247, +247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247, +248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248, +248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248, +248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248, +248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248, +248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248, +248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248, +248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248, +248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248, +248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248, +248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248, +248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248, +248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248, +248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248, +248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248, +248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248, +248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248, +248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248, +248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248, +248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248, +248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248, +248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248, +248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248, +248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248, +248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248, +248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248, +248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248, +248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248, +248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248, +248,248,248,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249, +249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249, +249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249, +249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249, +249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249, +249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249, +249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249, +249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249, +249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249, +249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249, +249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249, +249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249, +249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249, +249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249, +249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249, +249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249, +249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249, +249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249, +249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249, +249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249, +249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249, +249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249, +249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249, +249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249, +249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249, +249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249, +249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249, +249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249, +249,249,249,249,249,249,249,249,249,249,250,250,250,250,250,250,250,250,250,250, +250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250, +250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250, +250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250, +250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250, +250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250, +250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250, +250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250, +250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250, +250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250, +250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250, +250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250, +250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250, +250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250, +250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250, +250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250, +250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250, +250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250, +250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250, +250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250, +250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250, +250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250, +250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250, +250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250, +250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250, +250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250, +250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250, +250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250, +250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,251, +251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251, +251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251, +251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251, +251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251, +251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251, +251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251, +251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251, +251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251, +251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251, +251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251, +251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251, +251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251, +251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251, +251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251, +251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251, +251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251, +251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251, +251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251, +251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251, +251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251, +251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251, +251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251, +251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251, +251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251, +251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251, +251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251, +251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251, +251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251, +251,251,251,251,251,251,251,251,251,251,251,251,252,252,252,252,252,252,252,252, +252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252, +252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252, +252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252, +252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252, +252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252, +252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252, +252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252, +252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252, +252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252, +252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252, +252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252, +252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252, +252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252, +252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252, +252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252, +252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252, +252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252, +252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252, +252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252, +252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252, +252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252, +252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252, +252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252, +252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252, +252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252, +252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252, +252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252, +252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252, +252,252,252,252,252,252,252,253,253,253,253,253,253,253,253,253,253,253,253,253, +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, +253,253,253,253,253,253,254,254,254,254,254,254,254,254,254,254,254,254,254,254, +254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254, +254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254, +254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254, +254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254, +254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254, +254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254, +254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254, +254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254, +254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254, +254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254, +254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254, +254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254, +254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254, +254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254, +254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254, +254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254, +254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254, +254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254, +254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254, +254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254, +254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254, +254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254, +254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254, +254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254, +254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254, +254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254, +254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254, +254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254, +254,254,254,254,254,254,254,254,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255 +}; + +static const float u8_gamma_minimums[257] = +{ +0.0, +0x1.3e6p-13, /* 0.000152, 1 */ +0x1.dd7p-12, /* 0.000455, 2 */ +0x1.8dd8p-11, /* 0.000759, 3 */ +0x1.168p-10, /* 0.001062, 4 */ +0x1.661p-10, /* 0.001366, 5 */ +0x1.b5ap-10, /* 0.001669, 6 */ +0x1.029ap-9, /* 0.001973, 7 */ +0x1.2a62p-9, /* 0.002276, 8 */ +0x1.522ap-9, /* 0.002580, 9 */ +0x1.79f4p-9, /* 0.002884, 10 */ +0x1.a1e6p-9, /* 0.003188, 11 */ +0x1.cbf8p-9, /* 0.003509, 12 */ +0x1.f86ap-9, /* 0.003848, 13 */ +0x1.13a1p-8, /* 0.004206, 14 */ +0x1.2c47p-8, /* 0.004582, 15 */ +0x1.462ap-8, /* 0.004977, 16 */ +0x1.614fp-8, /* 0.005391, 17 */ +0x1.7dbap-8, /* 0.005825, 18 */ +0x1.9b6fp-8, /* 0.006278, 19 */ +0x1.ba73p-8, /* 0.006751, 20 */ +0x1.dacap-8, /* 0.007245, 21 */ +0x1.fc77p-8, /* 0.007759, 22 */ +0x1.0fbf8p-7, /* 0.008293, 23 */ +0x1.21f28p-7, /* 0.008848, 24 */ +0x1.34d68p-7, /* 0.009425, 25 */ +0x1.486ep-7, /* 0.010023, 26 */ +0x1.5cbap-7, /* 0.010642, 27 */ +0x1.71bc8p-7, /* 0.011283, 28 */ +0x1.87778p-7, /* 0.011947, 29 */ +0x1.9dedp-7, /* 0.012632, 30 */ +0x1.b51ep-7, /* 0.013340, 31 */ +0x1.cd0dp-7, /* 0.014070, 32 */ +0x1.e5bbp-7, /* 0.014823, 33 */ +0x1.ff2a8p-7, /* 0.015600, 34 */ +0x1.0cae4p-6, /* 0.016399, 35 */ +0x1.1a294p-6, /* 0.017222, 36 */ +0x1.28074p-6, /* 0.018068, 37 */ +0x1.3649p-6, /* 0.018938, 38 */ +0x1.44ef8p-6, /* 0.019832, 39 */ +0x1.53fbp-6, /* 0.020751, 40 */ +0x1.636ccp-6, /* 0.021693, 41 */ +0x1.73454p-6, /* 0.022661, 42 */ +0x1.83858p-6, /* 0.023652, 43 */ +0x1.942dcp-6, /* 0.024669, 44 */ +0x1.a53f8p-6, /* 0.025711, 45 */ +0x1.b6bacp-6, /* 0.026778, 46 */ +0x1.c8a08p-6, /* 0.027870, 47 */ +0x1.daf18p-6, /* 0.028988, 48 */ +0x1.edae8p-6, /* 0.030132, 49 */ +0x1.006cp-5, /* 0.031301, 50 */ +0x1.0a378p-5, /* 0.032497, 51 */ +0x1.1439ep-5, /* 0.033719, 52 */ +0x1.1e73ap-5, /* 0.034967, 53 */ +0x1.28e52p-5, /* 0.036242, 54 */ +0x1.338eap-5, /* 0.037544, 55 */ +0x1.3e706p-5, /* 0.038872, 56 */ +0x1.498aep-5, /* 0.040227, 57 */ +0x1.54de6p-5, /* 0.041610, 58 */ +0x1.606b2p-5, /* 0.043020, 59 */ +0x1.6c318p-5, /* 0.044457, 60 */ +0x1.7831ep-5, /* 0.045922, 61 */ +0x1.846c8p-5, /* 0.047415, 62 */ +0x1.90e1ap-5, /* 0.048936, 63 */ +0x1.9d91ap-5, /* 0.050484, 64 */ +0x1.aa7dp-5, /* 0.052062, 65 */ +0x1.b7a3cp-5, /* 0.053667, 66 */ +0x1.c5064p-5, /* 0.055301, 67 */ +0x1.d2a4ep-5, /* 0.056963, 68 */ +0x1.e08p-5, /* 0.058655, 69 */ +0x1.ee97ap-5, /* 0.060375, 70 */ +0x1.fcec6p-5, /* 0.062124, 71 */ +0x1.05bf3p-4, /* 0.063903, 72 */ +0x1.0d26fp-4, /* 0.065711, 73 */ +0x1.14adap-4, /* 0.067548, 74 */ +0x1.1c536p-4, /* 0.069415, 75 */ +0x1.24185p-4, /* 0.071312, 76 */ +0x1.2bfcap-4, /* 0.073239, 77 */ +0x1.34007p-4, /* 0.075196, 78 */ +0x1.3c23ep-4, /* 0.077183, 79 */ +0x1.44671p-4, /* 0.079200, 80 */ +0x1.4cca3p-4, /* 0.081248, 81 */ +0x1.554d5p-4, /* 0.083326, 82 */ +0x1.5df0ap-4, /* 0.085435, 83 */ +0x1.66b44p-4, /* 0.087574, 84 */ +0x1.6f984p-4, /* 0.089745, 85 */ +0x1.789cep-4, /* 0.091946, 86 */ +0x1.81c23p-4, /* 0.094179, 87 */ +0x1.8b085p-4, /* 0.096443, 88 */ +0x1.946f7p-4, /* 0.098739, 89 */ +0x1.9df7bp-4, /* 0.101066, 90 */ +0x1.a7a12p-4, /* 0.103425, 91 */ +0x1.b16bfp-4, /* 0.105816, 92 */ +0x1.bb584p-4, /* 0.108238, 93 */ +0x1.c5662p-4, /* 0.110693, 94 */ +0x1.cf95cp-4, /* 0.113180, 95 */ +0x1.d9e74p-4, /* 0.115699, 96 */ +0x1.e45abp-4, /* 0.118251, 97 */ +0x1.eef03p-4, /* 0.120835, 98 */ +0x1.f9a8p-4, /* 0.123451, 99 */ +0x1.02411p-3, /* 0.126101, 100 */ +0x1.07bf68p-3, /* 0.128783, 101 */ +0x1.0d4f08p-3, /* 0.131498, 102 */ +0x1.12eff8p-3, /* 0.134247, 103 */ +0x1.18a25p-3, /* 0.137028, 104 */ +0x1.1e6628p-3, /* 0.139843, 105 */ +0x1.243b88p-3, /* 0.142692, 106 */ +0x1.2a228p-3, /* 0.145574, 107 */ +0x1.301b28p-3, /* 0.148489, 108 */ +0x1.36258p-3, /* 0.151439, 109 */ +0x1.3c41ap-3, /* 0.154422, 110 */ +0x1.426f98p-3, /* 0.157439, 111 */ +0x1.48af7p-3, /* 0.160491, 112 */ +0x1.4f014p-3, /* 0.163577, 113 */ +0x1.556508p-3, /* 0.166697, 114 */ +0x1.5bdaep-3, /* 0.169851, 115 */ +0x1.6262dp-3, /* 0.173040, 116 */ +0x1.68fcfp-3, /* 0.176264, 117 */ +0x1.6fa948p-3, /* 0.179522, 118 */ +0x1.7667ep-3, /* 0.182815, 119 */ +0x1.7d38d8p-3, /* 0.186144, 120 */ +0x1.841c28p-3, /* 0.189507, 121 */ +0x1.8b11f8p-3, /* 0.192905, 122 */ +0x1.921a4p-3, /* 0.196339, 123 */ +0x1.99352p-3, /* 0.199808, 124 */ +0x1.a06298p-3, /* 0.203313, 125 */ +0x1.a7a2b8p-3, /* 0.206853, 126 */ +0x1.aef598p-3, /* 0.210429, 127 */ +0x1.b65b38p-3, /* 0.214041, 128 */ +0x1.bdd3bp-3, /* 0.217689, 129 */ +0x1.c55f08p-3, /* 0.221373, 130 */ +0x1.ccfd5p-3, /* 0.225093, 131 */ +0x1.d4ae88p-3, /* 0.228849, 132 */ +0x1.dc72dp-3, /* 0.232641, 133 */ +0x1.e44a28p-3, /* 0.236470, 134 */ +0x1.ec34ap-3, /* 0.240335, 135 */ +0x1.f43258p-3, /* 0.244237, 136 */ +0x1.fc435p-3, /* 0.248175, 137 */ +0x1.0233c4p-2, /* 0.252151, 138 */ +0x1.064f98p-2, /* 0.256163, 139 */ +0x1.0a7518p-2, /* 0.260212, 140 */ +0x1.0ea45p-2, /* 0.264299, 141 */ +0x1.12dd44p-2, /* 0.268422, 142 */ +0x1.172p-2, /* 0.272583, 143 */ +0x1.1b6c84p-2, /* 0.276781, 144 */ +0x1.1fc2ep-2, /* 0.281017, 145 */ +0x1.242314p-2, /* 0.285290, 146 */ +0x1.288d28p-2, /* 0.289601, 147 */ +0x1.2d0124p-2, /* 0.293950, 148 */ +0x1.317f0cp-2, /* 0.298336, 149 */ +0x1.3606e8p-2, /* 0.302761, 150 */ +0x1.3a98cp-2, /* 0.307223, 151 */ +0x1.3f3498p-2, /* 0.311724, 152 */ +0x1.43da74p-2, /* 0.316263, 153 */ +0x1.488a5cp-2, /* 0.320840, 154 */ +0x1.4d4454p-2, /* 0.325456, 155 */ +0x1.520864p-2, /* 0.330110, 156 */ +0x1.56d694p-2, /* 0.334803, 157 */ +0x1.5baee8p-2, /* 0.339534, 158 */ +0x1.60916p-2, /* 0.344305, 159 */ +0x1.657e0cp-2, /* 0.349114, 160 */ +0x1.6a74fp-2, /* 0.353962, 161 */ +0x1.6f760cp-2, /* 0.358849, 162 */ +0x1.748168p-2, /* 0.363775, 163 */ +0x1.79971p-2, /* 0.368740, 164 */ +0x1.7eb704p-2, /* 0.373745, 165 */ +0x1.83e15p-2, /* 0.378789, 166 */ +0x1.8915fp-2, /* 0.383873, 167 */ +0x1.8e54f4p-2, /* 0.388996, 168 */ +0x1.939e6p-2, /* 0.394159, 169 */ +0x1.98f238p-2, /* 0.399361, 170 */ +0x1.9e508p-2, /* 0.404604, 171 */ +0x1.a3b94p-2, /* 0.409886, 172 */ +0x1.a92c8p-2, /* 0.415209, 173 */ +0x1.aeaa44p-2, /* 0.420571, 174 */ +0x1.b4329p-2, /* 0.425974, 175 */ +0x1.b9c56cp-2, /* 0.431417, 176 */ +0x1.bf62d8p-2, /* 0.436900, 177 */ +0x1.c50aep-2, /* 0.442424, 178 */ +0x1.cabd88p-2, /* 0.447989, 179 */ +0x1.d07ad4p-2, /* 0.453594, 180 */ +0x1.d642c8p-2, /* 0.459239, 181 */ +0x1.dc156cp-2, /* 0.464925, 182 */ +0x1.e1f2c4p-2, /* 0.470653, 183 */ +0x1.e7dad8p-2, /* 0.476421, 184 */ +0x1.edcdacp-2, /* 0.482230, 185 */ +0x1.f3cb4cp-2, /* 0.488080, 186 */ +0x1.f9d3bcp-2, /* 0.493972, 187 */ +0x1.ffe70cp-2, /* 0.499905, 188 */ +0x1.03028cp-1, /* 0.505879, 189 */ +0x1.06170ap-1, /* 0.511895, 190 */ +0x1.0930f8p-1, /* 0.517952, 191 */ +0x1.0c5058p-1, /* 0.524050, 192 */ +0x1.0f752ep-1, /* 0.530191, 193 */ +0x1.129f7cp-1, /* 0.536373, 194 */ +0x1.15cf44p-1, /* 0.542597, 195 */ +0x1.19048cp-1, /* 0.548863, 196 */ +0x1.1c3f56p-1, /* 0.555171, 197 */ +0x1.1f7fa4p-1, /* 0.561521, 198 */ +0x1.22c578p-1, /* 0.567913, 199 */ +0x1.2610d8p-1, /* 0.574347, 200 */ +0x1.2961c2p-1, /* 0.580824, 201 */ +0x1.2cb83ep-1, /* 0.587343, 202 */ +0x1.30144cp-1, /* 0.593905, 203 */ +0x1.3375eep-1, /* 0.600509, 204 */ +0x1.36dd26p-1, /* 0.607156, 205 */ +0x1.3a49fap-1, /* 0.613846, 206 */ +0x1.3dbc6ap-1, /* 0.620578, 207 */ +0x1.413478p-1, /* 0.627353, 208 */ +0x1.44b228p-1, /* 0.634172, 209 */ +0x1.48357cp-1, /* 0.641033, 210 */ +0x1.4bbe76p-1, /* 0.647937, 211 */ +0x1.4f4d18p-1, /* 0.654885, 212 */ +0x1.52e168p-1, /* 0.661876, 213 */ +0x1.567b64p-1, /* 0.668910, 214 */ +0x1.5a1b1p-1, /* 0.675988, 215 */ +0x1.5dc07p-1, /* 0.683109, 216 */ +0x1.616b86p-1, /* 0.690273, 217 */ +0x1.651c54p-1, /* 0.697482, 218 */ +0x1.68d2dcp-1, /* 0.704734, 219 */ +0x1.6c8f22p-1, /* 0.712030, 220 */ +0x1.705126p-1, /* 0.719369, 221 */ +0x1.7418eep-1, /* 0.726753, 222 */ +0x1.77e67ap-1, /* 0.734180, 223 */ +0x1.7bb9cep-1, /* 0.741652, 224 */ +0x1.7f92eap-1, /* 0.749168, 225 */ +0x1.8371d6p-1, /* 0.756728, 226 */ +0x1.87568ep-1, /* 0.764332, 227 */ +0x1.8b411ap-1, /* 0.771981, 228 */ +0x1.8f317ap-1, /* 0.779674, 229 */ +0x1.9327bp-1, /* 0.787412, 230 */ +0x1.9723cp-1, /* 0.795195, 231 */ +0x1.9b25aap-1, /* 0.803022, 232 */ +0x1.9f2d74p-1, /* 0.810894, 233 */ +0x1.a33b1ep-1, /* 0.818810, 234 */ +0x1.a74eacp-1, /* 0.826772, 235 */ +0x1.ab682p-1, /* 0.834779, 236 */ +0x1.af877cp-1, /* 0.842831, 237 */ +0x1.b3accp-1, /* 0.850927, 238 */ +0x1.b7d7f2p-1, /* 0.859069, 239 */ +0x1.bc0914p-1, /* 0.867257, 240 */ +0x1.c04026p-1, /* 0.875489, 241 */ +0x1.c47d2ap-1, /* 0.883767, 242 */ +0x1.c8c024p-1, /* 0.892091, 243 */ +0x1.cd0918p-1, /* 0.900460, 244 */ +0x1.d15804p-1, /* 0.908875, 245 */ +0x1.d5acecp-1, /* 0.917335, 246 */ +0x1.da07d4p-1, /* 0.925841, 247 */ +0x1.de68bcp-1, /* 0.934393, 248 */ +0x1.e2cfa8p-1, /* 0.942991, 249 */ +0x1.e73c9ap-1, /* 0.951634, 250 */ +0x1.ebaf96p-1, /* 0.960324, 251 */ +0x1.f0289ep-1, /* 0.969060, 252 */ +0x1.f4a7b6p-1, /* 0.977842, 253 */ +0x1.f92cep-1, /* 0.986670, 254 */ +0x1.fdb822p-1, /* 0.995545, 255 */ +999.0 +}; diff --git a/extensions/two-table.c b/extensions/two-table.c new file mode 100644 index 0000000..8becfee --- /dev/null +++ b/extensions/two-table.c @@ -0,0 +1,254 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2013, Daniel Sabo + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include +#include "babl.h" + +#include "base/util.h" +#include "extensions/two-table-tables.h" + +static inline unsigned char +conv_float_u8_two_table_map (float value) +{ + if (value < 0.0f) + { + return 0; + } + else if (value <= 1.0f) + { + unsigned short index; + unsigned char result; + + index = (unsigned short) (value * 0xFFFF); + result = linear_to_gamma[index]; + + if (value < u8_gamma_minimums[result]) + result -= 1; + else if (value >= u8_gamma_minimums[result+1]) + result += 1; + + return result; + } + else /* value > 1.0f || isnan (value) */ + { + return 0xFF; + } +} + +static void +conv_rgbafloat_linear_cairo24_le (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst, + long samples) +{ + long n = samples; + float *src = (float*)src_char; + + while (n--) + { + dst[0] = conv_float_u8_two_table_map (src[2]); + dst[1] = conv_float_u8_two_table_map (src[1]); + dst[2] = conv_float_u8_two_table_map (src[0]); + src += 4; + dst += 4; + } +} + +static void +conv_rgbfloat_linear_cairo24_le (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst, + long samples) +{ + long n = samples; + float *src = (float*)src_char; + + while (n--) + { + dst[0] = conv_float_u8_two_table_map (src[2]); + dst[1] = conv_float_u8_two_table_map (src[1]); + dst[2] = conv_float_u8_two_table_map (src[0]); + + src += 3; + dst += 4; + } +} + +static void +conv_rgbafloat_linear_rgbu8_gamma (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst, + long samples) +{ + long n = samples; + float *src = (float*)src_char; + + while (n--) + { + dst[0] = conv_float_u8_two_table_map (src[0]); + dst[1] = conv_float_u8_two_table_map (src[1]); + dst[2] = conv_float_u8_two_table_map (src[2]); + src += 4; + dst += 3; + } +} + + +static void +conv_rgbafloat_linear_rgbau8_gamma (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst, + long samples) +{ + long n = samples; + float *src = (float*)src_char; + + while (n--) + { + dst[0] = conv_float_u8_two_table_map (src[0]); + dst[1] = conv_float_u8_two_table_map (src[1]); + dst[2] = conv_float_u8_two_table_map (src[2]); + dst[3] = src[3] * 0xff + 0.5; + src += 4; + dst += 4; + } +} + +static void +conv_rgbfloat_linear_rgbu8_gamma (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst, + long samples) +{ + long n = samples; + float *src = (float*)src_char; + + while (n--) + { + dst[0] = conv_float_u8_two_table_map (src[0]); + dst[1] = conv_float_u8_two_table_map (src[1]); + dst[2] = conv_float_u8_two_table_map (src[2]); + + src += 3; + dst += 3; + } +} + +static void +conv_yfloat_linear_yu8_gamma (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst, + long samples) +{ + long n = samples; + float *src = (float*)src_char; + + while (n--) + { + *dst++ = conv_float_u8_two_table_map (*src++); + } +} + +static void +conv_yafloat_linear_yau8_gamma (const Babl *conversion, + unsigned char *src_char, + unsigned char *dst, + long samples) +{ + long n = samples; + float *src = (float*)src_char; + + while (n--) + { + long int alpha; + *dst++ = conv_float_u8_two_table_map (*src++); + + alpha = rint (*src++ * 255.0); + *dst++ = (alpha < 0) ? 0 : ((alpha > 255) ? 255 : alpha); + } +} + +int init (void); + +int +init (void) +{ + int testint = 23; + char *testchar = (char*) &testint; + int littleendian = (testchar[0] == 23); + + return 0; // temporarily disable, it is interfering with space invasion + + if (littleendian) + { + const Babl *f24 = babl_format_new ( + "name", "cairo-RGB24", + babl_model ("R'G'B'"), + babl_type ("u8"), + babl_component ("B'"), + babl_component ("G'"), + babl_component ("R'"), + babl_component ("PAD"), + NULL + ); + + babl_conversion_new (babl_format ("RGB float"), + f24, + "linear", + conv_rgbfloat_linear_cairo24_le, + NULL); + + babl_conversion_new (babl_format ("RGBA float"), + f24, + "linear", + conv_rgbafloat_linear_cairo24_le, + NULL); + } + + babl_conversion_new (babl_format ("RGBA float"), + babl_format ("R'G'B' u8"), + "linear", + conv_rgbafloat_linear_rgbu8_gamma, + NULL); + + babl_conversion_new (babl_format ("RGBA float"), + babl_format ("R'G'B'A u8"), + "linear", + conv_rgbafloat_linear_rgbau8_gamma, + NULL); + + babl_conversion_new (babl_format ("RGB float"), + babl_format ("R'G'B' u8"), + "linear", + conv_rgbfloat_linear_rgbu8_gamma, + NULL); + + babl_conversion_new (babl_format ("Y float"), + babl_format ("Y' u8"), + "linear", + conv_yfloat_linear_yu8_gamma, + NULL); + + babl_conversion_new (babl_format ("YA float"), + babl_format ("Y'A u8"), + "linear", + conv_yafloat_linear_yau8_gamma, + NULL); + + return 0; +} diff --git a/extensions/u16.c b/extensions/u16.c new file mode 100644 index 0000000..87d2907 --- /dev/null +++ b/extensions/u16.c @@ -0,0 +1,115 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2016, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include +#include + +#include "babl.h" + +#include "base/util.h" +#include "extensions/util.h" + +static void +conv_rgbu16_rgbau16 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) + + +{ + uint16_t *src16 = (uint16_t*) src; + uint16_t *dst16 = (uint16_t*) dst; + long n = samples; + + while (n--) + { + *dst16++ = *src16++; + *dst16++ = *src16++; + *dst16++ = *src16++; + *dst16++ = 0xffff; + } +} + +static void +conv_yu16_yau16 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) + + +{ + uint16_t *src16 = (uint16_t*) src; + uint16_t *dst16 = (uint16_t*) dst; + long n = samples; + + while (n--) + { + *dst16++ = *src16++; + *dst16++ = 0xffff; + } +} + +int init (void); + +int +init (void) +{ + babl_conversion_new ( + babl_format ("R'G'B' u16"), + babl_format ("R'G'B'A u16"), + "linear", + conv_rgbu16_rgbau16, + NULL); + + babl_conversion_new ( + babl_format ("R~G~B~ u16"), + babl_format ("R~G~B~A u16"), + "linear", + conv_rgbu16_rgbau16, + NULL); + + babl_conversion_new ( + babl_format ("Y' u16"), + babl_format ("Y'A u16"), + "linear", + conv_yu16_yau16, + NULL); + + babl_conversion_new ( + babl_format ("Y~ u16"), + babl_format ("Y~A u16"), + "linear", + conv_yu16_yau16, + NULL); + + babl_conversion_new ( + babl_format ("RGB u16"), + babl_format ("RGBA u16"), + "linear", + conv_rgbu16_rgbau16, + NULL); + + babl_conversion_new ( + babl_format ("Y u16"), + babl_format ("YA u16"), + "linear", + conv_yu16_yau16, + NULL); + return 0; +} diff --git a/extensions/u32.c b/extensions/u32.c new file mode 100644 index 0000000..f9d563d --- /dev/null +++ b/extensions/u32.c @@ -0,0 +1,436 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2018, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include +#include + +#include "babl.h" + +#include "base/util.h" +#include "extensions/util.h" + +static inline void +conv_u32_u16 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) + + +{ + uint32_t *src32 = (uint32_t*) src; + uint16_t *dst16 = (uint16_t*) dst; + long n = samples; + + while (n--) + { + *dst16++ = (*src32++)>>16; + } +} + +static inline void +conv_u16_u32 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) + + +{ + uint16_t *src16 = (uint16_t*) src; + uint32_t *dst32 = (uint32_t*) dst; + long n = samples; + + while (n--) + { + *dst32++ = (*src16++) * 65536.99f; + } +} + + +static void +conv_yau32_yau16 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) + + +{ + conv_u32_u16 (conversion, src, dst, samples * 2); +} + +static void +conv_rgbu32_rgbu16 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) + + +{ + conv_u32_u16 (conversion, src, dst, samples * 3); +} + +static void +conv_rgbu16_rgbu32 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) + + +{ + conv_u16_u32 (conversion, src, dst, samples * 3); +} + +static void +conv_yau16_yau32 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) + + +{ + conv_u16_u32 (conversion, src, dst, samples * 2); +} + + +static void +conv_rgbau32_rgbau16 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) + + +{ + conv_u32_u16 (conversion, src, dst, samples * 4); +} + +static void +conv_rgbau16_rgbau32 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) + + +{ + conv_u16_u32 (conversion, src, dst, samples * 4); +} + + +static inline void +conv_rgba32_rgb32 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + uint32_t *src32 = (uint32_t*) src; + uint32_t *dst32 = (uint32_t*) dst; + long n = samples; + + while (n--) + { + *dst32++ = (*src32++); + *dst32++ = (*src32++); + *dst32++ = (*src32++); + src32++; + } +} + +static inline void +conv_rgb32_rgba32 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + uint32_t *src32 = (uint32_t*) src; + uint32_t *dst32 = (uint32_t*) dst; + long n = samples; + + while (n--) + { + *dst32++ = (*src32++); + *dst32++ = (*src32++); + *dst32++ = (*src32++); + *dst32++ = 4294967295; + } +} + + +static inline void +conv_yu32_yau32 (const Babl *conversion, + unsigned char *src, + unsigned char *dst, + long samples) +{ + uint32_t *src32 = (uint32_t*) src; + uint32_t *dst32 = (uint32_t*) dst; + long n = samples; + + while (n--) + { + *dst32++ = (*src32++); + *dst32++ = 4294967295; + } +} + + + +int init (void); + +int +init (void) +{ + babl_conversion_new ( + babl_format ("R'G'B'A u32"), + babl_format ("R'G'B'A u16"), + "linear", + conv_rgbau32_rgbau16, + NULL); + babl_conversion_new ( + babl_format ("R'G'B' u32"), + babl_format ("R'G'B' u16"), + "linear", + conv_rgbu32_rgbu16, + NULL); + babl_conversion_new ( + babl_format ("R~G~B~A u32"), + babl_format ("R~G~B~A u16"), + "linear", + conv_rgbau32_rgbau16, + NULL); + babl_conversion_new ( + babl_format ("R~G~B~ u32"), + babl_format ("R~G~B~ u16"), + "linear", + conv_rgbu32_rgbu16, + NULL); + babl_conversion_new ( + babl_format ("RGB u32"), + babl_format ("RGB u16"), + "linear", + conv_rgbu32_rgbu16, + NULL); + babl_conversion_new ( + babl_format ("R'G'B' u16"), + babl_format ("R'G'B' u32"), + "linear", + conv_rgbu16_rgbu32, + NULL); + babl_conversion_new ( + babl_format ("R~G~B~ u16"), + babl_format ("R~G~B~ u32"), + "linear", + conv_rgbu16_rgbu32, + NULL); + babl_conversion_new ( + babl_format ("RGB u16"), + babl_format ("RGB u32"), + "linear", + conv_rgbu16_rgbu32, + NULL); + babl_conversion_new ( + babl_format ("RGBA u32"), + babl_format ("RGBA u16"), + "linear", + conv_rgbau32_rgbau16, + NULL); + babl_conversion_new ( + babl_format ("RGBA u16"), + babl_format ("RGBA u32"), + "linear", + conv_rgbau16_rgbau32, + NULL); + + babl_conversion_new ( + babl_format ("RaGaBaA u32"), + babl_format ("RaGaBaA u16"), + "linear", + conv_rgbau32_rgbau16, + NULL); + babl_conversion_new ( + babl_format ("RaGaBaA u16"), + babl_format ("RaGaBaA u32"), + "linear", + conv_rgbau16_rgbau32, + NULL); + babl_conversion_new ( + babl_format ("RGBA u32"), + babl_format ("RGB u32"), + "linear", + conv_rgba32_rgb32, + NULL); + babl_conversion_new ( + babl_format ("RGB u32"), + babl_format ("RGBA u32"), + "linear", + conv_rgb32_rgba32, + NULL); + babl_conversion_new ( + babl_format ("R'G'B'A u32"), + babl_format ("R'G'B' u32"), + "linear", + conv_rgba32_rgb32, + NULL); + babl_conversion_new ( + babl_format ("R'G'B' u32"), + babl_format ("R'G'B'A u32"), + "linear", + conv_rgb32_rgba32, + NULL); + babl_conversion_new ( + babl_format ("R~G~B~A u32"), + babl_format ("R~G~B~ u32"), + "linear", + conv_rgba32_rgb32, + NULL); + babl_conversion_new ( + babl_format ("R~G~B~ u32"), + babl_format ("R~G~B~A u32"), + "linear", + conv_rgb32_rgba32, + NULL); + babl_conversion_new ( + babl_format ("Y u32"), + babl_format ("Y u16"), + "linear", + conv_u32_u16, + NULL); + babl_conversion_new ( + babl_format ("Y' u32"), + babl_format ("Y' u16"), + "linear", + conv_u32_u16, + NULL); + babl_conversion_new ( + babl_format ("Y~ u32"), + babl_format ("Y~ u16"), + "linear", + conv_u32_u16, + NULL); + babl_conversion_new ( + babl_format ("Y u16"), + babl_format ("Y u32"), + "linear", + conv_u16_u32, + NULL); + babl_conversion_new ( + babl_format ("Y' u16"), + babl_format ("Y' u32"), + "linear", + conv_u16_u32, + NULL); + babl_conversion_new ( + babl_format ("Y~ u16"), + babl_format ("Y~ u32"), + "linear", + conv_u16_u32, + NULL); + + babl_conversion_new ( + babl_format ("YA u32"), + babl_format ("YA u16"), + "linear", + conv_yau32_yau16, + NULL); + babl_conversion_new ( + babl_format ("YaA u32"), + babl_format ("YaA u16"), + "linear", + conv_yau32_yau16, + NULL); + babl_conversion_new ( + babl_format ("Y'A u32"), + babl_format ("Y'A u16"), + "linear", + conv_yau32_yau16, + NULL); + + babl_conversion_new ( + babl_format ("Y~A u32"), + babl_format ("Y~A u16"), + "linear", + conv_yau32_yau16, + NULL); + babl_conversion_new ( + babl_format ("Y'aA u32"), + babl_format ("Y'aA u16"), + "linear", + conv_yau32_yau16, + NULL); + babl_conversion_new ( + babl_format ("YA u16"), + babl_format ("YA u32"), + "linear", + conv_yau16_yau32, + NULL); + babl_conversion_new ( + babl_format ("YaA u16"), + babl_format ("YaA u32"), + "linear", + conv_yau16_yau32, + NULL); + babl_conversion_new ( + babl_format ("Y'A u16"), + babl_format ("Y'A u32"), + "linear", + conv_yau16_yau32, + NULL); + + babl_conversion_new ( + babl_format ("Y~A u16"), + babl_format ("Y~A u32"), + "linear", + conv_yau16_yau32, + NULL); + babl_conversion_new ( + babl_format ("Y'aA u16"), + babl_format ("Y'aA u32"), + "linear", + conv_yau16_yau32, + NULL); + babl_conversion_new ( + babl_format ("Y u32"), + babl_format ("YA u32"), + "linear", + conv_yu32_yau32, + NULL); + babl_conversion_new ( + babl_format ("Y u32"), + babl_format ("YaA u32"), + "linear", + conv_yu32_yau32, + NULL); + babl_conversion_new ( + babl_format ("Y' u32"), + babl_format ("Y'A u32"), + "linear", + conv_yu32_yau32, + NULL); + babl_conversion_new ( + babl_format ("Y~ u32"), + babl_format ("Y~A u32"), + "linear", + conv_yu32_yau32, + NULL); + babl_conversion_new ( + babl_format ("Y' u32"), + babl_format ("Y'aA u32"), + "linear", + conv_yu32_yau32, + NULL); + + return 0; +} diff --git a/extensions/util.h b/extensions/util.h new file mode 100644 index 0000000..d4d48ac --- /dev/null +++ b/extensions/util.h @@ -0,0 +1,56 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#ifndef _UTIL_H +#define _UTIL_H + +#include +#include + +#ifndef BABL_LIBRARY +#error "config.h must be included prior to util.h" +#endif + +#ifndef HAVE_RINT +# define rint(f) (floor (((double) (f)) + 0.5)) +#endif + + +#define BABL_PLANAR_SANITY \ + { \ + assert(src_bands>0); \ + assert(dst_bands>0); \ + assert(src); \ + assert(*src); \ + assert(dst); \ + assert(*dst); \ + assert(n>0); \ + assert(*src_pitch); \ + } + +#define BABL_PLANAR_STEP \ + { \ + int i; \ + for (i=0; i< src_bands; i++) \ + src[i]+=src_pitch[i]; \ + for (i=0; i< dst_bands; i++) \ + dst[i]+=dst_pitch[i]; \ + } + +#endif + diff --git a/extensions/ycbcr.c b/extensions/ycbcr.c new file mode 100644 index 0000000..fabc44d --- /dev/null +++ b/extensions/ycbcr.c @@ -0,0 +1,259 @@ +/* babl - dynamically extendable universal pixel conversion library. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" + +#include +#include + +#include "babl.h" +#include "base/util.h" + + +static void components (void); +static void models (void); +static void conversions (void); +static void formats (void); + +int init (void); + + +int +init (void) +{ + components (); + models (); + conversions (); + formats (); + + return 0; +} + + +static void +components (void) +{ + babl_component_new ("alpha", NULL); +} + + +static void +models (void) +{ + babl_model_new ( + "name", "Y'CbCr709", + babl_component ("Y'"), + babl_component ("Cb"), + babl_component ("Cr"), + NULL); + + babl_model_new ( + "name", "Y'CbCrA709", + babl_component ("Y'"), + babl_component ("Cb"), + babl_component ("Cr"), + babl_component ("alpha"), + "alpha", + NULL); +} + + +static void +rgba_to_ycbcra709 (const Babl *conversion, + char *src, + char *dst, + long n) +{ + while (n--) + { + double red = ((double *) src)[0]; + double green = ((double *) src)[1]; + double blue = ((double *) src)[2]; + double alpha = ((double *) src)[3]; + + double luminance, cb, cr; + + red = linear_to_gamma_2_2 (red); + green = linear_to_gamma_2_2 (green); + blue = linear_to_gamma_2_2 (blue); + + luminance = 0.2126 * red + 0.7152 * green + 0.0722 * blue; + cb = (blue - luminance) / 1.8556; + cr = (red - luminance) / 1.5748; + + ((double *) dst)[0] = luminance; + ((double *) dst)[1] = cb; + ((double *) dst)[2] = cr; + ((double *) dst)[3] = alpha; + + src += sizeof (double) * 4; + dst += sizeof (double) * 4; + } +} + + +static void +rgba_to_ycbcr709 (const Babl *conversion, + char *src, + char *dst, + long n) +{ + while (n--) + { + double red = ((double *) src)[0]; + double green = ((double *) src)[1]; + double blue = ((double *) src)[2]; + + double luminance, cb, cr; + + red = linear_to_gamma_2_2 (red); + green = linear_to_gamma_2_2 (green); + blue = linear_to_gamma_2_2 (blue); + + luminance = 0.2126 * red + 0.7152 * green + 0.0722 * blue; + cb = (blue - luminance) / 1.8556; + cr = (red - luminance) / 1.5748; + + ((double *) dst)[0] = luminance; + ((double *) dst)[1] = cb; + ((double *) dst)[2] = cr; + + src += sizeof (double) * 4; + dst += sizeof (double) * 3; + } +} + + +static void +ycbcra709_to_rgba (const Babl *conversion, + char *src, + char *dst, + long n) +{ + while (n--) + { + double luminance = ((double *) src)[0]; + double cb = ((double *) src)[1]; + double cr = ((double *) src)[2]; + double alpha = ((double *) src)[3]; + + double red, green, blue; + + red = 1.0 * luminance + 0.0 * cb + 1.5748 * cr; + green = 1.0 * luminance - 0.1873 * cb - 0.4681 * cr; + blue = 1.0 * luminance + 1.8556 * cb + 0.0 * cr; + + red = gamma_2_2_to_linear (red); + green = gamma_2_2_to_linear (green); + blue = gamma_2_2_to_linear (blue); + + ((double *) dst)[0] = red; + ((double *) dst)[1] = green; + ((double *) dst)[2] = blue; + ((double *) dst)[3] = alpha; + + src += sizeof (double) * 4; + dst += sizeof (double) * 4; + } +} + + +static void +ycbcr709_to_rgba (const Babl *conversion, + char *src, + char *dst, + long n) +{ + while (n--) + { + double luminance = ((double *) src)[0]; + double cb = ((double *) src)[1]; + double cr = ((double *) src)[2]; + + double red, green, blue; + + red = 1.0 * luminance + 0.0 * cb + 1.5748 * cr; + green = 1.0 * luminance - 0.1873 * cb - 0.4681 * cr; + blue = 1.0 * luminance + 1.8556 * cb + 0.0 * cr; + + red = gamma_2_2_to_linear (red); + green = gamma_2_2_to_linear (green); + blue = gamma_2_2_to_linear (blue); + + ((double *) dst)[0] = red; + ((double *) dst)[1] = green; + ((double *) dst)[2] = blue; + ((double *) dst)[3] = 1.0; + + src += sizeof (double) * 3; + dst += sizeof (double) * 4; + } +} + + +static void +conversions (void) +{ + babl_conversion_new ( + babl_model ("RGBA"), + babl_model ("Y'CbCr709"), + "linear", rgba_to_ycbcr709, + NULL + ); + babl_conversion_new ( + babl_model ("RGBA"), + babl_model ("Y'CbCrA709"), + "linear", rgba_to_ycbcra709, + NULL + ); + babl_conversion_new ( + babl_model ("Y'CbCrA709"), + babl_model ("RGBA"), + "linear", ycbcra709_to_rgba, + NULL + ); + babl_conversion_new ( + babl_model ("Y'CbCr709"), + babl_model ("RGBA"), + "linear", ycbcr709_to_rgba, + NULL + ); +} + + +static void +formats (void) +{ + babl_format_new ( + babl_model ("Y'CbCrA709"), + babl_type ("float"), + babl_component ("Y'"), + babl_type ("float"), + babl_component ("Cb"), + babl_component ("Cr"), + babl_component ("alpha"), + NULL); + + babl_format_new ( + babl_model ("Y'CbCr709"), + babl_type ("float"), + babl_component ("Y'"), + babl_type ("float"), + babl_component ("Cb"), + babl_component ("Cr"), + NULL); +} diff --git a/gen_babl_map.py b/gen_babl_map.py new file mode 100644 index 0000000..1ed4172 --- /dev/null +++ b/gen_babl_map.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 + +import sys + +export_symbols=sys.argv[1] +version_file=sys.argv[2] +version_file_clang=sys.argv[2] + ".clang" + +with open(export_symbols, 'r') as syms, \ + open(version_file, 'w') as version: + version.write("V0_1_0 {\n global:\n") + for sym in syms: + version.write(" {};\n".format(sym.strip())) + version.write(" local:\n *;\n};\n") + +with open(export_symbols, 'r') as syms, \ + open(version_file_clang, 'w') as version: + for sym in syms: + version.write("_{}\n".format(sym.strip())) diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..e4bdc38 --- /dev/null +++ b/meson.build @@ -0,0 +1,492 @@ +project('babl', 'c', + license: 'LGPL3+', + version: '0.1.82', + meson_version: '>=0.54.0', + default_options: [ + 'buildtype=debugoptimized' + ], + # https://gitlab.gnome.org/GNOME/babl/issues/ +) + +# Making releases on the stable branch: +# BABL_MICRO_VERSION += 1; +# BABL_INTERFACE_AGE += 1; +# BABL_BINARY_AGE += 1; +# if any functions have been added, +# set BABL_INTERFACE_AGE to 0. +# if backwards compatibility has been broken, +# set BABL_BINARY_AGE _and_ BABL_INTERFACE_AGE to 0. + +conf = configuration_data() + +pkgconfig = import('pkgconfig') +gnome = import('gnome') +python = import('python').find_installation() + +cc = meson.get_compiler('c') +prefix = get_option('prefix') +buildtype = get_option('buildtype') + +babl_prefix = get_option('prefix') +babl_libdir = join_paths(babl_prefix, get_option('libdir')) + +################################################################################ +# Projects infos + +version = meson.project_version() +array_version = version.split('.') +major_version = array_version[0].to_int() +minor_version = array_version[1].to_int() +micro_version = array_version[2].to_int() +interface_age = 1 + +binary_age = 100 * minor_version + micro_version + +lt_current = binary_age - interface_age + +api_version = '@0@.@1@'.format(major_version, minor_version) +lib_version = '@0@:@1@:@2@'.format(lt_current, interface_age, lt_current) +so_version = '@0@.@1@.@2@'.format(0, lt_current, interface_age) +lib_name = meson.project_name() + '-' + api_version + +stability_version_number = (major_version != 0 ? minor_version : micro_version) +stable = (stability_version_number % 2 == 0) + +conf.set10('BABL_UNSTABLE', not stable, Description: + 'Define to 1 if this is an unstable version of BABL.') + +conf.set ('BABL_MAJOR_VERSION', '@0@'.format(major_version)) +conf.set ('BABL_MINOR_VERSION', '@0@'.format(minor_version)) +conf.set ('BABL_MICRO_VERSION', '@0@'.format(micro_version)) +conf.set_quoted('BABL_INTERFACE_AGE', '@0@'.format(interface_age)) +conf.set_quoted('BABL_BINARY_AGE', '@0@'.format(binary_age)) +conf.set_quoted('BABL_VERSION', '@0@'.format(version)) +conf.set_quoted('BABL_REAL_VERSION', '@0@'.format(version)) +conf.set_quoted('BABL_API_VERSION', '@0@'.format(api_version)) +conf.set_quoted('BABL_RELEASE', '@0@'.format(api_version)) +conf.set_quoted('BABL_LIBRARY_VERSION', '@0@'.format(lib_version)) +conf.set_quoted('BABL_CURRENT_MINUS_AGE','@0@'.format(0)) +conf.set_quoted('BABL_LIBRARY', '@0@'.format(lib_name)) + +################################################################################ +# Host system environment + +platform_android = false +platform_osx = false +platform_win32 = false + +host_cpu_family = host_machine.cpu_family() +if host_cpu_family == 'x86' + have_x86 = true + conf.set10('ARCH_X86', true) +elif host_cpu_family == 'x86_64' + have_x86 = true + conf.set10('ARCH_X86', true) + conf.set10('ARCH_X86_64', true) +elif host_cpu_family == 'ppc' + have_ppc = true + conf.set10('ARCH_PPC', true) +elif host_cpu_family == 'ppc64' + have_ppc = true + conf.set10('ARCH_PPC', true) + conf.set10('ARCH_PPC64', true) +endif + +host_os = host_machine.system() +message('Host os: ' + host_os) + +platform_win32 = (host_os.startswith('mingw') or + host_os.startswith('cygwin') or + host_os.startswith('windows')) + +platform_osx = host_os.startswith('darwin') +if platform_osx + if cc.get_id() != 'clang' + error('You should use Clang/Clang++ on OSX.') + endif +endif + +platform_android = host_os.contains('android') + +path_sep = ( platform_win32 ? ';' : ':' ) +dirs_sep = ( platform_win32 ? '\\\\' : '/' ) +if platform_win32 + lib_ext = '.dll' +elif platform_osx + lib_ext = '.dylib' +else + lib_ext = '.so' +endif + +conf.set('BABL_PATH_SEPARATOR', '\'' + path_sep + '\'', description: + 'separator between paths in BABL_PATH') +conf.set_quoted('BABL_DIR_SEPARATOR', dirs_sep, description: + 'separator between directories in BABL_PATH') +conf.set_quoted('SHREXT', lib_ext, description: + 'File extension for shared libraries') + +# assume *nix if not android/osx/win32 +platform_unix = not ( + platform_android or + platform_osx or + platform_win32 +) + +# Build system environment +build_os = build_machine.system() +message('Build os: ' + build_os) + +build_platform_win32 = (build_os.startswith('mingw') or + build_os.startswith('cygwin') or + build_os.startswith('windows')) + +# Only try to run compiled programs if native compile or cross-compile +# and have exe wrapper. If we don't need a wrapper (e.g. 32 bit build in +# 64-bit environment) then set proprty has_exe_wrapper=true in cross +# file +can_run_host_binaries = meson.has_exe_wrapper() + + +################################################################################ +# Compiler arguments + +common_c_flags = [] + +if buildtype == 'debugoptimized' or buildtype == 'release' + common_c_flags += cc.get_supported_arguments(['-Ofast']) +endif +common_c_flags += cc.get_supported_arguments( + ['-fno-unsafe-math-optimizations'] +) + +extra_warnings_list = [ + '-Wdeclaration-after-statement', + '-Winit-self', + '-Wmissing-declarations', + '-Wmissing-prototypes', + '-Wold-style-definition', + '-Wpointer-arith', +] +common_c_flags += cc.get_supported_arguments(extra_warnings_list) + +add_project_arguments(common_c_flags, language: 'c') + +# Linker arguments +if platform_win32 and cc.has_link_argument('-Wl,--no-undefined') + no_undefined = '-Wl,--no-undefined' +else + no_undefined = [] +endif + + +################################################################################ +# Check for compiler CPU extensions + +# intialize these to nothing, so meson doesn't complain on non-x86 + +have_mmx = false +have_sse = false +have_sse2 = false +have_sse4_1 = false +have_avx2 = false +have_f16c = false + +sse2_cflags = [] +f16c_cflags = [] +sse4_1_cflags = [] +avx2_cflags = [] + +# mmx assembly +if get_option('enable-mmx') and cc.has_argument('-mmmx') + if cc.compiles('asm ("movq 0, %mm0");') + message('mmx assembly available') + add_project_arguments('-mmmx', language: 'c') + conf.set('USE_MMX', 1, description: + 'Define to 1 if MMX assembly is available.') + have_mmx = true + + # sse assembly + if get_option('enable-sse') and cc.has_argument('-msse') + if cc.compiles('asm ("movntps %xmm0, 0");') + add_project_arguments('-msse', language: 'c') + message('sse assembly available') + conf.set('USE_SSE', 1, description: + 'Define to 1 if SSE assembly is available.') + have_sse = true + sse_args = ['-mfpmath=sse'] + if platform_win32 + sse_args += '-mstackrealign' + endif + + foreach sse_arg : sse_args + if cc.has_argument(sse_arg) + add_project_arguments(sse_arg, language: 'c') + endif + endforeach + + # sse2 assembly + if get_option('enable-sse2') and cc.has_argument('-msse2') + if cc.compiles('asm ("punpckhwd %xmm0,%xmm1");') + message('sse2 assembly available') + sse2_cflags = '-msse2' + conf.set('USE_SSE2', 1, description: + 'Define to 1 if sse2 assembly is available.') + have_sse2 = true + + # sse4.1 assembly + if get_option('enable-sse4_1') and cc.has_argument('-msse4.1') + if cc.compiles('asm ("pmovzxbd %xmm0,%xmm1");') + message('sse4.1 assembly available') + sse4_1_cflags = '-msse4.1' + conf.set('USE_SSE4_1', 1, description: + 'Define to 1 if sse4.1 assembly is available.') + have_sse4_1 = true + endif + + # avx2 assembly + if get_option('enable-avx2') and cc.has_argument('-mavx2') + if cc.compiles('asm ("vpgatherdd %ymm0,(%eax,%ymm1,4),%ymm2");') + message('avx2 assembly available') + avx2_cflags = '-mavx2' + conf.set('USE_AVX2', 1, description: + 'Define to 1 if avx2 assembly is available.') + have_avx2 = true + endif + endif + endif + endif + endif + endif + if get_option('enable-f16c') and cc.has_argument('-mf16c') + if cc.compiles( + 'asm ("#include ],' + + '[__m128 val = _mm_cvtph_ps ((__m128i)_mm_setzero_ps());' + + ' __m128i val2 = _mm_insert_epi64((__m128i)_mm_setzero_ps(),0,0);");' + ) + message('Can compile half-floating point code (f16c)') + f16c_cflags = '-mf16c' + conf.set('USE_F16C', 1, description: + 'Define to 1 if f16c intrinsics are available.') + have_f16c = true + endif + endif + endif + endif +endif + +################################################################################ +# Check environment + +# Check headers +check_headers = [ + ['HAVE_STDATOMIC_H', 'stdatomic.h'] +] +# Don't check for dynamic load on windows +if not platform_win32 + check_headers += [ + ['HAVE_DLFCN_H', 'dlfcn.h'], + ['HAVE_DL_H', 'dl.h'], + ] +endif +foreach header: check_headers + if cc.has_header(header[1]) + conf.set(header[0], 1, description: + 'Define to 1 if the <@0@> header is available'.format(header[1])) + endif +endforeach + + +# Check functions +# general +check_functions = [ + ['HAVE_GETTIMEOFDAY', 'gettimeofday', ''], + ['HAVE_RINT', 'rint' , ''], + ['HAVE_SRANDOM', 'srandom' , ''], +] +foreach func: check_functions + if cc.has_function(func[1], prefix: '#include ' + func[2]) + conf.set(func[0], 1, description: + 'Define to 1 if the @0@() function is available'.format(func[1])) + endif +endforeach + + +# Check for uncommon features + +# babl_fish_reference(), create_name() would like this +if cc.compiles('int main() { static __thread char buf[1024]; }') + conf.set('HAVE_TLS', 1, description: + 'Define to 1 if compiler supports __thread') +endif + + +################################################################################ +# Dependencies + +math = cc.find_library('m', required: false) +thread = dependency('threads', required: false) +if platform_android + log = cc.find_library('log', required: false) +else + log = [] +endif +if platform_win32 + dl = [] +else + dl = cc.find_library('dl', required: false) +endif + + +# gobject introspection +g_ir = dependency('gobject-introspection-1.0', version: '>=1.32.0', + required: false) + +# lcms +if get_option('with-lcms') + lcms = dependency('lcms2', version: '>=2.8', required: true) + if lcms.found() + conf.set('HAVE_LCMS', 1, description: + 'Define to 1 if liblcms2 is available') + endif +else + lcms = declare_dependency() +endif + +# vapigen +vapigen = dependency('vapigen', version:'>=0.20.0', required: false) + + +################################################################################ +# Build utilities + +# build from git repo +git_bin = find_program('git', required: false, native: true) + +# docs +env_bin = find_program('env', required: false, native: true) +rsvg_convert_bin = find_program('rsvg-convert', required: false, + native: true) +w3m_bin = find_program('w3m', required: false, native: true) + + +################################################################################ +# Build flags + +# Docs - don't build by default in cross-build environments +# can't build if no env binary +build_docs = true +if get_option('with-docs') != 'false' and not env_bin.found() + build_docs = false + warning('env is required to build documentation') +elif get_option('with-docs') == 'auto' + if meson.is_cross_build() + build_docs = false + message( + 'configure with -Ddocs=true to cross-build documentation' + ) + endif +elif get_option('with-docs') == 'false' + build_docs = false +endif + +# Introspection - don't build by default on cross-build environments +if get_option('enable-gir') == 'auto' + build_gir = meson.is_cross_build() ? false : true +else + build_gir = get_option('enable-gir') == 'true' ? true : false +endif +if not g_ir.found() + build_gir = false +endif + +# Vapi - only build if building introspection +if build_gir and get_option('enable-vapi') and vapigen.found() + build_vapi = true +else + build_vapi = false +endif + +################################################################################ +# Configuration files + +# config.h +configure_file( + output: 'config.h', + configuration: conf +) + + +################################################################################ +# Subdirs + +rootInclude = include_directories('.') + +subdir('babl') +subdir('extensions') +subdir('tests') +subdir('tools') +if build_docs + subdir('docs') +endif + +# Create README file from web page +if w3m_bin.found() and build_docs + custom_target('README', + input: index_html, + output: 'README', + command: [ + w3m_bin, + '-cols', '72', + '-dump', + '@INPUT@', + ], + capture: true, + build_by_default: true + ) +endif + + +# pkg-config file +pkgconfig.generate(filebase: 'babl', + name: 'babl', + description: 'Pixel encoding and color space conversion engine.', + version: meson.project_version(), + libraries: [ babl ], + libraries_private: [ + '-lm', + ], + subdirs: [ + lib_name, + ], +) + +################################################################################ +# Build summary +summary( + { + 'prefix': babl_prefix, + 'libdir': get_option('libdir'), + }, section: 'Directories' +) +summary( + { + 'BABL docs' : build_docs, + 'Introspection' : build_gir, + 'VALA support' : build_vapi, + }, section: 'Optional features' +) +summary( + { + 'mmx' : have_mmx, + 'sse' : have_sse, + 'sse2' : have_sse2, + 'sse4_1' : have_sse4_1, + 'avx2' : have_avx2, + 'f16c (half fp)' : have_f16c, + }, section: 'Processor extensions' +) +summary( + { + 'lcms' : get_option('with-lcms'), + }, section: 'Optional dependencies' +) diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000..fe18662 --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,55 @@ +# Optional features +option('with-docs', + type: 'combo', + choices: ['auto', 'true', 'false'], + description: 'build documentation' +) +option('enable-gir', + type: 'combo', + choices: ['auto', 'true', 'false'], + description: 'gobject introspection .gir generation' +) +option('enable-vapi', + type: 'boolean', + value: 'true', + description: 'Vala .vapi generation - depends on introspection' +) + +# Compiler extensions +option('enable-mmx', + type: 'boolean', + value: 'true', + description: 'MMX support - disables all compiler extensons' +) +option('enable-sse', + type: 'boolean', + value: 'true', + description: 'SSE support - depends on MMX' +) +option('enable-sse2', + type: 'boolean', + value: 'true', + description: 'SSE2 support - depends on SSE' +) +option('enable-sse4_1', + type: 'boolean', + value: 'true', + description: 'SSE4.1 support - depends on SSE2' +) +option('enable-avx2', + type: 'boolean', + value: 'true', + description: 'AVX2 support - depends on SSE4.1' +) +option('enable-f16c', + type: 'boolean', + value: 'true', + description: 'Hardware half-float support - depends on SSE' +) + +# Optional dependencies +option('with-lcms', + type: 'boolean', + value: 'true', + description: 'build with lcms' +) diff --git a/tests/alpha_symmetric_transform.c b/tests/alpha_symmetric_transform.c new file mode 100644 index 0000000..a42709a --- /dev/null +++ b/tests/alpha_symmetric_transform.c @@ -0,0 +1,111 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, 2017 Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include +#include "babl-internal.h" + +#define TOLERANCE 0.001 +#define PIXELS 12 + +float source_buf [PIXELS * 4] = +{ 10.0, 1.0, 0.1, 1.0, + 10.0, 1.0, 0.1, 0.5, + 10.0, 1.0, 0.1, 0.1, + 10.0, 1.0, 0.1, 0.01, + 10.0, 1.0, 0.1, -0.01, + 10.0, 1.0, 0.1, 1.5, + 10.0, 1.0, 0.0001, 0.000001, + 10.0, 1.0, 0.1 , -0.00001, + 10.0, 1.0, 0.1, 0.0, + 10.0, 1.0, 0.1, -0.5, + 1000.0,10000.0, 100000.0, 0.001, + 5000.0,50000.0, 500000.0, 0.01, +}; + +float bounce_buf [PIXELS * 4]; +float destination_buf [PIXELS * 4]; + +static int +test (void) +{ + int i; + int OK = 1; + + babl_process (babl_fish ("RGBA float", "RaGaBaA float"), + source_buf, bounce_buf, + PIXELS); + babl_process (babl_fish ("RaGaBaA float", "RGBA float"), + bounce_buf, destination_buf, + PIXELS); + + for (i = 0; i < PIXELS; i++) + { + for (int c = 0; c < 4; c++) + { + if (fabs (destination_buf[i*4+c] - source_buf[i*4+c]) > TOLERANCE) + { + babl_log ("separate alpha %i.%i: %.9f!=%.9f(ref) ", i, c, destination_buf[i*4+c], + source_buf[i*4+c]); + OK = 0; + } + // fprintf (stdout, "%.19f ", destination_buf[i*4+c]); + } + // fprintf (stdout, "\n"); + } + + fprintf (stdout, "\n"); + + babl_process (babl_fish ("RaGaBaA float", "RGBA float"), + source_buf, bounce_buf, + PIXELS); + babl_process (babl_fish ("RGBA float", "RaGaBaA float"), + bounce_buf, destination_buf, + PIXELS); + + for (i = 0; i < PIXELS; i++) + { + for (int c = 0; c < 4; c++) + { + if (fabs (destination_buf[i*4+c] - source_buf[i*4+c]) > TOLERANCE) + { + babl_log ("associatd-alpha %i.%i: %.9f!=%.9f(ref) ", i, c, destination_buf[i*4+c], + source_buf[i*4+c]); + OK = 0; + } + // fprintf (stdout, "%.19f ", destination_buf[i*4+c]); + } + // fprintf (stdout, "\n"); + } + + + if (!OK) + return -1; + return 0; +} + +int +main (int argc, + char **argv) +{ + babl_init (); + if (test ()) + return -1; + babl_exit (); + return 0; +} diff --git a/tests/babl_class_name.c b/tests/babl_class_name.c new file mode 100644 index 0000000..c0724f0 --- /dev/null +++ b/tests/babl_class_name.c @@ -0,0 +1,74 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include +#include +#include "babl-internal.h" + +struct +{ + long klass; const char *name; +} reference[] = { + { BABL_INSTANCE, "BablInstance" }, + { BABL_TYPE, "BablType" }, + { BABL_TYPE_INTEGER, "BablTypeInteger" }, + { BABL_TYPE_FLOAT, "BablTypeFloat" }, + { BABL_SAMPLING, "BablSampling" }, + { BABL_COMPONENT, "BablComponent" }, + { BABL_MODEL, "BablModel" }, + { BABL_FORMAT, "BablFormat" }, + { BABL_CONVERSION, "BablConversion" }, + { BABL_CONVERSION_LINEAR, "BablConversionLinear" }, + { BABL_CONVERSION_PLANE, "BablConversionPlane" }, + { BABL_CONVERSION_PLANAR, "BablConversionPlanar" }, + { BABL_FISH, "BablFish" }, + { BABL_FISH_REFERENCE, "BablFishReference" }, + { BABL_IMAGE, "BablImage" }, + { BABL_SKY, "BablSky" }, + { 0, NULL } +}; + +static int +test (void) +{ + int i = 0; + int OK = 1; + + while (reference[i].klass) + { + if (strcmp (reference[i].name, babl_class_name (reference[i].klass))) + { + OK = 0; + babl_log ("'%s'!='%s'\n", reference[i].name, babl_class_name (reference[i].klass)); + } + i++; + } + return !OK; +} + +int +main (int argc, + char **argv) +{ + babl_init (); + if (test ()) + return -1; + babl_exit (); + return 0; +} diff --git a/tests/cairo-RGB24.c b/tests/cairo-RGB24.c new file mode 100644 index 0000000..31367f7 --- /dev/null +++ b/tests/cairo-RGB24.c @@ -0,0 +1,95 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include +#include +#include "babl.h" + +static int +cairo24_rgb_cairo24 (void) +{ + int OK = 1, i; + + for (i = 0; i < 256; ++i) + { + /* Valgrind complains if 'tmp' is not initialized + * and the brittle RTTI (BABL_IS_BABL) produces a + * crash if it contains { 0x00, 0xb1, 0xba, 0x00 } + */ + unsigned char tmp[4] = { 0, /*0xb1, 0xba, 0x00*/ }; + /* Valgrind complains if 'output' is not initialized + * and the brittle RTTI (BABL_IS_BABL) produces a + * crash if it contains 0xbab100 + */ + unsigned int output = ~ 0xbab100; + unsigned int input = (i * 256 + i) * 256 + i; + + babl_process (babl_fish ("cairo-RGB24", "R'G'B' u8"), &input, &tmp[0], 1); + babl_process (babl_fish ("R'G'B' u8", "cairo-RGB24"), &tmp[0], &output, 1); + + if ((input & 0x00ffffff) != (output & 0x00ffffff)) + { + fprintf (stderr , "%08x -> %d %d %d -> %08x\n", + input, tmp[0], tmp[1], tmp[2], output); + OK = 0; + } + } + + return OK; +} + +static int +rgb_cairo24_rgb (void) +{ + int OK = 1, i; + + for (i = 0; i < 256; ++i) + { + /* As above */ + unsigned int tmp = ~ 0xbab100; + unsigned char output[4] = { 0x00, /*0xb1, 0xba, 0x00*/ }; + unsigned char input[4] = { i, i, i, 17 }; + + babl_process (babl_fish ("R'G'B' u8", "cairo-RGB24"), input, &tmp, 1); + babl_process (babl_fish ("cairo-RGB24", "R'G'B' u8"), &tmp, output, 1); + + if (input[0] != output[0] || input[1] != output[1] || input[2] != output[2]) + { + fprintf (stderr , "%d %d %d -> %08x -> %d %d %d\n", + input[0], input[1], input[2], tmp, output[0], output[1], output[2]); + OK = 0; + } + } + + return OK; +} + +int +main (void) +{ + int OK; + + babl_init (); + + OK = cairo24_rgb_cairo24 () && rgb_cairo24_rgb (); + + babl_exit (); + + return !OK; +} diff --git a/tests/cairo_cmyk_hack.c b/tests/cairo_cmyk_hack.c new file mode 100644 index 0000000..1f308fe --- /dev/null +++ b/tests/cairo_cmyk_hack.c @@ -0,0 +1,80 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include +#include +#include + +#define PIXELS 6 +#define TOLERANCE 0 + +unsigned char source_buf [PIXELS * 5] = +{ 0, 0, 0, 22, 33, + 127, 127, 127, 12, 33, + 255, 225, 255, 33, 33, + 255, 0.0, 0.0, 4, 33, + 0.0, 255, 0.0, 122,33, + 0.0, 0.0, 255, 222,33}; + +unsigned char cmk_buf [PIXELS * 4]; +unsigned char cyk_buf [PIXELS * 4]; +unsigned char dest_buf [PIXELS * 5]; + +static int +test (void) +{ + int i; + int OK = 1; + + babl_process (babl_fish ("camayakaA u8", "cairo-ACYK32"), + source_buf, cyk_buf, + PIXELS); + babl_process (babl_fish ("camayakaA u8", "cairo-ACMK32"), + source_buf, cmk_buf, + PIXELS); + + babl_process (babl_fish ("cairo-ACMK32", "camayakaA u8"), + cmk_buf, dest_buf, + PIXELS); + babl_process (babl_fish ("cairo-ACYK32", "camayakaA u8"), + cyk_buf, dest_buf, + PIXELS); + + for (i = 0; i < PIXELS * 5; i++) + { + if (fabs (dest_buf[i] - source_buf[i] * 1.0) > TOLERANCE) + { + fprintf (stderr, "%i is wrong\n", i); + OK = 0; + } + } + if (!OK) + return -1; + return 0; +} + +int +main (int argc, + char **argv) +{ + babl_init (); + if (test ()) + return -1; + babl_exit (); + return 0; +} diff --git a/tests/chromaticities.c b/tests/chromaticities.c new file mode 100644 index 0000000..a57cead --- /dev/null +++ b/tests/chromaticities.c @@ -0,0 +1,77 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, 2017 Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include +#include "babl-internal.h" + +#define PIXELS 6 +#define TOLERANCE 0 + +unsigned char source_buf [PIXELS * 3] = +{ 0, 0, 0, + 127, 127, 127, + 255, 255, 255, + 255, 0.0, 0.0, + 0.0, 255, 0.0, + 0.0, 0.0, 255 }; + +unsigned char reference_buf [PIXELS * 3] = +{ 0, 0, 0, + 145, 145, 145, + 255, 255, 255, + 255, 43, 6, + 0.0, 250, 48, + 25, 34, 251}; + +unsigned char destination_buf [PIXELS * 3]; + +static int +test (void) +{ + int i; + int OK = 1; + + babl_process (babl_fish (babl_format_with_space ("R'G'B' u8", babl_space("Apple")), "R'G'B' u8"), + source_buf, destination_buf, + PIXELS); + + for (i = 0; i < PIXELS * 3; i++) + { + if (abs (destination_buf[i] - reference_buf[i]) > TOLERANCE) + { + babl_log ("%2i (%2i%%3=%i, %2i/3=%i) is %i should be %i", + i, i, i % 3, i, i / 3, destination_buf[i], reference_buf[i]); + OK = 0; + } + } + if (!OK) + return -1; + return 0; +} + +int +main (int argc, + char **argv) +{ + babl_init (); + if (test ()) + return -1; + babl_exit (); + return 0; +} diff --git a/tests/cmyk.c b/tests/cmyk.c new file mode 100644 index 0000000..3b11e44 --- /dev/null +++ b/tests/cmyk.c @@ -0,0 +1,56 @@ +/* babl - dynamically extendable universal pixel conversion library. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include + +#include + +#include "common.inc" + + +int +main (int argc, + char **argv) +{ + int OK = 1; + + float rgba[][4] = {{1.0 , 1.0 , 1.0 , 1.0}, + {0.0 , 1.0 , 0.0 , 1.0}, + {0.5 , 0.5 , 0.5 , 1.0}, + {0.0 , 1.0 , 1.0 , 1.0}}; + + float cmyk[][4] = {{0.0, 0.0 , 0.0 , 0.0}, + {1.0, 0.0 , 1.0 , 0.0}, + {0.0, 0.0 , 0.0 , 0.5}, + {1.0, 0.0 , 0.0 , 0.0}}; + + babl_init (); + + CHECK_CONV_FLOAT ("rgba to cmyk ", float, 0.001, + babl_format ("RGBA float"), + babl_format ("CMYK float"), + rgba, cmyk); + + CHECK_CONV_FLOAT ("cmyk to rgba ", float, 0.001, + babl_format ("CMYK float"), + babl_format ("RGBA float"), + cmyk, rgba); + + babl_exit (); + + return !OK; +} diff --git a/tests/common.inc b/tests/common.inc new file mode 100644 index 0000000..bca5056 --- /dev/null +++ b/tests/common.inc @@ -0,0 +1,53 @@ + +#include +#include "babl/babl-introspect.h" + +#define CHECK_CONV(test_name, componenttype, src_fmt, dst_fmt, src_pix, expected_pix) \ + { \ + const Babl *fish; \ + int i; \ + fish = babl_fish (src_fmt, dst_fmt); \ + if (!fish) \ + { \ + printf (" %s failed to make fish\n", test_name); \ + OK = 0; \ + } \ + for (i = 0; i < sizeof(src_pix)/sizeof(src_pix[0]); i ++) \ + { \ + int c;\ + componenttype result[10]; \ + babl_process (fish, src_pix[i], result, 1); \ + for (c = 0; c < sizeof(expected_pix[i])/sizeof(expected_pix[i][0]); c++) \ + if (result[c] != expected_pix[i][c]) \ + { \ + printf (" %s failed #%i[%i] got %i expected %i\n", test_name, i, c, result[c], expected_pix[i][c]); \ + OK = 0; \ + babl_introspect((Babl *)fish); \ + } \ + } \ + } + +#define CHECK_CONV_FLOAT(test_name, componenttype, max_error, src_fmt, dst_fmt, src_pix, expected_pix) \ + { \ + const Babl *fish; \ + int i; \ + fish = babl_fish (src_fmt, dst_fmt); \ + if (!fish) \ + { \ + printf (" %s failed to make fish\n", test_name); \ + OK = 0; \ + } \ + for (i = 0; i < sizeof(src_pix)/sizeof(src_pix[0]); i ++) \ + { \ + int c;\ + componenttype result[10]; \ + babl_process (fish, src_pix[i], result, 1); \ + for (c = 0; c < sizeof(expected_pix[i])/sizeof(expected_pix[i][0]); c++) \ + if (fabs(result[c] - expected_pix[i][c]) > max_error) \ + { \ + printf (" %s failed #%i[%i] got %lf expected %lf\n", test_name, i, c, result[c], expected_pix[i][c]); \ + OK = 0; \ + babl_introspect((Babl *)fish); \ + } \ + } \ + } diff --git a/tests/concurrency-stress-test.c b/tests/concurrency-stress-test.c new file mode 100644 index 0000000..a02a519 --- /dev/null +++ b/tests/concurrency-stress-test.c @@ -0,0 +1,82 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2009 Martin Nordholts + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + + +#include "config.h" + +#include +#include + +#include "babl.h" + + +#define N_THREADS 10 +#define N_ITERATIONS_PER_THREAD 100 + + +static void * +babl_fish_path_stress_test_thread_func (void *not_used) +{ + int i; + + for (i = 0; i < N_ITERATIONS_PER_THREAD; i++) + { + /* Try to get a fish with an as complex conversion path as + * possible + */ + const Babl *fish = babl_fish ("R'G'B'A u16", "YA double"); + + /* Just do something random with the fish */ + babl_get_name (fish); + } + + return NULL; +} + +int +main (int argc, + char **argv) +{ + pthread_t threads[N_THREADS]; + int i; + + babl_init (); + + /* Run a few threads at the same time */ + for (i = 0; i < N_THREADS; i++) + { + pthread_create (&threads[i], + NULL, /* attr */ + babl_fish_path_stress_test_thread_func, + NULL /* arg */); + } + + /* Wait for them all to finish */ + for (i = 0; i < N_THREADS; i++) + { + pthread_join (threads[i], + NULL /* thread_return */); + } + + babl_exit (); + + /* If we didn't crash we assume we're OK. We might want to add more + * asserts in the test later + */ + return 0; +} diff --git a/tests/conversions.c b/tests/conversions.c new file mode 100644 index 0000000..9503d04 --- /dev/null +++ b/tests/conversions.c @@ -0,0 +1,73 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include "babl-internal.h" + + static const struct + { + const char *from_format; + const char *to_format; + } + fishes[] = + { + { "Y' u8", "RaGaBaA float" }, + { "Y u8", "RaGaBaA float" }, + { "R'G'B'A u8", "RaGaBaA float" }, + { "R'G'B'A float", "R'G'B'A u8" }, + { "R'G'B'A float", "R'G'B' u8" }, + { "R'G'B'A u8", "RGBA float" }, + { "RGBA float", "R'G'B'A u8" }, + { "RGBA float", "R'G'B'A u8" }, + { "RGBA float", "R'G'B'A float" }, + { "Y' u8", "R'G'B' u8" }, + { "Y u8", "Y float" }, + { "R'G'B' u8", "cairo-RGB24" }, + { "R'G'B' u8", "R'G'B'A float" }, + { "R'G'B' u8", "R'G'B'A u8" }, + { "R'G'B'A u8", "R'G'B'A float" }, + { "R'G'B'A u8", "cairo-ARGB32" }, + { "R'G'B'A double", "RGBA float" }, + { "R'G'B'A float", "RGBA double" }, + { "R'G'B' u8", "RGB float" }, + { "RGB float", "R'G'B'A float" }, + { "R'G'B' u8", "RGBA float" }, + { "RaGaBaA float", "R'G'B'A float" }, + { "RaGaBaA float", "RGBA float" }, + { "RGBA float", "RaGaBaA float" }, + { "R'G'B' u8", "RaGaBaA float" }, + { "cairo-ARGB32", "R'G'B'A u8" } + }; + +int +main (int argc, + char **argv) +{ + putenv ("BABL_DEBUG_CONVERSIONS" "=" "1"); + putenv ("BABL_DEBUG_MISSING" "=" "1"); + babl_init (); + + for (int i = 0; i < sizeof (fishes)/sizeof(fishes[0]);i ++) + { + babl_fish (babl_format (fishes[i].from_format), + babl_format (fishes[i].to_format)); + } + + babl_exit (); + return 0; +} diff --git a/tests/extract.c b/tests/extract.c new file mode 100644 index 0000000..ffd9f5c --- /dev/null +++ b/tests/extract.c @@ -0,0 +1,48 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include +#include +#include +#include "babl.h" +#include "common.inc" + +int +main (int argc, + char **argv) +{ + int OK = 1; + babl_init (); + { + unsigned char in[][4] = {{0,1,2,3 },{4,5,6,7 },{8,9,10,11 }}; + unsigned char out[][1] = { {2 }, {6} , {10} }; + + CHECK_CONV("extract B'", unsigned char, + babl_format("R'G'B'A u8"), + babl_format_new ("name", "B' u8", + babl_model ("R'G'B'A"), + babl_type ("u8"), + babl_component ("B'"), + NULL), + in, out); + } + + babl_exit (); + return !OK; +} diff --git a/tests/float-to-8bit.c b/tests/float-to-8bit.c new file mode 100644 index 0000000..1a3cafc --- /dev/null +++ b/tests/float-to-8bit.c @@ -0,0 +1,102 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include +#include +#include +#include "babl.h" + +#include "common.inc" + + +int +main (int argc, + char **argv) +{ + int OK = 1; + + babl_init (); + + //for (i = 0; i < 400000; i++) + { + { + float in[][4] = {{ 0.21582, -0.55, -0.14, 1.0 }, {0.2, 0.3, 0.5, 0.6}, {0.0, 1.0, 2.0, 3.0}}; + unsigned char out[][4] = {{ 55, 0, 0, 255 }, {51,77,128,153}, {0,255,255,255}}; + + CHECK_CONV("float -> u8 1", unsigned char, + babl_format("R'G'B'A float"), + babl_format("R'G'B'A u8"), + in, out); + } + + { + float in[][4] = {{ 0.21582, -0.55, -0.14, 1.0 }, {0.2, 0.3, 0.5, 0.6}, {0.0, 1.0, 2.0, 3.0}}; + unsigned char out[][4] = {{ 10, 0, 0, 255 }, {8,19,55,153}, {0,255,255,255}}; + + CHECK_CONV("float -> u8 2", unsigned char, + babl_format("R'G'B'A float"), + babl_format("RGBA u8"), + in, out); + } + + { + float in[][4] = {{ 0.21582, -0.55, -0.14, 1.0 }, {0.2, 0.3, 0.5, 0.6}, {0.0, 1.0, 2.0, 3.0}}; + unsigned char out[][4] = {{ 55, 0, 0, 255 }, {51,77,128,153}, {0,255,255,255}}; + + CHECK_CONV("float -> u8 3", unsigned char, + babl_format("RGBA float"), + babl_format("RGBA u8"), + in, out); + } + + { + float in[][4] = {{ 0.21582, -0.55, -0.14, 1.0 }, {0.2, 0.3, 0.5, 0.6}, {0.0, 1.0, 2.0, 3.0}}; + unsigned char out[][3] = {{128, 0, 0}, {124,149,188}, {0,255,255}}; + + CHECK_CONV("float -> u8 4", unsigned char, + babl_format("RGBA float"), + babl_format("R'G'B' u8"), + in, out); + } + + { + float in[][4] = {{ 0.21582, -0.55, -0.14, 1.0 }, {0.2, 0.3, 0.5, 0.6}, {0.0, 1.0, 2.0, 3.0}}; + unsigned char out[][4] = {{128, 0, 0, 255 }, {156,188,235,153}, {0,156,213,255}}; + + CHECK_CONV("float -> u8 5", unsigned char, + babl_format("RaGaBaA float"), + babl_format("R'G'B'A u8"), + in, out); + } + + { + /* (0.5 / 0.6) * 255 = 212.5, I'm not going to worry about rounding that close... */ + float in[][4] = {{ 0.21582, -0.55, -0.14, 1.0 }, {0.2, 0.301, 0.49998, 0.6}, {0.0, 3.0, 6.0, 3.0}}; + unsigned char out[][4] = {{55, 0, 0, 255 }, {85,128,212,153}, {0,255,255,255}}; + + CHECK_CONV("float -> u8 6", unsigned char, + babl_format("R'aG'aB'aA float"), + babl_format("R'G'B'A u8"), + in, out); + } + } + + babl_exit (); + return !OK; +} diff --git a/tests/floatclamp.c b/tests/floatclamp.c new file mode 100644 index 0000000..7960e13 --- /dev/null +++ b/tests/floatclamp.c @@ -0,0 +1,46 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include +#include +#include +#include "babl.h" + +#include "common.inc" + + +int +main (int argc, + char **argv) +{ + int OK = 1; + babl_init (); + { + float in[][4] = {{ 0.21582, -0.55, -0.14, 1.0 }, {0.0, 1.0, 2.0, 3.0}}; + unsigned char out[][4] = {{ 55, 0, 0, 255 }, {0,255,255,255}}; + + CHECK_CONV("float -> u8", unsigned char, + babl_format("R'G'B'A float"), + babl_format("R'G'B'A u8"), + in, out); + } + + babl_exit (); + return !OK; +} diff --git a/tests/format_with_space.c b/tests/format_with_space.c new file mode 100644 index 0000000..34f5332 --- /dev/null +++ b/tests/format_with_space.c @@ -0,0 +1,109 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, 2017 Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include +#include "babl-internal.h" + +static int +test2 (void) +{ + int OK = 1; + const Babl *sRGB = babl_space ("sRGB"); + const Babl *fmt; + + fmt = babl_format ("R'G'B' u8"); + if (babl_format_get_space (fmt) != sRGB) + { + babl_log ("created space %s doesn't have sRGB when it should", babl_get_name (fmt)); + OK = 0; + } + fmt = babl_format_with_space ("R'G'B' u8", NULL); + if (babl_format_get_space (fmt) != sRGB) + { + babl_log ("created space %s doesn't have sRGB when it should", babl_get_name (fmt)); + OK = 0; + } + fmt = babl_format_with_space ("R'G'B' u8", sRGB); + if (babl_format_get_space (fmt) != sRGB) + { + babl_log ("created space %s doesn't have sRGB when it should", babl_get_name (fmt)); + OK = 0; + } + fmt = babl_format_with_space ("CIE Lab float", sRGB); + if (babl_format_get_space (fmt) != sRGB) + { + babl_log ("created space %s doesn't have sRGB when it should", babl_get_name (fmt)); + OK = 0; + } + + if (!OK) + return -1; + return 0; +} + +static int +test3 (void) +{ + int OK = 1; + const Babl *apple = babl_space ("Apple"); + const Babl *sRGB = babl_space ("sRGB"); + const Babl *fmt; + + fmt = babl_format ("R'G'B' u8"); + if (babl_format_get_space (fmt) != sRGB) + { + babl_log ("created space %s doesn't have sRGB when it should", babl_get_name (fmt)); + OK = 0; + } + fmt = babl_format_with_space ("R'G'B' u8", NULL); + if (babl_format_get_space (fmt) != sRGB) + { + babl_log ("created space %s doesn't have sRGB when it should", babl_get_name (fmt)); + OK = 0; + } + fmt = babl_format_with_space ("R'G'B' u8", apple); + if (babl_format_get_space (fmt) != apple) + { + babl_log ("created space %s doesn't have apple when it should", babl_get_name (fmt)); + OK = 0; + } + fmt = babl_format_with_space ("CIE Lab float", apple); + if (babl_format_get_space (fmt) != apple) + { + babl_log ("created space %s doesn't have apple when it should", babl_get_name (fmt)); + OK = 0; + } + + if (!OK) + return -1; + return 0; +} + +int +main (int argc, + char **argv) +{ + babl_init (); + if (test2 ()) + return -1; + if (test3 ()) + return -1; + babl_exit (); + return 0; +} diff --git a/tests/grayscale_to_rgb.c b/tests/grayscale_to_rgb.c new file mode 100644 index 0000000..c3ec7c7 --- /dev/null +++ b/tests/grayscale_to_rgb.c @@ -0,0 +1,86 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include "babl-internal.h" + +#define PIXELS 5 + +float grayscale_buf [PIXELS] = { -0.1, 0.0, 0.4, 1.0, 2.0 }; + +float rgb_buf_ref [PIXELS * 3] = +{ -0.1, -0.1, -0.1, 0.0, 0.0, 0.0, 0.4, 0.4, 0.4, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0 }; + +float rgb_buf [PIXELS * 3]; + +static int +test (void) +{ + const Babl *fish; + int i; + int OK = 1; + + + fish = babl_fish ( + babl_format_new ( + babl_model ("Y"), + babl_type ("float"), + babl_component ("Y"), + NULL + ), + babl_format_new ( + babl_model ("RGB"), + babl_type ("float"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + NULL + ) + ); + + babl_process (fish, + grayscale_buf, rgb_buf, + PIXELS); + + for (i = 0; i < PIXELS * 3; i++) + { + if (fabs (rgb_buf[i] - rgb_buf_ref[i]) > 0.0000001) + { + babl_log ("index %i is problematic : %.12f instead of %.12f", + i, rgb_buf[i], rgb_buf_ref[i]); + OK = 0; + } + } + if (!OK) + return -1; + return 0; +} + +int +main (int argc, + char **argv) +{ + babl_init (); + if (test ()) + return -1; + babl_exit (); + return 0; +} + + + diff --git a/tests/hsl.c b/tests/hsl.c new file mode 100644 index 0000000..aaa1855 --- /dev/null +++ b/tests/hsl.c @@ -0,0 +1,86 @@ +/* babl - dynamically extendable universal pixel conversion library. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include + +#include + +#include "common.inc" + + +int +main (int argc, + char **argv) +{ + int OK = 1; + + float rgba[][4] = {{1.0 , 1.0 , 1.0 , 1.0}, + {0.214041, 0.214041, 0.214041, 1.0}, + {0.0 , 0.0 , 0.0 , 1.0}, + {1.0 , 0.0 , 0.0 , 1.0}, + {0.522519, 0.522519, 0.0 , 1.0}, + {0.0 , 0.214041, 0.0 , 1.0}, + {0.214041, 1.0 , 1.0 , 1.0}, + {0.214041, 0.214041, 1.0 , 1.0}, + {0.522520, 0.050876, 0.522521, 1.0}, + {0.353069, 0.372000, 0.017878, 1.0}, + {0.052772, 0.010679, 0.823194, 1.0}, + {0.012693, 0.414530, 0.052934, 1.0}, + {0.870621, 0.579515, 0.004228, 1.0}, + {0.453672, 0.029212, 0.781390, 1.0}, + {0.850554, 0.181933, 0.081839, 1.0}, + {0.995195, 0.941644, 0.244979, 1.0}, + {0.009836, 0.595745, 0.308242, 1.0}, + {0.036595, 0.019338, 0.315257, 1.0}, + {0.209470, 0.207646, 0.478434, 1.0}}; + + float hsla[][4] = {{0.0, 0.0 , 1.0 , 1.0}, + {0.0, 0.0 , 0.500, 1.0}, + {0.0, 0.0 , 0.0 , 1.0}, + {0.0, 1.0 , 0.500, 1.0}, + {0.166667, 1.0 , 0.375, 1.0}, + {0.333333, 1.0 , 0.250, 1.0}, + {0.5, 1.0 , 0.750, 1.0}, + {0.666666, 1.0 , 0.750, 1.0}, + {0.833333, 0.500, 0.500, 1.0}, + {0.171666, 0.638, 0.393, 1.0}, + {0.6975, 0.832, 0.511, 1.0}, + {0.374722, 0.707, 0.396, 1.0}, + {0.1375, 0.893, 0.497, 1.0}, + {0.788028, 0.775, 0.542, 1.0}, + {0.039837, 0.817, 0.624, 1.0}, + {0.158083, 0.991, 0.765, 1.0}, + {0.451149, 0.779, 0.447, 1.0}, + {0.689732, 0.601, 0.373, 1.0}, + {0.668129, 0.290, 0.607, 1.0}}; + + babl_init (); + + CHECK_CONV_FLOAT ("rgba to hsla ", float, 0.001, + babl_format ("RGBA float"), + babl_format ("HSLA float"), + rgba, hsla); + + CHECK_CONV_FLOAT ("hsla to rgba ", float, 0.001, + babl_format ("HSLA float"), + babl_format ("RGBA float"), + hsla, rgba); + + babl_exit (); + + return !OK; +} diff --git a/tests/hsva.c b/tests/hsva.c new file mode 100644 index 0000000..66b93b8 --- /dev/null +++ b/tests/hsva.c @@ -0,0 +1,93 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2012, Maxime Nicco + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + + /* + * Adding test fo hsva colorspace + * + * The test is at 0.001 precision + */ + +#include "config.h" +#include +#include +#include +#include "babl.h" + +#include "common.inc" + + +int +main (int argc, + char **argv) +{ + int OK = 1; + + float rgba[][4] = {{ 1.0, 1.0, 1.0, 1.0 }, + { 0.2140, 0.2140, 0.2140, 1.0 }, + { 0, 0, 0, 1.0 }, + { 1, 0, 0, 1.0 }, + { 0.5209, 0.5225, 0, 1.0 }, + { 0, 0.2140, 0, 1.0 }, + { 0.2140, 1, 1, 1.0 }, + { 0.2140, 0.2140, 1, 1.0 }, + { 0.5215, 0.0508, 0.5225, 1.0 }, + { 0.3509, 0.3710, 0.0178, 1.0 }, + { 0.0533, 0.0106, 0.8235, 1.0 }, + { 0.0126, 0.4132, 0.0529, 1.0 }, + { 0.8709, 0.5754, 0.0042, 1.0 }, + { 0.4537, 0.0291, 0.7814, 1.0 }, + { 0.8501, 0.1813, 0.0814, 1.0 }, + { 0.9954, 0.9418, 0.2448, 1.0 }, + { 0.0099, 0.5953, 0.3081, 1.0 }, + { 0.0366, 0.0193, 0.3150, 1.0 }}; + + float hsva[][4] = {{ 0.0, 0.0, 1.0, 1.0 }, + { 0.0, 0.0, 0.5, 1.0 }, + { 0.0, 0.0, 0.0, 1.0 }, + { 0.0, 1.0, 1.0, 1.0 }, + { 0.167, 1.0, 0.75, 1.0 }, + { 0.333, 1.0, 0.5, 1.0 }, + { 0.5, 0.5, 1.0, 1.0 }, + { 0.667, 0.5, 1.0, 1.0 }, + { 0.833, 0.666, 0.75, 1.0 }, + { 0.172, 0.779, 0.643, 1.0 }, + { 0.698, 0.887, 0.918, 1.0 }, + { 0.375, 0.828, 0.675, 1.0 }, + { 0.137, 0.944, 0.941, 1.0 }, + { 0.788, 0.792, 0.897, 1.0 }, + { 0.040, 0.661, 0.931, 1.0 }, + { 0.158, 0.467, 0.998, 1.0 }, + { 0.451, 0.875, 0.795, 1.0 }, + { 0.690, 0.75, 0.597, 1.0 }}; + + babl_init (); + + CHECK_CONV_FLOAT ("rgba to hsva ", float, 0.001, + babl_format ("RGBA float"), + babl_format ("HSVA float"), + rgba, hsva); + + CHECK_CONV_FLOAT ("hsva to rgba ", float, 0.001, + babl_format ("HSVA float"), + babl_format ("RGBA float"), + hsva, rgba); + + babl_exit (); + + return !OK; +} diff --git a/tests/meson.build b/tests/meson.build new file mode 100644 index 0000000..5c68a78 --- /dev/null +++ b/tests/meson.build @@ -0,0 +1,54 @@ + +test_names = [ + 'babl_class_name', + 'cairo_cmyk_hack', + 'cairo-RGB24', + 'cmyk', + 'chromaticities', + 'conversions', + 'extract', + 'floatclamp', + 'float-to-8bit', + 'format_with_space', + 'grayscale_to_rgb', + 'hsl', + 'hsva', + 'models', + 'n_components', + 'n_components_cast', + 'nop', + 'palette', + 'rgb_to_bgr', + 'rgb_to_ycbcr', + 'sanity', + 'srgb_to_lab_u8', + 'transparent', + 'alpha_symmetric_transform', + 'types', +] +if platform_unix + test_names += [ + 'concurrency-stress-test', + 'palette-concurrency-stress-test', + ] +endif + +test_env = environment() +test_env.set('BABL_PATH', babl_extensions_build_dir) + +foreach test_name : test_names + test = executable(test_name, + test_name + '.c', + include_directories: [rootInclude, bablInclude], + link_with: babl, + dependencies: thread, + export_dynamic: true, + install: false, + ) + + test(test_name, + test, + env: test_env, + workdir: meson.current_build_dir(), + ) +endforeach diff --git a/tests/models.c b/tests/models.c new file mode 100644 index 0000000..2920c2f --- /dev/null +++ b/tests/models.c @@ -0,0 +1,34 @@ +/* perform a symmetricality of conversion test on a set of randomized + * RGBA data */ + +#include "config.h" +#include +#include +#include "babl-internal.h" + +int OK = 1; + + +static int model_check (Babl *babl, + void *userdata) +{ + if (!babl_model_is_symmetric (babl)) + { + babl_log ("%s is not symmetric", babl->instance.name); + OK = 0; + } + return 0; +} + + +int main (void) +{ + babl_init (); + + babl_set_extender (babl_extension_quiet_log ()); + babl_model_class_for_each (model_check, NULL); + + babl_exit (); + + return !OK; +} diff --git a/tests/n_components.c b/tests/n_components.c new file mode 100644 index 0000000..afe5d25 --- /dev/null +++ b/tests/n_components.c @@ -0,0 +1,116 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + + +#include "config.h" +#include +#include "babl-internal.h" + +#define PIXELS 7 +#define COMPONENTS 2048 +#define TOLERANCE 0 + +float source_buf [PIXELS * COMPONENTS] = +{ + 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, + 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, + 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, + 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, + 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, + 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, + 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, + 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, + 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, + 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, + 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, + 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, + 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, + 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, + 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, + 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, + /* the rest of the input buffer is nulls */ +}; + +unsigned char reference_buf [PIXELS * COMPONENTS] = +{ + 26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153, + 26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153, + 26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153, + 26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153, + 26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153, + 26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153, + 26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153, + 26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153, + 26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153, + 26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153, + 26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153, + 26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153, + 26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153, + 26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153, + 26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153, + 26, 51, 77, 102, 128, 153, 26, 51, 77, 102, 128, 153, + /* the rest of the reference buffer is nulls */ +}; + +unsigned char destination_buf [PIXELS * COMPONENTS]; + +static int +test (void) +{ + int components; + int OK = 1; + + for (components = 1; components < 2048; components ++) + { + const Babl *fish; + const Babl *src_fmt; + const Babl *dst_fmt; + int i; + + src_fmt = babl_format_n (babl_type ("float"), components); + dst_fmt = babl_format_n (babl_type ("u8"), components); + + fish = babl_fish (src_fmt, dst_fmt); + + babl_process (fish, source_buf, destination_buf, PIXELS); + + for (i = 0; i < PIXELS * components; i++) + { + if (abs (destination_buf[i] - reference_buf[i]) > TOLERANCE) + { + babl_log ("%i-components, pixel %i component %i is %i should be %i", + components, i / components, i % components, destination_buf[i], reference_buf[i]); + OK = 0; + } + } + } + if (!OK) + return -1; + return 0; +} + +int +main (int argc, + char **argv) +{ + babl_init (); + if (test ()) + return -1; + babl_exit (); + return 0; +} diff --git a/tests/n_components_cast.c b/tests/n_components_cast.c new file mode 100644 index 0000000..86c6437 --- /dev/null +++ b/tests/n_components_cast.c @@ -0,0 +1,97 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include +#include +#include +#include "babl.h" +#include "common.inc" + +int +main (int argc, + char **argv) +{ + int OK = 1; + babl_init (); + { + unsigned char in[][4] = {{0,1,2,3 },{4,5,6,7 },{8,9,10,11 }}; + unsigned char out1[][1] = {{0}, {4}, {8} }; + unsigned char out2[][2] = {{0,1}, {4,5}, {8,9} }; + unsigned char out4[][4] = {{0,1,2,3}, {4,5,6,7}, {8,9,10,11} }; + unsigned char out5[][5] = {{0,1,2,3,0}, {4,5,6,7,0},{8,9,10,11,0} }; + + CHECK_CONV("RGBAu8 to n1'", unsigned char, + babl_format("R'G'B'A u8"), + babl_format_n (babl_type ("u8"), 1), + in, out1); + + CHECK_CONV("RGBAu8 to n2'", unsigned char, + babl_format("R'G'B'A u8"), + babl_format_n (babl_type ("u8"), 2), + in, out2); + + CHECK_CONV("RGBAu8 to n4'", unsigned char, + babl_format("R'G'B'A u8"), + babl_format_n (babl_type ("u8"), 4), + in, out4); + + CHECK_CONV("RGBAu8 to n5'", unsigned char, + babl_format("R'G'B'A u8"), + babl_format_n (babl_type ("u8"), 5), + in, out5); + } + { + unsigned char in[][3] = {{0,1,2 },{4,5,6 },{8,9,10 }}; + unsigned char out1[][1] = {{0}, {4}, {8} }; + unsigned char out2[][2] = {{0,1}, {4,5}, {8,9} }; + unsigned char out4[][4] = {{0,1,2,0}, {4,5,6,0}, {8,9,10,0} }; + unsigned char out5[][5] = {{0,1,2,0,0}, {4,5,6,0,0},{8,9,10,0,0} }; + unsigned char out6[][6] = {{0,1,2,0,0,0}, {4,5,6,0,0,0},{8,9,10,0,0,0} }; + + CHECK_CONV("RGBu8 to n1'", unsigned char, + babl_format("R'G'B' u8"), + babl_format_n (babl_type ("u8"), 1), + in, out1); + + + CHECK_CONV("RGBu8 to n2'", unsigned char, + babl_format("R'G'B' u8"), + babl_format_n (babl_type ("u8"), 2), + in, out2); + + + CHECK_CONV("RGBu8 to n4'", unsigned char, + babl_format("R'G'B' u8"), + babl_format_n (babl_type ("u8"), 4), + in, out4); + + CHECK_CONV("RGBu8 to n5'", unsigned char, + babl_format("R'G'B' u8"), + babl_format_n (babl_type ("u8"), 5), + in, out5); + + CHECK_CONV("RGBu8 to n6'", unsigned char, + babl_format("R'G'B' u8"), + babl_format_n (babl_type ("u8"), 6), + in, out6); + } + + babl_exit (); + return !OK; +} diff --git a/tests/nop.c b/tests/nop.c new file mode 100644 index 0000000..0ea6fe0 --- /dev/null +++ b/tests/nop.c @@ -0,0 +1,29 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include "babl.h" + +int +main (int argc, + char **argv) +{ + babl_init (); + babl_exit (); + return 0; +} diff --git a/tests/palette-concurrency-stress-test.c b/tests/palette-concurrency-stress-test.c new file mode 100644 index 0000000..a42b15d --- /dev/null +++ b/tests/palette-concurrency-stress-test.c @@ -0,0 +1,133 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2009 Martin Nordholts + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + + +#include "config.h" + +#include +#include + +#include "babl.h" + + +#define N_THREADS 10 +#define N_PIXELS 1000000 /* (per thread) */ + + +/* should be the same as HASH_TABLE_SIZE in babl/babl-palette.c */ +#define BABL_PALETTE_HASH_TABLE_SIZE 1111 + + +typedef struct +{ + const Babl *fish; + unsigned char src[4 * N_PIXELS]; + unsigned char dest[N_PIXELS]; +} ThreadContext; + + +static void * +thread_proc (void *data) +{ + ThreadContext *ctx = data; + + babl_process (ctx->fish, ctx->src, ctx->dest, N_PIXELS); + + return NULL; +} + +int +main (int argc, + char **argv) +{ + const Babl *pal; + const Babl *pal_format; + unsigned char colors[4 * N_THREADS]; + pthread_t threads[N_THREADS]; + ThreadContext *ctx[N_THREADS]; + int i, j; + int OK = 1; + + babl_init (); + + /* create a palette of N_THREADS different colors, all of which have the same + * hash + */ + pal = babl_new_palette (NULL, &pal_format, NULL); + + for (i = 0; i < N_THREADS; i++) + { + unsigned char *p = &colors[4 * i]; + unsigned int v; + + v = i * BABL_PALETTE_HASH_TABLE_SIZE; + + p[0] = (v >> 0) & 0xff; + p[1] = (v >> 8) & 0xff; + p[2] = (v >> 16) & 0xff; + p[3] = 0xff; + } + + babl_palette_set_palette (pal, babl_format ("R'G'B'A u8"), colors, N_THREADS); + + /* initialize the thread contexts such that each thread processes a buffer + * containing a single, distinct color + */ + for (i = 0; i < N_THREADS; i++) + { + ctx[i] = malloc (sizeof (ThreadContext)); + + ctx[i]->fish = babl_fish (babl_format ("R'G'B'A u8"), pal_format); + + for (j = 0; j < 4 * N_PIXELS; j++) + { + ctx[i]->src[j] = colors[4 * i + j % 4]; + } + } + + /* run all threads at the same time */ + for (i = 0; i < N_THREADS; i++) + { + pthread_create (&threads[i], + NULL, /* attr */ + thread_proc, + ctx[i]); + } + + /* wait for them to finish */ + for (i = 0; i < N_THREADS; i++) + { + pthread_join (threads[i], + NULL /* thread_return */); + } + + /* verify the results */ + for (i = 0; i < N_THREADS; i++) + { + for (j = 0; OK && j < N_PIXELS; j++) + { + OK = (ctx[i]->dest[j] == i); + } + + free (ctx[i]); + } + + babl_exit (); + + return ! OK; +} diff --git a/tests/palette.c b/tests/palette.c new file mode 100644 index 0000000..92651d0 --- /dev/null +++ b/tests/palette.c @@ -0,0 +1,161 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include +#include +#include +#include "babl.h" +#include "common.inc" + +int +main (int argc, + char **argv) +{ + int OK = 1; + babl_init (); + OK = ! babl_format_is_palette (babl_format_n (babl_type ("double"), 3)); + if(1){ + unsigned char in[][1] = {{ 0},{ 1},{ 2},{15}}; + unsigned char out[][4] = {{0,0,0,255},{127,0,0,255},{0,127,0,255},{255,255,255,255}}; + const Babl *palA;// = babl_new_palette (NULL, 0); + //Babl *palB = babl_new_palette (NULL, 0); + // + babl_new_palette (NULL, &palA, NULL); + assert (palA); + + CHECK_CONV("pal to rgba", unsigned char, + palA, babl_format("R'G'B'A u8"), + in, out); + } + { + unsigned char in[][2] = {{ 0,255},{ 1,255},{ 2,255},{15,200}}; + unsigned char out[][4] = {{0,0,0,255},{127,0,0,255},{0,127,0,255},{255,255,255,200}}; + const Babl *palA; + babl_new_palette (NULL, NULL, &palA); + assert (palA); + + CHECK_CONV("palA to rgba", unsigned char, + palA, babl_format("R'G'B'A u8"), + in, out); + } +#if 1 + { + unsigned char in[][4] = {{0,0,0,255},{140,0,0,255},{0,127,0,255}}; + unsigned char out[][1] = {{ 0},{ 1},{ 2}}; + const Babl *palA; + babl_new_palette ("palC", &palA, NULL); + + CHECK_CONV("rgba to pal", unsigned char, + babl_format("R'G'B'A u8"), palA, + in, out); + } + + { + unsigned char in[][4] = {{0,0,0,255},{140,0,0,255},{0,127,0,127}}; + unsigned char out[][2] = {{ 0,255},{ 1,255},{ 2,127}}; + const Babl *pal; + babl_new_palette ("palC", NULL, &pal); + + CHECK_CONV("rgba to pal+alpha", unsigned char, + babl_format("R'G'B'A u8"), pal, + in, out); + } + + /* check with a custom floating point palette, _and_ alpha component */ + { + float palette[] = { + 0.5, 1.0, + 0.23, 0.42, + 1.0, 0.2 + }; + + unsigned char in[][2] = {{ 0,255},{0,127},{ 1,255},{ 2,255}}; + unsigned char out[][4] = {{128,128,128,255},{128,128,128,127},{59,59,59,107},{255,255,255,51}}; + + const Babl *pal; + babl_new_palette (NULL, NULL, &pal); + + babl_palette_set_palette (pal, babl_format ("YA float"), palette, 3); + + CHECK_CONV("rgba to YA float pal+alpha", unsigned char, + pal, babl_format("RGBA u8"), + in, out); + } + + /* check with a custom floating point palette, _and_ alpha component */ + { + float palette[] = { + 0.5, 1.0, + 0.23, 0.42, + 1.0, 0.2 + }; + + unsigned char in[][2] = {{ 0,255},{0,127},{ 1,255},{ 2,255}}; + unsigned char out[][4] = {{128,128,128,255},{128,128,128,127},{59,59,59,107},{255,255,255,51}}; + + const Babl *pal; + babl_new_palette (NULL, NULL, &pal); + + babl_palette_set_palette (pal, babl_format ("YA float"), palette, 3); + + CHECK_CONV("rgba to YA float pal+alpha", unsigned char, + pal, babl_format("RGBA u8"), + in, out); + } + + /* check with a custom floating point palette */ + { + float palette[] = { + 0.5, 1.0, + 0.23, 0.42, + 1.0, 0.2 + }; + + unsigned char in[][1] = {{ 0},{ 1},{ 2}}; + unsigned char out[][4] = {{128,128,128,255},{59,59,59,107},{255,255,255,51}}; + + const Babl *pal; + babl_new_palette (NULL, &pal, NULL); + + babl_palette_set_palette (pal, babl_format ("YA float"), palette, 3); + + CHECK_CONV("rgba to float pal", unsigned char, + pal, babl_format("RGBA u8"), + in, out); + + { + const Babl *p2; + p2 = babl_format_with_space ((void*)pal, babl_space ("ACEScg")); + + + CHECK_CONV("rgba to float pal", unsigned char, + p2, babl_format("RGBA u8"), + in, out); + + + } + + } +#endif + + + + babl_exit (); + return !OK; +} diff --git a/tests/rgb_to_bgr.c b/tests/rgb_to_bgr.c new file mode 100644 index 0000000..4e63222 --- /dev/null +++ b/tests/rgb_to_bgr.c @@ -0,0 +1,90 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + + +#include "config.h" +#include +#include "babl-internal.h" + +#define PIXELS 3 +#define TOLERANCE 0 + +unsigned char source_buf [PIXELS * 3] = +{ 10, 20, 30, + 30, 30, 30, + 40, 50, 60 }; + +unsigned char reference_buf [PIXELS * 3] = +{ 30, 20, 10, + 30, 30, 30, + 60, 50, 40 }; + +unsigned char destination_buf [PIXELS * 3]; + +static int +test (void) +{ + const Babl *fish; + int i; + int OK = 1; + + fish = babl_fish ( + babl_format_new ( + babl_model ("RGB"), + babl_type ("u8"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + NULL + ), + babl_format_new ( + babl_model ("RGB"), + babl_type ("u8"), + babl_component ("B"), + babl_component ("G"), + babl_component ("R"), + NULL + ) + ); + + babl_process (fish, source_buf, destination_buf, PIXELS); + + for (i = 0; i < PIXELS * 3; i++) + { + if (abs (destination_buf[i] - reference_buf[i]) > TOLERANCE) + { + babl_log ("%2i (%2i%%3=%i, %2i/3=%i) is %i should be %i", + i, i, i % 3, i, i / 3, destination_buf[i], reference_buf[i]); + OK = 0; + } + } + if (!OK) + return -1; + return 0; +} + +int +main (int argc, + char **argv) +{ + babl_init (); + if (test ()) + return -1; + babl_exit (); + return 0; +} diff --git a/tests/rgb_to_ycbcr.c b/tests/rgb_to_ycbcr.c new file mode 100644 index 0000000..c02f743 --- /dev/null +++ b/tests/rgb_to_ycbcr.c @@ -0,0 +1,97 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + + +#include "config.h" +#include +#include "babl-internal.h" + +#define PIXELS 6 +#define TOLERANCE 0.000001 + +float source_buf [PIXELS * 3] = +{ 0.0, 0.0, 0.0, + 0.5, 0.5, 0.5, + 1.0, 1.0, 1.0, + 1.0, 0.0, 0.0, + 0.0, 1.0, 0.0, + 0.0, 0.0, 1.0 }; + +float reference_buf [PIXELS * 3] = +{ 0.0, 0.0, 0.0, + 0.735357, 0.0, 0.0, + 1.0, 0.0, 0.0, + 0.299, -0.168736, 0.5, + 0.587, -0.331264, -0.418688, + 0.114, 0.5, -0.081312 }; + + +float destination_buf [PIXELS * 3]; + +static int +test (void) +{ + const Babl *fish; + int i; + int OK = 1; + + fish = babl_fish ( + babl_format_new ( + babl_model ("RGB"), + babl_type ("float"), + babl_component ("R"), + babl_component ("G"), + babl_component ("B"), + NULL + ), + babl_format_new ( + babl_model ("Y'CbCr"), + babl_type ("float"), + babl_component ("Y'"), + babl_component ("Cb"), + babl_component ("Cr"), + NULL + ) + ); + + babl_process (fish, source_buf, destination_buf, PIXELS); + + for (i = 0; i < PIXELS * 3; i++) + { + if (fabs (destination_buf[i] - reference_buf[i]) > TOLERANCE) + { + babl_log ("%2i (%2i%%3=%i, %2i/3=%i) is %f should be %f", + i, i, i % 3, i, i / 3, destination_buf[i], reference_buf[i]); + OK = 0; + } + } + if (!OK) + return -1; + return 0; +} + +int +main (int argc, + char **argv) +{ + babl_init (); + if (test ()) + return -1; + babl_exit (); + return 0; +} diff --git a/tests/sanity.c b/tests/sanity.c new file mode 100644 index 0000000..28158ee --- /dev/null +++ b/tests/sanity.c @@ -0,0 +1,31 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include "babl-internal.h" + +int +main (int argc, + char **argv) +{ + babl_init (); + if (!babl_sanity ()) + return -1; + babl_exit (); + return 0; +} diff --git a/tests/srgb_to_lab_u8.c b/tests/srgb_to_lab_u8.c new file mode 100644 index 0000000..b99538f --- /dev/null +++ b/tests/srgb_to_lab_u8.c @@ -0,0 +1,77 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include +#include +#include + +#define PIXELS 6 +#define TOLERANCE 0 + +unsigned char source_buf [PIXELS * 3] = +{ 0, 0, 0, + 127, 127, 127, + 255, 255, 255, + 255, 0.0, 0.0, + 0.0, 255, 0.0, + 0.0, 0.0, 255 }; + +unsigned char reference_buf [PIXELS * 3] = +{ 0, 128, 128, + 136, 128, 128, + 255, 128, 128, + 138, 209, 198, + 224, 49, 209, + 75, 196, 16 }; + +unsigned char destination_buf [PIXELS * 3]; + +static int +test (void) +{ + int i; + int OK = 1; + + babl_process (babl_fish ("R'G'B' u8", "CIE Lab u8"), + source_buf, destination_buf, + PIXELS); + + for (i = 0; i < PIXELS * 3; i++) + { + if (fabs (1.0 * destination_buf[i] - reference_buf[i]) > TOLERANCE) + { + fprintf (stderr, "%2i (%2i%%3=%i, %2i/3=%i) is %i should be %i", + i, i, i % 3, i, i / 3, destination_buf[i], reference_buf[i]); + OK = 0; + } + } + if (!OK) + return -1; + return 0; +} + +int +main (int argc, + char **argv) +{ + babl_init (); + if (test ()) + return -1; + babl_exit (); + return 0; +} diff --git a/tests/transparent.c b/tests/transparent.c new file mode 100644 index 0000000..7cbc6ea --- /dev/null +++ b/tests/transparent.c @@ -0,0 +1,80 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +/* Verify that conversion of fully-transparent pixels preserves color + * information, when relevant for the source and destination formats. + * In particular, make sure that the conversion path doesn't pass + * through a format with premultiplied alpha. See bug #780016. + * + * Note that this test can, and will, result in false positives; i.e., + * if the test passes, it means nothing -- we only watch for the + * occasional failure. Fun, right? + */ + +#include "config.h" +#include +#include +#include +#include "babl-internal.h" + +#include "common.inc" + + +#define NUMBER_OF_TRIALS 50 + +static void +clear_fish_db (void) +{ + /* so ugly... */ + *babl_fish_db () = *babl_db_init (); +} + +int +main (int argc, + char **argv) +{ + int OK = 1; + int i; + + babl_init (); + + for (i = 0; OK && i < NUMBER_OF_TRIALS; i++) + { + clear_fish_db (); + + { + uint16_t in [][4] = {{0xffff, 0xffff, 0xffff, 0}}; + float out[][4] = {{1.0, 1.0, 1.0, 0.0}}; + + /* this conversion is known to have been problematic. + * see bug #780016. + */ + CHECK_CONV_FLOAT ("u16' -> float", float, 0.001, + babl_format("R'G'B'A u16"), + babl_format("RGBA float"), + in, out); + } + } + + /* be nice and don't overwrite the fish cache, since we cleared all the + * fishes. + */ + /* babl_exit (); */ + + return !OK; +} diff --git a/tests/types.c b/tests/types.c new file mode 100644 index 0000000..1b86cea --- /dev/null +++ b/tests/types.c @@ -0,0 +1,28 @@ +#include "config.h" +#include +#include "babl-internal.h" + +int OK = 1; + +static int type_check (Babl *babl, + void *userdata) +{ + if (!babl_type_is_symmetric (babl)) + { + babl_log ("%s is not symmetric", babl->instance.name); + OK = 0; + } + return 0; +} + +int main (void) +{ + babl_init (); + + babl_set_extender (babl_extension_quiet_log ()); + babl_type_class_for_each (type_check, NULL); + + babl_exit (); + + return !OK; +} diff --git a/tools/babl-benchmark.c b/tools/babl-benchmark.c new file mode 100644 index 0000000..1fd9e78 --- /dev/null +++ b/tools/babl-benchmark.c @@ -0,0 +1,196 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, 2017 Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include +#include "babl-internal.h" + +#ifndef HAVE_SRANDOM +#define srandom srand +#define random rand +#endif + +int ITERATIONS = 1; +#define N_PIXELS (512*1024) // a too small batch makes the test set live + // in l2 cache skewing results + + // we could also add a cache purger.. + + +#define N_BYTES N_PIXELS * (4 * 8) + +static const char * +unicode_hbar (int width, + double fraction) +{ + static char ret[200]=""; + const char *block[9]= {" ", "▏", "▎", "▍", "▌", "▋", "▊", "▉","█"}; + int i; + if (width > 100) width = 100; + + ret[0]=0; + for (i = 0; i < width; i++) + { + double start = i * 1.0 / width; + if (start < fraction) + strcat (ret, block[8]); + else + { + double miss = (start - fraction) * width; + if (miss < 1.0) + strcat (ret, block[(int)((1.0-miss) * 8.999)]); + else + strcat (ret, block[0]); + } + } + return ret; +} + +static int +test (void) +{ + int i, j; + int OK = 1; + + char *src_data = babl_malloc (N_BYTES); + char *dst_data = babl_malloc (N_BYTES); + double sum = 0; + + + const Babl *formats[]={ +#if 0 + babl_format("R'G'B'A u8"), + babl_format("Y float"), + babl_format("R'G'B'A u16"), + babl_format_with_space("RGBA float", babl_space("ProPhoto")), + babl_format_with_space("R'G'B' u16", babl_space("ProPhoto")), +#endif + //babl_format("R'G'B'A u8"), + babl_format("R'G'B'A u16"), + //babl_format_with_space("R'G'B'A u8", babl_space("ProPhoto")), + //babl_format_with_space("Y'A u8", babl_space("ProPhoto")), + babl_format_with_space("Y'A u16", babl_space("ProPhoto")), + babl_format_with_space("Y' u16", babl_space("ProPhoto")), + //babl_format_with_space("Y' u8", babl_space("ProPhoto")), + babl_format_with_space("Y float", babl_space("ProPhoto")), + babl_format_with_space("YaA float", babl_space("ProPhoto")), + babl_format_with_space("YA float", babl_space("ProPhoto")), + //babl_format_with_space("YA u16", babl_space("ProPhoto")), + //babl_format_with_space("R'G'B'A half", babl_space("ProPhoto")), + babl_format_with_space("R'G'B'A float", babl_space("ProPhoto")), + babl_format_with_space("RaGaBaA float", babl_space("ProPhoto")), + babl_format_with_space("cairo-RGB24", babl_space("Adobe")), + babl_format_with_space("cairo-ARGB32", babl_space("Adobe")), + + }; + int n_formats = sizeof (formats) / sizeof (formats[0]); + const Babl *fishes[50 * 50]; + double mbps[50 * 50] = {0,}; + long n; + double max = 0.0; + + assert (n_formats < 50); + + for (i = 0; i < N_BYTES; i++) + src_data[i] = random(); + + + fprintf (stdout,"%i iterations of %i pixels, mb/s is for sum of source and destinations bytes\n", ITERATIONS, N_PIXELS); + + n = 0; + for (i = 0; i < n_formats; i++) + for (j = 0; j < n_formats; j++) + if (i != j) + { + const Babl *fish = babl_fish (formats[i], formats[j]); + long end, start; + int iters = ITERATIONS; + + fprintf (stderr, "%s to %s \r", babl_get_name (formats[i]), + babl_get_name (formats[j])); + fflush (0); + + /* a quarter round of warmup */ + babl_process (fish, src_data, dst_data, N_PIXELS * 0.25); + start = babl_ticks (); + while (iters--) + { + babl_process (fish, src_data, dst_data, N_PIXELS); + } + end = babl_ticks (); + fishes[n] = fish; + mbps [n] = (babl_format_get_bytes_per_pixel (formats[i]) + + babl_format_get_bytes_per_pixel (formats[j])) * + (N_PIXELS * ITERATIONS / 1024.0 / 1024.0) / ((end-start)/(1000.0*1000.0)); + + sum += mbps[n]; + if (mbps[n] > max) + max = mbps[n]; + n++; + } + + n = 0; + for (i = 0; i < n_formats; i++) + for (j = 0; j < n_formats; j++) + if (i != j) + { + fprintf (stdout, "%s %03.1f mb/s\t%s to %s %.9f", + unicode_hbar(16, mbps[n] / max), + mbps[n], + babl_get_name (formats[i]), + babl_get_name (formats[j]), + fishes[n]->fish.error); + if (fishes[n]->class_type == BABL_FISH_REFERENCE) + { + fprintf (stdout, "[R]"); + } + else if (fishes[n]->class_type == BABL_FISH_PATH) + { + int k; + //fprintf (stdout, "[%d]", fishes[n]->fish_path.conversion_list->count); + for (k = 0; k < fishes[n]->fish_path.conversion_list->count; k++) + { + fprintf (stdout, "\n\t\t\t\t%s", babl_get_name ( + fishes[n]->fish_path.conversion_list->items[k])); + } + } + fprintf (stdout, "\n"); + n++; + } + fprintf (stdout, "\n%s %03.1f mb/s\taverage\n", + unicode_hbar(16, sum / (n_formats * n_formats - n_formats) / max), + sum / (n_formats * n_formats - n_formats)); + + fflush (0); + + if (!OK) + return -1; + return 0; +} + +int +main (int argc, + char **argv) +{ + if (argv[1]) ITERATIONS = atoi (argv[1]); + babl_init (); + if (test ()) + return -1; + babl_exit (); + return 0; +} diff --git a/tools/babl-gen-test-pixels.c b/tools/babl-gen-test-pixels.c new file mode 100644 index 0000000..7130e56 --- /dev/null +++ b/tools/babl-gen-test-pixels.c @@ -0,0 +1,204 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005 Øyvind Kolås + * 2013 Daniel Sabo + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include +#include + +#ifndef HAVE_SRANDOM +#define srandom srand +#define random rand +#endif + +#define BABL_PATH_NUM_TEST_PIXELS 3072 +#define BABL_CONVERSION_NUM_TEST_PIXELS 128 +#define BABL_FROMAT_NUM_TEST_PIXELS 256 +#define BABL_MODEL_NUM_TEST_PIXELS 512 +#define BABL_TYPE_NUM_TEST_PIXELS 512 + +#define BABL_COMPONENT_FMT_STR "%.13f" +#define BABL_PIXEL_FMT_STR BABL_COMPONENT_FMT_STR ", " \ + BABL_COMPONENT_FMT_STR ", " \ + BABL_COMPONENT_FMT_STR ", " \ + BABL_COMPONENT_FMT_STR + +static double +rand_double (void) +{ + return (double) random () / RAND_MAX; +} + +static double +rand_range_double (double min, + double max) +{ + return rand_double () * (max - min) + min; +} + +static void +gen_path_pixels (void) +{ + int i; + srandom (20050728); + + printf ("static const int babl_num_path_test_pixels = %d;\n\n", BABL_PATH_NUM_TEST_PIXELS); + + printf ("static const double babl_path_test_pixels[%d] = {\n", BABL_PATH_NUM_TEST_PIXELS * 4); + + /* add 256 pixels in the valid range between 0.0 and 1.0 */ + for (i = 0; i < 256; i++) + { + printf (BABL_PIXEL_FMT_STR ",\n", + rand_double (), + rand_double (), + rand_double (), + rand_double ()); + } + + /* add 16 pixels between -1.0 and 0.0 */ + for (i = 0; i < 16; i++) + { + printf (BABL_PIXEL_FMT_STR ",\n", + rand_range_double (-1.0, 0.0), + rand_range_double (-1.0, 0.0), + rand_range_double (-1.0, 0.0), + rand_range_double (-1.0, 0.0)); + } + + /* add 16 pixels between 1.0 and 2.0 */ + for (i = 0; i < 16; i++) + { + printf (BABL_PIXEL_FMT_STR ",\n", + rand_range_double (1.0, 2.0), + rand_range_double (1.0, 2.0), + rand_range_double (1.0, 2.0), + rand_range_double (1.0, 2.0)); + } + + /* add 16 pixels with an alpha of 0.0, to penalize conversions that + * destroy color information of fully-transparent pixels, when + * relevant. see bug #780016. + */ + for (i = 0; i < 16; i++) + { + printf (BABL_PIXEL_FMT_STR ",\n", + rand_double (), + rand_double (), + rand_double (), + 0.0); + } + + for (i = 304; i < BABL_PATH_NUM_TEST_PIXELS; i++) + { + printf (BABL_PIXEL_FMT_STR ",\n", + rand_double (), + rand_double (), + rand_double (), + rand_double ()); + } + + printf ("};\n\n"); + + printf ("static const int babl_num_conversion_test_pixels = %d;\n\n", BABL_CONVERSION_NUM_TEST_PIXELS); + + printf ("static const double *babl_conversion_test_pixels = babl_path_test_pixels;\n\n"); + + printf ("static const int babl_num_format_test_pixels = %d;\n\n", BABL_FROMAT_NUM_TEST_PIXELS); + + printf ("static const double *babl_format_test_pixels = babl_path_test_pixels;\n\n"); +} + +static void +gen_model_pixels (void) +{ + int i; + srandom (20050728); + + printf ("static const int babl_num_model_test_pixels = %d;\n\n", BABL_MODEL_NUM_TEST_PIXELS); + + printf ("static const double babl_model_test_pixels[%d] = {\n", BABL_MODEL_NUM_TEST_PIXELS * 4); + + /* add 128 pixels in the valid range between 0.0 and 1.0 */ + for (i = 0; i < BABL_MODEL_NUM_TEST_PIXELS; i++) + { + printf (BABL_PIXEL_FMT_STR ",\n", + rand_range_double (-0.2, 1.2), + rand_range_double (-0.2, 1.2), + rand_range_double (-0.2, 1.2), + rand_range_double (-0.2, 1.2)); + } + + printf ("};\n\n"); +} + +static void +gen_type_pixels (void) +{ + int i; + srandom (20050728); + + printf ("static const int babl_num_type_test_pixels = %d;\n\n", BABL_TYPE_NUM_TEST_PIXELS); + + printf ("static const double babl_type_test_pixels[%d] = {\n", BABL_TYPE_NUM_TEST_PIXELS * 4); + + /* add 128 pixels in the valid range between 0.0 and 1.0 */ + for (i = 0; i < BABL_MODEL_NUM_TEST_PIXELS; i++) + { + printf (BABL_PIXEL_FMT_STR ",\n", + rand_range_double (0.0, 128.0), + rand_range_double (0.0, 128.0), + rand_range_double (0.0, 128.0), + rand_range_double (0.0, 128.0)); + } + + printf ("};\n\n"); +} + +int +main (int argc, + char **argv) +{ + printf ( + "/* babl - dynamically extendable universal pixel conversion library.\n" + " * Copyright (C) 2005 Øyvind Kolås\n" + " * 2013 Daniel Sabo\n" + " *\n" + " * This library is free software; you can redistribute it and/or\n" + " * modify it under the terms of the GNU Lesser General Public\n" + " * License as published by the Free Software Foundation; either\n" + " * version 3 of the License, or (at your option) any later version.\n" + " *\n" + " * This library is distributed in the hope that it will be useful,\n" + " * but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n" + " * Lesser General Public License for more details.\n" + " *\n" + " * You should have received a copy of the GNU Lesser General\n" + " * Public License along with this library; if not, see\n" + " * .\n" + " */\n" + "\n"); + + printf ("/* THIS IS A GENERATED FILE - DO NOT EDIT */\n\n"); + + gen_path_pixels (); + gen_model_pixels (); + gen_type_pixels (); + + return 0; +} diff --git a/tools/babl-html-dump.c b/tools/babl-html-dump.c new file mode 100644 index 0000000..1a1545c --- /dev/null +++ b/tools/babl-html-dump.c @@ -0,0 +1,293 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + * + */ + +#include "config.h" +#include "babl-internal.h" /* needed for babl_log */ + +static void +model_html (Babl *babl); + +static void +type_html (Babl *babl); + +static void +format_html (Babl *babl); + +static void +space_html (Babl *babl); + +static void +conversion_html (Babl *babl); + +static int +each_item (Babl *babl, + void *user_data); + +int +main (void) +{ + babl_init (); + + printf ("
"); + printf ("

Types

"); + babl_type_class_for_each (each_item, NULL); + printf ("
\n"); + + printf ("
"); + printf ("

Models

"); + babl_model_class_for_each (each_item, NULL); + printf ("
\n"); + + + printf ("
"); + printf ("

Pixelformats

"); + babl_format_class_for_each (each_item, NULL); + printf ("
\n"); + +/* + printf ("
"); + printf ("
\n"); + babl_conversion_each (each_item, NULL); + printf ("
\n"); + printf ("
\n"); + */ + babl_exit (); + + return 0; +} + + +static char normalized_buf[512]; + +static const char * +normalize (const char *str) +{ + char *s = normalized_buf; + + strcpy (normalized_buf, str); + + while (*s) + { + if ((*s >= 'a' && *s <= 'z') || + (*s >= 'A' && *s <= 'Z') || + (*s >= '0' && *s <= '9')) + { + } + else if (*s == '~') + { + } + else + { + *s = '_'; + } + s++; + } + return normalized_buf; +} + + +static int +each_item (Babl *babl, + void *user_data) +{ + const char *fun_pre = "babl_type"; + const char *fun_post = ")"; + + switch (babl->class_type) + { + case BABL_MODEL: fun_pre = "babl_model"; break; + case BABL_FORMAT: fun_pre = "babl_format_with_space"; + fun_post = ", space|NULL)"; + break; + } + + printf ("
\n", + normalize (babl->instance.name), + normalize (babl->instance.name), + fun_pre, + babl->instance.name, + fun_post); + printf ("
"); + + + switch (babl->class_type) + { + case BABL_TYPE: + type_html (babl); + break; + + case BABL_MODEL: + model_html (babl); + break; + + case BABL_FORMAT: + format_html (babl); + break; + + case BABL_SPACE: + space_html (babl); + break; + + case BABL_CONVERSION: + case BABL_CONVERSION_LINEAR: + case BABL_CONVERSION_PLANE: + case BABL_CONVERSION_PLANAR: + conversion_html (babl); + break; + + default: + break; + } + + printf ("
\n"); + printf ("
\n"); + return 0; +} + +static void +model_doc (const Babl *babl) +{ + if (babl->instance.doc) + printf ("%s", babl->instance.doc); + else + { + BablModelFlag flags = babl_get_model_flags (babl); + if (flags & BABL_MODEL_FLAG_RGB) + { + printf ("RGB"); + + if (flags & BABL_MODEL_FLAG_LINEAR) + printf (" linear"); + if (flags & BABL_MODEL_FLAG_NONLINEAR) + printf (" with TRC from space"); + if (flags & BABL_MODEL_FLAG_PERCEPTUAL) + printf (" with perceptual (sRGB) TRC"); + } + else if (flags & BABL_MODEL_FLAG_GRAY) + { + if (flags & BABL_MODEL_FLAG_LINEAR) + printf (" Luminance"); + if (flags & BABL_MODEL_FLAG_NONLINEAR) + printf (" Grayscale with TRC from space"); + if (flags & BABL_MODEL_FLAG_PERCEPTUAL) + printf (" Grayscale with perceptual (sRGB) TRC"); + } + else if (flags & BABL_MODEL_FLAG_CMYK) + { + if (flags & BABL_MODEL_FLAG_INVERTED) + printf ("CMYK with inverted color components (0.0=full coverage), for additive compositing"); + else + printf ("CMYK"); + } + + if (flags & BABL_MODEL_FLAG_ALPHA) + { + if (flags & BABL_MODEL_FLAG_ASSOCIATED) + { + printf (", associated alpha"); + } + else + { + printf (", separate alpha"); + } + } + + } +} + + +static void +model_html (Babl *babl) +{ + int i; + printf ("

"); + model_doc (babl); + printf ("

"); + + printf ("
"); + printf ("
components
"); + + for (i = 0; i < babl->model.components; i++) + { + printf ("", + BABL (babl->model.component[i])->instance.name); + } + printf ("
%s
"); +} + +static void +type_html (Babl *babl) +{ + if (babl->instance.doc) + printf ("

%s

", babl->instance.doc); + + printf ("
bits
%i
", babl->type.bits); + printf ("
bytes
%i
", babl->type.bits / 8); +} + + +static void +conversion_html (Babl *babl) +{ + printf ("%s
\n", babl->instance.name); +} + +static void +space_html (Babl *babl) +{ + printf ("%s
\n", babl->instance.name); +} + +static void +format_html (Babl *babl) +{ + int i; + const Babl *model = BABL (babl->format.model); + + printf ("

"); + if (babl->instance.doc) + printf ("%s", babl->instance.doc); + else + { + //const Babl *type = BABL (babl->format.type[0]); + model_doc (model); + //if (type->instance.doc) + // printf (" %s", type->instance.doc); + //else + // printf (" %s", type->instance.name); + } + printf ("

"); + + printf ("
"); + printf ("
bytes/pixel
%i
", babl->format.bytes_per_pixel); + printf ("
model
%s
", + normalize( BABL (babl->format.model)->instance.name), + BABL (babl->format.model)->instance.name); + printf ("
components
"); + + for (i = 0; i < babl->format.components; i++) + { + printf ("", + normalize(BABL (babl->format.type[i])->instance.name), + BABL (babl->format.type[i])->instance.name, + BABL (babl->format.component[i])->instance.name); + } + printf ("
%s%s
"); +} + diff --git a/tools/babl-icc-dump.c b/tools/babl-icc-dump.c new file mode 100644 index 0000000..b90590b --- /dev/null +++ b/tools/babl-icc-dump.c @@ -0,0 +1,719 @@ +#include +#include +#include +#include + +static int +file_get_contents (const char *path, + char **contents, + long *length, + void *error); + +typedef struct { + int16_t integer; + uint16_t fraction; +} s15f16_t; + +typedef struct { + int16_t integer; + uint16_t fraction; +} u8f8_t; + +#define ICC_HEADER_LEN 128 +#define TAG_COUNT_OFF ICC_HEADER_LEN + +static int +load_u8 (const char *icc, + int length, + int offset) +{ +/* all reading functions take both the char *pointer and the length of the + * buffer, and all reads thus gets protected by this condition. + */ + if (offset < 0 || offset > length) + return 0; + + return *(uint8_t*) (&icc[offset]); +} + +static int +load_s8 (const char *icc, + int length, + int offset) +{ + if (offset < 0 || offset > length) + return 0; + + return *(int8_t*) (&icc[offset]); +} + +static int16_t +load_u1f15 (const char *icc, + int length, + int offset) +{ + return load_u8 (icc, length, offset + 1) + + (load_s8 (icc, length, offset + 0) << 8); +} + +static uint16_t +load_u16 (const char *icc, + int length, + int offset) +{ + return load_u8 (icc, length, offset + 1) + + (load_u8 (icc, length, offset + 0) << 8); +} + +static u8f8_t +load_u8f8_ (const char *icc, + int length, + int offset) +{ + u8f8_t ret ={load_u8 (icc, length, offset), + load_u8 (icc, length, offset + 1)}; + return ret; +} + +static s15f16_t +load_s15f16_ (const char *icc, + int length, + int offset) +{ + s15f16_t ret ={load_u1f15 (icc, length, offset), + load_u16 (icc, length, offset + 2)}; + return ret; +} + +static double +s15f16_to_d (s15f16_t fix) +{ + return fix.integer + fix.fraction / 65535.0; +} + +static double +u8f8_to_d (u8f8_t fix) +{ + return fix.integer + fix.fraction / 255.0; +} + +static double +load_s15f16 (const char *icc, + int length, + int offset) +{ + return s15f16_to_d (load_s15f16_ (icc, length, offset)); +} + +static double +load_u8f8 (const char *icc, + int length, + int offset) +{ + return u8f8_to_d (load_u8f8_ (icc, length, offset)); +} + +static void +print_u8f8 (u8f8_t fix) +{ + int i; + uint32_t foo; + foo = fix.fraction; + fprintf (stdout, "%i.", fix.integer); + for (i = 0; i < 18; i++) + { + foo *= 10; + fprintf (stdout, "%i", (foo / 256) % 10); + foo = foo & 0xff; + } +} + +static void +print_s15f16 (s15f16_t fix) +{ + int i; + uint32_t foo; + foo = fix.fraction; + if (fix.integer < 0) + { + if (fix.integer == -1) + fprintf (stdout, "-"); + fprintf (stdout, "%i.", fix.integer + 1); + foo = 65535-fix.fraction; + for (i = 0; i < 18; i++) + { + foo *= 10; + fprintf (stdout, "%i", (foo / 65536) % 10); + foo = foo & 0xffff; + } + } + else + { + fprintf (stdout, "%i.", fix.integer); + for (i = 0; i < 18; i++) + { + foo *= 10; + fprintf (stdout, "%i", (foo / 65536) % 10); + foo = foo & 0xffff; + } + } +} + +static uint32_t +load_u32 (const char *icc, + int length, + int offset) +{ + return load_u8 (icc, length, offset + 3) + + (load_u8 (icc, length, offset + 2) << 8) + + (load_u8 (icc, length, offset + 1) << 16) + + (load_u8 (icc, length, offset + 0) << 24); +} + +static void +load_sign (const char *icc, + int length, + int offset, + char *sign) +{ + sign[0]=load_u8(icc, length, offset); + sign[1]=load_u8(icc, length, offset + 1); + sign[2]=load_u8(icc, length, offset + 2); + sign[3]=load_u8(icc, length, offset + 3); + sign[4]=0; +} + +/* looks up offset and length for a specific icc tag + */ +static int +icc_tag (const char *icc, + int length, + const char *tag, + int *offset, + int *el_length) +{ + int tag_count = load_u32 (icc, length, TAG_COUNT_OFF); + int t; + + for (t = 0; t < tag_count; t++) + { + char tag_signature[5]; + load_sign (icc, length, TAG_COUNT_OFF + 4 + 12 * t, tag_signature); + if (!strcmp (tag_signature, tag)) + { + if (offset) + *offset = load_u32 (icc, length, TAG_COUNT_OFF + 4 + 12* t + 4); + if (el_length) + *el_length = load_u32 (icc, length, TAG_COUNT_OFF + 4 + 12* t + 4*2); + return 1; + } + } + return 0; +} + +#if 0 + +#define ICC_HEADER_LEN 128 +#define TAG_COUNT_OFF ICC_HEADER_LEN + +static int load_u8 (const char *icc, int offset) +{ + return *(uint8_t*) (&icc[offset]); +} + +static int16_t load_u1Fixed15 (const char *icc, int offset) +{ + return load_u8 (icc, offset + 1) + + (load_u8 (icc, offset + 0) << 8); +} + +static uint16_t load_u16 (const char *icc, int offset) +{ + return load_u8 (icc, offset + 1) + + (load_u8 (icc, offset + 0) << 8); +} + +static double load_s15f16 (const char *icc, int offset) +{ + return load_u1Fixed15 (icc, offset) + load_u16 (icc, offset + 2) / 65535.0f; +} + +static double load_u16f16 (const char *icc, int offset) +{ + return load_u16 (icc, offset) + load_u16 (icc, offset + 2) / 65535.0; +} + +static uint32_t load_u32 (const char *icc, int offset) +{ + return load_u8 (icc, offset + 3) + + (load_u8 (icc, offset + 2) << 8) + + (load_u8 (icc, offset + 1) << 16) + + (load_u8 (icc, offset + 0) << 24); +} + +static float load_float32 (const char *icc, int offset) +{ + char buf[4]={load_u8 (icc, offset + 3), + load_u8 (icc, offset + 2), + load_u8 (icc, offset + 1), + load_u8 (icc, offset + 0)}; + float *val = (float*)(&buf[0]); + return *val; +} + +static uint64_t load_uint64 (const char *icc, int offset) +{ + return ((uint64_t)load_u8 (icc, offset + 7) << (8*0)) + + ((uint64_t)load_u8 (icc, offset + 6) << (8*1)) + + ((uint64_t)load_u8 (icc, offset + 5) << (8*2)) + + ((uint64_t)load_u8 (icc, offset + 4) << (8*3)) + + ((uint64_t)load_u8 (icc, offset + 3) << (8*4)) + + ((uint64_t)load_u8 (icc, offset + 2) << (8*5)) + + ((uint64_t)load_u8 (icc, offset + 1) << (8*6)) + + ((uint64_t)load_u8 (icc, offset + 0) << (8*7)); +} + +static void load_sign (const char *icc, int offset, char *sign) +{ + sign[0]=load_u8(icc, offset); + sign[1]=load_u8(icc, offset + 1); + sign[2]=load_u8(icc, offset + 2); + sign[3]=load_u8(icc, offset + 3); + sign[4]=0; +} + +static int icc_tag (const char *icc, const char *tag, int *offset, int *length) +{ + int tag_count = load_u32 (icc, TAG_COUNT_OFF); + int profile_size = load_u32 (icc, 0); + int t; + + for (t = 0; t < tag_count; t++) + { + char tag_signature[5]; + load_sign (icc, TAG_COUNT_OFF + 4 + 12 * t, tag_signature); + if (!strcmp (tag_signature, tag)) + { + *offset = load_u32 (icc, TAG_COUNT_OFF + 4 + 12* t + 4); + *length = load_u32 (icc, TAG_COUNT_OFF + 4 + 12* t + 4 * 2); + /* avert potential for maliciousnes.. */ + if (*offset >= profile_size) + { + *offset = profile_size - 1; + } + if (*offset + *length >= profile_size) + { + *length = profile_size - *offset - 1; + } + return 1; + } + } + return 0; +} +#endif + +int exact = 0; + +static int +load_icc_from_memory (const char *icc, + long length, + char **error) +{ + int tag_count = load_u32 (icc, length, TAG_COUNT_OFF); + int profile_size = load_u32 (icc, length, 0); + int profile_version_major = load_u8 (icc, length, 8); + int profile_version_minor = load_u8 (icc, length, 9) >> 4; + int profile_version_micro = load_u8 (icc, length, 9) & 0xf; + char profile_class[5]; + char color_space[5]; + char pcs_space[5]; + int rendering_intent = load_u32 (icc, length, 64); + int t; + // 64..67 rendering intent + // 68..79 XYZ of D50 + + load_sign (icc, length, 16, color_space); + load_sign (icc, length, 20, pcs_space); + load_sign (icc, length, 12, profile_class); + + if (strcmp (profile_class, "mntr")) + { + *error = "not a monitor-class profile"; + return -1; + } + if (strcmp (color_space, "RGB ")) + { + *error = "not defining an RGB space"; + return -1; + } +#if 0 + if (profile_version_major > 2) + { + *error = "only ICC v2 profiles supported"; + return -1; + } +#endif + { + int offset, element_size; + icc_tag (icc, length, "desc", &offset, &element_size); + if (!strcmp (icc + offset, "mluc")) + { + fprintf (stdout, "desc: [babl-icc doesnt decode unicode]\n"); + } + else + if (!strcmp (icc + offset, "desc")) + fprintf (stdout, "desc: %s\n", icc + offset + 12); + } + { + int offset, element_size; + icc_tag (icc, length, "cprt", &offset, &element_size); + fprintf (stdout, "copyright: %s\n", icc + offset + 8); + } + +#if 1 + fprintf (stdout, "icc version: %i.%i.%i\n", profile_version_major, profile_version_minor, profile_version_micro); + fprintf (stdout, "profile-size: %i\n", profile_size); + fprintf (stdout, "profile-class: %s\n", profile_class); + fprintf (stdout, "color-space: %s\n", color_space); + fprintf (stdout, "rendering-intent: %i\n", rendering_intent); + fprintf (stdout, "pcs-space: %s\n", pcs_space); + fprintf (stdout, "length: %li\n", length); +#if 0 + fprintf (stdout, "tag-count: %i\n", tag_count); + + for (t = 0; t < tag_count; t++) + { + char tag_signature[5]; + int offset, element_size; + load_sign (icc, length, TAG_COUNT_OFF + 4 + 12 * t, tag_signature); + icc_tag (icc, length, tag_signature, &offset, &element_size); + fprintf (stdout, "tag %i %s %i %i\n", t, tag_signature, offset, element_size); + } +#endif +#endif + fprintf (stdout, "tags: "); + for (t = 0; t < tag_count; t++) + { + char tag_signature[5]; + int offset, element_size; + load_sign (icc, length, TAG_COUNT_OFF + 4 + 12 * t, tag_signature); + icc_tag (icc, length, tag_signature, &offset, &element_size); + fprintf (stdout, "%s[%i@%i] ", tag_signature, element_size, offset); + } + fprintf (stdout, "\n"); + fprintf (stdout, "\n"); + + + { + int offset, element_size; + if (icc_tag (icc, length, "chrm", &offset, &element_size)) + { + int channels = load_u16 (icc, length, offset + 8); + int phosporant = load_u16 (icc, length, offset + 10); + double redX = load_s15f16 (icc, length, offset + 12); + double redY = load_s15f16 (icc, length, offset + 12 + 4); + double greenX = load_s15f16 (icc, length, offset + 20); + double greenY = load_s15f16 (icc, length, offset + 20 + 4); + double blueX = load_s15f16 (icc, length, offset + 28); + double blueY = load_s15f16 (icc, length, offset + 28 + 4); + fprintf (stdout, "chromaticity:\n"); + fprintf (stdout, " channels: %i\n", channels); + fprintf (stdout, " phosphorant: %i\n", phosporant); + fprintf (stdout, " CIE xy red: %.6f %.6f\n", redX, redY); + fprintf (stdout, " CIE xy green: %.6f %.6f\n", greenX, greenY); + fprintf (stdout, " CIE xy blue: %.6f %.6f\n", blueX, blueY); + if (exact) + { + fprintf (stdout, " exact: "); + print_s15f16 (load_s15f16_ (icc, length, offset + 12)); + fprintf (stdout, " "); + print_s15f16 (load_s15f16_ (icc, length, offset + 12 + 4)); + fprintf (stdout, "\n"); + + fprintf (stdout, " "); + print_s15f16 (load_s15f16_ (icc, length, offset + 20)); + fprintf (stdout, " "); + print_s15f16 (load_s15f16_ (icc, length, offset + 20 + 4)); + fprintf (stdout, "\n"); + + fprintf (stdout, " "); + print_s15f16 (load_s15f16_ (icc, length, offset + 28)); + fprintf (stdout, " "); + print_s15f16 (load_s15f16_ (icc, length, offset + 28 + 4)); + fprintf (stdout, "\n"); + } + + } + } + + { + int offset, element_size; + if (icc_tag (icc, length, "bkpt", &offset, &element_size)) + { + double wX = load_s15f16 (icc, length, offset + 8); + double wY = load_s15f16 (icc, length, offset + 8 + 4); + double wZ = load_s15f16 (icc, length, offset + 8 + 4 * 2); + fprintf (stdout, "blackpoint CIE XYZ: %.6f %.6f %.6f\n", wX, wY, wZ); + + if (exact) + { + fprintf (stdout, "exact: "); + print_s15f16 (load_s15f16_ (icc, length, offset + 8)); + fprintf (stdout, " "); + print_s15f16 (load_s15f16_ (icc, length, offset + 8 + 4)); + fprintf (stdout, " "); + print_s15f16 (load_s15f16_ (icc, length, offset + 8 + 4 * 2)); + fprintf (stdout, "\n"); + } + } + + } + + { + int offset, element_size; + if (icc_tag (icc, length, "wtpt", &offset, &element_size)) + { + double wX = load_s15f16 (icc, length, offset + 8); + double wY = load_s15f16 (icc, length, offset + 8 + 4); + double wZ = load_s15f16 (icc, length, offset + 8 + 4 * 2); + fprintf (stdout, "whitepoint CIE XYZ: %.6f %.6f %.6f\n", wX, wY, wZ); + + if (exact) + { + fprintf (stdout, "exact: "); + print_s15f16 (load_s15f16_ (icc, length, offset + 8)); + fprintf (stdout, " "); + print_s15f16 (load_s15f16_ (icc, length, offset + 8 + 4)); + fprintf (stdout, " "); + print_s15f16 (load_s15f16_ (icc, length, offset + 8 + 4 * 2)); + fprintf (stdout, "\n"); + } + + } + } + + + { + int offset, element_size; + if (icc_tag (icc, length, "rXYZ", &offset, &element_size)) + { + double wX = load_s15f16 (icc, length, offset + 8); + double wY = load_s15f16 (icc, length, offset + 8 + 4); + double wZ = load_s15f16 (icc, length, offset + 8 + 4 * 2); + fprintf (stdout, "red CIE XYZ: %.6f %.6f %.6f\n", wX, wY, wZ); + } + if (icc_tag (icc, length, "gXYZ", &offset, &element_size)) + { + double wX = load_s15f16 (icc, length, offset + 8); + double wY = load_s15f16 (icc, length, offset + 8 + 4); + double wZ = load_s15f16 (icc, length, offset + 8 + 4 * 2); + fprintf (stdout, "green CIE XYZ: %.6f %.6f %.6f\n", wX, wY, wZ); + } + if (icc_tag (icc, length, "bXYZ", &offset, &element_size)) + { + double wX = load_s15f16 (icc, length, offset + 8); + double wY = load_s15f16 (icc, length, offset + 8 + 4); + double wZ = load_s15f16 (icc, length, offset + 8 + 4 * 2); + fprintf (stdout, "blue CIE XYZ: %.6f %.6f %.6f\n", wX, wY, wZ); + } + } + if(exact){ + int offset, element_size; + if (icc_tag (icc, length, "rXYZ", &offset, &element_size)) + { + fprintf (stdout, "exact: "); + print_s15f16 (load_s15f16_ (icc, length, offset + 8)); + fprintf (stdout, " "); + print_s15f16 (load_s15f16_ (icc, length, offset + 8 + 4)); + fprintf (stdout, " "); + print_s15f16 (load_s15f16_ (icc, length, offset + 8 + 4 * 2)); + fprintf (stdout, "\n"); + } + if (icc_tag (icc, length, "gXYZ", &offset, &element_size)) + { + fprintf (stdout, " "); + print_s15f16 (load_s15f16_ (icc, length, offset + 8)); + fprintf (stdout, " "); + print_s15f16 (load_s15f16_ (icc, length, offset + 8 + 4)); + fprintf (stdout, " "); + print_s15f16 (load_s15f16_ (icc, length, offset + 8 + 4 * 2)); + fprintf (stdout, "\n"); + } + if (icc_tag (icc, length, "bXYZ", &offset, &element_size)) + { + fprintf (stdout, " "); + print_s15f16 (load_s15f16_ (icc, length, offset + 8)); + fprintf (stdout, " "); + print_s15f16 (load_s15f16_ (icc, length, offset + 8 + 4)); + fprintf (stdout, " "); + print_s15f16 (load_s15f16_ (icc, length, offset + 8 + 4 * 2)); + fprintf (stdout, "\n"); + } + } + + if (1) { + int offset, element_size; + if (icc_tag (icc, length, "rTRC", &offset, &element_size)) + { + int count = load_u32 (icc, length, offset + 8); + int i; + if (!strcmp (icc + offset, "para")) + { + int function_type = load_u16 (icc, length, offset + 8); + float g,a,b,c,d,e,f; + switch (function_type) + { + case 0: + g = load_s15f16 (icc, length, offset + 12 + 2 * 0); + fprintf (stdout, "parametric TRC gamma type %.6f\n", g); + if (exact) + { + fprintf (stdout, " exact:"); + print_s15f16 (load_s15f16_ (icc, length, offset + 12 + 2 * 0)); + fprintf (stdout, "\n"); + } + + break; + + case 3: + g = load_s15f16 (icc, length, offset + 12 + 2 * 0); + a = load_s15f16 (icc, length, offset + 12 + 2 * 1); + b = load_s15f16 (icc, length, offset + 12 + 2 * 2); + c = load_s15f16 (icc, length, offset + 12 + 2 * 3); + d = load_s15f16 (icc, length, offset + 12 + 2 * 4); + e = load_s15f16 (icc, length, offset + 12 + 2 * 5); + f = load_s15f16 (icc, length, offset + 12 + 2 * 6); + fprintf (stdout, "parametric TRC sRGB type %.6f %.6f %.6f %.6f %.6f %.6f %.6f\n", g, a, b, c, d, e, f); + if (exact) + { + int i; + fprintf (stdout, " exact:"); + for (i = 0; i < 7; i++) + { + print_s15f16 (load_s15f16_ (icc, length, offset + 12 + 2 * i)); + fprintf (stdout, " "); + } + fprintf (stdout, "\n"); + } + break; + default: + fprintf (stdout, "unhandled parametric TRC type %i\n", function_type); + break; + } + } + else + { + fprintf (stdout, "rTRC count: %i %s\n", count, icc + offset); + if (count == 0) + { + fprintf (stdout, "linear TRC\n"); + } + else if (count == 1) + { + fprintf (stdout, "gamma TRC of: %.6f\n", + load_u8f8 (icc,length, offset + 12)); + if (exact) + { + fprintf (stdout, " exact: "); + print_u8f8 (load_u8f8_ (icc,length, offset + 12)); + fprintf (stdout, "\n"); + + } + } + else for (i = 0; i < count && i < 10; i ++) + { + fprintf (stdout, "%i=%i ", i, load_u16 (icc, length, offset + 12 + i * 2)); + if (i % 7 == 0) + fprintf (stdout, "\n"); + } + } + } + } + return 0; +} + +static int +load_icc (const char *path, + char **error) +{ + char *icc = NULL; + long length = 0; + int ret = 0; + file_get_contents (path, &icc, &length, NULL); + if (icc) + { + ret = load_icc_from_memory (icc, length, error); + free (icc); + } + return ret; +} + +static int +file_get_contents (const char *path, + char **contents, + long *length, + void *error) +{ + FILE *file; + long size; + char *buffer; + + file = fopen (path,"rb"); + + if (!file) + return -1; + + fseek (file, 0, SEEK_END); + *length = size = ftell (file); + rewind (file); + buffer = malloc(size + 8); + + if (!buffer) + { + fclose(file); + return -1; + } + + size -= fread (buffer, 1, size, file); + if (size) + { + fclose (file); + free (buffer); + return -1; + } + fclose (file); + *contents = buffer; + return 0; +} + +int +main (int argc, + char **argv) +{ + int i = 1; + if (argc < 2) + { + fprintf (stdout, "usage: babl-icc-dump [options] \n"); + return -1; + } + + if (argv[i] && (!strcmp (argv[i], "-e") || + !strcmp (argv[i], "--exact"))) + { + exact = 1; + i++; + } + + for (; argv[i]; i++) + { + char *error = NULL; + fprintf (stdout, "\nfile: %s\n", argv[i]); + load_icc (argv[i], &error); + if (error) + { + fprintf (stdout, "icc-parse-problem: %s\n", error); + } + } + + return 0; +} diff --git a/tools/babl-icc-rewrite.c b/tools/babl-icc-rewrite.c new file mode 100644 index 0000000..5f87dc1 --- /dev/null +++ b/tools/babl-icc-rewrite.c @@ -0,0 +1,197 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, 2017 Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include +#include "../babl/babl-internal.h" + +static int +file_get_contents (const char *path, + char **contents, + long *length, + void *error); + +void +file_set_contents (const char *path, + const char *data, + long length); + +int +main (int argc, + char **argv) +{ + BablICCFlags flags = 0; + const Babl *babl; + char *icc_data = NULL; + long icc_len; + int genlen; + char *description = NULL; + char *copyright = NULL; + const char *error; + const char *la = NULL; + const char *co = NULL; + + const char *input = NULL; + const char *output = NULL; + int i; + + babl_init (); + + + for (i = 1; argv[i]; i++) + { + if (!strcmp (argv[i], "-d") || + !strcmp (argv[i], "--description")) + { + description = argv[++i]; + } + else if (!strcmp (argv[i], "-c") || + !strcmp (argv[i], "--copyright")) + { + copyright = argv[++i]; + } + else if (!strcmp (argv[i], "--compact-trc")) + { + flags |= BABL_ICC_COMPACT_TRC_LUT; + } + else if (argv[i][0] == '-') + { + fprintf (stderr, "unknown option %s\n", argv[i]); + return -1; + } + else + { + if (!input) input = argv[i]; + else if (!output) output = argv[i]; + } + } + + if (!input || !output) + { + fprintf (stderr, "usage: %s [options] \n", argv[0]); + fprintf (stderr, " where recognized options are: \n"); + fprintf (stderr, " -d \n"); + fprintf (stderr, " -c \n"); + fprintf (stderr, " --compact-trc\n"); + return -1; + } + + if (file_get_contents (input, &icc_data, &icc_len, NULL)) + return -1; + + if (!description) + { + description = babl_icc_get_key (icc_data, icc_len, "description", la, co); + if (description) + fprintf (stderr, "description: %s\n", description); + } + + if (!copyright) + { + copyright = babl_icc_get_key (icc_data, icc_len, "copyright", la, co); + if (copyright) + { + fprintf (stderr, "copyright: %s\n", copyright); + } + } + { + char *str = babl_icc_get_key (icc_data, icc_len, "device", la, co); + if (str) + { + fprintf (stderr, "device: %s\n", str); + free (str); + } + } + { + char *str = babl_icc_get_key (icc_data, icc_len, "manufacturer", la, co); + if (str) + { + fprintf (stderr, "manufacturer: %s\n", str); + free (str); + } + } + babl = babl_icc_make_space (icc_data, icc_len, 0, &error); + free (icc_data); + if (error || !babl) + { + fprintf (stderr, "%s error %s", argv[0], error); + return -1; + } + + icc_data = (char *)babl_space_to_icc (babl, description, + copyright, flags, + &genlen); + if (icc_data) + { + file_set_contents (output, icc_data, genlen); + } + fprintf (stderr, "[%s]\n", output); + + babl_exit (); + return 0; +} + +static int +file_get_contents (const char *path, + char **contents, + long *length, + void *error) +{ + FILE *file; + long size; + char *buffer; + + file = fopen (path,"rb"); + + if (!file) + return -1; + + fseek (file, 0, SEEK_END); + *length = size = ftell (file); + rewind (file); + buffer = malloc(size + 8); + + if (!buffer) + { + fclose(file); + return -1; + } + + size -= fread (buffer, 1, size, file); + if (size) + { + fclose (file); + free (buffer); + return -1; + } + fclose (file); + *contents = buffer; + return 0; +} + +void +file_set_contents (const char *path, + const char *data, + long length) +{ + FILE *fp = fopen (path, "wb"); + if (length == -1) + length = strlen (data); + fwrite(data, length, 1, fp); + fclose (fp); +} diff --git a/tools/babl-verify.c b/tools/babl-verify.c new file mode 100644 index 0000000..de3bbd1 --- /dev/null +++ b/tools/babl-verify.c @@ -0,0 +1,127 @@ +#include +#include +#include "../config.h" +#include "babl/babl-internal.h" + +//#define SPACE1 babl_space("ProPhoto") +#define SPACE1 babl_space("Apple") +//#define SPACE1 babl_space("sRGB") +//#define SPACE2 babl_space("Apple") + +static int +file_get_contents (const char *path, + char **contents, + long *length, + void *error) +{ + FILE *file; + long size; + char *buffer; + + file = fopen (path,"rb"); + + if (!file) + return -1; + + if (fseek (file, 0, SEEK_END) == -1 || (size = ftell (file)) == -1) + { + fclose (file); + return -1; + } + if (length) *length = size; + rewind (file); + if ((size_t) size > SIZE_MAX - 8) + { + fclose (file); + return -1; + } + buffer = calloc(size + 8, 1); + + if (!buffer) + { + fclose(file); + return -1; + } + + size -= fread (buffer, 1, size, file); + if (size) + { + fclose (file); + free (buffer); + return -1; + } + fclose (file); + *contents = buffer; + return 0; +} + +int +main (int argc, + char **argv) +{ + int final = 0; + const Babl *fish; + const Babl *SPACE2 = NULL; + + + if (argc < 3) + { + fprintf (stderr, "need two args, from and to babl-formats\n"); + return -1; + } + if (argc == 4) + final = 1; + + if (!final) + { + putenv ("BABL_DEBUG_CONVERSIONS" "=" "1"); + putenv ("BABL_TOLERANCE" "=" "0.2"); + } + + babl_init (); + +#define ICC_PATH "/tmp/my.icc" +//#define ICC_PATH "/usr/share/color/icc/colord/AppleRGB.icc" +//#define ICC_PATH "/tmp/ACEScg-elle-V2-labl.icc" +//#define ICC_PATH "/tmp/ACEScg-elle-V2-g10.icc" +//#define ICC_PATH "/tmp/ACEScg-elle-V4-g10.icc" +//#define ICC_PATH "/tmp/ACEScg-elle-V4-g22.icc" + + + { + char *icc_data = NULL; + long length = 0; + file_get_contents (ICC_PATH, &icc_data, &length, NULL); + SPACE2 = babl_space_from_icc (icc_data, length, BABL_ICC_INTENT_RELATIVE_COLORIMETRIC, NULL); + //SPACE2 = babl_space ("sRGB"); + } + + fish = babl_fish (babl_format_with_space(argv[1], SPACE1), babl_format_with_space (argv[2], SPACE2)); + if (!fish) + { + fprintf (stderr, "!!!! %s %s\n", argv[1], argv[2]); + return -1; + } + + if (final) + switch (fish->class_type) + { + case BABL_FISH: + fprintf (stderr, ">%s\n", babl_get_name (fish)); + break; + case BABL_FISH_PATH: + fprintf (stderr, "chosen %s to %s: steps: %i error: %.12f cost: %f\n", argv[1], argv[2], fish->fish_path.conversion_list->count, fish->fish.error, fish->fish_path.cost); + for (int i = 0; i < fish->fish_path.conversion_list->count; i++) + { + fprintf (stderr, "\t%s (cost: %li)\n", + babl_get_name(fish->fish_path.conversion_list->items[i] ), + fish->fish_path.conversion_list->items[i]->conversion.cost); + } + break; + } + + + babl_exit (); + + return 0; +} diff --git a/tools/babl-verify.sh b/tools/babl-verify.sh new file mode 100755 index 0000000..0dcaa93 --- /dev/null +++ b/tools/babl-verify.sh @@ -0,0 +1,47 @@ +#!/bin/sh + +# this is a tool for debugging available babl fast paths relatd to +# a given pixel format - the script is intended to be run as is - +# as well as modified as needed including more relevant conversions + +rm ~/.cache/babl/babl-fishes + +format=$1 +if [ "x$format" = "x" ];then + echo "pass a babl format to verify (in quotes) - running with \"R'G'B'A u8\"" + format="R'G'B'A u8" +fi + +base_path=`realpath $0` +base_path=`dirname $base_path`/.. +base_path=`realpath $base_path` +echo $base_path + +make -C $base_path/extensions || exit + +export BABL_PATH=$base_path/extensions/.libs + +echo "" +echo "[$format]" +$base_path/tools/babl-verify "$format" "cairo-ARGB32" "x" +$base_path/tools/babl-verify "cairo-ARGB32" "$format" "x" +$base_path/tools/babl-verify "$format" "RaGaBaA float" "x" +$base_path/tools/babl-verify "RaGaBaA float" "$format" "x" +$base_path/tools/babl-verify "$format" "RGBA float" "x" +$base_path/tools/babl-verify "RGBA float" "$format" "x" +$base_path/tools/babl-verify "$format" "R'G'B'A float" "x" +$base_path/tools/babl-verify "R'G'B'A float" "$format" "x" +$base_path/tools/babl-verify "$format" "R~G~B~A float" "x" +$base_path/tools/babl-verify "R~G~B~A float" "$format" "x" + +$base_path/tools/babl-verify "$format" "cairo-ARGB32" +$base_path/tools/babl-verify "cairo-ARGB32" "$format" +$base_path/tools/babl-verify "$format" "RaGaBaA float" +$base_path/tools/babl-verify "RaGaBaA float" "$format" +$base_path/tools/babl-verify "$format" "RGBA float" +$base_path/tools/babl-verify "RGBA float" "$format" +$base_path/tools/babl-verify "$format" "R'G'B'A float" +$base_path/tools/babl-verify "R'G'B'A float" "$format" +$base_path/tools/babl-verify "$format" "R~G~B~A float" +$base_path/tools/babl-verify "R~G~B~A float" "$format" + diff --git a/tools/babl_fish_path_fitness.c b/tools/babl_fish_path_fitness.c new file mode 100644 index 0000000..9b0cfc5 --- /dev/null +++ b/tools/babl_fish_path_fitness.c @@ -0,0 +1,339 @@ +/* perform a symmetricality of conversion test on a set of randomized + * RGBA data */ + +#include "config.h" +#include +#include +#include "babl-internal.h" + +#ifndef HAVE_SRANDOM +#define srandom srand +#define random rand +#endif + +int total_length = 0; +int total_cost = 0; +int total = 0; +int ok = 0; + +static int qux = 0; + +//#define UTF8 + +#ifdef UTF8 + +static char *utf8_bar[] = { " %s%s", "·%s%s", "▁%s%s", "▂%s%s", "▃%s%s", "▄%s%s", "▅%s%s", "▆%s%s", "▇%s%s", "█%s%s" }; +#define DIRECT " " +#define SELF " " +#define EMPTY " %s%s" +#define SL "" +#define NL "\n" + +#else + + +static char *utf8_bar[] = { " ", + "▄", + "▄", + "▄", + "▄", + "▄", + "▄", + "▄", + "▄"}; +#define SL "
" +#define SELF " " +#define EMPTY "▄" +#define NL "
\n" + +#endif + + + +/* +static char *utf8_bar[]= {"!","▁","▃","▅","▇","█","!","!","!"}; +static char *utf8_bar[]={"·", "█", "▇", "▆", "▅", "▄", "▃", "▂", "▁", }; +static char *utf8_bar[]={" ","1","2","3","4","5","6","7","8"}; +*/ + +#define NUM_TEST_PIXELS (1024*1024) +static float test_pixels_float[NUM_TEST_PIXELS*4]; +static char test_pixels_in[NUM_TEST_PIXELS * 6 * 8]; +static char test_pixels_out[NUM_TEST_PIXELS * 6 * 8]; + + +static double +rand_double (void) +{ + return (double) random () / RAND_MAX; +} + +static double +rand_range_double (double min, + double max) +{ + return rand_double () * (max - min) + min; +} + +static void +init_test_pixels (void) +{ + static int done = 0; + int i = 0; + int pix_no = 0; + srandom (111); + + if (done) + return; + done = 1; + + + for (i = 0; i < 256 && pix_no < NUM_TEST_PIXELS; i++) + { + test_pixels_float[pix_no*4+0] = rand_double(); + test_pixels_float[pix_no*4+1] = rand_double(); + test_pixels_float[pix_no*4+2] = rand_double(); + test_pixels_float[pix_no*4+3] = rand_double(); + pix_no ++; + } + for (i = 0; i < 256 && pix_no < NUM_TEST_PIXELS; i++) + { + test_pixels_float[pix_no*4+0] = rand_range_double(1.0, 2.0); + test_pixels_float[pix_no*4+1] = rand_range_double(1.0, 2.0); + test_pixels_float[pix_no*4+2] = rand_range_double(1.0, 2.0); + test_pixels_float[pix_no*4+3] = rand_range_double(1.0, 2.0); + pix_no ++; + } + for (i = 0; i < 256 && pix_no < NUM_TEST_PIXELS; i++) + { + test_pixels_float[pix_no*4+0] = rand_range_double(-1.0, 1.0); + test_pixels_float[pix_no*4+1] = rand_range_double(-1.0, 1.0); + test_pixels_float[pix_no*4+2] = rand_range_double(-1.0, 1.0); + test_pixels_float[pix_no*4+3] = rand_range_double(-1.0, 1.0); + pix_no ++; + } + for (i = 0; i < 16 && pix_no < NUM_TEST_PIXELS; i++) + { + test_pixels_float[pix_no*4+0] = rand_range_double(0.0, 1.0); + test_pixels_float[pix_no*4+1] = rand_range_double(0.0, 1.0); + test_pixels_float[pix_no*4+2] = rand_range_double(0.0, 1.0); + test_pixels_float[pix_no*4+3] = 0; + pix_no ++; + } + for (i = 0; i < 16 && pix_no < NUM_TEST_PIXELS; i++) + { + test_pixels_float[pix_no*4+0] = rand_range_double(0.0, 16.0); + test_pixels_float[pix_no*4+1] = rand_range_double(0.0, 16.0); + test_pixels_float[pix_no*4+2] = rand_range_double(0.0, 16.0); + test_pixels_float[pix_no*4+2] = rand_range_double(-1.0, 1.0); + pix_no ++; + } + for (i = 0; pix_no < NUM_TEST_PIXELS; i++) + { + test_pixels_float[pix_no*4+0] = rand_range_double(-1.0, 61.0); + test_pixels_float[pix_no*4+1] = rand_range_double(-1.0, 61.0); + test_pixels_float[pix_no*4+2] = rand_range_double(-1.0, 66.0); + test_pixels_float[pix_no*4+3] = rand_range_double(-1.0, 3.0); + pix_no ++; + } + for (i = 0; i < sizeof(test_pixels_in); i++) + test_pixels_in[i]=(rand()/10000)&0xff; +} + +static int destination_each (Babl *babl, + void *userdata) +{ + Babl *source = userdata; + Babl *destination = babl; + init_test_pixels (); + + if (qux % babl_formats_count () == qux / babl_formats_count ()) + printf (SELF); + else + { + Babl *temp = babl_fish_path (source, destination); + const Babl *fish = babl_fish (source, destination); + + char style[128] = ""; + char title[1024] = ""; +#ifdef UTF8 +#else + { + float pixels_per_second; + long ticks_start, ticks_end; + + ticks_start = babl_ticks (); + babl_process (fish, &test_pixels_in[0], + &test_pixels_out[0], + NUM_TEST_PIXELS); + ticks_end = babl_ticks (); + + pixels_per_second = (NUM_TEST_PIXELS) / ((ticks_end - ticks_start)/1000.0); + + { + float colval = pixels_per_second/1000/1000.0/0.7; + if (colval > 1) + colval = 1; + + if (colval < 0.2) + { + sprintf (style, "color:rgb(%i, 0, 0);", (int)(colval * 5 * 255)); + } + else if (colval < 0.4) + { + sprintf (style, "color:rgb(255, %i, 0);", (int)((colval-0.2) * 5 * 255)); + } + else + { + sprintf (style, "color:rgb(255, 255, %i);", (int)((colval-0.4) * 1.666 * 255)); + } + + } + { + int steps = 0; + if (temp) + steps = babl_list_size (temp->fish_path.conversion_list); + sprintf (title, "%s to %s %i steps %.3f mpix/s ", babl_get_name (source), babl_get_name (destination), steps, pixels_per_second/1000.0); + } + } +#endif + + if (temp) + { + printf (utf8_bar[babl_list_size (temp->fish_path.conversion_list)], title, style); + total_length += babl_list_size (temp->fish_path.conversion_list); + total_cost += temp->fish_path.cost; + ok++; + total++; + } + else + { + printf (EMPTY, title, style); + total++; + } + } + qux++; + return 0; +} + +static int source_no = 0; + +static int source_each (Babl *babl, + void *userdata) +{ + printf ("%s", SL); + babl_format_class_for_each (destination_each, babl); +#ifdef UTF8 + printf ("──%2i %s%s", source_no++, babl->instance.name, NL); +#else + printf ("%2i:%s%s", source_no++, babl->instance.name, NL); +#endif + return 0; +} + +int +main (void) +{ + babl_init (); + + babl_set_extender (babl_extension_quiet_log ()); + +#ifndef UTF8 + printf ("\n"); + printf ("\n"); + + printf ("\n"); + printf ("

babl profiling matrix, rows are source formats columns are destinations, blue background means direct conversion and blue left border means multi-step conversion, no blue means reference conversion, gradient from black, through red, yellow and white indicates memory-bandwidth sum bytes read + bytes written / time, hover items to see further details on an individual conversion.

\n"); + +#endif + + babl_format_class_for_each (source_each, NULL); + +#ifdef UTF8 + { + int i; + + for (i = 0; i < babl_formats_count (); i++) + printf ("|"); + + printf ("\n"); + + for (i = 0; i < babl_formats_count (); i++) + { + if (i / 100 == 0) + printf ("|"); + else + printf ("%i", (i / 100) % 10); + } + + printf ("\n"); + + for (i = 0; i < babl_formats_count (); i++) + { + if (i / 10 == 0) + printf ("|"); + else + printf ("%i", (i / 10) % 10); + } + + printf ("\n"); + /* + for (i = 0; i < babl_formats_count (); i++) + printf ("│"); + + printf ("\n"); + + for (i = 0; i < babl_formats_count (); i++) + { + if (i / 10 == 0) + printf ("│"); + else + printf ("%i", (i / 10) % 10); + } + + printf ("\n"); + */ + + for (i = 0; i < babl_formats_count (); i++) + printf ("%i", (i) % 10); + + printf ("\n"); + } + + printf ("total length: %i\n", total_length); + printf ("total cost : %i\n", total_cost); + /*printf ("ok / total : %i %i %f\n", ok, total, (1.0*ok) / total); + */ +#else + printf ("\n"); +#endif + + babl_exit (); + + return 0; +} diff --git a/tools/conversions.c b/tools/conversions.c new file mode 100644 index 0000000..946bfb9 --- /dev/null +++ b/tools/conversions.c @@ -0,0 +1,37 @@ +/* perform a symmetricality of conversion test on a set of randomized + * RGBA data */ + +#include "config.h" +#include +#include +#include "babl-internal.h" + +#define ERROR_TOLERANCE 0.5 + +static int OK = 1; + +static int +each_conversion (Babl *babl, + void *userdata) +{ + double error = babl->conversion.error; + + if (error >= ERROR_TOLERANCE) + { + babl_log ("%s\terror:%f", babl->instance.name, error); + OK = 0; + } + return 0; +} + +int main (void) +{ + babl_init (); + + babl_set_extender (babl_extension_quiet_log ()); + babl_conversion_class_for_each (each_conversion, NULL); + + babl_exit (); + + return !OK; +} diff --git a/tools/formats.c b/tools/formats.c new file mode 100644 index 0000000..7f032ee --- /dev/null +++ b/tools/formats.c @@ -0,0 +1,29 @@ +/* perform a symmetricality of conversion test on a set of randomized + * RGBA data */ + +#include "config.h" +#include +#include +#include "babl-internal.h" + + +static int +format_check (Babl *babl, + void *userdata) +{ + babl_log ("%s\tloss: %f", babl->instance.name, babl->format.loss); + return 0; +} + +int +main (void) +{ + babl_init (); + + babl_set_extender (babl_extension_quiet_log ()); + babl_format_class_for_each (format_check, (void *) 1); + + babl_exit (); + + return 0; +} diff --git a/tools/introspect.c b/tools/introspect.c new file mode 100644 index 0000000..5cd667f --- /dev/null +++ b/tools/introspect.c @@ -0,0 +1,30 @@ +/* babl - dynamically extendable universal pixel conversion library. + * Copyright (C) 2005, Øyvind Kolås. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * . + */ + +#include "config.h" +#include "babl-internal.h" + +int +main (int argc, + char **argv) +{ + babl_init (); + babl_introspect (NULL); + babl_exit (); + return 0; +} diff --git a/tools/meson.build b/tools/meson.build new file mode 100644 index 0000000..12180de --- /dev/null +++ b/tools/meson.build @@ -0,0 +1,27 @@ + +tool_names = [ + 'babl_fish_path_fitness', + 'babl-benchmark', + 'babl-html-dump', + 'babl-icc-dump', + 'babl-icc-rewrite', + 'babl-verify', + 'conversions', + 'formats', + 'introspect', + 'trc-validator', +] + +foreach tool_name : tool_names + tool = executable(tool_name, + tool_name + '.c', + include_directories: [rootInclude, bablInclude], + link_with: babl, + dependencies: [math, thread], + install: false, + ) + + if tool_name == 'babl-html-dump' + babl_html_dump = tool + endif +endforeach diff --git a/tools/trc-validator.c b/tools/trc-validator.c new file mode 100644 index 0000000..7bf1eaa --- /dev/null +++ b/tools/trc-validator.c @@ -0,0 +1,225 @@ +// utility program for validating lolremez approximation constants, and +// BablPolynomial based approximations, for TRCs +// the currently used apprimxations for 1.8 and 2.2 gamma pow functions are +// validated to be loss-less when coded for 8bit. + +#include "config.h" +#include +#include +#include +#include +#include "babl-internal.h" + +#if 0 + +#define GAMMA 2.2 + +static inline float from_linear (float x) +{ + if (x >= 0.01f && x < 0.25f) + { + double u = -1.1853049266795914e+8; + u = u * x + 1.6235355750617304e+8; + u = u * x + -9.6434183855508922e+7; + u = u * x + 3.2595749146174438e+7; + u = u * x + -6.9216734175519044e+6; + u = u * x + 9.6337373983643336e+5; + u = u * x + -8.9295299887376452e+4; + u = u * x + 5.5387559329470092e+3; + u = u * x + -2.3522564268245811e+2; + u = u * x + 8.8234901614165394; + return u * x + 5.3919966190648492e-2; + } else if (x >= 0.25f && x < 1.0f) + { + double u = -2.1065242890384543e-1; + u = u * x + 1.7554867367832886; + u = u * x + -6.6371047248064382; + u = u * x + 1.5049549954517457e+1; + u = u * x + -2.279671781745644e+1; + u = u * x + 2.4331499227325978e+1; + u = u * x + -1.8839523095731037e+1; + u = u * x + 1.0802279176589768e+1; + u = u * x + -4.7776729355620852; + u = u * x + 2.1410886948010769; + return u * x + 1.817672123838504e-1; + } + return powf (x, 1.0f/2.2f); +} + +static inline float to_linear (float x) +{ + if (x >= 0.01f && x < 1.0f) + { + double u = -1.7565198334207539; + u = u * x + 9.4503605497836926; + u = u * x + -2.2016178903082791e+1; + u = u * x + 2.9177361786084179e+1; + u = u * x + -2.4368251609523336e+1; + u = u * x + 1.3522663223248737e+1; + u = u * x + -5.253344907664925; + u = u * x + 1.7182864905042889; + u = u * x + 5.2860458501353106e-1; + u = u * x + -3.0000031884069502e-3; + return u * x + 1.6952727496833812e-5; + } + return powf (x, 2.2); +} +#endif + +#if 0 + +#define GAMMA 1.8 + +static inline float from_linear (float x) +{ + if (x >= 0.01f && x < 0.25f) + { + double u = -7.0287082190390287e+7; + u = u * x + 9.6393346352028194e+7; + u = u * x + -5.734540040993472e+7; + u = u * x + 1.9423130902481005e+7; + u = u * x + -4.1360185772523716e+6; + u = u * x + 5.7798684366021459e+5; + u = u * x + -5.3914765738125787e+4; + u = u * x + 3.3827381495697474e+3; + u = u * x + -1.4758049734050082e+2; + u = u * x + 6.34823684277896; + return u * x + 2.5853366952641552e-2; + } else if (x >= 0.25f && x < 1.1f) + { + double u = -1.0514013917303294; + u = u * x + 7.7742547018698687; + u = u * x + -2.5688463052927626e+1; + u = u * x + 5.009448068094152e+1; + u = u * x + -6.4160579394623318e+1; + u = u * x + 5.6890996491836047e+1; + u = u * x + -3.5956430472666212e+1; + u = u * x + 1.6565821666356617e+1; + u = u * x + -5.8508167212560416; + u = u * x + 2.2859969154731878; + return u * x + 9.6140522367339399e-2; + } + return powf (x, 1.0f/1.8f); +} + +static inline float to_linear (float x) +{ + if (x >= 0.01f && x < 0.7f) + { + double u = -1.326432065236105e+1; + u = u * x + 7.7192973347868776e+1; + u = u * x + -1.9639662782311719e+2; + u = u * x + 2.8719828602066411e+2; + u = u * x + -2.6718118019754855e+2; + u = u * x + 1.6562450069335532e+2; + u = u * x + -6.9988172743274441e+1; + u = u * x + 2.0568254985551865e+1; + u = u * x + -4.5302829214271245; + u = u * x + 1.7636048338730889; + u = u * x + 1.3015451332543148e-2; + return u * x + -5.4445726922508747e-5; + } + else if (x >= 0.7f && x < 1.4f) + { + double u = 2.4212422421184617e-3; + u = u * x + -2.0853930731707795e-2; + u = u * x + 8.2416801461966525e-2; + u = u * x + -2.1755799369117727e-1; + u = u * x + 1.0503926510667593; + u = u * x + 1.1196374095271941e-1; + return u * x + -8.7825075945914206e-3; + } + return powf (x, 1.8); +} +#endif + +#if 1 + +#define GAMMA 2.2 +#define X0 ( 0.5f / 255.0f) +#define X1 (254.5f / 255.0f) +#define DEGREE 6 +#define SCALE 2 + +static inline float +from_linear (float x) +{ + if (x >= X0 && x <= X1) + { + BablPolynomial poly; + + babl_polynomial_approximate_gamma (&poly, + 1.0 / GAMMA, X0, X1, DEGREE, SCALE); + + return babl_polynomial_eval (&poly, x); + } + return powf (x, 1.0f/GAMMA); +} + +static inline float +to_linear (float x) +{ + if (x >= X0 && x <= X1) + { + BablPolynomial poly; + + babl_polynomial_approximate_gamma (&poly, + GAMMA, X0, X1, DEGREE, SCALE); + + return babl_polynomial_eval (&poly, x); + } + return powf (x, GAMMA); +} +#endif + +static inline float +from_linear_ref (float x) +{ + return powf (x, 1.0/GAMMA); +} + +static inline float +to_linear_ref (float x) +{ + return powf (x, GAMMA); +} + +int +main (int argc, + char **argv) +{ + int i; + float max_diff = 0.0; + int max_diff_u8 = 0; + int u8_diff_count = 0; + + for (i = 0; i < 256; i++) + { + float val = i / 255.0; + float from_ref = from_linear_ref (val); + float to_ref = to_linear_ref (val); + float from = from_linear (val); + float to = to_linear (val); + int from_ref_u8 = from_ref * 255.5; + int to_ref_u8 = to_ref * 255.5; + int from_u8 = from * 255.5; + int to_u8 = to * 255.5; + float from_diff = fabs (from_ref - from); + float to_diff = fabs (to_ref - to); + int from_diff_u8 = abs (from_u8 -from_ref_u8); + int to_diff_u8 = abs (to_u8 -to_ref_u8); + + if (max_diff < from_diff) max_diff = from_diff; + if (max_diff < to_diff) max_diff = to_diff; + + if (from_diff_u8 || to_diff_u8) + { + u8_diff_count ++; + if (from_diff_u8 > max_diff_u8) max_diff_u8 = from_diff_u8; + if (to_diff_u8 > max_diff_u8) max_diff_u8 = to_diff_u8; + } + } + fprintf (stderr, "diffs: %i max-u8-diff: %i: max-diff: %f(%f)\n", u8_diff_count, max_diff_u8, max_diff, max_diff * 256.0); +} + + diff --git a/tools/xml-insert.py b/tools/xml-insert.py new file mode 100644 index 0000000..cbe63dc --- /dev/null +++ b/tools/xml-insert.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python3 +# +# Utility script to insert an xml snippet into an existing document +# +# Re-implements xml_insert.sh in python with extra options to send the +# output to a new file. +# +# Copyright John Marshall 2020 +# + +from __future__ import print_function + +import os +import sys +import argparse + +class Args(): + def __init__(self): + parser = argparse.ArgumentParser() + parser.add_argument( + '--output', + metavar='OUTPUT_FILE', + help='output file - otherwise output to STDOUT' + ) + parser.add_argument( + '--insert', + action='append', + nargs=2, + required=True, + metavar=('TAG', 'INSERT_FILE'), + help='insert file tag and file name' + ) + parser.add_argument( + 'FILE', + metavar='INPUT_FILE', + help='input file' + ) + + self.input = os.path.realpath(parser.parse_args().FILE) + if parser.parse_args().output: + self.output = os.path.realpath(parser.parse_args().output) + else: + self.output = None + self.inserts = parser.parse_args().insert + + +def main(): + args = Args() + + try: + in_file = open(args.input, 'r') + except IOError: + print('cannot access input file ' + args.input, + file=sys.stderr) + sys.exit(1) + + doc = in_file.read().splitlines() + in_file.close() + + # get insert files + inserts = args.inserts + for insert in inserts: + ins_tag = '' + + # find tag instances in input file + indices = [] + for i, line in enumerate(doc): + if ins_tag in line: + indices.append(i) + + if not indices: + print(ins_tag + ' not in input file - skipping', + file=sys.stderr) + continue + + # read in insert file + try: + ins_file = open(os.path.realpath(insert[1]), 'r') + except IOError: + print ('cannot open insert file %s - skipping' % insert[1], + file=sys.stderr) + continue + + if ins_file: + ins_doc = ins_file.read().splitlines() + ins_file.close() + + # insert in reverse order so that remaining inert positions + # remain valid + for index in reversed(indices): + doc[index+1:index+1] = ins_doc + + # output to file or stdout + if args.output: + try: + out_file = open(os.path.realpath(args.output), 'w') + except IOError: + print('cannot open output file %s' % args.output) + sys.exit(1) + else: + out_file = sys.stdout + + for line in doc: + print(line, file=out_file) + + sys.exit(0) + + +if __name__ == "__main__": + main() \ No newline at end of file -- 2.30.2