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 <QScopedPointer>
9 
10 #include "lcms2.h"
11 #include "paletteloader_cxf.h"
12 
13 #include "cxfcolor.h"
14 #include "cxfobject.h"
15 #include "sccolor.h"
16 #include "scribuscore.h"
17 #include "scribusdoc.h"
18 #include "util.h"
19 #include "util_formats.h"
20 
21 #include "colormgmt/sce308tables.h"
22 #include "ui/cxfimportdialog.h"
23 
PaletteLoader_CxF()24 PaletteLoader_CxF::PaletteLoader_CxF()
25 				 : m_spectrumConvertor(ScE308Table5_D50_2deg())
26 {
27 
28 }
29 
isFileSupported(const QString & fileName) const30 bool PaletteLoader_CxF::isFileSupported(const QString & fileName) const
31 {
32 	QFileInfo fi = QFileInfo(fileName);
33 	QString ext = fi.suffix().toLower();
34 	if (ext != "cxf")
35 		return false;
36 
37 	QFile file(fileName);
38 	if (!file.open(QIODevice::ReadOnly))
39 		return false;
40 
41 	QByteArray bytes = file.read(1024);
42 	if (bytes.indexOf("<?xml") < 0)
43 		return false;
44 	return (bytes.indexOf("CxF") >= 0);
45 }
46 
getAvailableColorspaces() const47 QList<eColorSpaceType> PaletteLoader_CxF::getAvailableColorspaces() const
48 {
49 	bool importableAsRgb  = false;
50 	bool importableAsCmyk = false;
51 	bool importableAsLab  = false;
52 
53 	int objectCount = m_cxfDoc.objectCount();
54 	for (int i = 0; i < objectCount; ++i)
55 	{
56 		const CxfObject* object = m_cxfDoc.objectAt(i);
57 
58 		if (!importableAsRgb)
59 			importableAsRgb = canImportObjectAsRgb(object);
60 		if (!importableAsCmyk)
61 			importableAsCmyk = canImportObjectAsCmyk(object);
62 		if (!importableAsLab)
63 			importableAsLab = canImportObjectAsLab(object);
64 
65 		if (importableAsRgb && importableAsCmyk && importableAsLab)
66 			break;
67 	}
68 
69 	QList<eColorSpaceType> colorspaces;
70 	if (importableAsLab)
71 		colorspaces.append(ColorSpace_Lab);
72 	if (importableAsCmyk)
73 		colorspaces.append(ColorSpace_Cmyk);
74 	if (importableAsRgb)
75 		colorspaces.append(ColorSpace_Rgb);
76 	return colorspaces;
77 }
78 
importFile(const QString & fileName,bool)79 bool PaletteLoader_CxF::importFile(const QString& fileName, bool /*merge*/)
80 {
81 	if (!m_cxfDoc.parse(fileName))
82 		return false;
83 
84 	QList<eColorSpaceType> colorspaces = getAvailableColorspaces();
85 	if (colorspaces.count() <= 0)
86 		return false;
87 
88 	if (colorspaces.count() > 1)
89 	{
90 		QScopedPointer<CxfImportDialog> cxfImportDia(new CxfImportDialog(ScCore->primaryMainWindow()));
91 		cxfImportDia->setPriorities(colorspaces);
92 		if (cxfImportDia->exec() != QDialog::Accepted)
93 			return true;
94 		colorspaces = cxfImportDia->priorities();
95 	}
96 
97 	QList<PaletteLoader_CxF::ColorImportFunction> importFunctions;
98 	for (int i = 0; i < colorspaces.count(); ++i)
99 	{
100 		eColorSpaceType colorspace = colorspaces.at(i);
101 		if (colorspace == ColorSpace_Rgb)
102 			importFunctions.append(&PaletteLoader_CxF::importObjectAsRgbColor);
103 		else if (colorspace == ColorSpace_Cmyk)
104 			importFunctions.append(&PaletteLoader_CxF::importObjectAsCmykColor);
105 		else if (colorspace == ColorSpace_Lab)
106 			importFunctions.append(&PaletteLoader_CxF::importObjectAsLabColor);
107 	}
108 
109 	ColorImportFunction singleImportFunc = nullptr;
110 	if (importFunctions.count() == 1)
111 		singleImportFunc = importFunctions.at(0);
112 
113 	int importCount = 0;
114 	int objectCount = m_cxfDoc.objectCount();
115 
116 	for (int i = 0; i < objectCount; ++i)
117 	{
118 		const CxfObject* object = m_cxfDoc.objectAt(i);
119 
120 		if (singleImportFunc)
121 		{
122 			if ((this->*singleImportFunc)(object))
123 				++importCount;
124 			continue;
125 		}
126 
127 		for (int j = 0; j < importFunctions.count(); ++j)
128 		{
129 			ColorImportFunction importFunc = importFunctions.at(j);
130 			if ((this->*importFunc)(object))
131 			{
132 				++importCount;
133 				break;
134 			}
135 		}
136 	}
137 
138 	return (importCount > 0);
139 }
140 
canImportObjectAsRgb(const CxfObject * object) const141 bool PaletteLoader_CxF::canImportObjectAsRgb(const CxfObject* object) const
142 {
143 	if (object->hasColor(cxfColorRGB))
144 		return true;
145 	if (object->hasColor(cxfColorSRGB))
146 		return true;
147 	if (object->hasColor(cxfColorAdobeRGB))
148 		return true;
149 	if (object->hasColor(cxfColorHTML))
150 		return true;
151 	return false;
152 }
153 
canImportObjectAsCmyk(const CxfObject * object) const154 bool PaletteLoader_CxF::canImportObjectAsCmyk(const CxfObject* object) const
155 {
156 	return object->hasColor(cxfColorCMYK);
157 }
158 
canImportObjectAsLab(const CxfObject * object) const159 bool PaletteLoader_CxF::canImportObjectAsLab(const CxfObject* object) const
160 {
161 	if (object->hasColor(cxfReflectanceSpectrum))
162 		return true;
163 	if (object->hasColor(cxfColorCIELab))
164 		return true;
165 	if (object->hasColor(cxfColorCIELCh))
166 		return true;
167 	if (object->hasColor(cxfColorCIEXYZ))
168 		return true;
169 	return false;
170 }
171 
importObjectAsRgbColor(const CxfObject * object)172 bool PaletteLoader_CxF::importObjectAsRgbColor(const CxfObject* object)
173 {
174 	ScColor color;
175 
176 	const CxfColorRGB* cxfRgbColor = dynamic_cast<const CxfColorRGB*>(object->color(cxfColorRGB));
177 	if (cxfRgbColor)
178 	{
179 		double range = cxfRgbColor->maxRange();
180 		double red   = cxfRgbColor->red() / range;
181 		double green = cxfRgbColor->green() / range;
182 		double blue  = cxfRgbColor->blue() / range;
183 		color.setRgbColorF(red, green, blue);
184 		color.setSpotColor(false);
185 		color.setRegistrationColor(false);
186 		m_colors->tryAddColor(object->name(), color);
187 		return true;
188 	}
189 
190 	const CxfColorSRGB* cxfsRgbColor = dynamic_cast<const CxfColorSRGB*>(object->color(cxfColorSRGB));
191 	if (cxfsRgbColor)
192 	{
193 		double range = cxfsRgbColor->maxRange();
194 		double red = cxfsRgbColor->red() / range;
195 		double green = cxfsRgbColor->green() / range;
196 		double blue = cxfsRgbColor->blue() / range;
197 		color.setRgbColorF(red, green, blue);
198 		color.setSpotColor(false);
199 		color.setRegistrationColor(false);
200 		m_colors->tryAddColor(object->name(), color);
201 		return true;
202 	}
203 
204 	const CxfColorAdobeRGB* cxfAdobeRgbColor = dynamic_cast<const CxfColorAdobeRGB*>(object->color(cxfColorAdobeRGB));
205 	if (cxfAdobeRgbColor)
206 	{
207 		double range = cxfAdobeRgbColor->maxRange();
208 		double red = cxfAdobeRgbColor->red() / range;
209 		double green = cxfAdobeRgbColor->green() / range;
210 		double blue = cxfAdobeRgbColor->blue() / range;
211 		color.setRgbColorF(red, green, blue);
212 		color.setSpotColor(false);
213 		color.setRegistrationColor(false);
214 		m_colors->tryAddColor(object->name(), color);
215 		return true;
216 	}
217 
218 	const CxfColorHTML* cxfHTMLColor = dynamic_cast<const CxfColorHTML*>(object->color(cxfColorHTML));
219 	if (cxfHTMLColor)
220 	{
221 		double red = cxfHTMLColor->red() / 255.0;
222 		double green = cxfHTMLColor->green() / 255.0;
223 		double blue = cxfHTMLColor->blue() / 255.0;
224 		color.setRgbColorF(red, green, blue);
225 		color.setSpotColor(false);
226 		color.setRegistrationColor(false);
227 		m_colors->tryAddColor(object->name(), color);
228 		return true;
229 	}
230 
231 	return false;
232 }
233 
importObjectAsCmykColor(const CxfObject * object)234 bool PaletteLoader_CxF::importObjectAsCmykColor(const CxfObject* object)
235 {
236 	ScColor color;
237 
238 	const CxfColorCMYK* cxfCmykColor = dynamic_cast<const CxfColorCMYK*>(object->color(cxfColorCMYK));
239 	if (cxfCmykColor)
240 	{
241 		double c = cxfCmykColor->cyan() / 100.0;
242 		double m = cxfCmykColor->magenta() / 100.0;
243 		double y = cxfCmykColor->yellow() / 100.0;
244 		double k = cxfCmykColor->black() / 100.0;
245 		color.setCmykColorF(c, m, y, k);
246 		color.setSpotColor(false);
247 		color.setRegistrationColor(false);
248 		m_colors->tryAddColor(object->name(), color);
249 		return true;
250 	}
251 
252 	return false;
253 }
254 
importObjectAsLabColor(const CxfObject * object)255 bool PaletteLoader_CxF::importObjectAsLabColor(const CxfObject* object)
256 {
257 	ScColor color;
258 
259 	const CxfReflectanceSpectrum* spectrum = dynamic_cast<const CxfReflectanceSpectrum*>(object->color(cxfReflectanceSpectrum));
260 	if (spectrum)
261 	{
262 		ScLab labVal = m_spectrumConvertor.toLab(spectrum->wavelengths(), spectrum->values());
263 		color.setLabColor(labVal.L, labVal.a, labVal.b);
264 		color.setSpotColor(false);
265 		color.setRegistrationColor(false);
266 		m_colors->tryAddColor(object->name(), color);
267 		return true;
268 	}
269 
270 	const CxfColorCIELab* cxfLabColor = dynamic_cast<const CxfColorCIELab*>(object->color(cxfColorCIELab));
271 	if (cxfLabColor)
272 	{
273 		const CxfColorSpecification* colorSpec = cxfLabColor->colorSpecification();
274 		const CxfTristimulusSpec& tristimulusSpec = colorSpec->tristimulusSpec();
275 		if (tristimulusSpec.isD50_2degree())
276 		{
277 			color.setLabColor(cxfLabColor->L(), cxfLabColor->a(), cxfLabColor->b());
278 			color.setSpotColor(false);
279 			color.setRegistrationColor(false);
280 			m_colors->tryAddColor(object->name(), color);
281 			return true;
282 		}
283 	}
284 
285 	const CxfColorCIELCh* cxfLChColor = dynamic_cast<const CxfColorCIELCh*>(object->color(cxfColorCIELCh));
286 	if (cxfLChColor)
287 	{
288 		const CxfColorSpecification* colorSpec = cxfLChColor->colorSpecification();
289 		const CxfTristimulusSpec& tristimulusSpec = colorSpec->tristimulusSpec();
290 		if (tristimulusSpec.isD50_2degree())
291 		{
292 			ScLab labVal = cxfLChColor->lab();
293 			color.setLabColor(labVal.L, labVal.a, labVal.b);
294 			color.setSpotColor(false);
295 			color.setRegistrationColor(false);
296 			m_colors->tryAddColor(object->name(), color);
297 			return true;
298 		}
299 	}
300 
301 	const CxfColorCIEXYZ* cxfXYZColor = dynamic_cast<const CxfColorCIEXYZ*>(object->color(cxfColorCIEXYZ));
302 	if (cxfXYZColor)
303 	{
304 		const CxfColorSpecification* colorSpec = cxfXYZColor->colorSpecification();
305 		const CxfTristimulusSpec& tristimulusSpec = colorSpec->tristimulusSpec();
306 		if (tristimulusSpec.isD50_2degree())
307 		{
308 			cmsCIELab cmsLab;
309 			cmsCIEXYZ cmsXYZ = { cxfXYZColor->X(),  cxfXYZColor->Y(), cxfXYZColor->Z() };
310 			cmsXYZ2Lab(cmsD50_XYZ(), &cmsLab, &cmsXYZ);
311 			color.setLabColor(cmsLab.L, cmsLab.a, cmsLab.b);
312 			color.setSpotColor(false);
313 			color.setRegistrationColor(false);
314 			m_colors->tryAddColor(object->name(), color);
315 			return true;
316 		}
317 	}
318 
319 	return false;
320 }
321