1 /* 2 Copyright (c) 2003-2010 Sony Pictures Imageworks Inc., et al. 3 All Rights Reserved. 4 5 Redistribution and use in source and binary forms, with or without 6 modification, are permitted provided that the following conditions are 7 met: 8 * Redistributions of source code must retain the above copyright 9 notice, this list of conditions and the following disclaimer. 10 * Redistributions in binary form must reproduce the above copyright 11 notice, this list of conditions and the following disclaimer in the 12 documentation and/or other materials provided with the distribution. 13 * Neither the name of Sony Pictures Imageworks nor the names of its 14 contributors may be used to endorse or promote products derived from 15 this software without specific prior written permission. 16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <cstdio> 30 #include <iostream> 31 #include <iterator> 32 33 #include <OpenColorIO/OpenColorIO.h> 34 35 #include "FileTransform.h" 36 #include "Lut1DOp.h" 37 #include "Lut3DOp.h" 38 #include "ParseUtils.h" 39 #include "pystring/pystring.h" 40 41 OCIO_NAMESPACE_ENTER 42 { 43 namespace 44 { 45 class LocalCachedFile : public CachedFile 46 { 47 public: 48 LocalCachedFile () 49 { 50 lut3D = Lut3D::Create(); 51 }; 52 ~LocalCachedFile() {}; 53 54 Lut3DRcPtr lut3D; 55 }; 56 57 typedef OCIO_SHARED_PTR<LocalCachedFile> LocalCachedFileRcPtr; 58 59 60 61 class LocalFileFormat : public FileFormat 62 { 63 public: 64 65 ~LocalFileFormat() {}; 66 67 virtual void GetFormatInfo(FormatInfoVec & formatInfoVec) const; 68 69 virtual CachedFileRcPtr Read(std::istream & istream) const; 70 71 virtual void BuildFileOps(OpRcPtrVec & ops, 72 const Config& config, 73 const ConstContextRcPtr & context, 74 CachedFileRcPtr untypedCachedFile, 75 const FileTransform& fileTransform, 76 TransformDirection dir) const; 77 }; 78 79 void LocalFileFormat::GetFormatInfo(FormatInfoVec & formatInfoVec) const 80 { 81 FormatInfo info; 82 info.name = "pandora_mga"; 83 info.extension = "mga"; 84 info.capabilities = FORMAT_CAPABILITY_READ; 85 formatInfoVec.push_back(info); 86 87 FormatInfo info2; 88 info2.name = "pandora_m3d"; 89 info2.extension = "m3d"; 90 info2.capabilities = FORMAT_CAPABILITY_READ; 91 formatInfoVec.push_back(info2); 92 } 93 94 CachedFileRcPtr 95 LocalFileFormat::Read(std::istream & istream) const 96 { 97 // this shouldn't happen 98 if(!istream) 99 { 100 throw Exception ("File stream empty when trying to read Pandora lut"); 101 } 102 103 // Validate the file type 104 std::string line; 105 106 // Parse the file 107 std::string format; 108 int lutEdgeLen = 0; 109 int outputBitDepthMaxValue = 0; 110 std::vector<int> raw3d; 111 112 { 113 std::vector<std::string> parts; 114 std::vector<int> tmpints; 115 bool inLut3d = false; 116 117 while(nextline(istream, line)) 118 { 119 // Strip, lowercase, and split the line 120 pystring::split(pystring::lower(pystring::strip(line)), parts); 121 if(parts.empty()) continue; 122 123 // Skip all lines starting with '#' 124 if(pystring::startswith(parts[0],"#")) continue; 125 126 if(parts[0] == "channel") 127 { 128 if(parts.size() != 2 || pystring::lower(parts[1]) != "3d") 129 { 130 throw Exception("Parse error in Pandora lut. Only 3d luts are currently supported. (channel: 3d)."); 131 } 132 } 133 else if(parts[0] == "in") 134 { 135 int inval = 0; 136 if(parts.size() != 2 || !StringToInt( &inval, parts[1].c_str())) 137 { 138 throw Exception("Malformed 'in' tag in Pandora lut."); 139 } 140 raw3d.reserve(inval*3); 141 lutEdgeLen = Get3DLutEdgeLenFromNumPixels(inval); 142 } 143 else if(parts[0] == "out") 144 { 145 if(parts.size() != 2 || !StringToInt( &outputBitDepthMaxValue, parts[1].c_str())) 146 { 147 throw Exception("Malformed 'out' tag in Pandora lut."); 148 } 149 } 150 else if(parts[0] == "format") 151 { 152 if(parts.size() != 2 || pystring::lower(parts[1]) != "lut") 153 { 154 throw Exception("Parse error in Pandora lut. Only luts are currently supported. (format: lut)."); 155 } 156 } 157 else if(parts[0] == "values") 158 { 159 if(parts.size() != 4 || 160 pystring::lower(parts[1]) != "red" || 161 pystring::lower(parts[2]) != "green" || 162 pystring::lower(parts[3]) != "blue") 163 { 164 throw Exception("Parse error in Pandora lut. Only rgb luts are currently supported. (values: red green blue)."); 165 } 166 167 inLut3d = true; 168 } 169 else if(inLut3d) 170 { 171 if(!StringVecToIntVec(tmpints, parts) || tmpints.size() != 4) 172 { 173 std::ostringstream os; 174 os << "Parse error in Pandora lut. Expected to find 4 integers. Instead found '" 175 << line << "'"; 176 throw Exception(os.str().c_str()); 177 } 178 179 raw3d.push_back(tmpints[1]); 180 raw3d.push_back(tmpints[2]); 181 raw3d.push_back(tmpints[3]); 182 } 183 } 184 } 185 186 // Interpret the parsed data, validate lut sizes 187 if(lutEdgeLen*lutEdgeLen*lutEdgeLen != static_cast<int>(raw3d.size()/3)) 188 { 189 std::ostringstream os; 190 os << "Parse error in Pandora lut. "; 191 os << "Incorrect number of lut3d entries. "; 192 os << "Found " << raw3d.size()/3 << ", expected " << lutEdgeLen*lutEdgeLen*lutEdgeLen << "."; 193 throw Exception(os.str().c_str()); 194 } 195 196 if(lutEdgeLen*lutEdgeLen*lutEdgeLen == 0) 197 { 198 std::ostringstream os; 199 os << "Parse error in Pandora lut. "; 200 os << "No 3D Lut entries found."; 201 throw Exception(os.str().c_str()); 202 } 203 204 if(outputBitDepthMaxValue <= 0) 205 { 206 std::ostringstream os; 207 os << "Parse error in Pandora lut. "; 208 os << "A valid 'out' tag was not found."; 209 throw Exception(os.str().c_str()); 210 } 211 212 LocalCachedFileRcPtr cachedFile = LocalCachedFileRcPtr(new LocalCachedFile()); 213 214 // Reformat 3D data 215 cachedFile->lut3D->size[0] = lutEdgeLen; 216 cachedFile->lut3D->size[1] = lutEdgeLen; 217 cachedFile->lut3D->size[2] = lutEdgeLen; 218 cachedFile->lut3D->lut.reserve(raw3d.size()); 219 220 float scale = 1.0f / ((float)outputBitDepthMaxValue - 1.0f); 221 222 for(int rIndex=0; rIndex<lutEdgeLen; ++rIndex) 223 { 224 for(int gIndex=0; gIndex<lutEdgeLen; ++gIndex) 225 { 226 for(int bIndex=0; bIndex<lutEdgeLen; ++bIndex) 227 { 228 int i = GetLut3DIndex_B(rIndex, gIndex, bIndex, 229 lutEdgeLen, lutEdgeLen, lutEdgeLen); 230 cachedFile->lut3D->lut.push_back(static_cast<float>(raw3d[i+0]) * scale); 231 cachedFile->lut3D->lut.push_back(static_cast<float>(raw3d[i+1]) * scale); 232 cachedFile->lut3D->lut.push_back(static_cast<float>(raw3d[i+2]) * scale); 233 } 234 } 235 } 236 237 return cachedFile; 238 } 239 240 void 241 LocalFileFormat::BuildFileOps(OpRcPtrVec & ops, 242 const Config& /*config*/, 243 const ConstContextRcPtr & /*context*/, 244 CachedFileRcPtr untypedCachedFile, 245 const FileTransform& fileTransform, 246 TransformDirection dir) const 247 { 248 LocalCachedFileRcPtr cachedFile = DynamicPtrCast<LocalCachedFile>(untypedCachedFile); 249 250 // This should never happen. 251 if(!cachedFile) 252 { 253 std::ostringstream os; 254 os << "Cannot build Truelight .cub Op. Invalid cache type."; 255 throw Exception(os.str().c_str()); 256 } 257 258 TransformDirection newDir = CombineTransformDirections(dir, 259 fileTransform.getDirection()); 260 if(newDir == TRANSFORM_DIR_UNKNOWN) 261 { 262 std::ostringstream os; 263 os << "Cannot build file format transform,"; 264 os << " unspecified transform direction."; 265 throw Exception(os.str().c_str()); 266 } 267 268 if(newDir == TRANSFORM_DIR_FORWARD) 269 { 270 CreateLut3DOp(ops, cachedFile->lut3D, 271 fileTransform.getInterpolation(), newDir); 272 } 273 else if(newDir == TRANSFORM_DIR_INVERSE) 274 { 275 CreateLut3DOp(ops, cachedFile->lut3D, 276 fileTransform.getInterpolation(), newDir); 277 } 278 } 279 } 280 281 FileFormat * CreateFileFormatPandora() 282 { 283 return new LocalFileFormat(); 284 } 285 } 286 OCIO_NAMESPACE_EXIT 287