|
1 /* |
|
2 * Copyright (c) 2004-2008 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: Black & White provides functionality to convert bitmaps to black & white. |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 // INCLUDE FILES |
|
20 #include "AknsRlEffectPluginBlackWhite.h" |
|
21 #include "AknsRlEffectUtil.h" |
|
22 |
|
23 // ==================== INTERNAL IMPL. OF BLACK & WHITE ======================== |
|
24 /** |
|
25 * Template implementation of Black&White. Type defines the used data type for |
|
26 * iterating over the bitmap data. X, R, G and B define the used pixel color bit |
|
27 * layout. |
|
28 */ |
|
29 template<class Type,TInt X, TInt R, TInt G, TInt B> |
|
30 class AknsRlEffectBlackWhite |
|
31 { |
|
32 public: |
|
33 //------------------------------------------------------------------------ |
|
34 static void ProcessRgbToRgb( const CFbsBitmap& aTarget, |
|
35 const CFbsBitmap& aSource, |
|
36 const TInt aTreshold, |
|
37 const TInt aBlendFactor ) |
|
38 { |
|
39 // ScanLineLength returns bytes, but width must match the Type |
|
40 TInt width = CFbsBitmap::ScanLineLength( aSource.SizeInPixels().iWidth, |
|
41 aSource.DisplayMode() ) / sizeof(Type); |
|
42 TInt height = aSource.SizeInPixels().iHeight; |
|
43 |
|
44 TInt pixelCount = width * height; |
|
45 TInt shade; |
|
46 TInt r,g,b; |
|
47 |
|
48 aTarget.LockHeap( ETrue ); // Lock the global bitmap heap |
|
49 Type* dataT = reinterpret_cast<Type*>( aTarget.DataAddress() ); |
|
50 Type* dataS = reinterpret_cast<Type*>( aSource.DataAddress() ); |
|
51 |
|
52 for( TInt index = 0; index < pixelCount; ++index ) |
|
53 { |
|
54 r = AknsRlRgb<Type,X,R,G,B>::R8(*dataS); |
|
55 g = AknsRlRgb<Type,X,R,G,B>::G8(*dataS); |
|
56 b = AknsRlRgb<Type,X,R,G,B>::B8(*dataS); |
|
57 |
|
58 // Pixel intensity = grayscale value |
|
59 shade = AknsRlUtil::Grayscale( TUint8(r), TUint8(g), TUint8(b) ); |
|
60 |
|
61 // Convert to B&W |
|
62 if( shade < aTreshold ) |
|
63 shade = 0; |
|
64 else |
|
65 shade = 255; |
|
66 |
|
67 // Exposure blending |
|
68 // Note: It is assumed that arithmetic shifting is supported |
|
69 // -> negative values are shifted correctly |
|
70 r = (shade * aBlendFactor + (255 - aBlendFactor) * r) >> 8; |
|
71 g = (shade * aBlendFactor + (255 - aBlendFactor) * g) >> 8; |
|
72 b = (shade * aBlendFactor + (255 - aBlendFactor) * b) >> 8; |
|
73 |
|
74 if( r < 0 ) r = 0; else if( r > 255 ) r = 255; |
|
75 if( g < 0 ) g = 0; else if( g > 255 ) g = 255; |
|
76 if( b < 0 ) b = 0; else if( b > 255 ) b = 255; |
|
77 |
|
78 AknsRlRgb<Type,X,R,G,B>::SetRgb8( dataT, TUint8(r), TUint8(g), TUint8(b) ); |
|
79 |
|
80 dataT++; |
|
81 dataS++; |
|
82 } |
|
83 |
|
84 aTarget.UnlockHeap( ETrue ); // Unlock the global bitmap heap |
|
85 } |
|
86 //------------------------------------------------------------------------ |
|
87 static void ProcessRgbToGray( const CFbsBitmap& aTarget, |
|
88 const CFbsBitmap& aSource, |
|
89 const TInt aTreshold ) |
|
90 { |
|
91 TInt width = aSource.SizeInPixels().iWidth; |
|
92 TInt height = aSource.SizeInPixels().iHeight; |
|
93 |
|
94 // ScanLineLength returns bytes, but width must match the Type |
|
95 TInt scanT = CFbsBitmap::ScanLineLength(width, aTarget.DisplayMode()); |
|
96 TInt scanS = CFbsBitmap::ScanLineLength(width, aSource.DisplayMode()) / sizeof(Type); |
|
97 |
|
98 TInt shade; |
|
99 |
|
100 TInt pitchT = scanT - width; |
|
101 TInt pitchS = scanS - width; |
|
102 |
|
103 aTarget.LockHeap( ETrue ); // Lock the global bitmap heap |
|
104 TUint8* dataT = reinterpret_cast<TUint8*>( aTarget.DataAddress() ); |
|
105 Type* dataS = reinterpret_cast<Type*>( aSource.DataAddress() ); |
|
106 |
|
107 TInt x, y; |
|
108 for( y=0; y < height; y++ ) |
|
109 { |
|
110 for( x=0; x < width; x++ ) |
|
111 { |
|
112 // Pixel intensity = grayscale value |
|
113 shade = AknsRlUtil::Grayscale( AknsRlRgb<Type,X,R,G,B>::R8(*dataS), |
|
114 AknsRlRgb<Type,X,R,G,B>::G8(*dataS), |
|
115 AknsRlRgb<Type,X,R,G,B>::B8(*dataS) ); |
|
116 |
|
117 // Convert to B&W |
|
118 if( shade < aTreshold ) |
|
119 *dataT = 0; |
|
120 else |
|
121 *dataT = 255; |
|
122 |
|
123 dataT++; |
|
124 dataS++; |
|
125 } |
|
126 |
|
127 dataT = dataT + pitchT; |
|
128 dataS = dataS + pitchS; |
|
129 } |
|
130 |
|
131 aTarget.UnlockHeap( ETrue ); // Unlock the global bitmap heap |
|
132 } |
|
133 //------------------------------------------------------------------------ |
|
134 static void ProcessGrayToRgb( const CFbsBitmap& aTarget, |
|
135 const CFbsBitmap& aSource, |
|
136 const TInt aTreshold ) |
|
137 { |
|
138 TInt width = aSource.SizeInPixels().iWidth; |
|
139 TInt height = aSource.SizeInPixels().iHeight; |
|
140 |
|
141 // ScanLineLength returns bytes, but width must match the Type |
|
142 TInt scanT = CFbsBitmap::ScanLineLength(width, aTarget.DisplayMode()) / sizeof(Type); |
|
143 TInt scanS = CFbsBitmap::ScanLineLength(width, aSource.DisplayMode()); |
|
144 |
|
145 TInt pitchT = scanT - width; |
|
146 TInt pitchS = scanS - width; |
|
147 |
|
148 aTarget.LockHeap( ETrue ); // Lock the global bitmap heap |
|
149 Type* dataT = reinterpret_cast<Type*>( aTarget.DataAddress() ); |
|
150 TUint8* dataS = reinterpret_cast<TUint8*>( aSource.DataAddress() ); |
|
151 |
|
152 TInt x, y; |
|
153 for( y=0; y < height; y++ ) |
|
154 { |
|
155 for( x=0; x < width; x++ ) |
|
156 { |
|
157 // Convert to B&W |
|
158 if( *dataS < aTreshold ) |
|
159 AknsRlRgb<Type,X,R,G,B>::SetRgb8( dataT, TUint8(0), TUint8(0), TUint8(0) ); |
|
160 else |
|
161 AknsRlRgb<Type,X,R,G,B>::SetRgb8( dataT, TUint8(255), TUint8(255), TUint8(255) ); |
|
162 |
|
163 dataT++; |
|
164 dataS++; |
|
165 } |
|
166 |
|
167 dataT = dataT + pitchT; |
|
168 dataS = dataS + pitchS; |
|
169 } |
|
170 |
|
171 aTarget.UnlockHeap( ETrue ); // Unlock the global bitmap heap |
|
172 } |
|
173 }; // End of AknsRlEffectBlackWhite |
|
174 |
|
175 |
|
176 // ==================== GRAYSCALE IMPL. OF BLACK & WHITE ======================= |
|
177 class AknsRlEffectBlackWhiteGray |
|
178 { |
|
179 public: |
|
180 //------------------------------------------------------------------------ |
|
181 static void Process( const CFbsBitmap& aTarget, |
|
182 const CFbsBitmap& aSource, |
|
183 const TInt aTreshold, |
|
184 const TInt aBlendFactor ) |
|
185 { |
|
186 TInt width = CFbsBitmap::ScanLineLength( aSource.SizeInPixels().iWidth, |
|
187 aSource.DisplayMode() ); |
|
188 TInt height = aSource.SizeInPixels().iHeight; |
|
189 |
|
190 TInt pixelCount = width * height; |
|
191 TInt shade, bw; |
|
192 |
|
193 aTarget.LockHeap( ETrue ); // Lock the global bitmap heap |
|
194 TUint8* dataT = reinterpret_cast<TUint8*>( aTarget.DataAddress() ); |
|
195 TUint8* dataS = reinterpret_cast<TUint8*>( aSource.DataAddress() ); |
|
196 |
|
197 for( TInt index = 0; index < pixelCount; ++index ) |
|
198 { |
|
199 shade = *dataS; |
|
200 |
|
201 // Convert to B&W |
|
202 if( shade < aTreshold ) |
|
203 bw = 0; |
|
204 else |
|
205 bw = 255; |
|
206 |
|
207 // Exposure blending |
|
208 // Note: It is assumed that arithmetic shifting is supported |
|
209 // -> negative values are shifted correctly |
|
210 bw = (bw * aBlendFactor + (255 - aBlendFactor) * shade) >> 8; //lint !e702 Arithmetic shifting assumed |
|
211 |
|
212 if( bw < 0 ) |
|
213 *dataT = 0; |
|
214 else if( bw > 255 ) |
|
215 *dataT = 255; |
|
216 else |
|
217 *dataT = TUint8(bw); |
|
218 |
|
219 dataT++; |
|
220 dataS++; |
|
221 } |
|
222 |
|
223 aTarget.UnlockHeap( ETrue ); // Unlock the global bitmap heap |
|
224 } |
|
225 }; // End of AknsRlEffectBlackWhiteGray |
|
226 |
|
227 // ============================ MEMBER FUNCTIONS =============================== |
|
228 |
|
229 // ----------------------------------------------------------------------------- |
|
230 // CAknsRlEffectPluginBlackWhite::CAknsRlEffectPluginBlackWhite |
|
231 // C++ default constructor can NOT contain any code, that |
|
232 // might leave. |
|
233 // ----------------------------------------------------------------------------- |
|
234 // |
|
235 CAknsRlEffectPluginBlackWhite::CAknsRlEffectPluginBlackWhite() |
|
236 { |
|
237 } |
|
238 |
|
239 // ----------------------------------------------------------------------------- |
|
240 // Destructor |
|
241 // ----------------------------------------------------------------------------- |
|
242 // |
|
243 CAknsRlEffectPluginBlackWhite::~CAknsRlEffectPluginBlackWhite() |
|
244 { |
|
245 iContext = NULL; |
|
246 } |
|
247 |
|
248 // ----------------------------------------------------------------------------- |
|
249 // CAknsRlEffectPluginBlackWhite::EffectUid |
|
250 // ----------------------------------------------------------------------------- |
|
251 // |
|
252 TUid CAknsRlEffectPluginBlackWhite::EffectUid() const |
|
253 { |
|
254 return TUid::Uid( KAknsRlEffectPluginBlackWhiteUID ); |
|
255 } |
|
256 |
|
257 // ----------------------------------------------------------------------------- |
|
258 // CAknsRlEffectPluginBlackWhite::Effect |
|
259 // ----------------------------------------------------------------------------- |
|
260 // |
|
261 MAknsRlEffect* CAknsRlEffectPluginBlackWhite::Effect( const TInt aInterface ) |
|
262 { |
|
263 if( aInterface == KAknsRlEffectPluginInterfaceEffect ) |
|
264 return this; |
|
265 return NULL; |
|
266 } |
|
267 |
|
268 // ----------------------------------------------------------------------------- |
|
269 // CAknsRlEffectPluginBlackWhite::InitializeL |
|
270 // ----------------------------------------------------------------------------- |
|
271 // |
|
272 void CAknsRlEffectPluginBlackWhite::InitializeL() |
|
273 { |
|
274 iContext = NULL; |
|
275 } |
|
276 |
|
277 // ----------------------------------------------------------------------------- |
|
278 // CAknsRlEffectPluginBlackWhite::Release |
|
279 // ----------------------------------------------------------------------------- |
|
280 // |
|
281 void CAknsRlEffectPluginBlackWhite::Release() |
|
282 { |
|
283 } |
|
284 |
|
285 // ----------------------------------------------------------------------------- |
|
286 // CAknsRlEffectPluginBlackWhite::ActivateL |
|
287 // ----------------------------------------------------------------------------- |
|
288 // |
|
289 void CAknsRlEffectPluginBlackWhite::ActivateL( MAknsRlEffectContext* aContext ) |
|
290 { |
|
291 if( !aContext ) // We absolutely need the context |
|
292 { |
|
293 User::Leave( KErrArgument ); |
|
294 } |
|
295 |
|
296 iContext = aContext; |
|
297 |
|
298 iTreshold = 127; |
|
299 iBlend = 255; |
|
300 } |
|
301 |
|
302 // ----------------------------------------------------------------------------- |
|
303 // CAknsRlEffectPluginBlackWhite::Deactivate |
|
304 // ----------------------------------------------------------------------------- |
|
305 // |
|
306 void CAknsRlEffectPluginBlackWhite::Deactivate() |
|
307 { |
|
308 } |
|
309 |
|
310 // ----------------------------------------------------------------------------- |
|
311 // CAknsRlEffectPluginBlackWhite::SetParametersL |
|
312 // ----------------------------------------------------------------------------- |
|
313 // |
|
314 void CAknsRlEffectPluginBlackWhite::SetParametersL( MAknsRlParameterIterator& aParameters ) |
|
315 { |
|
316 // Iterate over available parameters |
|
317 while( aParameters.HasNext() ) |
|
318 { |
|
319 const TAknsRlParameterData* param = aParameters.NextL(); |
|
320 |
|
321 // Fetch treshold value |
|
322 if( param->iName->Compare( KAknsRlEffectBlackWhiteTreshold ) == 0 ) |
|
323 { |
|
324 if( param->iType != EAknsRlParameterTypeNumber ) |
|
325 User::Leave( KErrArgument ); |
|
326 |
|
327 iTreshold = param->iNumber; |
|
328 } |
|
329 // Fetch blend value |
|
330 else if( param->iName->Compare( KAknsRlEffectBlackWhiteBlendFactor ) == 0 ) |
|
331 { |
|
332 if( param->iType != EAknsRlParameterTypeNumber ) |
|
333 User::Leave( KErrArgument ); |
|
334 |
|
335 iBlend = param->iNumber; |
|
336 } |
|
337 } |
|
338 } |
|
339 |
|
340 // ----------------------------------------------------------------------------- |
|
341 // CAknsRlEffectPluginBlackWhite::GetCapabilities |
|
342 // ----------------------------------------------------------------------------- |
|
343 // |
|
344 void CAknsRlEffectPluginBlackWhite::GetCapabilities( TAknsRlEffectCaps& aCaps ) |
|
345 { |
|
346 aCaps.iOutputLayerSupport = KAknsRlLayerRGBOnly; |
|
347 aCaps.iInputLayerASupport = KAknsRlLayerRGBOnly; |
|
348 aCaps.iInputLayerBSupport = KAknsRlLayerNone; |
|
349 } |
|
350 |
|
351 // ----------------------------------------------------------------------------- |
|
352 // CAknsRlEffectPluginBlackWhite::Render |
|
353 // ----------------------------------------------------------------------------- |
|
354 // |
|
355 TInt CAknsRlEffectPluginBlackWhite::Render( const TAknsRlRenderOpParam& aParam ) |
|
356 { |
|
357 if( !iContext ) // We absolutely need the context |
|
358 { |
|
359 return KErrBadHandle; |
|
360 } |
|
361 |
|
362 // To do anything we need both, the output layer and input layer |
|
363 if( ( aParam.iOutputLayerStatus & KAknsRlLayerRGBOnly ) && |
|
364 ( aParam.iInputLayerAStatus & KAknsRlLayerRGBOnly ) ) |
|
365 { |
|
366 // Query the layers, uninitialized because we process the whole image |
|
367 TAknsRlLayerData dataTarget; |
|
368 TRAPD( err, iContext->GetLayerDataL( dataTarget, aParam.iOutputLayerIndex, |
|
369 aParam.iOutputLayerStatus, EFalse ) ); |
|
370 if( KErrNone != err ) |
|
371 return KErrArgument; |
|
372 |
|
373 TAknsRlLayerData dataSource; |
|
374 TRAP( err, iContext->GetLayerDataL( dataSource, aParam.iInputLayerAIndex, |
|
375 aParam.iInputLayerAStatus, EFalse ) ); |
|
376 if( KErrNone != err ) |
|
377 return KErrArgument; |
|
378 |
|
379 if( !dataTarget.iRGBBitmap ) // We need the target bitmap |
|
380 return KErrBadHandle; |
|
381 |
|
382 if( !dataSource.iRGBBitmap ) // We need the source bitmap |
|
383 return KErrBadHandle; |
|
384 |
|
385 TDisplayMode modeT = dataTarget.iRGBBitmap->DisplayMode(); |
|
386 TDisplayMode modeS = dataSource.iRGBBitmap->DisplayMode(); |
|
387 |
|
388 // Rgb -> Rgb modes |
|
389 if( EColor64K == modeS && EColor64K == modeT ) |
|
390 { |
|
391 AknsRlEffectBlackWhite<TUint16,0,5,6,5>::ProcessRgbToRgb( |
|
392 *dataTarget.iRGBBitmap, |
|
393 *dataSource.iRGBBitmap, |
|
394 iTreshold, |
|
395 iBlend ); |
|
396 } |
|
397 else if( EColor16MU == modeS && EColor16MU == modeT ) |
|
398 { |
|
399 AknsRlEffectBlackWhite<TUint32,8,8,8,8>::ProcessRgbToRgb( |
|
400 *dataTarget.iRGBBitmap, |
|
401 *dataSource.iRGBBitmap, |
|
402 iTreshold, |
|
403 iBlend ); |
|
404 } |
|
405 // Rgb -> Gray modes |
|
406 else if( EColor64K == modeS && EGray256 == modeT ) |
|
407 { |
|
408 AknsRlEffectBlackWhite<TUint16,0,5,6,5>::ProcessRgbToGray( |
|
409 *dataTarget.iRGBBitmap, |
|
410 *dataSource.iRGBBitmap, |
|
411 iTreshold ); |
|
412 } |
|
413 else if( EColor16MU == modeS && EGray256 == modeT ) |
|
414 { |
|
415 AknsRlEffectBlackWhite<TUint32,8,8,8,8>::ProcessRgbToGray( |
|
416 *dataTarget.iRGBBitmap, |
|
417 *dataSource.iRGBBitmap, |
|
418 iTreshold ); |
|
419 } |
|
420 // Gray -> Rgb modes |
|
421 else if( EGray256 == modeS && EColor64K == modeT ) |
|
422 { |
|
423 AknsRlEffectBlackWhite<TUint16,0,5,6,5>::ProcessGrayToRgb( |
|
424 *dataTarget.iRGBBitmap, |
|
425 *dataSource.iRGBBitmap, |
|
426 iTreshold ); |
|
427 } |
|
428 else if( EGray256 == modeS && EColor16MU == modeT ) |
|
429 { |
|
430 AknsRlEffectBlackWhite<TUint32,8,8,8,8>::ProcessGrayToRgb( |
|
431 *dataTarget.iRGBBitmap, |
|
432 *dataSource.iRGBBitmap, |
|
433 iTreshold ); |
|
434 } |
|
435 // Gray -> Gray mode |
|
436 else if( EGray256 == modeS && EGray256 == modeT ) |
|
437 { |
|
438 AknsRlEffectBlackWhiteGray::Process( |
|
439 *dataTarget.iRGBBitmap, |
|
440 *dataSource.iRGBBitmap, |
|
441 iTreshold, iBlend ); |
|
442 } |
|
443 else |
|
444 { |
|
445 // Provided layers have illegal display mode combination |
|
446 return KErrArgument; |
|
447 } |
|
448 } |
|
449 else |
|
450 { |
|
451 // Required layers were not provided |
|
452 return KErrArgument; |
|
453 } |
|
454 |
|
455 return KErrNone; |
|
456 } |
|
457 |
|
458 // End of File |