根据文章: Linux下支持AX206 LCD FOR AIDA64 Business ,可以实现输出png图片到AX206 LCD。那么如果我们想输出framebuffer的图像到LCD屏幕呢?如何实现?
根据[email protected]:ukoda/lcd4linux-ax206.git仓库的代码,我们可以看到png图片的渲染是通过widget_image.c中的 static void widget_image_render(const char *Name, WIDGET_IMAGE * Image) 函数实现的。
我们可以通过如下修改,实现输出framebuffer图像到AX206 LCD的效果:
diff --git a/contrib/picoLCD/dpf_480_320.conf b/contrib/picoLCD/dpf_480_320.conf new file mode 100644 index 0000000..34e6b51 --- /dev/null +++ b/contrib/picoLCD/dpf_480_320.conf @@ -0,0 +1,42 @@ +Display dpf { + Driver 'DPF' + Port 'usb0' + Font '6x8' + Foreground 'ffffff' + Background '000000' + Basecolor '000000' + Orientation 0 # 0 = landscape, 1 = portrait + # 2 = reverse landscape, 3 = reverse portrait + Backlight backlight # Backlight variable control, 0..7 (0=off, 7=max) +} + +Widget Bgnd { + class 'Image' + file '/dev/fb1' + reload 1 + update 1000 + inverted 0 + visible 1 + fb_width 480 + fb_height 320 + fb_bpp 32 +} + +Display 'DPF' + +Layout layout_480x320 { + Layer 2 { + X1.Y1 'Bgnd' + } +} + +Layout 'layout_480x320' + +Variables { + backlight 7 + tick 500 + tack 200 + minute 60000 +} + + diff --git a/widget_image.c b/widget_image.c index accabfe..2238731 100644 --- a/widget_image.c +++ b/widget_image.c @@ -38,6 +38,10 @@ #include <string.h> #include <ctype.h> #include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> #ifdef HAVE_GD_GD_H #include <gd/gd.h> @@ -69,6 +73,111 @@ #include <dmalloc.h> #endif +static int obtain_frame_from_framebuffer(unsigned char *frame_buf, + char *fb_dev, int width, int height, int bpp) +{ + int fb_fd = open(fb_dev, O_RDWR); + if (fb_fd < 0) { + error("open dev %s failed", fb_dev); + return -1; + } + + int nread = read(fb_fd, frame_buf, width*height*bpp); + if (nread <= 0) { + error("read failed from framebuffer:%d", nread); + close(fb_fd); + return -1; + } + + close(fb_fd); + return 0; +} + +static gdImagePtr createImageFromRgb32(unsigned char *rgbData, int width, int height) +{ + gdImagePtr im; + int x, y; + int color; + + im = gdImageCreateTrueColor(width, height); + if (!im) { + error("Could not create image.\n"); + return NULL; + } + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + int index = (y * width + x) * 4; + + unsigned char b = rgbData[index]; + unsigned char g = rgbData[index + 1]; + unsigned char r = rgbData[index + 2]; + + color = gdImageColorAllocate(im, r, g, b); + + gdImageSetPixel(im, x, y, color); + } + } + + return im; +} + +static gdImagePtr createImageFromRgb24(unsigned char *rgbData, int width, int height) +{ + gdImagePtr im; + int x, y; + int color; + + im = gdImageCreateTrueColor(width, height); + if (!im) { + error("Could not create image.\n"); + return NULL; + } + + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { + int index = (y * width + x) * 3; + + unsigned char r = rgbData[index]; + unsigned char g = rgbData[index + 1]; + unsigned char b = rgbData[index + 2]; + + color = gdImageColorAllocate(im, r, g, b); + + gdImageSetPixel(im, x, y, color); + } + } + + return im; +} + +static int create_image_from_framebuffer(char *dev_fb, WIDGET_IMAGE *Image) +{ + int width, height, Bpp; + int retval; + + width = P2N(&Image->fb_width); + height = P2N(&Image->fb_height); + Bpp = P2N(&Image->fb_bpp) / 8; + unsigned char img_buf[width*height*Bpp]; + + /* we only support rgba and rgb current */ + if (width <= 0 || height <= 0 || (Bpp != 4 && Bpp != 3)) + return -1; + + retval = obtain_frame_from_framebuffer(img_buf, dev_fb, width, height, Bpp); + if (retval) + return -1; + + if (Bpp == 4) + Image->gdImage = createImageFromRgb32(img_buf, width, height); + else if (Bpp == 3) + Image->gdImage = createImageFromRgb24(img_buf, width, height); + else + return -1; + + return 0; +} static void widget_image_render(const char *Name, WIDGET_IMAGE * Image) { @@ -105,13 +214,22 @@ static void widget_image_render(const char *Name, WIDGET_IMAGE * Image) return; } - fd = fopen(file, "rb"); - if (fd == NULL) { - error("Warning: Image %s: fopen(%s) failed: %s", Name, file, strerror(errno)); - return; - } - Image->gdImage = gdImageCreateFromPng(fd); - fclose(fd); + char *f_ptr = strstr(file, "/dev/fb"); + if (f_ptr) { + int retval = create_image_from_framebuffer(file, Image); + if (retval) { + error("Warning: get frame from %s failed", file); + return; + } + } else { + fd = fopen(file, "rb"); + if (fd == NULL) { + error("Warning: Image %s: fopen(%s) failed: %s", Name, file, strerror(errno)); + return; + } + Image->gdImage = gdImageCreateFromPng(fd); + fclose(fd); + } if (Image->gdImage == NULL) { fd = fopen(file, "rb"); @@ -293,6 +411,9 @@ static void widget_image_update(void *Self) property_eval(&Image->visible); property_eval(&Image->inverted); property_eval(&Image->center); + property_eval(&Image->fb_width); + property_eval(&Image->fb_height); + property_eval(&Image->fb_bpp); /* render image into bitmap */ widget_image_render(W->name, Image); @@ -343,6 +464,9 @@ int widget_image_init(WIDGET * Self) property_load(section, "visible", "1", &Image->visible); property_load(section, "inverted", "0", &Image->inverted); property_load(section, "center", "0", &Image->center); + property_load(section, "fb_width", "480", &Image->fb_width); + property_load(section, "fb_height", "320", &Image->fb_height); + property_load(section, "fb_bpp", "32", &Image->fb_bpp); /* sanity checks */ if (!property_valid(&Image->file)) { @@ -389,6 +513,10 @@ int widget_image_quit(WIDGET * Self) property_free(&Image->visible); property_free(&Image->inverted); property_free(&Image->center); + property_free(&Image->fb_width); + property_free(&Image->fb_height); + property_free(&Image->fb_bpp); + free(Self->data); Self->data = NULL; } diff --git a/widget_image.h b/widget_image.h index 6ead2b4..4d64a9a 100644 --- a/widget_image.h +++ b/widget_image.h @@ -46,6 +46,9 @@ typedef struct WIDGET_IMAGE { PROPERTY visible; /* image visible? */ PROPERTY inverted; /* image inverted? */ PROPERTY center; /* image centered? */ + PROPERTY fb_width; /* size of the framebuffer width */ + PROPERTY fb_height; /* size of the framebuffer height */ + PROPERTY fb_bpp; /* bits per pixel */ } WIDGET_IMAGE; extern WIDGET_CLASS Widget_Image;
如上述修改所示,我们可以通过配置文件dpf_480_320.conf里Bgnd widget的文件名参数 file 来指定要使用哪个framebuffer设备。想要使用fb0就配置file为“/dev/fb0”, 想使用fb1就配置为"/dev/fb1"。这样可以兼容输出png图片到LCD的功能。
配置文件解析:
- dpf_480_320.conf里Bgnd widget的fb_width和fb_height分别表示AX206 LCD分辨率的宽和高。
- dpf_480_320.conf里Bgnd widget的fb_bpp参数根据你系统内framebuffer的bpp(bits per pixel)来决定。
-
- 如果framebuffer的bpp为32(RGBA), 则fb_bpp参数配置为32。如果framebuffer的bpp为24(RGB888),则fb_bpp参数配置为24。
framebuffer的bpp可以使用fbset工具来设置,具体使用方法如下:
fbset -fb /dev/fb1 -g 480 320 480 320 32
上面的命令是设置fb1的bpp为32, width为480,height为320。
我们可以通过dpf_480_320.conf里Bgnd widget的update参数调整LCD刷新的间隔,单位为ms。
上述 obtain_frame_from_framebuffer 函数实现从framebuffer里获取RGB raw数据。
由于GD库没有API直接实现把RGB raw数据生成gdImage的功能,我这里写了两个函数 createImageFromRgb32 和 createImageFromRgb24 来实现。
经过上述对lcd4linux源码的改动,我们已经可以输出framebuffer图像到AX206 LCD了。
标签:widget,Image,LCD,bpp,fb,lcd4linux,framebuffer,property,image From: https://www.cnblogs.com/wanglouxiaozi/p/18102315