1 /*
2 For general Scribus (>=1.3.2) copyright and licensing information please refer
3 to the COPYING file provided with the program. Following this notice may exist
4 a copyright and/or license notice that predates the release of Scribus 1.3.2
5 for which a new license (GPL+exception) is in place.
6 */
7
8 #include <cmath>
9
10 #include "cxfcolor.h"
11 #include "cxfcolorspecification.h"
12 #include "cxfdocument.h"
13 #include "cxfmeasurementspec.h"
14
15 #include "colormgmt/sccolormgmtstructs.h"
16
CxfColor(CxfDocument * cxfDoc)17 CxfColor::CxfColor(CxfDocument* cxfDoc)
18 {
19 m_cxfDoc = cxfDoc;
20 m_colorSpec = nullptr;
21 }
22
isValid() const23 bool CxfColor::isValid() const
24 {
25 bool valid = true;
26 valid &= (m_cxfDoc != nullptr);
27 valid &= (m_colorSpec != nullptr);
28 return valid;
29 }
30
reset()31 void CxfColor::reset()
32 {
33 m_colorSpec = nullptr;
34 }
35
CxfColorRGB(CxfDocument * cxfDoc)36 CxfColorRGB::CxfColorRGB(CxfDocument* cxfDoc)
37 : CxfColor(cxfDoc)
38 {
39 m_maxRange = 255.0;
40 m_values[0] = 0.0;
41 m_values[1] = 0.0;
42 m_values[2] = 0.0;
43 }
44
parse(QDomElement & colorElem)45 bool CxfColorRGB::parse(QDomElement& colorElem)
46 {
47 bool convOk = false;
48 bool gotRed(false);
49 bool gotGreen(false);
50 bool gotBlue(false);
51
52 reset();
53
54 QString colorSpec = colorElem.attribute("ColorSpecification");
55 if (colorSpec.isEmpty())
56 return false;
57
58 m_colorSpec = m_cxfDoc->colorSpecification(colorSpec);
59 if (!m_colorSpec)
60 return false;
61
62 QDomElement maxRangeElem = colorElem.firstChildElement("MaxRange");
63 if (!maxRangeElem.isNull())
64 {
65 QString str = maxRangeElem.text();
66 double maxRange = str.toDouble(&convOk);
67 if (!convOk)
68 return false;
69 m_maxRange = maxRange;
70 }
71
72 QDomNodeList childNodes = colorElem.childNodes();
73 for (int i = 0; i < childNodes.count(); ++i)
74 {
75 QDomNode childNode = childNodes.at(i);
76 if (!childNode.isElement())
77 continue;
78 QDomElement childElem = childNode.toElement();
79
80 QString tagName = childElem.tagName();
81 if (tagName == "R")
82 {
83 QString str = childElem.text();
84 double red = str.toDouble(&gotRed);
85 if (!gotRed)
86 return false;
87 m_values[0] = qMax(0.0, qMin(red, m_maxRange));
88 continue;
89 }
90 if (tagName == "G")
91 {
92 QString str = childElem.text();
93 double green = str.toDouble(&gotGreen);
94 if (!gotGreen)
95 return false;
96 m_values[1] = qMax(0.0, qMin(green, m_maxRange));
97 continue;
98 }
99 if (tagName == "B")
100 {
101 QString str = childElem.text();
102 double blue = str.toDouble(&gotBlue);
103 if (!gotBlue)
104 return false;
105 m_values[2] = qMax(0.0, qMin(blue, m_maxRange));
106 continue;
107 }
108 }
109
110 return (gotRed && gotGreen && gotBlue);
111 }
112
reset()113 void CxfColorRGB::reset()
114 {
115 CxfColor::reset();
116
117 m_maxRange = 255.0;
118 m_values[0] = 0.0;
119 m_values[1] = 0.0;
120 m_values[2] = 0.0;
121 }
122
CxfColorSRGB(CxfDocument * cxfDoc)123 CxfColorSRGB::CxfColorSRGB(CxfDocument* cxfDoc)
124 : CxfColorRGB(cxfDoc)
125 {
126
127 }
128
CxfColorAdobeRGB(CxfDocument * cxfDoc)129 CxfColorAdobeRGB::CxfColorAdobeRGB(CxfDocument* cxfDoc)
130 : CxfColorRGB(cxfDoc)
131 {
132
133 }
134
CxfColorHTML(CxfDocument * cxfDoc)135 CxfColorHTML::CxfColorHTML(CxfDocument* cxfDoc)
136 : CxfColorRGB(cxfDoc)
137 {
138
139 }
140
parse(QDomElement & colorElem)141 bool CxfColorHTML::parse(QDomElement& colorElem)
142 {
143 bool convOk = false;
144
145 reset();
146
147 QString colorSpec = colorElem.attribute("ColorSpecification");
148 if (colorSpec.isEmpty())
149 return false;
150
151 m_colorSpec = m_cxfDoc->colorSpecification(colorSpec);
152 if (!m_colorSpec)
153 return false;
154
155 QString html = colorElem.attribute("HTML");
156 if (html.length() < 6)
157 return false;
158
159 QString rStr = html.mid(0, 2);
160 int red = rStr.toInt(&convOk, 16);
161 if (!convOk)
162 return false;
163 m_values[0] = red;
164
165 QString gStr = html.mid(2, 2);
166 int green = gStr.toInt(&convOk, 16);
167 if (!convOk)
168 return false;
169 m_values[1] = green;
170
171 QString bStr = html.mid(4, 2);
172 int blue = bStr.toInt(&convOk, 16);
173 if (!convOk)
174 return false;
175 m_values[2] = blue;
176
177 return true;
178 }
179
CxfColorCMYK(CxfDocument * cxfDoc)180 CxfColorCMYK::CxfColorCMYK(CxfDocument* cxfDoc)
181 : CxfColor(cxfDoc)
182 {
183 m_values[0] = 0.0;
184 m_values[1] = 0.0;
185 m_values[2] = 0.0;
186 m_values[3] = 0.0;
187 }
188
parse(QDomElement & colorElem)189 bool CxfColorCMYK::parse(QDomElement& colorElem)
190 {
191 bool gotCyan(false);
192 bool gotMagenta(false);
193 bool gotYellow(false);
194 bool gotBlack(false);
195
196 reset();
197
198 QString colorSpec = colorElem.attribute("ColorSpecification");
199 if (colorSpec.isEmpty())
200 return false;
201
202 m_colorSpec = m_cxfDoc->colorSpecification(colorSpec);
203 if (!m_colorSpec)
204 return false;
205
206 QDomNodeList childNodes = colorElem.childNodes();
207 for (int i = 0; i < childNodes.count(); ++i)
208 {
209 QDomNode childNode = childNodes.at(i);
210 if (!childNode.isElement())
211 continue;
212 QDomElement childElem = childNode.toElement();
213
214 QString tagName = childElem.tagName();
215 if (tagName == "Cyan")
216 {
217 QString str = childElem.text();
218 double cyan = str.toDouble(&gotCyan);
219 if (!gotCyan)
220 return false;
221 m_values[0] = qMax(0.0, qMin(cyan, 100.0));
222 continue;
223 }
224 if (tagName == "Magenta")
225 {
226 QString str = childElem.text();
227 double magenta = str.toDouble(&gotMagenta);
228 if (!gotMagenta)
229 return false;
230 m_values[1] = qMax(0.0, qMin(magenta, 100.0));
231 continue;
232 }
233 if (tagName == "Yellow")
234 {
235 QString str = childElem.text();
236 double yellow = str.toDouble(&gotYellow);
237 if (!gotYellow)
238 return false;
239 m_values[2] = qMax(0.0, qMin(yellow, 100.0));
240 continue;
241 }
242 if (tagName == "Black")
243 {
244 QString str = childElem.text();
245 double black = str.toDouble(&gotBlack);
246 if (!gotBlack)
247 return false;
248 m_values[3] = qMax(0.0, qMin(black, 100.0));
249 continue;
250 }
251 }
252
253 return (gotCyan && gotMagenta && gotYellow && gotBlack);
254 }
255
reset()256 void CxfColorCMYK::reset()
257 {
258 CxfColor::reset();
259
260 m_values[0] = 0.0;
261 m_values[1] = 0.0;
262 m_values[2] = 0.0;
263 m_values[3] = 0.0;
264 }
265
CxfColorCIELab(CxfDocument * cxfDoc)266 CxfColorCIELab::CxfColorCIELab(CxfDocument* cxfDoc)
267 : CxfColor(cxfDoc)
268 {
269 m_values[0] = 0.0;
270 m_values[1] = 0.0;
271 m_values[2] = 0.0;
272 }
273
parse(QDomElement & colorElem)274 bool CxfColorCIELab::parse(QDomElement& colorElem)
275 {
276 bool gotLab_L(false);
277 bool gotLab_a(false);
278 bool gotLab_b(false);
279
280 reset();
281
282 QString colorSpec = colorElem.attribute("ColorSpecification");
283 if (colorSpec.isEmpty())
284 return false;
285
286 m_colorSpec = m_cxfDoc->colorSpecification(colorSpec);
287 if (!m_colorSpec)
288 return false;
289
290 QDomNodeList childNodes = colorElem.childNodes();
291 for (int i = 0; i < childNodes.count(); ++i)
292 {
293 QDomNode childNode = childNodes.at(i);
294 if (!childNode.isElement())
295 continue;
296 QDomElement childElem = childNode.toElement();
297
298 QString tagName = childElem.tagName();
299 if (tagName == "L")
300 {
301 QString str = childElem.text();
302 double lab_L = str.toDouble(&gotLab_L);
303 if (!gotLab_L)
304 return false;
305 m_values[0] = qMax(0.0, qMin(lab_L, 100.0));
306 continue;
307 }
308 if (tagName == "A")
309 {
310 QString str = childElem.text();
311 double lab_a = str.toDouble(&gotLab_a);
312 if (!gotLab_a)
313 return false;
314 m_values[1] = lab_a;
315 continue;
316 }
317 if (tagName == "B")
318 {
319 QString str = childElem.text();
320 double lab_b = str.toDouble(&gotLab_b);
321 if (!gotLab_b)
322 return false;
323 m_values[2] = lab_b;
324 continue;
325 }
326 }
327
328 return (gotLab_L && gotLab_a && gotLab_b);
329 }
330
reset()331 void CxfColorCIELab::reset()
332 {
333 CxfColor::reset();
334
335 m_values[0] = 0.0;
336 m_values[1] = 0.0;
337 m_values[2] = 0.0;
338 }
339
CxfColorCIELCh(CxfDocument * cxfDoc)340 CxfColorCIELCh::CxfColorCIELCh(CxfDocument* cxfDoc)
341 : CxfColor(cxfDoc)
342 {
343 m_values[0] = 0.0;
344 m_values[1] = 0.0;
345 m_values[2] = 0.0;
346 }
347
lab() const348 ScLab CxfColorCIELCh::lab() const
349 {
350 ScLab lab;
351 lab.L = m_values[0];
352 lab.a = m_values[1] * cos(m_values[2] * M_PI / 180.0);
353 lab.b = m_values[1] * cos(m_values[2] * M_PI / 180.0);
354 return lab;
355 }
356
parse(QDomElement & colorElem)357 bool CxfColorCIELCh::parse(QDomElement& colorElem)
358 {
359 bool gotLCh_L(false);
360 bool gotLCh_C(false);
361 bool gotLCh_h(false);
362
363 reset();
364
365 QString colorSpec = colorElem.attribute("ColorSpecification");
366 if (colorSpec.isEmpty())
367 return false;
368
369 m_colorSpec = m_cxfDoc->colorSpecification(colorSpec);
370 if (!m_colorSpec)
371 return false;
372
373 QDomNodeList childNodes = colorElem.childNodes();
374 for (int i = 0; i < childNodes.count(); ++i)
375 {
376 QDomNode childNode = childNodes.at(i);
377 if (!childNode.isElement())
378 continue;
379 QDomElement childElem = childNode.toElement();
380
381 QString tagName = childElem.tagName();
382 if (tagName == "L")
383 {
384 QString str = childElem.text();
385 double lch_L = str.toDouble(&gotLCh_L);
386 if (!gotLCh_L)
387 return false;
388 m_values[0] = qMax(0.0, qMin(lch_L, 100.0));
389 continue;
390 }
391 if (tagName == "C")
392 {
393 QString str = childElem.text();
394 double lch_C = str.toDouble(&gotLCh_C);
395 if (!gotLCh_C)
396 return false;
397 m_values[1] = qMax(0.0, lch_C);
398 continue;
399 }
400 if (tagName == "H")
401 {
402 QString str = childElem.text();
403 double lch_h = str.toDouble(&gotLCh_h);
404 if (!gotLCh_h)
405 return false;
406 while (lch_h < 0)
407 lch_h += 360.0;
408 while (lch_h > 360)
409 lch_h -= 360.0;
410 m_values[2] = lch_h;
411 continue;
412 }
413 }
414
415 return (gotLCh_L && gotLCh_C && gotLCh_h);
416 }
417
reset()418 void CxfColorCIELCh::reset()
419 {
420 CxfColor::reset();
421
422 m_values[0] = 0.0;
423 m_values[1] = 0.0;
424 m_values[2] = 0.0;
425 }
426
CxfColorCIEXYZ(CxfDocument * cxfDoc)427 CxfColorCIEXYZ::CxfColorCIEXYZ(CxfDocument* cxfDoc)
428 : CxfColor(cxfDoc)
429 {
430 m_values[0] = 0.0;
431 m_values[1] = 0.0;
432 m_values[2] = 0.0;
433 }
434
parse(QDomElement & colorElem)435 bool CxfColorCIEXYZ::parse(QDomElement& colorElem)
436 {
437 bool gotXYZ_X(false);
438 bool gotXYZ_Y(false);
439 bool gotXYZ_Z(false);
440
441 reset();
442
443 QString colorSpec = colorElem.attribute("ColorSpecification");
444 if (colorSpec.isEmpty())
445 return false;
446
447 m_colorSpec = m_cxfDoc->colorSpecification(colorSpec);
448 if (!m_colorSpec)
449 return false;
450
451 QDomNodeList childNodes = colorElem.childNodes();
452 for (int i = 0; i < childNodes.count(); ++i)
453 {
454 QDomNode childNode = childNodes.at(i);
455 if (!childNode.isElement())
456 continue;
457 QDomElement childElem = childNode.toElement();
458
459 QString tagName = childElem.tagName();
460 if (tagName == "X")
461 {
462 QString str = childElem.text();
463 double xyz_x = str.toDouble(&gotXYZ_X);
464 if (!gotXYZ_X)
465 return false;
466 m_values[0] = qMax(0.0, qMin(xyz_x, 100.0));
467 m_values[0] /= 100.0;
468 continue;
469 }
470 if (tagName == "Y")
471 {
472 QString str = childElem.text();
473 double xyz_y = str.toDouble(&gotXYZ_Y);
474 if (!gotXYZ_Y)
475 return false;
476 m_values[1] = qMax(0.0, qMin(xyz_y, 100.0));
477 m_values[1] /= 100.0;
478 continue;
479 }
480 if (tagName == "Z")
481 {
482 QString str = childElem.text();
483 double xyz_z = str.toDouble(&gotXYZ_Z);
484 if (!gotXYZ_Z)
485 return false;
486 m_values[2] = qMax(0.0, qMin(xyz_z, 100.0));
487 m_values[2] /= 100.0;
488 continue;
489 }
490 }
491
492 return (gotXYZ_X && gotXYZ_Y && gotXYZ_Z);
493 }
494
reset()495 void CxfColorCIEXYZ::reset()
496 {
497 CxfColor::reset();
498
499 m_values[0] = 0.0;
500 m_values[1] = 0.0;
501 m_values[2] = 0.0;
502 }
503
CxfReflectanceSpectrum(CxfDocument * cxfDoc)504 CxfReflectanceSpectrum::CxfReflectanceSpectrum(CxfDocument* cxfDoc)
505 : CxfColor(cxfDoc)
506 {
507 m_wavelengthStart = 0;
508 }
509
parse(QDomElement & colorElem)510 bool CxfReflectanceSpectrum::parse(QDomElement& colorElem)
511 {
512 bool convOk = false;
513
514 reset();
515
516 QString colorSpec = colorElem.attribute("ColorSpecification");
517 if (colorSpec.isEmpty())
518 return false;
519
520 m_colorSpec = m_cxfDoc->colorSpecification(colorSpec);
521 if (!m_colorSpec)
522 return false;
523
524 if (!m_colorSpec->hasWavelengthRange())
525 return false;
526
527 QString str = colorElem.attribute("StartWL");
528 if (str.length() > 0)
529 {
530 int wlStart = str.toInt(&convOk);
531 if (!convOk || (wlStart < 360) || (wlStart > 400))
532 return false;
533 m_wavelengthStart = wlStart;
534 }
535
536 QString spectrum = colorElem.text().trimmed();
537 if (spectrum.isEmpty())
538 return false;
539
540 QStringList values = spectrum.split(QChar(' '), Qt::SkipEmptyParts);
541 if (values.count() <= 0)
542 return false;
543
544 m_values.reserve(values.count());
545 for (int i = 0; i < values.count(); ++i)
546 {
547 str = values.at(i);
548 double d = str.toDouble(&convOk);
549 if (!convOk)
550 return false;
551 d = qMax(0.0, qMin(d, 1.0));
552 m_values.append(d);
553 }
554
555 return true;
556 }
557
reset()558 void CxfReflectanceSpectrum::reset()
559 {
560 m_values.clear();
561 m_wavelengthStart = 0;
562 }
563
wavelengthStart() const564 int CxfReflectanceSpectrum::wavelengthStart() const
565 {
566 if (m_wavelengthStart > 0)
567 return m_wavelengthStart;
568 return m_colorSpec->measurementSpec().wavelengthStart();
569 }
570
wavelengthIncrement() const571 int CxfReflectanceSpectrum::wavelengthIncrement() const
572 {
573 return m_colorSpec->measurementSpec().wavelengthIncrement();
574 }
575
wavelengths() const576 QVector<int> CxfReflectanceSpectrum::wavelengths() const
577 {
578 if (m_values.count() <= 0)
579 return QVector<int>();
580 int wlStart = wavelengthStart();
581 int wlInc = m_colorSpec->measurementSpec().wavelengthIncrement();
582 return CxfMeasurementSpec::wavelengths(wlStart, wlInc, m_values.count());
583 }
584