DrawingTidbits.cpp
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:18k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * DrawingTidbits.cpp
  3.  *****************************************************************************
  4.  * Copyright (C) 2001 the VideoLAN team
  5.  * $Id: 362933f5efd189ed8670a19d94c99d1d19e3e5a2 $
  6.  *
  7.  * Authors: Tony Castley <tcastley@mail.powerup.com.au>
  8.  *          Stephan Aßmus <stippi@yellowbites.com>
  9.  *
  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.
  14.  *
  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.
  19.  *
  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.  *****************************************************************************/
  24. #include <math.h>
  25. #include <Bitmap.h>
  26. #include <Debug.h>
  27. #include <Screen.h>
  28. #include "DrawingTidbits.h"
  29. // ShiftComponent
  30. inline uchar
  31. ShiftComponent(uchar component, float percent)
  32. {
  33.     // change the color by <percent>, make sure we aren't rounding
  34.     // off significant bits
  35.     if (percent >= 1)
  36.         return (uchar)(component * (2 - percent));
  37.     else
  38.         return (uchar)(255 - percent * (255 - component));
  39. }
  40. // ShiftColor
  41. rgb_color
  42. ShiftColor(rgb_color color, float percent)
  43. {
  44.     rgb_color result = {
  45.         ShiftComponent(color.red, percent),
  46.         ShiftComponent(color.green, percent),
  47.         ShiftComponent(color.blue, percent),
  48.         0
  49.     };
  50.     
  51.     return result;
  52. }
  53. // CompareColors
  54. static bool
  55. CompareColors(const rgb_color a, const rgb_color b)
  56. {
  57.     return a.red == b.red
  58.         && a.green == b.green
  59.         && a.blue == b.blue
  60.         && a.alpha == b.alpha;
  61. }
  62. // ==
  63. bool
  64. operator==(const rgb_color &a, const rgb_color &b)
  65. {
  66.     return CompareColors(a, b);
  67. }
  68. // !=
  69. bool
  70. operator!=(const rgb_color &a, const rgb_color &b)
  71. {
  72.     return !CompareColors(a, b);
  73. }
  74. // ReplaceColor
  75. void
  76. ReplaceColor(BBitmap *bitmap, rgb_color from, rgb_color to)
  77. {
  78.     ASSERT(bitmap->ColorSpace() == B_COLOR_8_BIT); // other color spaces not implemented yet
  79.     
  80.     BScreen screen(B_MAIN_SCREEN_ID);
  81.     uint32 fromIndex = screen.IndexForColor(from);
  82.     uint32 toIndex = screen.IndexForColor(to);
  83.     
  84.     uchar *bits = (uchar *)bitmap->Bits();
  85.     int32 bitsLength = bitmap->BitsLength();    
  86.     for (int32 index = 0; index < bitsLength; index++)
  87.         if (bits[index] == fromIndex)
  88.             bits[index] = toIndex;
  89. }
  90. // ReplaceTransparentColor
  91. void
  92. ReplaceTransparentColor(BBitmap *bitmap, rgb_color with)
  93. {
  94.     ASSERT(bitmap->ColorSpace() == B_COLOR_8_BIT); // other color spaces not implemented yet
  95.     
  96.     BScreen screen(B_MAIN_SCREEN_ID);
  97.     uint32 withIndex = screen.IndexForColor(with);
  98.     
  99.     uchar *bits = (uchar *)bitmap->Bits();
  100.     int32 bitsLength = bitmap->BitsLength();    
  101.     for (int32 index = 0; index < bitsLength; index++)
  102.         if (bits[index] == B_TRANSPARENT_8_BIT)
  103.             bits[index] = withIndex;
  104. }
  105. // ycrcb_to_rgb
  106. inline void
  107. ycbcr_to_rgb( uint8 y, uint8 cb, uint8 cr,
  108.               uint8& r, uint8& g, uint8& b)
  109. {
  110.     r = (uint8)max_c( 0, min_c( 255, 1.164 * ( y - 16 ) + 1.596 * ( cr - 128 ) ) );
  111.     g = (uint8)max_c( 0, min_c( 255, 1.164 * ( y - 16 ) - 0.813 * ( cr - 128 )
  112.                                 - 0.391 * ( cb - 128 ) ) );
  113.     b = (uint8)max_c( 0, min_c( 255, 1.164 * ( y - 16 ) + 2.018 * ( cb - 128 ) ) );
  114. }
  115. // this function will not produce visually pleasing results!
  116. // we'd have to convert to Lab colorspace, do the mixing
  117. // and convert back to RGB - in an ideal world...
  118. //
  119. // mix_colors
  120. inline void
  121. mix_colors( uint8 ra, uint8 ga, uint8 ba,
  122.             uint8 rb, uint8 gb, uint8 bb,
  123.             uint8& r, uint8& g, uint8& b, float mixLevel )
  124. {
  125.     float mixA = ( 1.0 - mixLevel );
  126.     float mixB = mixLevel;
  127.     r = (uint8)(mixA * ra + mixB * rb);
  128.     g = (uint8)(mixA * ga + mixB * gb);
  129.     b = (uint8)(mixA * ba + mixB * bb);
  130. }
  131. // the algorithm used is probably pretty slow, but it should be easy
  132. // to understand what's going on...
  133. //
  134. // scale_bitmap
  135. status_t
  136. scale_bitmap( BBitmap* bitmap, uint32 fromWidth, uint32 fromHeight )
  137. {
  138.     status_t status = B_BAD_VALUE;
  139.     
  140.     if ( bitmap && bitmap->IsValid()
  141.          && ( bitmap->ColorSpace() == B_RGB32 || bitmap->ColorSpace() == B_RGBA32 ) )
  142.     {
  143.         status = B_MISMATCHED_VALUES;
  144.         // we only support upscaling as of now
  145.         uint32 destWidth = bitmap->Bounds().IntegerWidth() + 1;
  146.         uint32 destHeight = bitmap->Bounds().IntegerHeight() + 1;
  147.         if ( fromWidth <= destWidth && fromHeight <= destHeight )
  148.         {
  149.             status = B_OK;
  150.             uint32 bpr = bitmap->BytesPerRow();
  151.             if ( fromWidth < destWidth )
  152.             {
  153.                 // scale horizontally
  154.                 uint8* src = (uint8*)bitmap->Bits();
  155.                 uint8* p = new uint8[fromWidth * 4];    // temp buffer
  156.                 for ( uint32 y = 0; y < fromHeight; y++ )
  157.                 {
  158.                     // copy valid pixels into temp buffer
  159.                     memcpy( p, src, fromWidth * 4 );
  160.                     for ( uint32 x = 0; x < destWidth; x++ )
  161.                     {
  162.                         // mix colors of left and right pixels and write it back
  163.                         // into the bitmap
  164.                         float xPos = ( (float)x / (float)destWidth ) * (float)fromWidth;
  165.                         uint32 leftIndex = (uint32)floorf( xPos ) * 4;
  166.                         uint32 rightIndex = (uint32)ceilf( xPos ) * 4;
  167.                         rgb_color left;
  168.                         left.red = p[leftIndex + 2];
  169.                         left.green = p[leftIndex + 1];
  170.                         left.blue = p[leftIndex + 0];
  171.                         rgb_color right;
  172.                         right.red = p[rightIndex + 2];
  173.                         right.green = p[rightIndex + 1];
  174.                         right.blue = p[rightIndex + 0];
  175.                         rgb_color mix;
  176.                         mix_colors( left.red, left.green, left.blue,
  177.                                     right.red, right.green, right.blue,
  178.                                     mix.red, mix.green, mix.blue, xPos - floorf( xPos ) );
  179.                         uint32 destIndex = x * 4;
  180.                         src[destIndex + 2] = mix.red;
  181.                         src[destIndex + 1] = mix.green;
  182.                         src[destIndex + 0] = mix.blue;
  183.                     }
  184.                     src += bpr;
  185.                 }
  186.                 delete[] p;
  187.             }
  188.             if ( fromHeight < destHeight )
  189.             {
  190.                 // scale vertically
  191.                 uint8* src = (uint8*)bitmap->Bits();
  192.                 uint8* p = new uint8[fromHeight * 3];    // temp buffer
  193.                 for ( uint32 x = 0; x < destWidth; x++ )
  194.                 {
  195.                     // copy valid pixels into temp buffer
  196.                     for ( uint32 y = 0; y < fromHeight; y++ )
  197.                     {
  198.                         uint32 destIndex = y * 3;
  199.                         uint32 srcIndex = x * 4 + y * bpr;
  200.                         p[destIndex + 0] = src[srcIndex + 0];
  201.                         p[destIndex + 1] = src[srcIndex + 1];
  202.                         p[destIndex + 2] = src[srcIndex + 2];
  203.                     }
  204.                     // do the scaling
  205.                     for ( uint32 y = 0; y < destHeight; y++ )
  206.                     {
  207.                         // mix colors of upper and lower pixels and write it back
  208.                         // into the bitmap
  209.                         float yPos = ( (float)y / (float)destHeight ) * (float)fromHeight;
  210.                         uint32 upperIndex = (uint32)floorf( yPos ) * 3;
  211.                         uint32 lowerIndex = (uint32)ceilf( yPos ) * 3;
  212.                         rgb_color upper;
  213.                         upper.red = p[upperIndex + 2];
  214.                         upper.green = p[upperIndex + 1];
  215.                         upper.blue = p[upperIndex + 0];
  216.                         rgb_color lower;
  217.                         lower.red = p[lowerIndex + 2];
  218.                         lower.green = p[lowerIndex + 1];
  219.                         lower.blue = p[lowerIndex + 0];
  220.                         rgb_color mix;
  221.                         mix_colors( upper.red, upper.green, upper.blue,
  222.                                     lower.red, lower.green, lower.blue,
  223.                                     mix.red, mix.green, mix.blue, yPos - floorf( yPos ) );
  224.                         uint32 destIndex = x * 4 + y * bpr;
  225.                         src[destIndex + 2] = mix.red;
  226.                         src[destIndex + 1] = mix.green;
  227.                         src[destIndex + 0] = mix.blue;
  228.                     }
  229.                 }
  230.                 delete[] p;
  231.             }
  232.         }
  233.     }
  234.     return status;
  235. }
  236. // convert_bitmap
  237. status_t
  238. convert_bitmap( BBitmap* inBitmap, BBitmap* outBitmap )
  239. {
  240.     status_t status = B_BAD_VALUE;
  241.     // see that we got valid bitmaps
  242.     if ( inBitmap && inBitmap->IsValid()
  243.          && outBitmap && outBitmap->IsValid() )
  244.     {
  245.         status = B_MISMATCHED_VALUES;
  246.         // see that bitmaps are compatible and that we support the conversion
  247.         if ( inBitmap->Bounds().Width() <= outBitmap->Bounds().Width()
  248.              && inBitmap->Bounds().Height() <= outBitmap->Bounds().Height()
  249.              && ( outBitmap->ColorSpace() == B_RGB32
  250.                   || outBitmap->ColorSpace() == B_RGBA32) )
  251.         {
  252.             int32 width = inBitmap->Bounds().IntegerWidth() + 1;
  253.             int32 height = inBitmap->Bounds().IntegerHeight() + 1;
  254.             int32 srcBpr = inBitmap->BytesPerRow();
  255.             int32 dstBpr = outBitmap->BytesPerRow();
  256.             uint8* srcBits = (uint8*)inBitmap->Bits();
  257.             uint8* dstBits = (uint8*)outBitmap->Bits();
  258.             switch (inBitmap->ColorSpace())
  259.             {
  260.                 case B_YCbCr422:
  261.                     // Y0[7:0]  Cb0[7:0]  Y1[7:0]  Cr0[7:0]
  262.                     // Y2[7:0]  Cb2[7:0]  Y3[7:0]  Cr2[7:0]
  263.                     for ( int32 y = 0; y < height; y++ )
  264.                     {
  265.                         for ( int32 x = 0; x < width; x += 2 )
  266.                         {
  267.                             int32 srcOffset = x * 2;
  268.                             int32 dstOffset = x * 4;
  269.                             ycbcr_to_rgb( srcBits[srcOffset + 0],
  270.                                           srcBits[srcOffset + 1],
  271.                                           srcBits[srcOffset + 3],
  272.                                           dstBits[dstOffset + 2],
  273.                                           dstBits[dstOffset + 1],
  274.                                           dstBits[dstOffset + 0] );
  275.                             ycbcr_to_rgb( srcBits[srcOffset + 2],
  276.                                           srcBits[srcOffset + 1],
  277.                                           srcBits[srcOffset + 3],
  278.                                           dstBits[dstOffset + 6],
  279.                                           dstBits[dstOffset + 5],
  280.                                           dstBits[dstOffset + 4] );
  281.                             // take care of alpha
  282.                             dstBits[x * 4 + 3] = 255;
  283.                             dstBits[x * 4 + 7] = 255;
  284.                         }
  285.                         srcBits += srcBpr;
  286.                         dstBits += dstBpr;
  287.                     }
  288.                     status = B_OK;
  289.                     break;
  290.                 case B_YCbCr420:
  291.                     // Non-interlaced only!
  292.                     // Cb0  Y0  Y1  Cb2 Y2  Y3  on even scan lines ...
  293.                     // Cr0  Y0  Y1  Cr2 Y2  Y3  on odd scan lines
  294.                     status = B_ERROR;
  295.                     break;
  296.                 case B_YUV422:
  297.                     // U0[7:0]  Y0[7:0]   V0[7:0]  Y1[7:0]
  298.                     // U2[7:0]  Y2[7:0]   V2[7:0]  Y3[7:0]
  299.                     status = B_ERROR;
  300.                     break;
  301.                 case B_RGB32:
  302.                 case B_RGBA32:
  303.                     memcpy( dstBits, srcBits, inBitmap->BitsLength() );
  304.                     status = B_OK;
  305.                     break;
  306.                 case B_RGB16:
  307.                     // G[2:0],B[4:0]  R[4:0],G[5:3]
  308.                     for ( int32 y = 0; y < height; y ++ )
  309.                     {
  310.                         for ( int32 x = 0; x < width; x++ )
  311.                         {
  312.                             int32 srcOffset = x * 2;
  313.                             int32 dstOffset = x * 4;
  314.                             uint8 blue = srcBits[srcOffset + 0] & 0x1f;
  315.                             uint8 green = ( srcBits[srcOffset + 0] >> 5 )
  316.                                           | ( ( srcBits[srcOffset + 1] & 0x07 ) << 3 );
  317.                             uint8 red = srcBits[srcOffset + 1] & 0xf8;
  318.                             // homogeneously scale each component to 8 bit
  319.                             dstBits[dstOffset + 0] = (blue << 3) | (blue >> 2);
  320.                             dstBits[dstOffset + 1] = (green << 2) | (green >> 4);
  321.                             dstBits[dstOffset + 2] = red | (red >> 5);
  322.                         }
  323.                         srcBits += srcBpr;
  324.                         dstBits += dstBpr;
  325.                     }
  326.                     status = B_OK;
  327.                     break;
  328.                 default:
  329.                     status = B_MISMATCHED_VALUES;
  330.                     break;
  331.             }
  332.             if ( status == B_OK )
  333.             {
  334.                 if ( width < outBitmap->Bounds().IntegerWidth() + 1
  335.                      || height < outBitmap->Bounds().IntegerHeight() + 1 )
  336.                 {
  337.                     scale_bitmap( outBitmap, width, height );
  338.                 }
  339.             }
  340.         }
  341.     }
  342.     return status;
  343. }
  344. // clip_float
  345. inline uint8
  346. clip_float(float value)
  347. {
  348.     if (value < 0)
  349.         value = 0;
  350.     if (value > 255)
  351.         value = 255;
  352.     return (uint8)value;
  353. }
  354. // dim_bitmap
  355. status_t
  356. dim_bitmap(BBitmap* bitmap, rgb_color center, float dimLevel)
  357. {
  358.     status_t status = B_BAD_VALUE;
  359.     if (bitmap && bitmap->IsValid())
  360.     {
  361.         switch (bitmap->ColorSpace())
  362.         {
  363.             case B_CMAP8:
  364.             {
  365.                 BScreen screen(B_MAIN_SCREEN_ID);
  366.                 if (screen.IsValid())
  367.                 {
  368.                     // iterate over each pixel, get the respective
  369.                     // color from the screen object, find the distance
  370.                     // to the "center" color and shorten the distance
  371.                     // by "dimLevel"
  372.                     int32 length = bitmap->BitsLength();
  373.                     uint8* bits = (uint8*)bitmap->Bits();
  374.                     for (int32 i = 0; i < length; i++)
  375.                     {
  376.                         // preserve transparent pixels
  377.                         if (bits[i] != B_TRANSPARENT_MAGIC_CMAP8)
  378.                         {
  379.                             // get color for this index
  380.                             rgb_color c = screen.ColorForIndex(bits[i]);
  381.                             // red
  382.                             float dist = (c.red - center.red) * dimLevel;
  383.                             c.red = clip_float(center.red + dist);
  384.                             // green
  385.                             dist = (c.green - center.green) * dimLevel;
  386.                             c.green = clip_float(center.green + dist);
  387.                             // blue
  388.                             dist = (c.blue - center.blue) * dimLevel;
  389.                             c.blue = clip_float(center.blue + dist);
  390.                             // write correct index of the dimmed color
  391.                             // back into bitmap (and hope the match is close...)
  392.                             bits[i] = screen.IndexForColor(c);
  393.                         }
  394.                     }
  395.                     status = B_OK;
  396.                 }
  397.                 break;
  398.             }
  399.             case B_RGB32:
  400.             case B_RGBA32:
  401.             {
  402.                 // iterate over each color component, find the distance
  403.                 // to the "center" color and shorten the distance
  404.                 // by "dimLevel"
  405.                 uint8* bits = (uint8*)bitmap->Bits();
  406.                 int32 bpr = bitmap->BytesPerRow();
  407.                 int32 pixels = bitmap->Bounds().IntegerWidth() + 1;
  408.                 int32 lines = bitmap->Bounds().IntegerHeight() + 1;
  409.                 // iterate over color components
  410.                 for (int32 y = 0; y < lines; y++) {
  411.                     for (int32 x = 0; x < pixels; x++) {
  412.                         int32 offset = 4 * x; // four bytes per pixel
  413.                         // blue
  414.                         float dist = (bits[offset + 0] - center.blue) * dimLevel;
  415.                         bits[offset + 0] = clip_float(center.blue + dist);
  416.                         // green
  417.                         dist = (bits[offset + 1] - center.green) * dimLevel;
  418.                         bits[offset + 1] = clip_float(center.green + dist);
  419.                         // red
  420.                         dist = (bits[offset + 2] - center.red) * dimLevel;
  421.                         bits[offset + 2] = clip_float(center.red + dist);
  422.                         // ignore alpha channel
  423.                     }
  424.                     // next line
  425.                     bits += bpr;
  426.                 }
  427.                 status = B_OK;
  428.                 break;
  429.             }
  430.             default:
  431.                 status = B_ERROR;
  432.                 break;
  433.         }
  434.     }
  435.     return status;
  436. }
  437. // dimmed_color_cmap8
  438. rgb_color
  439. dimmed_color_cmap8(rgb_color color, rgb_color center, float dimLevel)
  440. {
  441.     BScreen screen(B_MAIN_SCREEN_ID);
  442.     if (screen.IsValid())
  443.     {
  444.         // red
  445.         float dist = (color.red - center.red) * dimLevel;
  446.         color.red = clip_float(center.red + dist);
  447.         // green
  448.         dist = (color.green - center.green) * dimLevel;
  449.         color.green = clip_float(center.green + dist);
  450.         // blue
  451.         dist = (color.blue - center.blue) * dimLevel;
  452.         color.blue = clip_float(center.blue + dist);
  453.         // get color index for dimmed color
  454.         int32 index = screen.IndexForColor(color);
  455.         // put color at index (closest match in palette
  456.         // to dimmed result) into returned color
  457.         color = screen.ColorForIndex(index);
  458.     }
  459.     return color;
  460. }