1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <svx/Palette.hxx>
21 #include <tools/stream.hxx>
23 #include <palettes.hxx>
30 PaletteASE::~PaletteASE()
34 PaletteASE::PaletteASE( OUString aFPath
, OUString aFName
) :
35 mbValidPalette( false ),
36 maFPath (std::move( aFPath
)),
37 maASEPaletteName (std::move( aFName
))
42 void PaletteASE::LoadColorSet(SvxColorValueSet
& rColorSet
)
46 for (const auto& rColor
: maColors
)
48 rColorSet
.InsertItem(nIx
, rColor
.m_aColor
, rColor
.m_aName
);
53 const OUString
& PaletteASE::GetName()
55 return maASEPaletteName
;
58 const OUString
& PaletteASE::GetPath()
63 bool PaletteASE::IsValid()
65 return mbValidPalette
;
68 // CMYK values from 0 to 1
69 // TODO: Deduplicate me (taken from core/cui/source/dialogs/colorpicker.cxx)
70 static void lcl_CMYKtoRGB( float fCyan
, float fMagenta
, float fYellow
, float fKey
, float& dR
, float& dG
, float& dB
)
72 fCyan
= (fCyan
* ( 1.0 - fKey
)) + fKey
;
73 fMagenta
= (fMagenta
* ( 1.0 - fKey
)) + fKey
;
74 fYellow
= (fYellow
* ( 1.0 - fKey
)) + fKey
;
76 dR
= std::clamp( 1.0 - fCyan
, 0.0, 1.0 );
77 dG
= std::clamp( 1.0 - fMagenta
, 0.0, 1.0 );
78 dB
= std::clamp( 1.0 - fYellow
, 0.0, 1.0 );
81 void PaletteASE::LoadPalette()
83 SvFileStream
aFile(maFPath
, StreamMode::READ
);
84 aFile
.SetEndian(SvStreamEndian::BIG
);
86 // Verify magic first 4 characters
88 if ((aFile
.ReadBytes(cMagic
, 4) != 4) || (strncmp(cMagic
, "ASEF", 4) != 0))
90 mbValidPalette
= false;
94 // Ignore the version number
97 sal_uInt32 nBlocks
= 0;
98 aFile
.ReadUInt32(nBlocks
);
99 for (sal_uInt32 nI
= 0; nI
< nBlocks
; nI
++) {
100 sal_uInt32 nChunkType
= 0;
101 aFile
.ReadUInt32(nChunkType
);
106 // Grab chunk size, name length
107 sal_uInt16 nChunkSize
= 0;
108 sal_uInt16 nChars
= 0;
109 aFile
.ReadUInt16(nChunkSize
);
110 aFile
.ReadUInt16(nChars
);
112 OUString
aPaletteName("");
114 aPaletteName
= read_uInt16s_ToOUString(aFile
, nChars
);
118 if (nChunkType
== 0xC0010000)
120 // Got a start chunk, so set palette name
121 maASEPaletteName
= aPaletteName
;
122 // Is there color data? (shouldn't happen in a start block, but check anyway)
123 if (nChunkSize
> ((nChars
* 2) + 2))
124 aPaletteName
.clear();
129 char cColorModel
[5] = {0};
130 aFile
.ReadBytes(cColorModel
, 4);
131 OString
aColorModel(cColorModel
);
132 // r, g, and b are floats ranging from 0 to 1
133 float r
= 0, g
= 0, b
= 0;
135 if (aColorModel
.equalsIgnoreAsciiCase("cmyk"))
137 float c
= 0, m
= 0, y
= 0, k
= 0;
142 lcl_CMYKtoRGB(c
, m
, y
, k
, r
, g
, b
);
144 else if (aColorModel
.equalsIgnoreAsciiCase("rgb "))
150 else if (aColorModel
.equalsIgnoreAsciiCase("gray"))
153 aFile
.ReadFloat(nVal
);
158 float nL
= 0, nA
= 0, nB
= 0;
162 // TODO: How to convert LAB to RGB?
168 maColors
.emplace_back(Color(r
* 255, g
* 255, b
* 255), aPaletteName
);
171 mbValidPalette
= true;
174 Palette
* PaletteASE::Clone() const
176 return new PaletteASE(*this);
179 // PaletteGPL ------------------------------------------------------------------
181 static OString
lcl_getToken(OStringBuffer
& rStr
, sal_Int32
& index
);
183 PaletteGPL::PaletteGPL( OUString aFPath
, OUString aFName
) :
184 mbLoadedPalette( false ),
185 mbValidPalette( false ),
186 maFName(std::move( aFName
)),
187 maFPath(std::move( aFPath
))
192 PaletteGPL::~PaletteGPL()
196 const OUString
& PaletteGPL::GetName()
198 return maGPLPaletteName
;
201 const OUString
& PaletteGPL::GetPath()
206 void PaletteGPL::LoadColorSet(SvxColorValueSet
& rColorSet
)
212 for (const auto& rColor
: maColors
)
214 rColorSet
.InsertItem(nIx
, rColor
.m_aColor
, rColor
.m_aName
);
219 bool PaletteGPL::IsValid()
221 return mbValidPalette
;
224 bool PaletteGPL::ReadPaletteHeader(SvFileStream
& rFileStream
)
227 OString aPaletteName
;
229 rFileStream
.ReadLine(aLine
);
230 if( !aLine
.startsWith("GIMP Palette") ) return false;
231 rFileStream
.ReadLine(aLine
);
232 if( aLine
.startsWith("Name: ", &aPaletteName
) )
234 maGPLPaletteName
= OStringToOUString(aPaletteName
, RTL_TEXTENCODING_ASCII_US
);
235 rFileStream
.ReadLine(aLine
);
236 if( aLine
.startsWith("Columns: "))
237 rFileStream
.ReadLine(aLine
); // we can ignore this
241 maGPLPaletteName
= maFName
;
246 void PaletteGPL::LoadPaletteHeader()
248 SvFileStream
aFile(maFPath
, StreamMode::READ
);
249 mbValidPalette
= ReadPaletteHeader( aFile
);
252 void PaletteGPL::LoadPalette()
254 if( mbLoadedPalette
) return;
255 mbLoadedPalette
= true;
257 // TODO add error handling!!!
258 SvFileStream
aFile(maFPath
, StreamMode::READ
);
259 mbValidPalette
= ReadPaletteHeader( aFile
);
261 if( !mbValidPalette
) return;
268 if (aLine
[0] != '#' && aLine
[0] != '\n')
270 // TODO check if r,g,b are 0<= x <=255, or just clamp?
271 sal_Int32 nIndex
= 0;
274 token
= lcl_getToken(aLine
, nIndex
);
275 if(token
.isEmpty() || nIndex
== -1) continue;
276 sal_Int32 r
= token
.toInt32();
278 token
= lcl_getToken(aLine
, nIndex
);
279 if(token
.isEmpty() || nIndex
== -1) continue;
280 sal_Int32 g
= token
.toInt32();
282 token
= lcl_getToken(aLine
, nIndex
);
283 if(token
.isEmpty()) continue;
284 sal_Int32 b
= token
.toInt32();
286 std::string_view name
;
288 name
= std::string_view(aLine
).substr(nIndex
);
290 maColors
.emplace_back(
292 OStringToOUString(name
, RTL_TEXTENCODING_ASCII_US
));
294 } while (aFile
.ReadLine(aLine
));
297 Palette
* PaletteGPL::Clone() const
299 return new PaletteGPL(*this);
302 // finds first token in rStr from index, separated by whitespace
303 // returns position of next token in index
304 static OString
lcl_getToken(OStringBuffer
& rStr
, sal_Int32
& index
)
306 sal_Int32 substart
, toklen
= 0;
307 OUString
aWhitespaceChars( " \n\t" );
309 while(index
< rStr
.getLength() &&
310 aWhitespaceChars
.indexOf( rStr
[index
] ) != -1)
312 if(index
== rStr
.getLength())
319 //counts length of token
320 while(index
< rStr
.getLength() &&
321 aWhitespaceChars
.indexOf( rStr
[index
] ) == -1 )
327 //counts to position of next token
328 while(index
< rStr
.getLength() &&
329 aWhitespaceChars
.indexOf( rStr
[index
] ) != -1 )
331 if(index
== rStr
.getLength())
334 return OString(std::string_view(rStr
).substr(substart
, toklen
));
337 // PaletteSOC ------------------------------------------------------------------
339 PaletteSOC::PaletteSOC( OUString aFPath
, OUString aFName
) :
340 mbLoadedPalette( false ),
341 maFPath(std::move( aFPath
)),
342 maSOCPaletteName(std::move( aFName
))
346 PaletteSOC::~PaletteSOC()
350 const OUString
& PaletteSOC::GetName()
352 return maSOCPaletteName
;
355 const OUString
& PaletteSOC::GetPath()
360 void PaletteSOC::LoadColorSet(SvxColorValueSet
& rColorSet
)
362 if( !mbLoadedPalette
)
364 mbLoadedPalette
= true;
365 mpColorList
= XPropertyList::AsColorList(XPropertyList::CreatePropertyListFromURL(XPropertyListType::Color
, maFPath
));
366 (void)mpColorList
->Load();
369 if( mpColorList
.is() )
370 rColorSet
.addEntriesForXColorList( *mpColorList
);
373 bool PaletteSOC::IsValid()
378 Palette
* PaletteSOC::Clone() const
380 return new PaletteSOC(*this);
383 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */