DrawingTidbits.cpp
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:14k
源码类别:

多媒体

开发平台:

MultiPlatform

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