xref: /trunk/main/tools/source/generic/color.cxx (revision 1bd631be)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_tools.hxx"
26 
27 #include <stdlib.h>
28 #include <vos/macros.hxx>
29 #include <tools/color.hxx>
30 #include <tools/debug.hxx>
31 #include <tools/stream.hxx>
32 #include <tools/rc.hxx>
33 #include <tools/rcid.h>
34 #include <tools/resid.hxx>
35 #ifndef _SV_RC_H
36 #include <tools/rc.h>
37 #endif
38 
39 // -----------
40 // - Inlines -
41 // -----------
42 
_FRound(double fVal)43 static inline long _FRound( double fVal )
44 {
45 	return( fVal > 0.0 ? (long) ( fVal + 0.5 ) : -(long) ( -fVal + 0.5 ) );
46 }
47 
48 // ---------
49 // - Color -
50 // ---------
51 
Color(const ResId & rResId)52 Color::Color( const ResId& rResId )
53 {
54 	rResId.SetRT( RSC_COLOR );
55 	ResMgr* pResMgr = rResId.GetResMgr();
56 	if ( pResMgr && pResMgr->GetResource( rResId ) )
57 	{
58 		// Header ueberspringen
59 		pResMgr->Increment( sizeof( RSHEADER_TYPE ) );
60 
61 		// Daten laden
62 		sal_uInt16 nRed		= pResMgr->ReadShort();
63 		sal_uInt16 nGreen	= pResMgr->ReadShort();
64 		sal_uInt16 nBlue	= pResMgr->ReadShort();
65 		// one more historical sal_uIntPtr
66 		pResMgr->ReadLong();
67 
68 		// RGB-Farbe
69 		mnColor = RGB_COLORDATA( nRed>>8, nGreen>>8, nBlue>>8 );
70 	}
71 	else
72     {
73         mnColor = RGB_COLORDATA( 0, 0, 0 );
74     }
75 }
GetColorError(const Color & rCompareColor) const76 sal_uInt8 Color::GetColorError( const Color& rCompareColor ) const
77 {
78 	const long nErrAbs = labs( (long) rCompareColor.GetRed() - GetRed() ) +
79 						 labs( (long) rCompareColor.GetGreen() - GetGreen() ) +
80 						 labs( (long) rCompareColor.GetBlue() - GetBlue() );
81 
82 	return (sal_uInt8) _FRound( nErrAbs * 0.3333333333 );
83 }
84 
85 // -----------------------------------------------------------------------
86 
IncreaseLuminance(sal_uInt8 cLumInc)87 void Color::IncreaseLuminance( sal_uInt8 cLumInc )
88 {
89 	SetRed( (sal_uInt8) VOS_BOUND( (long) COLORDATA_RED( mnColor ) + cLumInc, 0L, 255L ) );
90 	SetGreen( (sal_uInt8) VOS_BOUND( (long) COLORDATA_GREEN( mnColor ) + cLumInc, 0L, 255L ) );
91 	SetBlue( (sal_uInt8) VOS_BOUND( (long) COLORDATA_BLUE( mnColor ) + cLumInc, 0L, 255L ) );
92 }
93 
94 // -----------------------------------------------------------------------
95 
DecreaseLuminance(sal_uInt8 cLumDec)96 void Color::DecreaseLuminance( sal_uInt8 cLumDec )
97 {
98 	SetRed( (sal_uInt8) VOS_BOUND( (long) COLORDATA_RED( mnColor ) - cLumDec, 0L, 255L ) );
99 	SetGreen( (sal_uInt8) VOS_BOUND( (long) COLORDATA_GREEN( mnColor ) - cLumDec, 0L, 255L ) );
100 	SetBlue( (sal_uInt8) VOS_BOUND( (long) COLORDATA_BLUE( mnColor ) - cLumDec, 0L, 255L ) );
101 }
102 
103 // -----------------------------------------------------------------------
104 
IncreaseContrast(sal_uInt8 cContInc)105 void Color::IncreaseContrast( sal_uInt8 cContInc )
106 {
107 	if( cContInc)
108 	{
109 		const double fM = 128.0 / ( 128.0 - 0.4985 * cContInc );
110 		const double fOff = 128.0 - fM * 128.0;
111 
112 		SetRed( (sal_uInt8) VOS_BOUND( _FRound( COLORDATA_RED( mnColor ) * fM + fOff ), 0L, 255L ) );
113 		SetGreen( (sal_uInt8) VOS_BOUND( _FRound( COLORDATA_GREEN( mnColor ) * fM + fOff ), 0L, 255L ) );
114 		SetBlue( (sal_uInt8) VOS_BOUND( _FRound( COLORDATA_BLUE( mnColor ) * fM + fOff ), 0L, 255L ) );
115 	}
116 }
117 
118 // -----------------------------------------------------------------------
119 
DecreaseContrast(sal_uInt8 cContDec)120 void Color::DecreaseContrast( sal_uInt8 cContDec )
121 {
122 	if( cContDec )
123 	{
124 		const double fM = ( 128.0 - 0.4985 * cContDec ) / 128.0;
125 		const double fOff = 128.0 - fM * 128.0;
126 
127 		SetRed( (sal_uInt8) VOS_BOUND( _FRound( COLORDATA_RED( mnColor ) * fM + fOff ), 0L, 255L ) );
128 		SetGreen( (sal_uInt8) VOS_BOUND( _FRound( COLORDATA_GREEN( mnColor ) * fM + fOff ), 0L, 255L ) );
129 		SetBlue( (sal_uInt8) VOS_BOUND( _FRound( COLORDATA_BLUE( mnColor ) * fM + fOff ), 0L, 255L ) );
130 	}
131 }
132 
133 // -----------------------------------------------------------------------
134 
Invert()135 void Color::Invert()
136 {
137 	SetRed( ~COLORDATA_RED( mnColor ) );
138 	SetGreen( ~COLORDATA_GREEN( mnColor ) );
139 	SetBlue( ~COLORDATA_BLUE( mnColor ) );
140 }
141 
142 // -----------------------------------------------------------------------
143 
IsDark() const144 sal_Bool Color::IsDark() const
145 {
146     return GetLuminance() <= 55;
147 }
148 
149 // -----------------------------------------------------------------------
150 
IsBright() const151 sal_Bool Color::IsBright() const
152 {
153     return GetLuminance() >= 245;
154 }
155 
156 // -----------------------------------------------------------------------
157 // color space conversion
158 // -----------------------------------------------------------------------
159 
RGBtoHSB(sal_uInt16 & nHue,sal_uInt16 & nSat,sal_uInt16 & nBri) const160 void Color::RGBtoHSB( sal_uInt16& nHue, sal_uInt16& nSat, sal_uInt16& nBri ) const
161 {
162 	sal_uInt8 c[3];
163 	sal_uInt8 cMax, cMin;
164 
165 	c[0] = GetRed();
166 	c[1] = GetGreen();
167 	c[2] = GetBlue();
168 
169 	cMax = c[0];
170 	if( c[1] > cMax )
171 		cMax = c[1];
172 	if( c[2] > cMax )
173 		cMax = c[2];
174 
175 	// Brightness = max(R, G, B);
176 	nBri = cMax * 100 / 255;
177 
178 	cMin = c[0];
179 	if( c[1] < cMin )
180 		cMin = c[1];
181 	if( c[2] < cMin )
182 		cMin = c[2];
183 
184 	sal_uInt8 cDelta = cMax - cMin;
185 
186 	// Saturation = max - min / max
187 	if( nBri > 0 )
188 		nSat = cDelta * 100 / cMax;
189 	else
190 		nSat = 0;
191 
192 	if( nSat == 0 )
193 		nHue = 0; // Default = undefined
194 	else
195 	{
196 		double dHue = 0.0;
197 
198 		if( c[0] == cMax )
199 		{
200 			dHue = (double)( c[1] - c[2] ) / (double)cDelta;
201 		}
202 		else if( c[1] == cMax )
203 		{
204 			dHue = 2.0 + (double)( c[2] - c[0] ) / (double)cDelta;
205 		}
206 		else if ( c[2] == cMax )
207 		{
208 			dHue = 4.0 + (double)( c[0] - c[1] ) / (double)cDelta;
209 		}
210 		dHue *= 60.0;
211 
212 		if( dHue < 0.0 )
213 			dHue += 360.0;
214 
215 		nHue = (sal_uInt16) dHue;
216 	}
217 }
218 
HSBtoRGB(sal_uInt16 nHue,sal_uInt16 nSat,sal_uInt16 nBri)219 ColorData Color::HSBtoRGB( sal_uInt16 nHue, sal_uInt16 nSat, sal_uInt16 nBri )
220 {
221 	sal_uInt8 cR=0,cG=0,cB=0;
222 	sal_uInt8 nB = (sal_uInt8) ( nBri * 255 / 100 );
223 
224 	if( nSat == 0 )
225 	{
226 		cR = nB;
227 		cG = nB;
228 		cB = nB;
229 	}
230 	else
231 	{
232 		double dH = nHue;
233 		double f;
234 		sal_uInt16 n;
235 		if( dH == 360.0 )
236 			dH = 0.0;
237 
238 		dH /= 60.0;
239 		n = (sal_uInt16) dH;
240 		f = dH - n;
241 
242 		sal_uInt8 a = (sal_uInt8) ( nB * ( 100 - nSat ) / 100 );
243 		sal_uInt8 b = (sal_uInt8) ( nB * ( 100 - ( (double)nSat * f ) ) / 100 );
244 		sal_uInt8 c = (sal_uInt8) ( nB * ( 100 - ( (double)nSat * ( 1.0 - f ) ) ) / 100 );
245 
246 		switch( n )
247 		{
248 			case 0: cR = nB;	cG = c;		cB = a; 	break;
249 			case 1: cR = b;		cG = nB;	cB = a; 	break;
250 			case 2: cR = a;		cG = nB;	cB = c;		break;
251 			case 3: cR = a;		cG = b; 	cB = nB;	break;
252 			case 4: cR = c;		cG = a; 	cB = nB;	break;
253 			case 5: cR = nB; 	cG = a;		cB = b;		break;
254 		}
255 	}
256 
257 	return RGB_COLORDATA( cR, cG, cB );
258 }
259 
260 // -----------------------------------------------------------------------
261 
262 // CMYK values from 0 to 1
CMYKtoRGB(double fCyan,double fMagenta,double fYellow,double fKey)263 ColorData Color::CMYKtoRGB( double fCyan, double fMagenta, double fYellow, double fKey )
264 {
265     fCyan = (fCyan * ( 1.0 - fKey )) + fKey;
266     fMagenta = (fMagenta * ( 1.0 - fKey )) + fKey;
267     fYellow = (fYellow * ( 1.0 - fKey )) + fKey;
268 
269     sal_uInt8 nRed = static_cast< sal_uInt8 >( std::max( std::min( ( 1.0 - fCyan ) * 255.0, 255.0), 0.0 ) );
270     sal_uInt8 nGreen = static_cast< sal_uInt8 >( std::max( std::min( ( 1.0 - fMagenta ) * 255.0, 255.0), 0.0 ) );
271     sal_uInt8 nBlue = static_cast< sal_uInt8 >( std::max( std::min( ( 1.0 - fYellow ) * 255.0, 255.0), 0.0 ) );
272 
273     return RGB_COLORDATA( nRed, nGreen, nBlue );
274 }
275 
276 // -----------------------------------------------------------------------
277 
278 // RGB values from 0 to 255
279 // CMY results from 0 to 1
RGBtoCMYK(double & fCyan,double & fMagenta,double & fYellow,double & fKey)280 void Color::RGBtoCMYK( double& fCyan, double& fMagenta, double& fYellow, double& fKey )
281 {
282     fCyan = 1 - ( GetRed() / 255.0 );
283     fMagenta = 1 - ( GetGreen() / 255.0 );
284     fYellow = 1 - ( GetBlue() / 255.0 );
285 
286     //CMYK and CMY values from 0 to 1
287     fKey = 1.0;
288     if( fCyan < fKey ) fKey = fCyan;
289     if( fMagenta < fKey ) fKey = fMagenta;
290     if( fYellow < fKey ) fKey = fYellow;
291 
292     if ( fKey == 1.0 )
293     {
294        //Black
295        fCyan = 0.0;
296        fMagenta = 0.0;
297        fYellow = 0.0;
298     }
299     else
300     {
301        fCyan = ( fCyan - fKey ) / ( 1.0 - fKey );
302        fMagenta = ( fMagenta - fKey ) / ( 1.0 - fKey );
303        fYellow = ( fYellow - fKey ) / ( 1.0 - fKey );
304     }
305 }
306 
307 // -----------------------------------------------------------------------
308 
Read(SvStream & rIStm,sal_Bool bNewFormat)309 SvStream& Color::Read( SvStream& rIStm, sal_Bool bNewFormat )
310 {
311 	if ( bNewFormat )
312 		rIStm >> mnColor;
313 	else
314 		rIStm >> *this;
315 
316 	return rIStm;
317 }
318 
319 // -----------------------------------------------------------------------
320 
Write(SvStream & rOStm,sal_Bool bNewFormat)321 SvStream& Color::Write( SvStream& rOStm, sal_Bool bNewFormat )
322 {
323 	if ( bNewFormat )
324 		rOStm << mnColor;
325 	else
326 		rOStm << *this;
327 
328 	return rOStm;
329 }
330 
331 // -----------------------------------------------------------------------
332 
333 #define COL_NAME_USER		((sal_uInt16)0x8000)
334 #define COL_RED_1B			((sal_uInt16)0x0001)
335 #define COL_RED_2B			((sal_uInt16)0x0002)
336 #define COL_GREEN_1B		((sal_uInt16)0x0010)
337 #define COL_GREEN_2B		((sal_uInt16)0x0020)
338 #define COL_BLUE_1B 		((sal_uInt16)0x0100)
339 #define COL_BLUE_2B 		((sal_uInt16)0x0200)
340 
341 // -----------------------------------------------------------------------
342 
operator >>(SvStream & rIStream,Color & rColor)343 SvStream& operator>>( SvStream& rIStream, Color& rColor )
344 {
345 	DBG_ASSERTWARNING( rIStream.GetVersion(), "Color::>> - Solar-Version not set on rIStream" );
346 
347 	sal_uInt16		nColorName;
348 	sal_uInt16		nRed;
349 	sal_uInt16		nGreen;
350 	sal_uInt16		nBlue;
351 
352 	rIStream >> nColorName;
353 
354 	if ( nColorName & COL_NAME_USER )
355 	{
356 		if ( rIStream.GetCompressMode() == COMPRESSMODE_FULL )
357 		{
358 			unsigned char	cAry[6];
359 			sal_uInt16			i = 0;
360 
361 			nRed	= 0;
362 			nGreen	= 0;
363 			nBlue	= 0;
364 
365 			if ( nColorName & COL_RED_2B )
366 				i += 2;
367 			else if ( nColorName & COL_RED_1B )
368 				i++;
369 			if ( nColorName & COL_GREEN_2B )
370 				i += 2;
371 			else if ( nColorName & COL_GREEN_1B )
372 				i++;
373 			if ( nColorName & COL_BLUE_2B )
374 				i += 2;
375 			else if ( nColorName & COL_BLUE_1B )
376 				i++;
377 
378 			rIStream.Read( cAry, i );
379 			i = 0;
380 
381 			if ( nColorName & COL_RED_2B )
382 			{
383 				nRed = cAry[i];
384 				nRed <<= 8;
385 				i++;
386 				nRed |= cAry[i];
387 				i++;
388 			}
389 			else if ( nColorName & COL_RED_1B )
390 			{
391 				nRed = cAry[i];
392 				nRed <<= 8;
393 				i++;
394 			}
395 			if ( nColorName & COL_GREEN_2B )
396 			{
397 				nGreen = cAry[i];
398 				nGreen <<= 8;
399 				i++;
400 				nGreen |= cAry[i];
401 				i++;
402 			}
403 			else if ( nColorName & COL_GREEN_1B )
404 			{
405 				nGreen = cAry[i];
406 				nGreen <<= 8;
407 				i++;
408 			}
409 			if ( nColorName & COL_BLUE_2B )
410 			{
411 				nBlue = cAry[i];
412 				nBlue <<= 8;
413 				i++;
414 				nBlue |= cAry[i];
415 				i++;
416 			}
417 			else if ( nColorName & COL_BLUE_1B )
418 			{
419 				nBlue = cAry[i];
420 				nBlue <<= 8;
421 				i++;
422 			}
423 		}
424 		else
425 		{
426 			rIStream >> nRed;
427 			rIStream >> nGreen;
428 			rIStream >> nBlue;
429 		}
430 
431 		rColor.mnColor = RGB_COLORDATA( nRed>>8, nGreen>>8, nBlue>>8 );
432 	}
433 	else
434 	{
435 		static ColorData aColAry[] =
436 		{
437 			COL_BLACK,							// COL_BLACK
438 			COL_BLUE,							// COL_BLUE
439 			COL_GREEN,							// COL_GREEN
440 			COL_CYAN,							// COL_CYAN
441 			COL_RED,							// COL_RED
442 			COL_MAGENTA,						// COL_MAGENTA
443 			COL_BROWN,							// COL_BROWN
444 			COL_GRAY,							// COL_GRAY
445 			COL_LIGHTGRAY,						// COL_LIGHTGRAY
446 			COL_LIGHTBLUE,						// COL_LIGHTBLUE
447 			COL_LIGHTGREEN, 					// COL_LIGHTGREEN
448 			COL_LIGHTCYAN,						// COL_LIGHTCYAN
449 			COL_LIGHTRED,						// COL_LIGHTRED
450 			COL_LIGHTMAGENTA,					// COL_LIGHTMAGENTA
451 			COL_YELLOW, 						// COL_YELLOW
452 			COL_WHITE,							// COL_WHITE
453 			COL_WHITE,							// COL_MENUBAR
454 			COL_BLACK,							// COL_MENUBARTEXT
455 			COL_WHITE,							// COL_POPUPMENU
456 			COL_BLACK,							// COL_POPUPMENUTEXT
457 			COL_BLACK,							// COL_WINDOWTEXT
458 			COL_WHITE,							// COL_WINDOWWORKSPACE
459 			COL_BLACK,							// COL_HIGHLIGHT
460 			COL_WHITE,							// COL_HIGHLIGHTTEXT
461 			COL_BLACK,							// COL_3DTEXT
462 			COL_LIGHTGRAY,						// COL_3DFACE
463 			COL_WHITE,							// COL_3DLIGHT
464 			COL_GRAY,							// COL_3DSHADOW
465 			COL_LIGHTGRAY,						// COL_SCROLLBAR
466 			COL_WHITE,							// COL_FIELD
467 			COL_BLACK							// COL_FIELDTEXT
468 		};
469 
470 		if ( nColorName < (sizeof( aColAry )/sizeof(ColorData)) )
471 			rColor.mnColor = aColAry[nColorName];
472 		else
473 			rColor.mnColor = COL_BLACK;
474 	}
475 
476 	return rIStream;
477 }
478 
479 // -----------------------------------------------------------------------
480 
operator <<(SvStream & rOStream,const Color & rColor)481 SvStream& operator<<( SvStream& rOStream, const Color& rColor )
482 {
483 	DBG_ASSERTWARNING( rOStream.GetVersion(), "Color::<< - Solar-Version not set on rOStream" );
484 
485 	sal_uInt16 nColorName	= COL_NAME_USER;
486 	sal_uInt16 nRed 		= rColor.GetRed();
487 	sal_uInt16 nGreen		= rColor.GetGreen();
488 	sal_uInt16 nBlue		= rColor.GetBlue();
489 	nRed	= (nRed<<8) + nRed;
490 	nGreen	= (nGreen<<8) + nGreen;
491 	nBlue	= (nBlue<<8) + nBlue;
492 
493 	if ( rOStream.GetCompressMode() == COMPRESSMODE_FULL )
494 	{
495 		unsigned char	cAry[6];
496 		sal_uInt16			i = 0;
497 
498 		if ( nRed & 0x00FF )
499 		{
500 			nColorName |= COL_RED_2B;
501 			cAry[i] = (unsigned char)(nRed & 0xFF);
502 			i++;
503 			cAry[i] = (unsigned char)((nRed >> 8) & 0xFF);
504 			i++;
505 		}
506 		else if ( nRed & 0xFF00 )
507 		{
508 			nColorName |= COL_RED_1B;
509 			cAry[i] = (unsigned char)((nRed >> 8) & 0xFF);
510 			i++;
511 		}
512 		if ( nGreen & 0x00FF )
513 		{
514 			nColorName |= COL_GREEN_2B;
515 			cAry[i] = (unsigned char)(nGreen & 0xFF);
516 			i++;
517 			cAry[i] = (unsigned char)((nGreen >> 8) & 0xFF);
518 			i++;
519 		}
520 		else if ( nGreen & 0xFF00 )
521 		{
522 			nColorName |= COL_GREEN_1B;
523 			cAry[i] = (unsigned char)((nGreen >> 8) & 0xFF);
524 			i++;
525 		}
526 		if ( nBlue & 0x00FF )
527 		{
528 			nColorName |= COL_BLUE_2B;
529 			cAry[i] = (unsigned char)(nBlue & 0xFF);
530 			i++;
531 			cAry[i] = (unsigned char)((nBlue >> 8) & 0xFF);
532 			i++;
533 		}
534 		else if ( nBlue & 0xFF00 )
535 		{
536 			nColorName |= COL_BLUE_1B;
537 			cAry[i] = (unsigned char)((nBlue >> 8) & 0xFF);
538 			i++;
539 		}
540 
541 		rOStream << nColorName;
542 		rOStream.Write( cAry, i );
543 	}
544 	else
545 	{
546 		rOStream << nColorName;
547 		rOStream << nRed;
548 		rOStream << nGreen;
549 		rOStream << nBlue;
550 	}
551 
552 	return rOStream;
553 }
554