xref: /trunk/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