1 /* 2 * Copyright 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <algorithm> 18 #include <fstream> 19 #include <iomanip> 20 #include <iostream> 21 #include <string> 22 23 #include <getopt.h> 24 25 #include <ui/ColorSpace.h> 26 27 using namespace android; 28 using namespace std; 29 30 uint32_t gSize = 32; 31 ColorSpace gColorSpaceSrc = ColorSpace::DisplayP3(); 32 ColorSpace gColorSpaceDst = ColorSpace::extendedSRGB(); 33 string gNameSrc = "DisplayP3"; 34 string gNameDst = "extendedSRGB"; 35 36 static void printHelp() { 37 cout << "lutgen -d SIZE -s SOURCE -t TARGET <lut file>" << endl; 38 cout << endl; 39 cout << "Generate a 3D LUT to convert between two color spaces." << endl; 40 cout << endl; 41 cout << "If <lut file> ends in .inc, data is generated without the array declaration." << endl; 42 cout << endl; 43 cout << "Options:" << endl; 44 cout << " --help, -h" << endl; 45 cout << " print this message" << endl; 46 cout << " --dimension=, -d" << endl; 47 cout << " the dimension of the 3D LUT. Example: 17 for a 17x17x17 LUT. 32 by default" << endl; 48 cout << " --source=COLORSPACE, -s" << endl; 49 cout << " the source color space, see below for available names. DisplayP3 by default" << endl; 50 cout << " --target=COLORSPACE, -t" << endl; 51 cout << " the target color space, see below for available names. extendedSRGB by default" << endl; 52 cout << endl; 53 cout << "Colorspace names:" << endl; 54 cout << " sRGB" << endl; 55 cout << " linearSRGB" << endl; 56 cout << " extendedSRGB" << endl; 57 cout << " linearExtendedSRGB" << endl; 58 cout << " NTSC" << endl; 59 cout << " BT709" << endl; 60 cout << " BT2020" << endl; 61 cout << " AdobeRGB" << endl; 62 cout << " ProPhotoRGB" << endl; 63 cout << " DisplayP3" << endl; 64 cout << " DCIP3" << endl; 65 cout << " ACES" << endl; 66 cout << " ACEScg" << endl; 67 } 68 69 static const ColorSpace findColorSpace(const string& name) { 70 if (name == "linearSRGB") return ColorSpace::linearSRGB(); 71 if (name == "extendedSRGB") return ColorSpace::extendedSRGB(); 72 if (name == "linearExtendedSRGB") return ColorSpace::linearExtendedSRGB(); 73 if (name == "NTSC") return ColorSpace::NTSC(); 74 if (name == "BT709") return ColorSpace::BT709(); 75 if (name == "BT2020") return ColorSpace::BT2020(); 76 if (name == "AdobeRGB") return ColorSpace::AdobeRGB(); 77 if (name == "ProPhotoRGB") return ColorSpace::ProPhotoRGB(); 78 if (name == "DisplayP3") return ColorSpace::DisplayP3(); 79 if (name == "DCIP3") return ColorSpace::DCIP3(); 80 if (name == "ACES") return ColorSpace::ACES(); 81 if (name == "ACEScg") return ColorSpace::ACEScg(); 82 return ColorSpace::sRGB(); 83 } 84 85 static int handleCommandLineArgments(int argc, char* argv[]) { 86 static constexpr const char* OPTSTR = "h:d:s:t:"; 87 static const struct option OPTIONS[] = { 88 { "help", no_argument, nullptr, 'h' }, 89 { "dimension", required_argument, nullptr, 'd' }, 90 { "source", required_argument, nullptr, 's' }, 91 { "target", required_argument, nullptr, 't' }, 92 { nullptr, 0, nullptr, 0 } // termination of the option list 93 }; 94 95 int opt; 96 int index = 0; 97 98 while ((opt = getopt_long(argc, argv, OPTSTR, OPTIONS, &index)) >= 0) { 99 string arg(optarg ? optarg : ""); 100 switch (opt) { 101 default: 102 case 'h': 103 printHelp(); 104 exit(0); 105 break; 106 case 'd': 107 gSize = max(2, min(stoi(arg), 256)); 108 break; 109 case 's': 110 gNameSrc = arg; 111 gColorSpaceSrc = findColorSpace(arg); 112 break; 113 case 't': 114 gNameDst = arg; 115 gColorSpaceDst = findColorSpace(arg); 116 break; 117 } 118 } 119 120 return optind; 121 } 122 123 int main(int argc, char* argv[]) { 124 int optionIndex = handleCommandLineArgments(argc, argv); 125 int numArgs = argc - optionIndex; 126 127 if (numArgs < 1) { 128 printHelp(); 129 return 1; 130 } 131 132 bool isInclude = false; 133 134 string filename(argv[optionIndex]); 135 size_t index = filename.find_last_of('.'); 136 137 if (index != string::npos) { 138 string extension(filename.substr(index + 1)); 139 isInclude = extension == "inc"; 140 } 141 142 ofstream outputStream(filename, ios::trunc); 143 if (outputStream.good()) { 144 auto lut = ColorSpace::createLUT(gSize, gColorSpaceSrc, gColorSpaceDst); 145 auto data = lut.get(); 146 147 outputStream << "// generated with lutgen " << filename.c_str() << endl; 148 outputStream << "// 3D LUT stored as an RGB16F texture, in GL order" << endl; 149 outputStream << "// Size is " << gSize << "x" << gSize << "x" << gSize << endl; 150 151 string src(gNameSrc); 152 string dst(gNameDst); 153 154 if (!isInclude) { 155 transform(src.begin(), src.end(), src.begin(), ::toupper); 156 transform(dst.begin(), dst.end(), dst.begin(), ::toupper); 157 158 outputStream << "const size_t LUT_" << src << "_TO_" << dst << "_SIZE = " << gSize << endl; 159 outputStream << "const uint16_t LUT_" << src << "_TO_" << dst << "[] = {"; 160 } else { 161 outputStream << "// From " << src << " to " << dst << endl; 162 } 163 164 for (size_t z = 0; z < gSize; z++) { 165 for (size_t y = 0; y < gSize; y++) { 166 for (size_t x = 0; x < gSize; x++) { 167 if (x % 4 == 0) outputStream << endl << " "; 168 169 half3 rgb = half3(*data++); 170 171 const uint16_t r = rgb.r.getBits(); 172 const uint16_t g = rgb.g.getBits(); 173 const uint16_t b = rgb.b.getBits(); 174 175 outputStream << "0x" << setfill('0') << setw(4) << hex << r << ", "; 176 outputStream << "0x" << setfill('0') << setw(4) << hex << g << ", "; 177 outputStream << "0x" << setfill('0') << setw(4) << hex << b << ", "; 178 } 179 } 180 } 181 182 if (!isInclude) { 183 outputStream << endl << "}; // end LUT" << endl; 184 } 185 186 outputStream << endl; 187 outputStream.flush(); 188 outputStream.close(); 189 } else { 190 cerr << "Could not write to file: " << filename << endl; 191 return 1; 192 193 } 194 195 return 0; 196 } 197