|  | /* | 
|  | * 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,       0, 'h' }, | 
|  | { "dimension",  required_argument, 0, 'd' }, | 
|  | { "source",     required_argument, 0, 's' }, | 
|  | { "target",     required_argument, 0, 't' }, | 
|  | { 0, 0, 0, 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; | 
|  | } |