Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

DrawingTidbits.cpp

00001 /*****************************************************************************
00002  * DrawingTidbits.cpp
00003  *****************************************************************************
00004  * Copyright (C) 2001 the VideoLAN team
00005  * $Id: DrawingTidbits.cpp 11664 2005-07-09 06:17:09Z courmisch $
00006  *
00007  * Authors: Tony Castley <[email protected]>
00008  *          Stephan Aßmus <[email protected]>
00009  *
00010  * This program is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version.
00014  *
00015  * This program is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
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 // ShiftComponent
00034 inline uchar
00035 ShiftComponent(uchar component, float percent)
00036 {
00037     // change the color by <percent>, make sure we aren't rounding
00038     // off significant bits
00039     if (percent >= 1)
00040         return (uchar)(component * (2 - percent));
00041     else
00042         return (uchar)(255 - percent * (255 - component));
00043 }
00044 
00045 // ShiftColor
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 // CompareColors
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 // ReplaceColor
00084 void
00085 ReplaceColor(BBitmap *bitmap, rgb_color from, rgb_color to)
00086 {
00087         ASSERT(bitmap->ColorSpace() == B_COLOR_8_BIT); // other color spaces not implemented yet
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 // ReplaceTransparentColor
00101 void 
00102 ReplaceTransparentColor(BBitmap *bitmap, rgb_color with)
00103 {
00104         ASSERT(bitmap->ColorSpace() == B_COLOR_8_BIT); // other color spaces not implemented yet
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 // ycrcb_to_rgb
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 // this function will not produce visually pleasing results!
00128 // we'd have to convert to Lab colorspace, do the mixing
00129 // and convert back to RGB - in an ideal world...
00130 //
00131 // mix_colors
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 // the algorithm used is probably pretty slow, but it should be easy
00145 // to understand what's going on...
00146 //
00147 // scale_bitmap
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                 // we only support upscaling as of now
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                                 // scale horizontally
00167                                 uint8* src = (uint8*)bitmap->Bits();
00168                                 uint8* p = new uint8[fromWidth * 4];    // temp buffer
00169                                 for ( uint32 y = 0; y < fromHeight; y++ )
00170                                 {
00171                                         // copy valid pixels into temp buffer
00172                                         memcpy( p, src, fromWidth * 4 );
00173                                         for ( uint32 x = 0; x < destWidth; x++ )
00174                                         {
00175                                                 // mix colors of left and right pixels and write it back
00176                                                 // into the bitmap
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                                 // scale vertically
00204                                 uint8* src = (uint8*)bitmap->Bits();
00205                                 uint8* p = new uint8[fromHeight * 3];   // temp buffer
00206                                 for ( uint32 x = 0; x < destWidth; x++ )
00207                                 {
00208                                         // copy valid pixels into temp buffer
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                                         // do the scaling
00218                                         for ( uint32 y = 0; y < destHeight; y++ )
00219                                         {
00220                                                 // mix colors of upper and lower pixels and write it back
00221                                                 // into the bitmap
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 // convert_bitmap
00251 status_t
00252 convert_bitmap( BBitmap* inBitmap, BBitmap* outBitmap )
00253 {
00254         status_t status = B_BAD_VALUE;
00255         // see that we got valid bitmaps
00256         if ( inBitmap && inBitmap->IsValid()
00257                  && outBitmap && outBitmap->IsValid() )
00258         {
00259                 status = B_MISMATCHED_VALUES;
00260                 // see that bitmaps are compatible and that we support the conversion
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                                         // Y0[7:0]  Cb0[7:0]  Y1[7:0]  Cr0[7:0]
00276                                         // Y2[7:0]  Cb2[7:0]  Y3[7:0]  Cr2[7:0]
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                                                         // take care of alpha
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                                         // Non-interlaced only!
00306                                         // Cb0  Y0  Y1  Cb2 Y2  Y3  on even scan lines ...
00307                                         // Cr0  Y0  Y1  Cr2 Y2  Y3  on odd scan lines
00308                                         status = B_ERROR;
00309                                         break;
00310                                 case B_YUV422:
00311                                         // U0[7:0]  Y0[7:0]   V0[7:0]  Y1[7:0] 
00312                                         // U2[7:0]  Y2[7:0]   V2[7:0]  Y3[7:0]
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                                         // G[2:0],B[4:0]  R[4:0],G[5:3]
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                                                         // homogeneously scale each component to 8 bit
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 // clip_float
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 // dim_bitmap
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                                         // iterate over each pixel, get the respective
00385                                         // color from the screen object, find the distance
00386                                         // to the "center" color and shorten the distance
00387                                         // by "dimLevel"
00388                                         int32 length = bitmap->BitsLength();
00389                                         uint8* bits = (uint8*)bitmap->Bits();
00390                                         for (int32 i = 0; i < length; i++)
00391                                         {
00392                                                 // preserve transparent pixels
00393                                                 if (bits[i] != B_TRANSPARENT_MAGIC_CMAP8)
00394                                                 {
00395                                                         // get color for this index
00396                                                         rgb_color c = screen.ColorForIndex(bits[i]);
00397                                                         // red
00398                                                         float dist = (c.red - center.red) * dimLevel;
00399                                                         c.red = clip_float(center.red + dist);
00400                                                         // green
00401                                                         dist = (c.green - center.green) * dimLevel;
00402                                                         c.green = clip_float(center.green + dist);
00403                                                         // blue
00404                                                         dist = (c.blue - center.blue) * dimLevel;
00405                                                         c.blue = clip_float(center.blue + dist);
00406                                                         // write correct index of the dimmed color
00407                                                         // back into bitmap (and hope the match is close...)
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                                 // iterate over each color component, find the distance
00419                                 // to the "center" color and shorten the distance
00420                                 // by "dimLevel"
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                                 // iterate over color components
00426                                 for (int32 y = 0; y < lines; y++) {
00427                                         for (int32 x = 0; x < pixels; x++) {
00428                                                 int32 offset = 4 * x; // four bytes per pixel
00429                                                 // blue
00430                                                 float dist = (bits[offset + 0] - center.blue) * dimLevel;
00431                                                 bits[offset + 0] = clip_float(center.blue + dist);
00432                                                 // green
00433                                                 dist = (bits[offset + 1] - center.green) * dimLevel;
00434                                                 bits[offset + 1] = clip_float(center.green + dist);
00435                                                 // red
00436                                                 dist = (bits[offset + 2] - center.red) * dimLevel;
00437                                                 bits[offset + 2] = clip_float(center.red + dist);
00438                                                 // ignore alpha channel
00439                                         }
00440                                         // next line
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 // dimmed_color_cmap8
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                 // red
00462                 float dist = (color.red - center.red) * dimLevel;
00463                 color.red = clip_float(center.red + dist);
00464                 // green
00465                 dist = (color.green - center.green) * dimLevel;
00466                 color.green = clip_float(center.green + dist);
00467                 // blue
00468                 dist = (color.blue - center.blue) * dimLevel;
00469                 color.blue = clip_float(center.blue + dist);
00470                 // get color index for dimmed color
00471                 int32 index = screen.IndexForColor(color);
00472                 // put color at index (closest match in palette
00473                 // to dimmed result) into returned color
00474                 color = screen.ColorForIndex(index);
00475         }
00476         return color;
00477 }

Generated on Tue Dec 20 10:14:36 2005 for vlc-0.8.4a by  doxygen 1.4.2