diff options
author | Steffen Trumtrar <s.trumtrar@pengutronix.de> | 2014-10-08 12:27:24 +0200 |
---|---|---|
committer | Steffen Trumtrar <s.trumtrar@pengutronix.de> | 2014-10-10 15:58:58 +0200 |
commit | 174986af4c7c7254f7b9e9e9eb2948321e9e7dcf (patch) | |
tree | 2171b42a728bb484152e79b553313c74f85d7ccc | |
parent | cd76e0932f6352bc1050681a90571424fa2adf96 (diff) | |
download | kmsfbwrap-174986af4c7c7254f7b9e9e9eb2948321e9e7dcf.tar.gz kmsfbwrap-174986af4c7c7254f7b9e9e9eb2948321e9e7dcf.tar.xz |
add png splash image support
Signed-off-by: Steffen Trumtrar <s.trumtrar@pengutronix.de>
-rw-r--r-- | Makefile.am | 7 | ||||
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | src/kmsfb-manage.c | 72 | ||||
-rw-r--r-- | src/kmsfb.h | 10 | ||||
-rw-r--r-- | src/png.c | 154 |
5 files changed, 242 insertions, 2 deletions
diff --git a/Makefile.am b/Makefile.am index 78f8275..8e1d1db 100644 --- a/Makefile.am +++ b/Makefile.am @@ -10,7 +10,8 @@ AM_CPPFLAGS = \ -I${top_srcdir}/src/kmsfbwrap \ -I${top_srcdir}/src \ $(DRM_CFLAGS) \ - $(FUSE_CFLAGS) + $(FUSE_CFLAGS) \ + $(LIBPNG_CFLAGS) AM_CFLAGS = ${my_CFLAGS} \ -fvisibility=hidden \ @@ -36,11 +37,13 @@ SED_PROCESS = \ bin_PROGRAMS = kmsfb-manage kmsfb_manage_SOURCES = \ + src/png.c \ src/kmsfb-manage.c \ src/bgi.c kmsfb_manage_LDADD = \ $(FUSE_LIBS) \ - $(DRM_LIBS) + $(DRM_LIBS) \ + $(LIBPNG_LIBS) noinst_HEADERS = src/kmsfb.h diff --git a/configure.ac b/configure.ac index 6e2ffd4..9ac00da 100644 --- a/configure.ac +++ b/configure.ac @@ -41,6 +41,7 @@ AC_SUBST([my_CFLAGS]) PKG_CHECK_MODULES(DRM, libdrm) PKG_CHECK_MODULES(FUSE, fuse) +PKG_CHECK_MODULES(LIBPNG, libpng) AC_CONFIG_HEADERS(config.h) AC_CONFIG_FILES([ diff --git a/src/kmsfb-manage.c b/src/kmsfb-manage.c index 2f0182a..49d90e2 100644 --- a/src/kmsfb-manage.c +++ b/src/kmsfb-manage.c @@ -125,6 +125,13 @@ static int kms_data_val_set(struct kms_data *kd, const char *key, const char *va kd->triplebuf = 1; else if (!strcmp(key, "fill")) kd->fill = 1; + else if (!strcmp(key, "file")) { + if (strlen(value) > MAX_FILENAME) { + pr_err("Filename '%s' is to long.\n", value); + return -EINVAL; + } + strcpy(kd->file, value); + } else if (!strcmp(key, "vsync")) kd->vsync = strtoul(value, NULL, 0); else if (!strcmp(key, "xpos")) @@ -1030,6 +1037,67 @@ struct cmd { int (*fn)(int fd, int argc, char **argv); }; +static void *convert_rgb2fb(unsigned char *rgb, unsigned int count, int bpp) +{ + void *result; + uint32_t *fbbuf; + int i; + + switch (bpp) { + case 32: + fbbuf = (uint32_t *)malloc(count * sizeof(*fbbuf)); + + for (i = 0; i < count; i++) { + fbbuf[i] = ((rgb[i*3] << 16) & 0xff0000) | + ((rgb[i*3+1] << 8) & 0xff00) | + ((rgb[i*3+2]) & 0xff); + } + result = (void *)fbbuf; + break; + default: + fprintf(stderr, "Unsupported video mode! You've got: %dbpp\n", bpp); + return NULL; + } + + return result; +} + +static int fb_splash(struct kms_fb *fb, char *filename) +{ + unsigned char *alpha; + unsigned char *line; + unsigned char *fbbuf; + struct splash img; + int y; + int cpp; + int ret; + + memset(&img, 0, sizeof(struct splash)); + + ret = png_load(filename, &img, &alpha); + if (ret) + return -EINVAL; + + fbbuf = convert_rgb2fb(img.rgb, img.width * img.height, fb->bpp); + if (!fbbuf) + return -ENOMEM; + + cpp = fb->bpp / 8; + + if (img.width < fb->xres || img.height < fb->yres) { + line = fb->fb; + for (y = 0; y < img.height; y++) { + memcpy(line, fbbuf, img.width * cpp); + line += fb->pitch; + fbbuf += img.width * cpp; + } + } else { + memcpy(fb->fb, fbbuf, img.width * img.height * cpp); + } + + return 0; +} + static int fb_create(struct drm_resource *res, int fd, const char *cmd) { int ret; @@ -1066,6 +1134,9 @@ static int fb_create(struct drm_resource *res, int fd, const char *cmd) if (ret) return ret; + if (strlen(kd.file) > 0) + fb_splash(fb, kd.file); + if (kd.fill) { int x, y; uint32_t *pix; @@ -1105,6 +1176,7 @@ static void usage(const char *prgname) " pitch [optional]: line pitch in bytes\n" " 3d [optional]: create a framebuffer suitable for 3D rendering\n" " fill [optional]: fill framebuffer with debug pattern\n" + " file [optional]: load file into framebuffer\n" " vsync [optional]: vsync mode:\n" " 0 - (default) don't wait for vsync when panning, but honor WAITFORVSYNC\n" " 1 - never wait for vsync\n" diff --git a/src/kmsfb.h b/src/kmsfb.h index b9d1c8a..21bdd21 100644 --- a/src/kmsfb.h +++ b/src/kmsfb.h @@ -22,6 +22,7 @@ static inline void *zalloc(size_t size) #define MAX_KMS_FBS 8 #define MAX_KMS_WINDOWS 8 +#define MAX_FILENAME 256 struct kms_window { uint32_t crtc_id; @@ -87,10 +88,19 @@ struct kms_data { int triplebuf; int fill; + char file[MAX_FILENAME]; int vsync; int alpha; }; +struct splash { + int width, height; + unsigned char *rgb; + unsigned char *alpha; +}; + +int png_load(char *name, struct splash *splash, unsigned char **alpha); + int bgi_init(struct kms_fb *fb); #endif /* __KMSFB_H */ diff --git a/src/png.c b/src/png.c new file mode 100644 index 0000000..0a89c15 --- /dev/null +++ b/src/png.c @@ -0,0 +1,154 @@ +/* + * Code based on: + * + * fbv -- simple image viewer for the linux framebuffer + * Copyright (C) 2000, 2001, 2003 Mateusz Golicz + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <errno.h> +#include <png.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include "kmsfb.h" + +#define PNG_BYTES_TO_CHECK 4 + +int png_load(char *name, struct splash *image, unsigned char **alpha) +{ + int bit_depth, color_type, interlace_type; + int number_passes,pass, trans = 0; + png_uint_32 width, height; + unsigned char *fbptr; + png_structp png_ptr; + png_infop info_ptr; + unsigned int i; + unsigned char *rp; + png_bytep rptr[2]; + FILE *fh; + int ret; + char id[4]; + + fh = fopen(name,"rb"); + if (fh == -1) + return -ENOENT; + + fread(&id, 1, 4, fh); + + if (!(id[1] == 'P' && id[2]=='N' && id[3]=='G')) + return -EINVAL; + + rewind(fh); + + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (png_ptr == NULL) + return -EINVAL; + + info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == NULL) { + png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); + fclose(fh); + + return -EINVAL; + } + + rp=0; + if (setjmp(png_ptr->jmpbuf)) { + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + + if(rp) + free(rp); + + fclose(fh); + + return -EINVAL; + } + + png_init_io(png_ptr,fh); + + png_read_info(png_ptr, info_ptr); + png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,&interlace_type, NULL, NULL); + + image->rgb = (unsigned char*) malloc(width * height * 3); + image->width = width; + image->height = height; + + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_expand(png_ptr); + + if (bit_depth < 8) + png_set_packing(png_ptr); + + if (color_type == PNG_COLOR_TYPE_GRAY || color_type== PNG_COLOR_TYPE_GRAY_ALPHA) + png_set_gray_to_rgb(png_ptr); + + if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { + trans = 1; + png_set_tRNS_to_alpha(png_ptr); + } + + if (bit_depth == 16) + png_set_strip_16(png_ptr); + + number_passes = png_set_interlace_handling(png_ptr); + png_read_update_info(png_ptr,info_ptr); + + if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA || color_type == PNG_COLOR_TYPE_RGB_ALPHA || trans) { + unsigned char * alpha_buffer = (unsigned char*) malloc(width * height); + unsigned char * aptr; + + rp = (unsigned char*) malloc(width * 4); + rptr[0] = (png_bytep) rp; + + *alpha = alpha_buffer; + + for (pass = 0; pass < number_passes; pass++) { + fbptr = image->rgb; + aptr = alpha_buffer; + + for(i=0; i<height; i++) { + unsigned int n; + unsigned char *trp = rp; + + png_read_rows(png_ptr, rptr, NULL, 1); + + for(n = 0; n < width; n++, fbptr += 3, trp += 4) { + memcpy(fbptr, trp, 3); + *(aptr++) = trp[3]; + } + } + } + free(rp); + } else { + for (pass = 0; pass < number_passes; pass++) { + fbptr = image->rgb; + for(i=0; i<height; i++, fbptr += width*3) { + rptr[0] = (png_bytep) fbptr; + png_read_rows(png_ptr, rptr, NULL, 1); + } + } + } + + png_read_end(png_ptr, info_ptr); + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + fclose(fh); + + return 0; +} |