Hoyt's FORK of DemoIccMAX 2.1.17.hoyt
Documentation for Hoyt's FORK of DemoIccMAX
Loading...
Searching...
No Matches
iccFromCube.cpp
Go to the documentation of this file.
1/*
2 File: iccFromCube.cpp
3
4 Contains: Console app to parse cube file and create ICC.2 device link profile
5
6 Version: V1
7
8 Copyright: (c) see below
9*/
10
11/*
12 * The ICC Software License, Version 0.2
13 *
14 *
15 * Copyright (c) 2003-2023 The International Color Consortium. All rights
16 * reserved.
17 *
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions
20 * are met:
21 *
22 * 1. Redistributions of source code must retain the above copyright
23 * notice, this list of conditions and the following disclaimer.
24 *
25 * 2. Redistributions in binary form must reproduce the above copyright
26 * notice, this list of conditions and the following disclaimer in
27 * the documentation and/or other materials provided with the
28 * distribution.
29 *
30 * 3. In the absence of prior written permission, the names "ICC" and "The
31 * International Color Consortium" must not be used to imply that the
32 * ICC organization endorses or promotes products derived from this
33 * software.
34 *
35 *
36 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39 * DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR
40 * ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 * SUCH DAMAGE.
48 * ====================================================================
49 *
50 * This software consists of voluntary contributions made by many
51 * individuals on behalf of the The International Color Consortium.
52 *
53 *
54 * Membership in the ICC is encouraged when this software is used for
55 * commercial purposes.
56 *
57 *
58 * For more information on The International Color Consortium, please
59 * see <http://www.color.org/>.
60 *
61 *
62 */
63
64//////////////////////////////////////////////////////////////////////
65// HISTORY:
66//
67// -Initial implementation by Max Derhak 3-09-2023
68//
69//////////////////////////////////////////////////////////////////////
70
71
72#include <stdio.h>
73#include <string>
74#include "IccProfile.h"
75#include "IccTagBasic.h"
76#include "IccTagMPE.h"
77#include "IccMpeBasic.h"
78#include "IccProfLibVer.h"
79#include "IccUtil.h"
80
82{
83public:
84 CubeFile(const char* szFilename)
85 {
86 m_sFilename = szFilename;
87 }
89
90 void close()
91 {
92 if (m_f)
93 fclose(m_f);
94 m_f = nullptr;
95 }
96
98 {
99 if (!open())
100 return false;
101
102 m_title.clear();
103 m_comments.clear();
104 m_sizeLut3D = 0;
105 m_fMinInput[0] = m_fMinInput[1] = m_fMinInput[2] = 0.0f;
106 m_fMaxInput[0] = m_fMaxInput[1] = m_fMaxInput[2] = 1.0f;
107
108 bool bAddBlankLine = false;
109 while (!isEOF()) {
110 long pos = ftell(m_f);
111 std::string line = getNextLine();
112
113 if (line[0] == '-' || line[0] == '.' || (line[0] >= '0' && line[0] <= '9')) {
114 //undo getNextLine so it can be 3D table can be parsed
115 fseek(m_f, pos, SEEK_SET);
116 break;
117 }
118
119 if (!line.size()) {
120 if (m_comments.size()) {
121 bAddBlankLine = true;
122 }
123 }
124 else if (line.substr(0, 6) == "TITLE ") {
125 if (m_title.size()) {
126 m_title += "\n";
127 }
128 m_title += getTitle(line.c_str() + 6);
129 }
130 else if (line[0] == '#') {
131 if (bAddBlankLine) {
132 m_comments += "\n";
133 }
134 if (line[1]==' ')
135 m_comments += line.c_str() + 2;
136 else
137 m_comments += line.c_str() + 1;
138 m_comments += '\n';
139
140 bAddBlankLine = false;
141 }
142 else if (line.substr(0, 12) == "LUT_1D_SiZE ") {
143 printf("1DLUTs are not supported\n");
144 return false;
145 }
146 else if (line.substr(0, 12) == "LUT_3D_SIZE ") {
147 m_sizeLut3D = atoi(line.c_str() + 12);
148 }
149 else if (line.substr(0, 19) == "LUT_3D_INPUT_RANGE ") {
150 m_fMinInput[0] = m_fMinInput[1] = m_fMinInput[2] = (icFloatNumber)atof(line.c_str() + 19);
151 const char* next = getNext(line.c_str() + 19);
152 if (next) {
153 m_fMaxInput[0] = m_fMaxInput[1] = m_fMaxInput[2] = (icFloatNumber)atof(next);
154 }
155 }
156 else if (line.substr(0, 11) == "DOMAIN_MIN ") {
157 m_fMinInput[0] = (icFloatNumber)atof(line.c_str() + 11);
158 const char* next = getNext(line.c_str());
159 if (next) {
160 m_fMinInput[1] = (icFloatNumber)atof(next);
161 next = getNext(next);
162 if (next) {
163 m_fMinInput[2] = (icFloatNumber)atof(next);
164 }
165 else
166 m_fMinInput[2] = m_fMinInput[1];
167 }
168 else {
170 }
171 }
172 else if (line.substr(0, 11) == "DOMAIN_MAX ") {
173 m_fMaxInput[0] = (icFloatNumber)atof(line.c_str() + 11);
174 const char* next = getNext(line.c_str());
175 if (next) {
176 m_fMaxInput[1] = (icFloatNumber)atof(next);
177 next = getNext(next);
178 if (next) {
179 m_fMaxInput[2] = (icFloatNumber)atof(next);
180 }
181 else
182 m_fMaxInput[2] = m_fMaxInput[1];
183 }
184 else {
186 }
187 }
188 else if (line.substr(0, 18) == "LUT_IN_VIDEO_RANGE")
189 m_bLutInVideoRange = true;
190 else if (line.substr(0, 19) == "LUT_OUT_VIDEO_RANGE")
191 m_bLutOutVideoRange = true;
192 else {
193 printf("Unknown keyword '%s'\n", line.c_str());
194 return false;
195 }
196 }
197
198 return !isEOF();
199 }
200
201 std::string getDescription() { return m_title; }
202 std::string getCopyright() { return m_comments; }
203
206
208 {
209 if (!icIsNear(m_fMinInput[0], 0.0) || !icIsNear(m_fMinInput[1], 0.0) || !icIsNear(m_fMinInput[2], 0.0) ||
210 !icIsNear(m_fMaxInput[0], 1.0) || !icIsNear(m_fMaxInput[1], 1.0) || !icIsNear(m_fMaxInput[2], 1.0))
211 return true;
212 return false;
213 }
214
215 int sizeLut3D() { return m_sizeLut3D; }
217 {
219
220 //
221 if (!m_sizeLut3D || nSizeLut != num*3)
222 return false;
223
224 const char* next;
225 for (auto n = 0u; n < num && !isEOF();) {
226 std::string line = getNextLine();
227
228 //Skip empty and commented lines
229 if (line[0] == '#' || line.size() == 0)
230 continue;
231 *toLut++ = (icFloatNumber)atof(line.c_str());
232 next = getNext(line.c_str());
233 if (!next) {
234 printf("Invalid 3DLUT entry\n");
235 return false;
236 }
237 *toLut++ = (icFloatNumber)atof(next);
238 next = getNext(next);
239 if (!next) {
240 printf("Invalid 3DLUT entry\n");
241 return false;
242 }
243 *toLut++ = (icFloatNumber)atof(next);
244
245 n++;
246 }
247 return true;
248 }
249
250protected:
251 std::string m_sFilename;
252
253 bool open()
254 {
255 if (!m_f) {
256 m_f = fopen(m_sFilename.c_str(), "rb");
257 }
258 else {
259 fseek(m_f, 0, SEEK_SET);
260 }
261 return m_f != nullptr;
262 }
263
264 std::string getTitle(const char* str)
265 {
266 std::string rv;
267 bool bNeedQuote = false;
268 if (*str == '\"') {
269 bNeedQuote = true;
270 str++;
271 }
272 while (*str && (!bNeedQuote || *str != '\"')) {
273 rv += *str++;
274 }
275
276 return rv;
277 }
278
279 const char* getNext(const char* str)
280 {
281 while (*str && *str == ' ') str++;
282 while (*str && *str != ' ') str++;
283 while (*str && *str == ' ') str++;
284
285 return str;
286 }
287
288 std::string toEnd(const char* str)
289 {
290 std::string rv;
291 while (*str && *str != '\"') {
292 rv += *str++;
293 }
294
295 return rv;
296 }
297
298 bool isEOF() { return m_f ? feof(m_f)!=0 : true; }
299
300#define MAX_LINE_LEN 255
301
302 std::string getNextLine()
303 {
304 std::string rv;
305 for (int n=0; n<MAX_LINE_LEN && !isEOF(); n++) {
306 char c = fgetc(m_f);
307
308 if ((c < 0 && feof(m_f)) || c == '\n')
309 break;
310
311 if (c == '\r') //skip unsupported carriage returns
312 continue;
313
314 rv += (unsigned char)c;
315 }
316
317 return rv;
318 }
319
320 FILE* m_f=nullptr;
321
322 int m_sizeLut3D = 0;
323 icFloatNumber m_fMinInput[3] = { 0.0f, 0.0f, 0.0f };
324 icFloatNumber m_fMaxInput[3] = { 1.0f, 1.0f, 1.0f };
325
326 std::string m_title;
327 std::string m_comments;
328
329 bool m_bLutInVideoRange = false;
331};
332
333int main(int argc, char* argv[])
334{
335 int nArg = 1;
336 long int verbosity = 100; // default is maximum verbosity (old behaviour)
337
338 if (argc <= 2) {
339 printf("Usage: iccFromCube cube_file output_icc_file\n");
340 printf("Built with IccProfLib version " ICCPROFLIBVER "\n");
341
342 return -1;
343 }
344
345 CubeFile cube(argv[1]);
346
347 if (!cube.parseHeader()) {
348 printf("Unable to parse '%s'\n", argv[1]);
349 return -2;
350 }
351
352 if (!cube.sizeLut3D()) {
353 printf("3DLUT not found in '%s'\n", argv[1]);
354 return -3;
355 }
356
357 CIccProfile profile;
358
359 //Initialize profile header
360 profile.InitHeader();
361 profile.m_Header.version = icVersionNumberV5;
362 profile.m_Header.colorSpace = icSigRgbData;
363 profile.m_Header.pcs = icSigRgbData;
364 profile.m_Header.deviceClass = icSigLinkClass;
365
366 //Create A2B0 Tag with LUT
368 if (cube.isCustomInputRange()) {
369 icFloatNumber* minVal = cube.getMinInput();
370 icFloatNumber* maxVal = cube.getMaxInput();
371 CIccMpeCurveSet* pCurves = new CIccMpeCurveSet(3);
372 CIccSingleSampledCurve* pCurve0 = new CIccSingleSampledCurve(minVal[0], maxVal[0]);
373
374 pCurve0->SetSize(2);
375 pCurve0->GetSamples()[0] = 0;
376 pCurve0->GetSamples()[1] = 1;
377
378 pCurves->SetCurve(0, pCurve0);
379
380 CIccSingleSampledCurve* pCurve1 = pCurve0;
381 if (minVal[1] != minVal[0] || maxVal[1] != maxVal[0]) {
382 pCurve1 = new CIccSingleSampledCurve(minVal[1], maxVal[1]);
383
384 pCurve1->SetSize(2);
385 pCurve1->GetSamples()[0] = 0;
386 pCurve1->GetSamples()[1] = 1;
387 }
388
389 pCurves->SetCurve(1, pCurve1);
390
391 CIccSingleSampledCurve* pCurve2 = pCurve0;
392
393 if (minVal[2] != minVal[0] || maxVal[2] != maxVal[0]) {
394 if (minVal[2] == minVal[1] && maxVal[2] == maxVal[1])
395 pCurve2 = pCurve1;
396 else {
397 pCurve2 = new CIccSingleSampledCurve(minVal[2], maxVal[2]);
398
399 pCurve2->SetSize(2);
400 pCurve2->GetSamples()[0] = 0;
401 pCurve2->GetSamples()[1] = 1;
402 }
403 }
404
405 pCurves->SetCurve(2, pCurve2);
406
407 pTag->Attach(pCurves);
408 }
409
410 CIccMpeCLUT* pMpeCLUT = new CIccMpeCLUT();
411 CIccCLUT* pCLUT = new CIccCLUT(3, 3);
412 pCLUT->Init(cube.sizeLut3D());
413 bool bSuccess = cube.parse3DTable(pCLUT->GetData(0), pCLUT->NumPoints()*3);
414
415 pMpeCLUT->SetCLUT(pCLUT);
416 pTag->Attach(pMpeCLUT);
417
418 profile.AttachTag(icSigAToB0Tag, pTag);
419
420 cube.close();
421
422 if (!bSuccess) {
423 printf("Unable to parse LUT from '%s'\n", argv[1]);
424 return (-4);
425 }
426
427 //Add description Tag
429 std::string desc = cube.getDescription();
430 if (desc.size()) {
431 pTextTag->SetText(desc.c_str());
432 }
433 else {
434 pTextTag->SetText((std::string("Device link created from ") + argv[1]).c_str());
435 }
436 profile.AttachTag(icSigProfileDescriptionTag, pTextTag);
437
438
439 //Add copyright Tag
440 if (cube.getCopyright().size()) {
441 pTextTag = new CIccTagMultiLocalizedUnicode();
442 pTextTag->SetText(cube.getCopyright().c_str());
443 profile.AttachTag(icSigCopyrightTag, pTextTag);
444 }
445
446 if (SaveIccProfile(argv[2], &profile)) {
447 printf("'%s' successfully created\n", argv[2]);
448 }
449 else {
450 printf("Unable to save profile '%s'\n", argv[2]);
451 return -5;
452 }
453
454 return 0;
455}
456
float icFloatNumber
All floating point operations/variables in IccProfLib use the icFloatNumber data type.
Definition IccDefs.h:100
File: IccMpeBasic.h.
#define ICCPROFLIBVER
bool SaveIccProfile(const icChar *szFilename, CIccProfile *pIcc, icProfileIDSaveMethod nWriteId)
Name: SaveIccProfile.
File: IccProfile.h.
File: IccTagBasic.h.
File: IccTagMPE.h.
bool icIsNear(icFloatNumber v1, icFloatNumber v2, icFloatNumber nearRange)
Name: icIsNear.
Definition IccUtil.cpp:142
File: IccUtil.h.
int main()
Core and external libraries necessary for the fuzzer functionality.
unsigned int icUInt32Number
Class: CIccCLUT.
Definition IccTagLut.h:326
icUInt32Number NumPoints() const
Definition IccTagLut.h:348
icFloatNumber * GetData(int index)
Definition IccTagLut.h:347
bool Init(icUInt8Number nGridPoints, icUInt32Number nMaxSize=0, icUInt8Number nBytesPerPoint=4)
Name: CIccCLUT::Init.
Class: CIccMpeCLUT.
void SetCLUT(CIccCLUT *pCLUT)
Name: CIccMpeCLUT::SetCLUT.
Class: CIccMpeCurveSet.
bool SetCurve(int nIndex, icCurveSetCurvePtr newCurve)
Name: CIccMpeCurveSet::SetCurve.
Class: CIccSingleSampledCurve.
virtual icFloatNumber * GetSamples()
virtual bool SetSize(icUInt32Number nSize, bool bZeroAlloc=true)
Name: CIccSingleSampledCurve::SetSize.
Class: CIccTagMultiLocalizedUnicode.
void SetText(const icChar *szText, icLanguageCode nLanguageCode=icLanguageCodeEnglish, icCountryCode nRegionCode=icCountryCodeUSA)
Name: refIccMAX::CIccTagMultiLocalizedUnicode::SetText.
Class: CIccTagMultiProcessElement.
Definition IccTagMPE.h:358
virtual void Attach(CIccMultiProcessElement *pElement)
Name: CIccTagMultiProcessElement::Attach.
bool open()
std::string getTitle(const char *str)
const char * getNext(const char *str)
std::string m_title
std::string toEnd(const char *str)
bool parseHeader()
bool m_bLutInVideoRange
std::string m_sFilename
std::string getDescription()
bool isCustomInputRange()
void close()
bool m_bLutOutVideoRange
std::string getNextLine()
std::string getCopyright()
std::string m_comments
bool isEOF()
bool parse3DTable(icFloatNumber *toLut, icUInt32Number nSizeLut)
icFloatNumber * getMinInput()
icFloatNumber * getMaxInput()
icFloatNumber m_fMaxInput[3]
CubeFile(const char *szFilename)
int sizeLut3D()
icFloatNumber m_fMinInput[3]
@ icSigLinkClass
@ icSigRgbData
#define icVersionNumberV5
@ icSigAToB0Tag
@ icSigProfileDescriptionTag
@ icSigCopyrightTag
#define MAX_LINE_LEN