1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2001 the VideoLAN team
7 * Authors: Tony Castley <tcastley@mail.powerup.com.au>
8 * Stephan Aßmus <stippi@yellowbites.com>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program 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 General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
31 #include "DrawingTidbits.h"
35 ShiftComponent(uchar component, float percent)
37 // change the color by <percent>, make sure we aren't rounding
38 // off significant bits
40 return (uchar)(component * (2 - percent));
42 return (uchar)(255 - percent * (255 - component));
47 ShiftColor(rgb_color color, float percent)
50 ShiftComponent(color.red, percent),
51 ShiftComponent(color.green, percent),
52 ShiftComponent(color.blue, percent),
61 CompareColors(const rgb_color a, const rgb_color b)
66 && a.alpha == b.alpha;
71 operator==(const rgb_color &a, const rgb_color &b)
73 return CompareColors(a, b);
78 operator!=(const rgb_color &a, const rgb_color &b)
80 return !CompareColors(a, b);
85 ReplaceColor(BBitmap *bitmap, rgb_color from, rgb_color to)
87 ASSERT(bitmap->ColorSpace() == B_COLOR_8_BIT); // other color spaces not implemented yet
89 BScreen screen(B_MAIN_SCREEN_ID);
90 uint32 fromIndex = screen.IndexForColor(from);
91 uint32 toIndex = screen.IndexForColor(to);
93 uchar *bits = (uchar *)bitmap->Bits();
94 int32 bitsLength = bitmap->BitsLength();
95 for (int32 index = 0; index < bitsLength; index++)
96 if (bits[index] == fromIndex)
97 bits[index] = toIndex;
100 // ReplaceTransparentColor
102 ReplaceTransparentColor(BBitmap *bitmap, rgb_color with)
104 ASSERT(bitmap->ColorSpace() == B_COLOR_8_BIT); // other color spaces not implemented yet
106 BScreen screen(B_MAIN_SCREEN_ID);
107 uint32 withIndex = screen.IndexForColor(with);
109 uchar *bits = (uchar *)bitmap->Bits();
110 int32 bitsLength = bitmap->BitsLength();
111 for (int32 index = 0; index < bitsLength; index++)
112 if (bits[index] == B_TRANSPARENT_8_BIT)
113 bits[index] = withIndex;
118 ycbcr_to_rgb( uint8 y, uint8 cb, uint8 cr,
119 uint8& r, uint8& g, uint8& b)
121 r = (uint8)max_c( 0, min_c( 255, 1.164 * ( y - 16 ) + 1.596 * ( cr - 128 ) ) );
122 g = (uint8)max_c( 0, min_c( 255, 1.164 * ( y - 16 ) - 0.813 * ( cr - 128 )
123 - 0.391 * ( cb - 128 ) ) );
124 b = (uint8)max_c( 0, min_c( 255, 1.164 * ( y - 16 ) + 2.018 * ( cb - 128 ) ) );
127 // this function will not produce visually pleasing results!
128 // we'd have to convert to Lab colorspace, do the mixing
129 // and convert back to RGB - in an ideal world...
133 mix_colors( uint8 ra, uint8 ga, uint8 ba,
134 uint8 rb, uint8 gb, uint8 bb,
135 uint8& r, uint8& g, uint8& b, float mixLevel )
137 float mixA = ( 1.0 - mixLevel );
138 float mixB = mixLevel;
139 r = (uint8)(mixA * ra + mixB * rb);
140 g = (uint8)(mixA * ga + mixB * gb);
141 b = (uint8)(mixA * ba + mixB * bb);
144 // the algorithm used is probably pretty slow, but it should be easy
145 // to understand what's going on...
149 scale_bitmap( BBitmap* bitmap, uint32 fromWidth, uint32 fromHeight )
151 status_t status = B_BAD_VALUE;
153 if ( bitmap && bitmap->IsValid()
154 && ( bitmap->ColorSpace() == B_RGB32 || bitmap->ColorSpace() == B_RGBA32 ) )
156 status = B_MISMATCHED_VALUES;
157 // we only support upscaling as of now
158 uint32 destWidth = bitmap->Bounds().IntegerWidth() + 1;
159 uint32 destHeight = bitmap->Bounds().IntegerHeight() + 1;
160 if ( fromWidth <= destWidth && fromHeight <= destHeight )
163 uint32 bpr = bitmap->BytesPerRow();
164 if ( fromWidth < destWidth )
166 // scale horizontally
167 uint8* src = (uint8*)bitmap->Bits();
168 uint8* p = new uint8[fromWidth * 4]; // temp buffer
169 for ( uint32 y = 0; y < fromHeight; y++ )
171 // copy valid pixels into temp buffer
172 memcpy( p, src, fromWidth * 4 );
173 for ( uint32 x = 0; x < destWidth; x++ )
175 // mix colors of left and right pixels and write it back
177 float xPos = ( (float)x / (float)destWidth ) * (float)fromWidth;
178 uint32 leftIndex = (uint32)floorf( xPos ) * 4;
179 uint32 rightIndex = (uint32)ceilf( xPos ) * 4;
181 left.red = p[leftIndex + 2];
182 left.green = p[leftIndex + 1];
183 left.blue = p[leftIndex + 0];
185 right.red = p[rightIndex + 2];
186 right.green = p[rightIndex + 1];
187 right.blue = p[rightIndex + 0];
189 mix_colors( left.red, left.green, left.blue,
190 right.red, right.green, right.blue,
191 mix.red, mix.green, mix.blue, xPos - floorf( xPos ) );
192 uint32 destIndex = x * 4;
193 src[destIndex + 2] = mix.red;
194 src[destIndex + 1] = mix.green;
195 src[destIndex + 0] = mix.blue;
201 if ( fromHeight < destHeight )
204 uint8* src = (uint8*)bitmap->Bits();
205 uint8* p = new uint8[fromHeight * 3]; // temp buffer
206 for ( uint32 x = 0; x < destWidth; x++ )
208 // copy valid pixels into temp buffer
209 for ( uint32 y = 0; y < fromHeight; y++ )
211 uint32 destIndex = y * 3;
212 uint32 srcIndex = x * 4 + y * bpr;
213 p[destIndex + 0] = src[srcIndex + 0];
214 p[destIndex + 1] = src[srcIndex + 1];
215 p[destIndex + 2] = src[srcIndex + 2];
218 for ( uint32 y = 0; y < destHeight; y++ )
220 // mix colors of upper and lower pixels and write it back
222 float yPos = ( (float)y / (float)destHeight ) * (float)fromHeight;
223 uint32 upperIndex = (uint32)floorf( yPos ) * 3;
224 uint32 lowerIndex = (uint32)ceilf( yPos ) * 3;
226 upper.red = p[upperIndex + 2];
227 upper.green = p[upperIndex + 1];
228 upper.blue = p[upperIndex + 0];
230 lower.red = p[lowerIndex + 2];
231 lower.green = p[lowerIndex + 1];
232 lower.blue = p[lowerIndex + 0];
234 mix_colors( upper.red, upper.green, upper.blue,
235 lower.red, lower.green, lower.blue,
236 mix.red, mix.green, mix.blue, yPos - floorf( yPos ) );
237 uint32 destIndex = x * 4 + y * bpr;
238 src[destIndex + 2] = mix.red;
239 src[destIndex + 1] = mix.green;
240 src[destIndex + 0] = mix.blue;
252 convert_bitmap( BBitmap* inBitmap, BBitmap* outBitmap )
254 status_t status = B_BAD_VALUE;
255 // see that we got valid bitmaps
256 if ( inBitmap && inBitmap->IsValid()
257 && outBitmap && outBitmap->IsValid() )
259 status = B_MISMATCHED_VALUES;
260 // see that bitmaps are compatible and that we support the conversion
261 if ( inBitmap->Bounds().Width() <= outBitmap->Bounds().Width()
262 && inBitmap->Bounds().Height() <= outBitmap->Bounds().Height()
263 && ( outBitmap->ColorSpace() == B_RGB32
264 || outBitmap->ColorSpace() == B_RGBA32) )
266 int32 width = inBitmap->Bounds().IntegerWidth() + 1;
267 int32 height = inBitmap->Bounds().IntegerHeight() + 1;
268 int32 srcBpr = inBitmap->BytesPerRow();
269 int32 dstBpr = outBitmap->BytesPerRow();
270 uint8* srcBits = (uint8*)inBitmap->Bits();
271 uint8* dstBits = (uint8*)outBitmap->Bits();
272 switch (inBitmap->ColorSpace())
275 // Y0[7:0] Cb0[7:0] Y1[7:0] Cr0[7:0]
276 // Y2[7:0] Cb2[7:0] Y3[7:0] Cr2[7:0]
277 for ( int32 y = 0; y < height; y++ )
279 for ( int32 x = 0; x < width; x += 2 )
281 int32 srcOffset = x * 2;
282 int32 dstOffset = x * 4;
283 ycbcr_to_rgb( srcBits[srcOffset + 0],
284 srcBits[srcOffset + 1],
285 srcBits[srcOffset + 3],
286 dstBits[dstOffset + 2],
287 dstBits[dstOffset + 1],
288 dstBits[dstOffset + 0] );
289 ycbcr_to_rgb( srcBits[srcOffset + 2],
290 srcBits[srcOffset + 1],
291 srcBits[srcOffset + 3],
292 dstBits[dstOffset + 6],
293 dstBits[dstOffset + 5],
294 dstBits[dstOffset + 4] );
295 // take care of alpha
296 dstBits[x * 4 + 3] = 255;
297 dstBits[x * 4 + 7] = 255;
305 // Non-interlaced only!
306 // Cb0 Y0 Y1 Cb2 Y2 Y3 on even scan lines ...
307 // Cr0 Y0 Y1 Cr2 Y2 Y3 on odd scan lines
311 // U0[7:0] Y0[7:0] V0[7:0] Y1[7:0]
312 // U2[7:0] Y2[7:0] V2[7:0] Y3[7:0]
317 memcpy( dstBits, srcBits, inBitmap->BitsLength() );
321 // G[2:0],B[4:0] R[4:0],G[5:3]
322 for ( int32 y = 0; y < height; y ++ )
324 for ( int32 x = 0; x < width; x++ )
326 int32 srcOffset = x * 2;
327 int32 dstOffset = x * 4;
328 uint8 blue = srcBits[srcOffset + 0] & 0x1f;
329 uint8 green = ( srcBits[srcOffset + 0] >> 5 )
330 | ( ( srcBits[srcOffset + 1] & 0x07 ) << 3 );
331 uint8 red = srcBits[srcOffset + 1] & 0xf8;
332 // homogeneously scale each component to 8 bit
333 dstBits[dstOffset + 0] = (blue << 3) | (blue >> 2);
334 dstBits[dstOffset + 1] = (green << 2) | (green >> 4);
335 dstBits[dstOffset + 2] = red | (red >> 5);
343 status = B_MISMATCHED_VALUES;
346 if ( status == B_OK )
348 if ( width < outBitmap->Bounds().IntegerWidth() + 1
349 || height < outBitmap->Bounds().IntegerHeight() + 1 )
351 scale_bitmap( outBitmap, width, height );
361 clip_float(float value)
372 dim_bitmap(BBitmap* bitmap, rgb_color center, float dimLevel)
374 status_t status = B_BAD_VALUE;
375 if (bitmap && bitmap->IsValid())
377 switch (bitmap->ColorSpace())
381 BScreen screen(B_MAIN_SCREEN_ID);
382 if (screen.IsValid())
384 // iterate over each pixel, get the respective
385 // color from the screen object, find the distance
386 // to the "center" color and shorten the distance
388 int32 length = bitmap->BitsLength();
389 uint8* bits = (uint8*)bitmap->Bits();
390 for (int32 i = 0; i < length; i++)
392 // preserve transparent pixels
393 if (bits[i] != B_TRANSPARENT_MAGIC_CMAP8)
395 // get color for this index
396 rgb_color c = screen.ColorForIndex(bits[i]);
398 float dist = (c.red - center.red) * dimLevel;
399 c.red = clip_float(center.red + dist);
401 dist = (c.green - center.green) * dimLevel;
402 c.green = clip_float(center.green + dist);
404 dist = (c.blue - center.blue) * dimLevel;
405 c.blue = clip_float(center.blue + dist);
406 // write correct index of the dimmed color
407 // back into bitmap (and hope the match is close...)
408 bits[i] = screen.IndexForColor(c);
418 // iterate over each color component, find the distance
419 // to the "center" color and shorten the distance
421 uint8* bits = (uint8*)bitmap->Bits();
422 int32 bpr = bitmap->BytesPerRow();
423 int32 pixels = bitmap->Bounds().IntegerWidth() + 1;
424 int32 lines = bitmap->Bounds().IntegerHeight() + 1;
425 // iterate over color components
426 for (int32 y = 0; y < lines; y++) {
427 for (int32 x = 0; x < pixels; x++) {
428 int32 offset = 4 * x; // four bytes per pixel
430 float dist = (bits[offset + 0] - center.blue) * dimLevel;
431 bits[offset + 0] = clip_float(center.blue + dist);
433 dist = (bits[offset + 1] - center.green) * dimLevel;
434 bits[offset + 1] = clip_float(center.green + dist);
436 dist = (bits[offset + 2] - center.red) * dimLevel;
437 bits[offset + 2] = clip_float(center.red + dist);
438 // ignore alpha channel
454 // dimmed_color_cmap8
456 dimmed_color_cmap8(rgb_color color, rgb_color center, float dimLevel)
458 BScreen screen(B_MAIN_SCREEN_ID);
459 if (screen.IsValid())
462 float dist = (color.red - center.red) * dimLevel;
463 color.red = clip_float(center.red + dist);
465 dist = (color.green - center.green) * dimLevel;
466 color.green = clip_float(center.green + dist);
468 dist = (color.blue - center.blue) * dimLevel;
469 color.blue = clip_float(center.blue + dist);
470 // get color index for dimmed color
471 int32 index = screen.IndexForColor(color);
472 // put color at index (closest match in palette
473 // to dimmed result) into returned color
474 color = screen.ColorForIndex(index);