electrlife 发表于 2013-3-9 22:52:06

UCGUI在16位LCD上如何实现渐变色显示效果?

本帖最后由 electrlife 于 2013-3-9 23:08 编辑

如题所示,最近想把界面做的好看些,于是似着在UCGUI上实现一个渐变色的函数,如下所示:
一个是常规实现方式,另一个是优化的方式。
如果24位的LCD上显示没问题,可是如果在16位的LCD显示,则不是很理想。因此需要使用
类似Floyd-Steinberg算法的来消除影响。不知各位做过没,效果如何,速度如何,类似单
片机即CORTEX-M3这种MCU在UCGUI环境下使用是否可以流畅显示。

不知大家还有没有其它的方法!

#include "GUI_Protected.h"

typedef void tfDrawLine(int x, int y, int z);

/*********************************************************************
*
*       Static code
*
**********************************************************************
*/
/*********************************************************************
*
*       _DrawGradient
*
*/
#if 1
static void _DrawGradient(int x0, int y0, int x1, int y1, GUI_COLOR Color0, GUI_COLOR Color1,
                        const tfDrawLine *pfDrawLine, int Vertical) {
GUI_COLOR Color, OldColor;
int i, r0, g0, b0, r1, g1, b1, r, g, b;
int dt;

if (Vertical) {
    dt = y1 - y0 + 1;
} else {
    dt = x1 - x0 + 1;
}

r0 = (Color0>>0) & 0xff;
g0 = (Color0>>8) & 0xff;
b0 = (Color0>> 16) & 0xff;

r1 = (Color1>>0) & 0xff;
g1 = (Color1>>8) & 0xff;
b1 = (Color1>> 16) & 0xff;

OldColor = GUI_GetColor();
for (i = 0; i < dt; i++) {
    r = r0 + (i * (r1 - r0)) / dt;
    g = g0 + (i * (g1 - g0)) / dt;
    b = b0 + (i * (b1 - b0)) / dt;

    Color = r + (g << 8) + (b << 16);
    LCD_SetColor(Color);

    if (Vertical) {
      /* void LCD_DrawHLine(int x0, int y,int x1) */
      pfDrawLine(x0, y0+i, x1);
    } else {
      /* void LCD_DrawVLine(int x, int y0,int y1) */
      pfDrawLine(x0+i, y0, y1);
    }
}
LCD_SetColor(OldColor);
}
#else
static void _DrawGradient(int x0, int y0, int x1, int y1, GUI_COLOR Color0, GUI_COLOR Color1,
                        const tfDrawLine *pfDrawLine, int Vertical) {
int i, r0, g0, b0, r1, g1, b1, r, g, b;
int dt;

GUI_COLOR OldColor = GUI_GetColor();

r0 = (Color0>>0) & 0xff;
g0 = (Color0>>8) & 0xff;
b0 = (Color0>> 16) & 0xff;

r1 = (Color1>>0) & 0xff;
g1 = (Color1>>8) & 0xff;
b1 = (Color1>> 16) & 0xff;

if (Vertical) {
    dt = y1 - y0 + 1;
    y1 = y0;
} else {
    dt = x1 - x0 + 1;
    x1 = x0;
}

for (i = 0; i < dt; i++) {
    r = r0 + (i * (r1 - r0)) / dt;
    g = g0 + (i * (g1 - g0)) / dt;
    b = b0 + (i * (b1 - b0)) / dt;

    Color1 = r + (g << 8) + (b << 16);
    if (Color1 != Color0) {
      LCD_SetColor(Color0);
      if (Vertical) {
      if (y1 != y0) {
          GUI_FillRect(x0, y0, x1, y1);
      } else {
          pfDrawLine(x0, y1, x1);
      }
      y1++;
      y0 = y1;
      } else {
      if (x1 != x0) {
          GUI_FillRect(x0, y0, x1, y1);
      } else {
          pfDrawLine(x1, y0, y1);
      }
      x1++;
      x0 = x1;
      }
      Color0 = Color1;
    } else {
      if (Vertical) {
      y1++;
      } else {
      x1++;
      }
    }
}

LCD_SetColor(Color0);
if (Vertical) {
    if (y1 != y0) {
      GUI_FillRect(x0, y0, x1, y1);
    } else {
      pfDrawLine(x0, y1, x1);
    }
} else {
    if (x1 != x0) {
      GUI_FillRect(x0, y0, x1, y1);
    } else {
      pfDrawLine(x1, y0, y1);
    }
}

LCD_SetColor(OldColor);
}
#endif

/*********************************************************************
*
*       Public code
*
**********************************************************************
*/

/*********************************************************************
*
*       GUI_DrawGradientV
*/
void GUI_DrawGradientV(int x0, int y0, int x1, int y1, GUI_COLOR Color0, GUI_COLOR Color1)
{
#if (GUI_WINSUPPORT)
    GUI_RECT r;
#endif
GUI_LOCK();
#if (GUI_WINSUPPORT)
    WM_ADDORG(x0,y0);
    WM_ADDORG(x1,y1);
    r.x0 = x0; r.x1 = x1;
    r.y0 = y0; r.y1 = y1;
    WM_ITERATE_START(&r); {
#endif
_DrawGradient(x0, y0, x1, y1, Color0, Color1, LCD_DrawHLine, 1);
#if (GUI_WINSUPPORT)
    } WM_ITERATE_END();
#endif
GUI_UNLOCK();
}

/*********************************************************************
*
*       GUI_DrawGradientH
*/
void GUI_DrawGradientH(int x0, int y0, int x1, int y1, GUI_COLOR Color0, GUI_COLOR Color1)
{
#if (GUI_WINSUPPORT)
    GUI_RECT r;
#endif
GUI_LOCK();
#if (GUI_WINSUPPORT)
    WM_ADDORG(x0,y0);
    WM_ADDORG(x1,y1);
    r.x0 = x0; r.x1 = x1;
    r.y0 = y0; r.y1 = y1;
    WM_ITERATE_START(&r); {
#endif
_DrawGradient(x0, y0, x1, y1, Color0, Color1, LCD_DrawVLine, 0);
#if (GUI_WINSUPPORT)
    } WM_ITERATE_END();
#endif
GUI_UNLOCK();
}

faduo2012 发表于 2013-3-10 00:34:37

你用16位的,你算法没改成相应的16位吗?如这里: r0 = (Color0>>0) & 0xff;
g0 = (Color0>>8) & 0xff;
b0 = (Color0>> 16) & 0xff;

electrlife 发表于 2013-3-10 07:24:17

faduo2012 发表于 2013-3-10 00:34 static/image/common/back.gif
你用16位的,你算法没改成相应的16位吗?如这里: r0 = (Color0>>0) & 0xff;
g0 = (Color0>>8) & 0xf ...

这个函数接口是在UCGUI系统环境下实现的,用户使用的颜色都是888真彩色,
当调用LCD_SetColor时会把相应的888转变成对应硬件支持的颜色。

electrlife 发表于 2013-3-11 11:59:21

自己顶起来,求推荐24BIT BMP转16BIT BMP小失真的软件!!
目前使用Photoshop Fireworks等转换均无果!!

ST_ATMEL_NXP 发表于 2013-3-25 14:53:30

Floyd-Steinberg算法可以比较接近原图的转换,但是我也在找这块资料。
页: [1]
查看完整版本: UCGUI在16位LCD上如何实现渐变色显示效果?