| /* | 
 |  * Copyright 2017 The Android Open Source Project | 
 |  * | 
 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
 |  * you may not use this file except in compliance with the License. | 
 |  * You may obtain a copy of the License at | 
 |  * | 
 |  *      http://www.apache.org/licenses/LICENSE-2.0 | 
 |  * | 
 |  * Unless required by applicable law or agreed to in writing, software | 
 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 |  * See the License for the specific language governing permissions and | 
 |  * limitations under the License. | 
 |  */ | 
 |  | 
 | #include <algorithm> | 
 | #include <fstream> | 
 | #include <iomanip> | 
 | #include <iostream> | 
 | #include <string> | 
 |  | 
 | #include <getopt.h> | 
 |  | 
 | #include <ui/ColorSpace.h> | 
 |  | 
 | using namespace android; | 
 | using namespace std; | 
 |  | 
 | uint32_t gSize = 32; | 
 | ColorSpace gColorSpaceSrc = ColorSpace::DisplayP3(); | 
 | ColorSpace gColorSpaceDst = ColorSpace::extendedSRGB(); | 
 | string gNameSrc = "DisplayP3"; | 
 | string gNameDst = "extendedSRGB"; | 
 |  | 
 | static void printHelp() { | 
 |     cout << "lutgen -d SIZE -s SOURCE -t TARGET <lut file>" << endl; | 
 |     cout << endl; | 
 |     cout << "Generate a 3D LUT to convert between two color spaces." << endl; | 
 |     cout << endl; | 
 |     cout << "If <lut file> ends in .inc, data is generated without the array declaration." << endl; | 
 |     cout << endl; | 
 |     cout << "Options:" << endl; | 
 |     cout << "  --help, -h" << endl; | 
 |     cout << "    print this message" << endl; | 
 |     cout << "  --dimension=, -d" << endl; | 
 |     cout << "    the dimension of the 3D LUT. Example: 17 for a 17x17x17 LUT. 32 by default" << endl; | 
 |     cout << "  --source=COLORSPACE, -s" << endl; | 
 |     cout << "    the source color space, see below for available names. DisplayP3 by default" << endl; | 
 |     cout << "  --target=COLORSPACE, -t" << endl; | 
 |     cout << "    the target color space, see below for available names. extendedSRGB by default" << endl; | 
 |     cout << endl; | 
 |     cout << "Colorspace names:" << endl; | 
 |     cout << "    sRGB" << endl; | 
 |     cout << "    linearSRGB" << endl; | 
 |     cout << "    extendedSRGB" << endl; | 
 |     cout << "    linearExtendedSRGB" << endl; | 
 |     cout << "    NTSC" << endl; | 
 |     cout << "    BT709" << endl; | 
 |     cout << "    BT2020" << endl; | 
 |     cout << "    AdobeRGB" << endl; | 
 |     cout << "    ProPhotoRGB" << endl; | 
 |     cout << "    DisplayP3" << endl; | 
 |     cout << "    DCIP3" << endl; | 
 |     cout << "    ACES" << endl; | 
 |     cout << "    ACEScg" << endl; | 
 | } | 
 |  | 
 | static const ColorSpace findColorSpace(const string& name) { | 
 |     if (name == "linearSRGB") return ColorSpace::linearSRGB(); | 
 |     if (name == "extendedSRGB") return ColorSpace::extendedSRGB(); | 
 |     if (name == "linearExtendedSRGB") return ColorSpace::linearExtendedSRGB(); | 
 |     if (name == "NTSC") return ColorSpace::NTSC(); | 
 |     if (name == "BT709") return ColorSpace::BT709(); | 
 |     if (name == "BT2020") return ColorSpace::BT2020(); | 
 |     if (name == "AdobeRGB") return ColorSpace::AdobeRGB(); | 
 |     if (name == "ProPhotoRGB") return ColorSpace::ProPhotoRGB(); | 
 |     if (name == "DisplayP3") return ColorSpace::DisplayP3(); | 
 |     if (name == "DCIP3") return ColorSpace::DCIP3(); | 
 |     if (name == "ACES") return ColorSpace::ACES(); | 
 |     if (name == "ACEScg") return ColorSpace::ACEScg(); | 
 |     return ColorSpace::sRGB(); | 
 | } | 
 |  | 
 | static int handleCommandLineArgments(int argc, char* argv[]) { | 
 |     static constexpr const char* OPTSTR = "h:d:s:t:"; | 
 |     static const struct option OPTIONS[] = { | 
 |             { "help",       no_argument,       nullptr, 'h' }, | 
 |             { "dimension",  required_argument, nullptr, 'd' }, | 
 |             { "source",     required_argument, nullptr, 's' }, | 
 |             { "target",     required_argument, nullptr, 't' }, | 
 |             { nullptr, 0, nullptr, 0 }  // termination of the option list | 
 |     }; | 
 |  | 
 |     int opt; | 
 |     int index = 0; | 
 |  | 
 |     while ((opt = getopt_long(argc, argv, OPTSTR, OPTIONS, &index)) >= 0) { | 
 |         string arg(optarg ? optarg : ""); | 
 |         switch (opt) { | 
 |             default: | 
 |             case 'h': | 
 |                 printHelp(); | 
 |                 exit(0); | 
 |                 break; | 
 |             case 'd': | 
 |                 gSize = max(2, min(stoi(arg), 256)); | 
 |                 break; | 
 |             case 's': | 
 |                 gNameSrc = arg; | 
 |                 gColorSpaceSrc = findColorSpace(arg); | 
 |                 break; | 
 |             case 't': | 
 |                 gNameDst = arg; | 
 |                 gColorSpaceDst = findColorSpace(arg); | 
 |                 break; | 
 |         } | 
 |     } | 
 |  | 
 |     return optind; | 
 | } | 
 |  | 
 | int main(int argc, char* argv[]) { | 
 |     int optionIndex = handleCommandLineArgments(argc, argv); | 
 |     int numArgs = argc - optionIndex; | 
 |  | 
 |     if (numArgs < 1) { | 
 |         printHelp(); | 
 |         return 1; | 
 |     } | 
 |      | 
 |     bool isInclude = false; | 
 |  | 
 |     string filename(argv[optionIndex]); | 
 |     size_t index = filename.find_last_of('.'); | 
 |  | 
 |     if (index != string::npos) { | 
 |         string extension(filename.substr(index + 1)); | 
 |         isInclude = extension == "inc"; | 
 |     } | 
 |  | 
 |     ofstream outputStream(filename, ios::trunc); | 
 |     if (outputStream.good()) { | 
 |         auto lut = ColorSpace::createLUT(gSize, gColorSpaceSrc, gColorSpaceDst); | 
 |         auto data = lut.get(); | 
 |  | 
 |         outputStream << "// generated with lutgen " << filename.c_str() << endl; | 
 |         outputStream << "// 3D LUT stored as an RGB16F texture, in GL order" << endl; | 
 |         outputStream << "// Size is " << gSize << "x" << gSize << "x" << gSize << endl; | 
 |  | 
 |         string src(gNameSrc); | 
 |         string dst(gNameDst); | 
 |  | 
 |         if (!isInclude) { | 
 |             transform(src.begin(), src.end(), src.begin(), ::toupper); | 
 |             transform(dst.begin(), dst.end(), dst.begin(), ::toupper); | 
 |  | 
 |             outputStream << "const size_t LUT_" << src << "_TO_" << dst << "_SIZE = " << gSize << endl; | 
 |             outputStream << "const uint16_t LUT_" << src << "_TO_" << dst << "[] = {"; | 
 |         } else { | 
 |             outputStream << "// From " << src << " to " << dst << endl; | 
 |         } | 
 |  | 
 |         for (size_t z = 0; z < gSize; z++) { | 
 |             for (size_t y = 0; y < gSize; y++) { | 
 |                 for (size_t x = 0; x < gSize; x++) { | 
 |                     if (x % 4 == 0) outputStream << endl << "    "; | 
 |  | 
 |                     half3 rgb = half3(*data++); | 
 |  | 
 |                     const uint16_t r = rgb.r.getBits(); | 
 |                     const uint16_t g = rgb.g.getBits(); | 
 |                     const uint16_t b = rgb.b.getBits(); | 
 |  | 
 |                     outputStream << "0x" << setfill('0') << setw(4) << hex << r << ", "; | 
 |                     outputStream << "0x" << setfill('0') << setw(4) << hex << g << ", "; | 
 |                     outputStream << "0x" << setfill('0') << setw(4) << hex << b << ", "; | 
 |                 } | 
 |             } | 
 |         } | 
 |  | 
 |         if (!isInclude) { | 
 |             outputStream << endl << "}; // end LUT" << endl; | 
 |         } | 
 |  | 
 |         outputStream << endl; | 
 |         outputStream.flush(); | 
 |         outputStream.close(); | 
 |     } else { | 
 |         cerr << "Could not write to file: " << filename << endl; | 
 |         return 1; | 
 |  | 
 |     } | 
 |  | 
 |     return 0; | 
 | } |