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