xref: /trunk/main/tools/source/generic/color.cxx (revision 5fa474865bd1ef366a21e2477014a2b707635425)
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 
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 
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 }
76 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 
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 
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 
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 
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 
135 void Color::Invert()
136 {
137     SetRed( ~COLORDATA_RED( mnColor ) );
138     SetGreen( ~COLORDATA_GREEN( mnColor ) );
139     SetBlue( ~COLORDATA_BLUE( mnColor ) );
140 }
141 
142 // -----------------------------------------------------------------------
143 
144 sal_Bool Color::IsDark() const
145 {
146     return GetLuminance() <= 38;
147 }
148 
149 // -----------------------------------------------------------------------
150 
151 sal_Bool Color::IsBright() const
152 {
153     return GetLuminance() >= 245;
154 }
155 
156 // -----------------------------------------------------------------------
157 // color space conversion
158 // -----------------------------------------------------------------------
159 
160 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 
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 SvStream& Color::Read( SvStream& rIStm, sal_Bool bNewFormat )
263 {
264     if ( bNewFormat )
265         rIStm >> mnColor;
266     else
267         rIStm >> *this;
268 
269     return rIStm;
270 }
271 
272 // -----------------------------------------------------------------------
273 
274 SvStream& Color::Write( SvStream& rOStm, sal_Bool bNewFormat )
275 {
276     if ( bNewFormat )
277         rOStm << mnColor;
278     else
279         rOStm << *this;
280 
281     return rOStm;
282 }
283 
284 // -----------------------------------------------------------------------
285 
286 #define COL_NAME_USER       ((sal_uInt16)0x8000)
287 #define COL_RED_1B          ((sal_uInt16)0x0001)
288 #define COL_RED_2B          ((sal_uInt16)0x0002)
289 #define COL_GREEN_1B        ((sal_uInt16)0x0010)
290 #define COL_GREEN_2B        ((sal_uInt16)0x0020)
291 #define COL_BLUE_1B         ((sal_uInt16)0x0100)
292 #define COL_BLUE_2B         ((sal_uInt16)0x0200)
293 
294 // -----------------------------------------------------------------------
295 
296 SvStream& operator>>( SvStream& rIStream, Color& rColor )
297 {
298     DBG_ASSERTWARNING( rIStream.GetVersion(), "Color::>> - Solar-Version not set on rIStream" );
299 
300     sal_uInt16      nColorName;
301     sal_uInt16      nRed;
302     sal_uInt16      nGreen;
303     sal_uInt16      nBlue;
304 
305     rIStream >> nColorName;
306 
307     if ( nColorName & COL_NAME_USER )
308     {
309         if ( rIStream.GetCompressMode() == COMPRESSMODE_FULL )
310         {
311             unsigned char   cAry[6];
312             sal_uInt16          i = 0;
313 
314             nRed    = 0;
315             nGreen  = 0;
316             nBlue   = 0;
317 
318             if ( nColorName & COL_RED_2B )
319                 i += 2;
320             else if ( nColorName & COL_RED_1B )
321                 i++;
322             if ( nColorName & COL_GREEN_2B )
323                 i += 2;
324             else if ( nColorName & COL_GREEN_1B )
325                 i++;
326             if ( nColorName & COL_BLUE_2B )
327                 i += 2;
328             else if ( nColorName & COL_BLUE_1B )
329                 i++;
330 
331             rIStream.Read( cAry, i );
332             i = 0;
333 
334             if ( nColorName & COL_RED_2B )
335             {
336                 nRed = cAry[i];
337                 nRed <<= 8;
338                 i++;
339                 nRed |= cAry[i];
340                 i++;
341             }
342             else if ( nColorName & COL_RED_1B )
343             {
344                 nRed = cAry[i];
345                 nRed <<= 8;
346                 i++;
347             }
348             if ( nColorName & COL_GREEN_2B )
349             {
350                 nGreen = cAry[i];
351                 nGreen <<= 8;
352                 i++;
353                 nGreen |= cAry[i];
354                 i++;
355             }
356             else if ( nColorName & COL_GREEN_1B )
357             {
358                 nGreen = cAry[i];
359                 nGreen <<= 8;
360                 i++;
361             }
362             if ( nColorName & COL_BLUE_2B )
363             {
364                 nBlue = cAry[i];
365                 nBlue <<= 8;
366                 i++;
367                 nBlue |= cAry[i];
368                 i++;
369             }
370             else if ( nColorName & COL_BLUE_1B )
371             {
372                 nBlue = cAry[i];
373                 nBlue <<= 8;
374                 i++;
375             }
376         }
377         else
378         {
379             rIStream >> nRed;
380             rIStream >> nGreen;
381             rIStream >> nBlue;
382         }
383 
384         rColor.mnColor = RGB_COLORDATA( nRed>>8, nGreen>>8, nBlue>>8 );
385     }
386     else
387     {
388         static ColorData aColAry[] =
389         {
390             COL_BLACK,                          // COL_BLACK
391             COL_BLUE,                           // COL_BLUE
392             COL_GREEN,                          // COL_GREEN
393             COL_CYAN,                           // COL_CYAN
394             COL_RED,                            // COL_RED
395             COL_MAGENTA,                        // COL_MAGENTA
396             COL_BROWN,                          // COL_BROWN
397             COL_GRAY,                           // COL_GRAY
398             COL_LIGHTGRAY,                      // COL_LIGHTGRAY
399             COL_LIGHTBLUE,                      // COL_LIGHTBLUE
400             COL_LIGHTGREEN,                     // COL_LIGHTGREEN
401             COL_LIGHTCYAN,                      // COL_LIGHTCYAN
402             COL_LIGHTRED,                       // COL_LIGHTRED
403             COL_LIGHTMAGENTA,                   // COL_LIGHTMAGENTA
404             COL_YELLOW,                         // COL_YELLOW
405             COL_WHITE,                          // COL_WHITE
406             COL_WHITE,                          // COL_MENUBAR
407             COL_BLACK,                          // COL_MENUBARTEXT
408             COL_WHITE,                          // COL_POPUPMENU
409             COL_BLACK,                          // COL_POPUPMENUTEXT
410             COL_BLACK,                          // COL_WINDOWTEXT
411             COL_WHITE,                          // COL_WINDOWWORKSPACE
412             COL_BLACK,                          // COL_HIGHLIGHT
413             COL_WHITE,                          // COL_HIGHLIGHTTEXT
414             COL_BLACK,                          // COL_3DTEXT
415             COL_LIGHTGRAY,                      // COL_3DFACE
416             COL_WHITE,                          // COL_3DLIGHT
417             COL_GRAY,                           // COL_3DSHADOW
418             COL_LIGHTGRAY,                      // COL_SCROLLBAR
419             COL_WHITE,                          // COL_FIELD
420             COL_BLACK                           // COL_FIELDTEXT
421         };
422 
423         if ( nColorName < (sizeof( aColAry )/sizeof(ColorData)) )
424             rColor.mnColor = aColAry[nColorName];
425         else
426             rColor.mnColor = COL_BLACK;
427     }
428 
429     return rIStream;
430 }
431 
432 // -----------------------------------------------------------------------
433 
434 SvStream& operator<<( SvStream& rOStream, const Color& rColor )
435 {
436     DBG_ASSERTWARNING( rOStream.GetVersion(), "Color::<< - Solar-Version not set on rOStream" );
437 
438     sal_uInt16 nColorName   = COL_NAME_USER;
439     sal_uInt16 nRed         = rColor.GetRed();
440     sal_uInt16 nGreen       = rColor.GetGreen();
441     sal_uInt16 nBlue        = rColor.GetBlue();
442     nRed    = (nRed<<8) + nRed;
443     nGreen  = (nGreen<<8) + nGreen;
444     nBlue   = (nBlue<<8) + nBlue;
445 
446     if ( rOStream.GetCompressMode() == COMPRESSMODE_FULL )
447     {
448         unsigned char   cAry[6];
449         sal_uInt16          i = 0;
450 
451         if ( nRed & 0x00FF )
452         {
453             nColorName |= COL_RED_2B;
454             cAry[i] = (unsigned char)(nRed & 0xFF);
455             i++;
456             cAry[i] = (unsigned char)((nRed >> 8) & 0xFF);
457             i++;
458         }
459         else if ( nRed & 0xFF00 )
460         {
461             nColorName |= COL_RED_1B;
462             cAry[i] = (unsigned char)((nRed >> 8) & 0xFF);
463             i++;
464         }
465         if ( nGreen & 0x00FF )
466         {
467             nColorName |= COL_GREEN_2B;
468             cAry[i] = (unsigned char)(nGreen & 0xFF);
469             i++;
470             cAry[i] = (unsigned char)((nGreen >> 8) & 0xFF);
471             i++;
472         }
473         else if ( nGreen & 0xFF00 )
474         {
475             nColorName |= COL_GREEN_1B;
476             cAry[i] = (unsigned char)((nGreen >> 8) & 0xFF);
477             i++;
478         }
479         if ( nBlue & 0x00FF )
480         {
481             nColorName |= COL_BLUE_2B;
482             cAry[i] = (unsigned char)(nBlue & 0xFF);
483             i++;
484             cAry[i] = (unsigned char)((nBlue >> 8) & 0xFF);
485             i++;
486         }
487         else if ( nBlue & 0xFF00 )
488         {
489             nColorName |= COL_BLUE_1B;
490             cAry[i] = (unsigned char)((nBlue >> 8) & 0xFF);
491             i++;
492         }
493 
494         rOStream << nColorName;
495         rOStream.Write( cAry, i );
496     }
497     else
498     {
499         rOStream << nColorName;
500         rOStream << nRed;
501         rOStream << nGreen;
502         rOStream << nBlue;
503     }
504 
505     return rOStream;
506 }
507