| /* |
| * 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; |
| } |