00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <math.h>
00026
00027 #include <Bitmap.h>
00028 #include <Debug.h>
00029 #include <Screen.h>
00030
00031 #include "DrawingTidbits.h"
00032
00033
00034 inline uchar
00035 ShiftComponent(uchar component, float percent)
00036 {
00037
00038
00039 if (percent >= 1)
00040 return (uchar)(component * (2 - percent));
00041 else
00042 return (uchar)(255 - percent * (255 - component));
00043 }
00044
00045
00046 rgb_color
00047 ShiftColor(rgb_color color, float percent)
00048 {
00049 rgb_color result = {
00050 ShiftComponent(color.red, percent),
00051 ShiftComponent(color.green, percent),
00052 ShiftComponent(color.blue, percent),
00053 0
00054 };
00055
00056 return result;
00057 }
00058
00059
00060 static bool
00061 CompareColors(const rgb_color a, const rgb_color b)
00062 {
00063 return a.red == b.red
00064 && a.green == b.green
00065 && a.blue == b.blue
00066 && a.alpha == b.alpha;
00067 }
00068
00069
00070 bool
00071 operator==(const rgb_color &a, const rgb_color &b)
00072 {
00073 return CompareColors(a, b);
00074 }
00075
00076
00077 bool
00078 operator!=(const rgb_color &a, const rgb_color &b)
00079 {
00080 return !CompareColors(a, b);
00081 }
00082
00083
00084 void
00085 ReplaceColor(BBitmap *bitmap, rgb_color from, rgb_color to)
00086 {
00087 ASSERT(bitmap->ColorSpace() == B_COLOR_8_BIT);
00088
00089 BScreen screen(B_MAIN_SCREEN_ID);
00090 uint32 fromIndex = screen.IndexForColor(from);
00091 uint32 toIndex = screen.IndexForColor(to);
00092
00093 uchar *bits = (uchar *)bitmap->Bits();
00094 int32 bitsLength = bitmap->BitsLength();
00095 for (int32 index = 0; index < bitsLength; index++)
00096 if (bits[index] == fromIndex)
00097 bits[index] = toIndex;
00098 }
00099
00100
00101 void
00102 ReplaceTransparentColor(BBitmap *bitmap, rgb_color with)
00103 {
00104 ASSERT(bitmap->ColorSpace() == B_COLOR_8_BIT);
00105
00106 BScreen screen(B_MAIN_SCREEN_ID);
00107 uint32 withIndex = screen.IndexForColor(with);
00108
00109 uchar *bits = (uchar *)bitmap->Bits();
00110 int32 bitsLength = bitmap->BitsLength();
00111 for (int32 index = 0; index < bitsLength; index++)
00112 if (bits[index] == B_TRANSPARENT_8_BIT)
00113 bits[index] = withIndex;
00114 }
00115
00116
00117 inline void
00118 ycbcr_to_rgb( uint8 y, uint8 cb, uint8 cr,
00119 uint8& r, uint8& g, uint8& b)
00120 {
00121 r = (uint8)max_c( 0, min_c( 255, 1.164 * ( y - 16 ) + 1.596 * ( cr - 128 ) ) );
00122 g = (uint8)max_c( 0, min_c( 255, 1.164 * ( y - 16 ) - 0.813 * ( cr - 128 )
00123 - 0.391 * ( cb - 128 ) ) );
00124 b = (uint8)max_c( 0, min_c( 255, 1.164 * ( y - 16 ) + 2.018 * ( cb - 128 ) ) );
00125 }
00126
00127
00128
00129
00130
00131
00132 inline void
00133 mix_colors( uint8 ra, uint8 ga, uint8 ba,
00134 uint8 rb, uint8 gb, uint8 bb,
00135 uint8& r, uint8& g, uint8& b, float mixLevel )
00136 {
00137 float mixA = ( 1.0 - mixLevel );
00138 float mixB = mixLevel;
00139 r = (uint8)(mixA * ra + mixB * rb);
00140 g = (uint8)(mixA * ga + mixB * gb);
00141 b = (uint8)(mixA * ba + mixB * bb);
00142 }
00143
00144
00145
00146
00147
00148 status_t
00149 scale_bitmap( BBitmap* bitmap, uint32 fromWidth, uint32 fromHeight )
00150 {
00151 status_t status = B_BAD_VALUE;
00152
00153 if ( bitmap && bitmap->IsValid()
00154 && ( bitmap->ColorSpace() == B_RGB32 || bitmap->ColorSpace() == B_RGBA32 ) )
00155 {
00156 status = B_MISMATCHED_VALUES;
00157
00158 uint32 destWidth = bitmap->Bounds().IntegerWidth() + 1;
00159 uint32 destHeight = bitmap->Bounds().IntegerHeight() + 1;
00160 if ( fromWidth <= destWidth && fromHeight <= destHeight )
00161 {
00162 status = B_OK;
00163 uint32 bpr = bitmap->BytesPerRow();
00164 if ( fromWidth < destWidth )
00165 {
00166
00167 uint8* src = (uint8*)bitmap->Bits();
00168 uint8* p = new uint8[fromWidth * 4];
00169 for ( uint32 y = 0; y < fromHeight; y++ )
00170 {
00171
00172 memcpy( p, src, fromWidth * 4 );
00173 for ( uint32 x = 0; x < destWidth; x++ )
00174 {
00175
00176
00177 float xPos = ( (float)x / (float)destWidth ) * (float)fromWidth;
00178 uint32 leftIndex = (uint32)floorf( xPos ) * 4;
00179 uint32 rightIndex = (uint32)ceilf( xPos ) * 4;
00180 rgb_color left;
00181 left.red = p[leftIndex + 2];
00182 left.green = p[leftIndex + 1];
00183 left.blue = p[leftIndex + 0];
00184 rgb_color right;
00185 right.red = p[rightIndex + 2];
00186 right.green = p[rightIndex + 1];
00187 right.blue = p[rightIndex + 0];
00188 rgb_color mix;
00189 mix_colors( left.red, left.green, left.blue,
00190 right.red, right.green, right.blue,
00191 mix.red, mix.green, mix.blue, xPos - floorf( xPos ) );
00192 uint32 destIndex = x * 4;
00193 src[destIndex + 2] = mix.red;
00194 src[destIndex + 1] = mix.green;
00195 src[destIndex + 0] = mix.blue;
00196 }
00197 src += bpr;
00198 }
00199 delete[] p;
00200 }
00201 if ( fromHeight < destHeight )
00202 {
00203
00204 uint8* src = (uint8*)bitmap->Bits();
00205 uint8* p = new uint8[fromHeight * 3];
00206 for ( uint32 x = 0; x < destWidth; x++ )
00207 {
00208
00209 for ( uint32 y = 0; y < fromHeight; y++ )
00210 {
00211 uint32 destIndex = y * 3;
00212 uint32 srcIndex = x * 4 + y * bpr;
00213 p[destIndex + 0] = src[srcIndex + 0];
00214 p[destIndex + 1] = src[srcIndex + 1];
00215 p[destIndex + 2] = src[srcIndex + 2];
00216 }
00217
00218 for ( uint32 y = 0; y < destHeight; y++ )
00219 {
00220
00221
00222 float yPos = ( (float)y / (float)destHeight ) * (float)fromHeight;
00223 uint32 upperIndex = (uint32)floorf( yPos ) * 3;
00224 uint32 lowerIndex = (uint32)ceilf( yPos ) * 3;
00225 rgb_color upper;
00226 upper.red = p[upperIndex + 2];
00227 upper.green = p[upperIndex + 1];
00228 upper.blue = p[upperIndex + 0];
00229 rgb_color lower;
00230 lower.red = p[lowerIndex + 2];
00231 lower.green = p[lowerIndex + 1];
00232 lower.blue = p[lowerIndex + 0];
00233 rgb_color mix;
00234 mix_colors( upper.red, upper.green, upper.blue,
00235 lower.red, lower.green, lower.blue,
00236 mix.red, mix.green, mix.blue, yPos - floorf( yPos ) );
00237 uint32 destIndex = x * 4 + y * bpr;
00238 src[destIndex + 2] = mix.red;
00239 src[destIndex + 1] = mix.green;
00240 src[destIndex + 0] = mix.blue;
00241 }
00242 }
00243 delete[] p;
00244 }
00245 }
00246 }
00247 return status;
00248 }
00249
00250
00251 status_t
00252 convert_bitmap( BBitmap* inBitmap, BBitmap* outBitmap )
00253 {
00254 status_t status = B_BAD_VALUE;
00255
00256 if ( inBitmap && inBitmap->IsValid()
00257 && outBitmap && outBitmap->IsValid() )
00258 {
00259 status = B_MISMATCHED_VALUES;
00260
00261 if ( inBitmap->Bounds().Width() <= outBitmap->Bounds().Width()
00262 && inBitmap->Bounds().Height() <= outBitmap->Bounds().Height()
00263 && ( outBitmap->ColorSpace() == B_RGB32
00264 || outBitmap->ColorSpace() == B_RGBA32) )
00265 {
00266 int32 width = inBitmap->Bounds().IntegerWidth() + 1;
00267 int32 height = inBitmap->Bounds().IntegerHeight() + 1;
00268 int32 srcBpr = inBitmap->BytesPerRow();
00269 int32 dstBpr = outBitmap->BytesPerRow();
00270 uint8* srcBits = (uint8*)inBitmap->Bits();
00271 uint8* dstBits = (uint8*)outBitmap->Bits();
00272 switch (inBitmap->ColorSpace())
00273 {
00274 case B_YCbCr422:
00275
00276
00277 for ( int32 y = 0; y < height; y++ )
00278 {
00279 for ( int32 x = 0; x < width; x += 2 )
00280 {
00281 int32 srcOffset = x * 2;
00282 int32 dstOffset = x * 4;
00283 ycbcr_to_rgb( srcBits[srcOffset + 0],
00284 srcBits[srcOffset + 1],
00285 srcBits[srcOffset + 3],
00286 dstBits[dstOffset + 2],
00287 dstBits[dstOffset + 1],
00288 dstBits[dstOffset + 0] );
00289 ycbcr_to_rgb( srcBits[srcOffset + 2],
00290 srcBits[srcOffset + 1],
00291 srcBits[srcOffset + 3],
00292 dstBits[dstOffset + 6],
00293 dstBits[dstOffset + 5],
00294 dstBits[dstOffset + 4] );
00295
00296 dstBits[x * 4 + 3] = 255;
00297 dstBits[x * 4 + 7] = 255;
00298 }
00299 srcBits += srcBpr;
00300 dstBits += dstBpr;
00301 }
00302 status = B_OK;
00303 break;
00304 case B_YCbCr420:
00305
00306
00307
00308 status = B_ERROR;
00309 break;
00310 case B_YUV422:
00311
00312
00313 status = B_ERROR;
00314 break;
00315 case B_RGB32:
00316 case B_RGBA32:
00317 memcpy( dstBits, srcBits, inBitmap->BitsLength() );
00318 status = B_OK;
00319 break;
00320 case B_RGB16:
00321
00322 for ( int32 y = 0; y < height; y ++ )
00323 {
00324 for ( int32 x = 0; x < width; x++ )
00325 {
00326 int32 srcOffset = x * 2;
00327 int32 dstOffset = x * 4;
00328 uint8 blue = srcBits[srcOffset + 0] & 0x1f;
00329 uint8 green = ( srcBits[srcOffset + 0] >> 5 )
00330 | ( ( srcBits[srcOffset + 1] & 0x07 ) << 3 );
00331 uint8 red = srcBits[srcOffset + 1] & 0xf8;
00332
00333 dstBits[dstOffset + 0] = (blue << 3) | (blue >> 2);
00334 dstBits[dstOffset + 1] = (green << 2) | (green >> 4);
00335 dstBits[dstOffset + 2] = red | (red >> 5);
00336 }
00337 srcBits += srcBpr;
00338 dstBits += dstBpr;
00339 }
00340 status = B_OK;
00341 break;
00342 default:
00343 status = B_MISMATCHED_VALUES;
00344 break;
00345 }
00346 if ( status == B_OK )
00347 {
00348 if ( width < outBitmap->Bounds().IntegerWidth() + 1
00349 || height < outBitmap->Bounds().IntegerHeight() + 1 )
00350 {
00351 scale_bitmap( outBitmap, width, height );
00352 }
00353 }
00354 }
00355 }
00356 return status;
00357 }
00358
00359
00360 inline uint8
00361 clip_float(float value)
00362 {
00363 if (value < 0)
00364 value = 0;
00365 if (value > 255)
00366 value = 255;
00367 return (uint8)value;
00368 }
00369
00370
00371 status_t
00372 dim_bitmap(BBitmap* bitmap, rgb_color center, float dimLevel)
00373 {
00374 status_t status = B_BAD_VALUE;
00375 if (bitmap && bitmap->IsValid())
00376 {
00377 switch (bitmap->ColorSpace())
00378 {
00379 case B_CMAP8:
00380 {
00381 BScreen screen(B_MAIN_SCREEN_ID);
00382 if (screen.IsValid())
00383 {
00384
00385
00386
00387
00388 int32 length = bitmap->BitsLength();
00389 uint8* bits = (uint8*)bitmap->Bits();
00390 for (int32 i = 0; i < length; i++)
00391 {
00392
00393 if (bits[i] != B_TRANSPARENT_MAGIC_CMAP8)
00394 {
00395
00396 rgb_color c = screen.ColorForIndex(bits[i]);
00397
00398 float dist = (c.red - center.red) * dimLevel;
00399 c.red = clip_float(center.red + dist);
00400
00401 dist = (c.green - center.green) * dimLevel;
00402 c.green = clip_float(center.green + dist);
00403
00404 dist = (c.blue - center.blue) * dimLevel;
00405 c.blue = clip_float(center.blue + dist);
00406
00407
00408 bits[i] = screen.IndexForColor(c);
00409 }
00410 }
00411 status = B_OK;
00412 }
00413 break;
00414 }
00415 case B_RGB32:
00416 case B_RGBA32:
00417 {
00418
00419
00420
00421 uint8* bits = (uint8*)bitmap->Bits();
00422 int32 bpr = bitmap->BytesPerRow();
00423 int32 pixels = bitmap->Bounds().IntegerWidth() + 1;
00424 int32 lines = bitmap->Bounds().IntegerHeight() + 1;
00425
00426 for (int32 y = 0; y < lines; y++) {
00427 for (int32 x = 0; x < pixels; x++) {
00428 int32 offset = 4 * x;
00429
00430 float dist = (bits[offset + 0] - center.blue) * dimLevel;
00431 bits[offset + 0] = clip_float(center.blue + dist);
00432
00433 dist = (bits[offset + 1] - center.green) * dimLevel;
00434 bits[offset + 1] = clip_float(center.green + dist);
00435
00436 dist = (bits[offset + 2] - center.red) * dimLevel;
00437 bits[offset + 2] = clip_float(center.red + dist);
00438
00439 }
00440
00441 bits += bpr;
00442 }
00443 status = B_OK;
00444 break;
00445 }
00446 default:
00447 status = B_ERROR;
00448 break;
00449 }
00450 }
00451 return status;
00452 }
00453
00454
00455 rgb_color
00456 dimmed_color_cmap8(rgb_color color, rgb_color center, float dimLevel)
00457 {
00458 BScreen screen(B_MAIN_SCREEN_ID);
00459 if (screen.IsValid())
00460 {
00461
00462 float dist = (color.red - center.red) * dimLevel;
00463 color.red = clip_float(center.red + dist);
00464
00465 dist = (color.green - center.green) * dimLevel;
00466 color.green = clip_float(center.green + dist);
00467
00468 dist = (color.blue - center.blue) * dimLevel;
00469 color.blue = clip_float(center.blue + dist);
00470
00471 int32 index = screen.IndexForColor(color);
00472
00473
00474 color = screen.ColorForIndex(index);
00475 }
00476 return color;
00477 }