9
0
Fork 0

Merge branch 'for-next/png'

Conflicts:
	common/filetype.c
	include/filetype.h
This commit is contained in:
Sascha Hauer 2012-10-03 21:12:19 +02:00
commit cd323c0224
42 changed files with 9442 additions and 248 deletions

View File

@ -18,7 +18,6 @@ available in @a Barebox:
@li @subpage _name
@li @subpage addpart_command
@li @subpage alternate
@li @subpage bmp_command
@li @subpage bootm_command
@li @subpage bootu
@li @subpage bootz
@ -95,6 +94,7 @@ available in @a Barebox:
@li @subpage sh
@li @subpage sleep
@li @subpage source
@li @subpage splash_command
@li @subpage test
@li @subpage timeout
@li @subpage true

View File

@ -1,11 +1,11 @@
#!/bin/sh
if [ -f /env/logo.bmp ]; then
bmp /env/logo.bmp
splash /env/logo.bmp
fb0.enable=1
elif [ -f /env/logo.bmp.lzo ]; then
uncompress /env/logo.bmp.lzo /logo.bmp
bmp /logo.bmp
splash /logo.bmp
fb0.enable=1
fi

View File

@ -17,11 +17,11 @@ if [ -e /dev/nand0 ]; then
fi
if [ -f /env/logo.bmp ]; then
bmp /env/logo.bmp
splash /env/logo.bmp
fb0.enable=1
elif [ -f /env/logo.bmp.lzo ]; then
uncompress /env/logo.bmp.lzo /logo.bmp
bmp /logo.bmp
splash /logo.bmp
fb0.enable=1
fi

View File

@ -1,12 +1,12 @@
#!/bin/sh
if [ -f /env/logo.bmp ]; then
bmp /env/logo.bmp
splash /env/logo.bmp
fb0.enable=1
gpio_set_value 1 1
elif [ -f /env/logo.bmp.lzo ]; then
uncompress /env/logo.bmp.lzo /logo.bmp
bmp /logo.bmp
splash /logo.bmp
fb0.enable=1
gpio_set_value 1 1
fi

View File

@ -1,12 +1,12 @@
#!/bin/sh
if [ -f /env/logo.bmp ]; then
bmp /env/logo.bmp
splash /env/logo.bmp
fb0.enable=1
gpio_set_value 1 1
elif [ -f /env/logo.bmp.lzo ]; then
uncompress /env/logo.bmp.lzo /logo.bmp
bmp /logo.bmp
splash /logo.bmp
fb0.enable=1
gpio_set_value 1 1
fi

View File

@ -1,6 +1,6 @@
if [ -e /dev/fb0 -a -e /env/splash.bmp ]; then
bmp /env/splash.bmp
splash /env/splash.bmp
fb0.enable=1
fi

View File

@ -12,7 +12,7 @@ led keyboard 0
sdcard_override
fb0.enable=1
bmp /dev/mtd0.barebox-logo
splash /dev/mtd0.barebox-logo
mtd_env_override
if [ $? = 0 ]; then

View File

@ -30,7 +30,7 @@ CONFIG_CMD_RESET=y
CONFIG_CMD_GO=y
CONFIG_CMD_TIMEOUT=y
CONFIG_CMD_PARTITION=y
CONFIG_CMD_BMP=y
CONFIG_CMD_SPLASH=y
CONFIG_CMD_GPIO=y
CONFIG_NET=y
CONFIG_NET_DHCP=y

View File

@ -45,7 +45,7 @@ CONFIG_CMD_TIMEOUT=y
CONFIG_CMD_PARTITION=y
CONFIG_CMD_MAGICVAR=y
CONFIG_CMD_MAGICVAR_HELP=y
CONFIG_CMD_BMP=y
CONFIG_CMD_SPLASH=y
CONFIG_CMD_GPIO=y
CONFIG_CMD_UNCOMPRESS=y
CONFIG_NET=y

View File

@ -43,7 +43,7 @@ CONFIG_CMD_TIMEOUT=y
CONFIG_CMD_PARTITION=y
CONFIG_CMD_MAGICVAR=y
CONFIG_CMD_MAGICVAR_HELP=y
CONFIG_CMD_BMP=y
CONFIG_CMD_SPLASH=y
CONFIG_CMD_GPIO=y
CONFIG_CMD_UNCOMPRESS=y
CONFIG_CMD_I2C=y

View File

@ -31,7 +31,7 @@ CONFIG_CMD_RESET=y
CONFIG_CMD_GO=y
CONFIG_CMD_TIMEOUT=y
CONFIG_CMD_PARTITION=y
CONFIG_CMD_BMP=y
CONFIG_CMD_SPLASH=y
CONFIG_CMD_GPIO=y
CONFIG_CMD_UNCOMPRESS=y
CONFIG_CMD_I2C=y

View File

@ -44,7 +44,7 @@ CONFIG_CMD_TIMEOUT=y
CONFIG_CMD_PARTITION=y
CONFIG_CMD_MAGICVAR=y
CONFIG_CMD_MAGICVAR_HELP=y
CONFIG_CMD_BMP=y
CONFIG_CMD_SPLASH=y
CONFIG_CMD_GPIO=y
CONFIG_CMD_UNCOMPRESS=y
CONFIG_CMD_I2C=y

View File

@ -42,7 +42,7 @@ CONFIG_CMD_TIMEOUT=y
CONFIG_CMD_PARTITION=y
CONFIG_CMD_MAGICVAR=y
CONFIG_CMD_MAGICVAR_HELP=y
CONFIG_CMD_BMP=y
CONFIG_CMD_SPLASH=y
CONFIG_CMD_GPIO=y
CONFIG_CMD_UNCOMPRESS=y
CONFIG_CMD_I2C=y

View File

@ -33,7 +33,7 @@ CONFIG_CMD_RESET=y
CONFIG_CMD_GO=y
CONFIG_CMD_TIMEOUT=y
CONFIG_CMD_PARTITION=y
CONFIG_CMD_BMP=y
CONFIG_CMD_SPLASH=y
CONFIG_CMD_GPIO=y
CONFIG_NET=y
CONFIG_NET_DHCP=y

View File

@ -38,7 +38,7 @@ CONFIG_CMD_BOOTM_INITRD=y
CONFIG_CMD_RESET=y
CONFIG_CMD_TIMEOUT=y
CONFIG_CMD_PARTITION=y
CONFIG_CMD_BMP=y
CONFIG_CMD_SPLASH=y
CONFIG_CMD_GPIO=y
CONFIG_CMD_UNCOMPRESS=y
CONFIG_CMD_LED=y

View File

@ -45,7 +45,7 @@ CONFIG_CMD_TIMEOUT=y
CONFIG_CMD_PARTITION=y
CONFIG_CMD_MAGICVAR=y
CONFIG_CMD_MAGICVAR_HELP=y
CONFIG_CMD_BMP=y
CONFIG_CMD_SPLASH=y
CONFIG_CMD_GPIO=y
CONFIG_CMD_UNCOMPRESS=y
CONFIG_NET=y

View File

@ -43,7 +43,7 @@ CONFIG_CMD_TIMEOUT=y
CONFIG_CMD_PARTITION=y
CONFIG_CMD_MAGICVAR=y
CONFIG_CMD_MAGICVAR_HELP=y
CONFIG_CMD_BMP=y
CONFIG_CMD_SPLASH=y
CONFIG_CMD_GPIO=y
CONFIG_CMD_UNCOMPRESS=y
CONFIG_NET=y

View File

@ -49,7 +49,7 @@ CONFIG_CMD_TIMEOUT=y
CONFIG_CMD_PARTITION=y
CONFIG_CMD_MAGICVAR=y
CONFIG_CMD_MAGICVAR_HELP=y
CONFIG_CMD_BMP=y
CONFIG_CMD_SPLASH=y
CONFIG_CMD_GPIO=y
CONFIG_CMD_UNCOMPRESS=y
CONFIG_NET=y

View File

@ -45,7 +45,7 @@ CONFIG_CMD_TIMEOUT=y
CONFIG_CMD_PARTITION=y
CONFIG_CMD_MAGICVAR=y
CONFIG_CMD_MAGICVAR_HELP=y
CONFIG_CMD_BMP=y
CONFIG_CMD_SPLASH=y
CONFIG_CMD_GPIO=y
CONFIG_CMD_UNCOMPRESS=y
CONFIG_NET=y

View File

@ -41,7 +41,7 @@ CONFIG_CMD_TIMEOUT=y
CONFIG_CMD_PARTITION=y
CONFIG_CMD_MAGICVAR=y
CONFIG_CMD_MAGICVAR_HELP=y
CONFIG_CMD_BMP=y
CONFIG_CMD_SPLASH=y
CONFIG_CMD_GPIO=y
CONFIG_CMD_UNCOMPRESS=y
CONFIG_NET=y

View File

@ -545,10 +545,11 @@ config CMD_LSMOD
depends on MODULES
prompt "lsmod"
config CMD_BMP
config CMD_SPLASH
bool
depends on VIDEO
prompt "bmp"
select IMAGE_RENDERER
prompt "splash"
help
show bmp files on framebuffer devices

View File

@ -49,7 +49,7 @@ obj-$(CONFIG_CMD_VERSION) += version.o
obj-$(CONFIG_CMD_HELP) += help.o
obj-$(CONFIG_CMD_LSMOD) += lsmod.o
obj-$(CONFIG_CMD_INSMOD) += insmod.o
obj-$(CONFIG_CMD_BMP) += bmp.o
obj-$(CONFIG_CMD_SPLASH) += splash.o
obj-$(CONFIG_USB_GADGET_DFU) += dfu.o
obj-$(CONFIG_USB_GADGET_SERIAL) += usbserial.o
obj-$(CONFIG_CMD_GPIO) += gpio.o

View File

@ -1,221 +0,0 @@
#include <common.h>
#include <command.h>
#include <fs.h>
#include <linux/stat.h>
#include <errno.h>
#include <malloc.h>
#include <getopt.h>
#include <fcntl.h>
#include <fb.h>
#include <bmp_layout.h>
#include <asm/byteorder.h>
static inline void set_pixel(struct fb_info *info, void *adr, int r, int g, int b)
{
u32 px;
px = (r >> (8 - info->red.length)) << info->red.offset |
(g >> (8 - info->green.length)) << info->green.offset |
(b >> (8 - info->blue.length)) << info->blue.offset;
switch (info->bits_per_pixel) {
case 8:
break;
case 16:
*(u16 *)adr = px;
break;
case 32:
*(u32 *)adr = px;
break;
}
}
static int do_bmp(int argc, char *argv[])
{
int ret, opt, fd;
char *fbdev = "/dev/fb0";
void *fb, *offscreenbuf = NULL;
struct fb_info info;
struct bmp_image *bmp;
char *bmpfile;
int bmpsize;
char *image;
int sw, sh, width, height, startx = -1, starty = -1;
int bits_per_pixel, fbsize;
int xres, yres;
int offscreen = 0;
void *adr, *buf;
while((opt = getopt(argc, argv, "f:x:y:o")) > 0) {
switch(opt) {
case 'f':
fbdev = optarg;
break;
case 'x':
startx = simple_strtoul(optarg, NULL, 0);
break;
case 'y':
starty = simple_strtoul(optarg, NULL, 0);
case 'o':
offscreen = 1;
}
}
if (optind == argc) {
printf("no filename given\n");
return 1;
}
bmpfile = argv[optind];
fd = open(fbdev, O_RDWR);
if (fd < 0) {
perror("open");
return 1;
}
fb = memmap(fd, PROT_READ | PROT_WRITE);
if (fb == (void *)-1) {
perror("memmap");
goto failed_memmap;
}
ret = ioctl(fd, FBIOGET_SCREENINFO, &info);
if (ret) {
perror("ioctl");
goto failed_memmap;
}
xres = info.xres;
yres = info.yres;
bmp = read_file(bmpfile, &bmpsize);
if (!bmp) {
printf("unable to read %s\n", bmpfile);
goto failed_memmap;
}
if (bmp->header.signature[0] != 'B' ||
bmp->header.signature[1] != 'M') {
printf("No valid bmp file\n");
}
sw = le32_to_cpu(bmp->header.width);
sh = le32_to_cpu(bmp->header.height);
if (startx < 0) {
startx = (xres - sw) / 2;
if (startx < 0)
startx = 0;
}
if (starty < 0) {
starty = (yres - sh) / 2;
if (starty < 0)
starty = 0;
}
width = min(sw, xres - startx);
height = min(sh, yres - starty);
bits_per_pixel = le16_to_cpu(bmp->header.bit_count);
fbsize = xres * yres * (info.bits_per_pixel >> 3);
if (offscreen) {
/* Don't fail if malloc fails, just continue rendering directly
* on the framebuffer
*/
offscreenbuf = malloc(fbsize);
if (offscreenbuf)
memcpy(offscreenbuf, fb, fbsize);
}
buf = offscreenbuf ? offscreenbuf : fb;
if (bits_per_pixel == 8) {
int x, y;
struct bmp_color_table_entry *color_table = bmp->color_table;
for (y = 0; y < height; y++) {
image = (char *)bmp +
le32_to_cpu(bmp->header.data_offset);
image += (sh - y - 1) * sw * (bits_per_pixel >> 3);
adr = buf + ((y + starty) * xres + startx) *
(info.bits_per_pixel >> 3);
for (x = 0; x < width; x++) {
int pixel;
pixel = *image;
set_pixel(&info, adr, color_table[pixel].red,
color_table[pixel].green,
color_table[pixel].blue);
adr += info.bits_per_pixel >> 3;
image += bits_per_pixel >> 3;
}
}
} else if (bits_per_pixel == 24) {
int x, y;
for (y = 0; y < height; y++) {
image = (char *)bmp +
le32_to_cpu(bmp->header.data_offset);
image += (sh - y - 1) * sw * (bits_per_pixel >> 3);
adr = buf + ((y + starty) * xres + startx) *
(info.bits_per_pixel >> 3);
for (x = 0; x < width; x++) {
char *pixel;
pixel = image;
set_pixel(&info, adr, pixel[2], pixel[1],
pixel[0]);
adr += info.bits_per_pixel >> 3;
image += bits_per_pixel >> 3;
}
}
} else
printf("bmp: illegal bits per pixel value: %d\n", bits_per_pixel);
if (offscreenbuf) {
memcpy(fb, offscreenbuf, fbsize);
free(offscreenbuf);
}
free(bmp);
close(fd);
return 0;
failed_memmap:
close(fd);
return 1;
}
BAREBOX_CMD_HELP_START(bmp)
BAREBOX_CMD_HELP_USAGE("bmp [OPTIONS] FILE\n")
BAREBOX_CMD_HELP_SHORT("Show the bitmap FILE on the framebuffer.\n")
BAREBOX_CMD_HELP_OPT ("-f <fb>", "framebuffer device (/dev/fb0)\n")
BAREBOX_CMD_HELP_OPT ("-x <xofs>", "x offset (default center)\n")
BAREBOX_CMD_HELP_OPT ("-y <yofs>", "y offset (default center)\n")
BAREBOX_CMD_HELP_OPT ("-o", "render offscreen\n")
BAREBOX_CMD_HELP_END
/**
* @page bmp_command
This command displays a graphics in the bitmap (.bmp) format on the
framebuffer. Currently the bmp command supports images with 8 and 24 bit
color depth.
\todo What does the -o (offscreen) option do?
*/
BAREBOX_CMD_START(bmp)
.cmd = do_bmp,
.usage = "show a bmp image",
BAREBOX_CMD_HELP(cmd_bmp_help)
BAREBOX_CMD_END

133
commands/splash.c Normal file
View File

@ -0,0 +1,133 @@
#include <common.h>
#include <command.h>
#include <fs.h>
#include <linux/stat.h>
#include <errno.h>
#include <malloc.h>
#include <getopt.h>
#include <fcntl.h>
#include <fb.h>
#include <image_renderer.h>
#include <graphic_utils.h>
static int do_splash(int argc, char *argv[])
{
int ret, opt, fd;
char *fbdev = "/dev/fb0";
void *fb;
struct fb_info info;
char *image_file;
int startx = -1, starty = -1;
int xres, yres;
int offscreen = 0;
u32 bg_color = 0x00000000;
bool do_bg = false;
void *offscreenbuf = NULL;
while((opt = getopt(argc, argv, "f:x:y:ob:")) > 0) {
switch(opt) {
case 'f':
fbdev = optarg;
break;
case 'b':
bg_color = simple_strtoul(optarg, NULL, 0);
do_bg = true;
break;
case 'x':
startx = simple_strtoul(optarg, NULL, 0);
break;
case 'y':
starty = simple_strtoul(optarg, NULL, 0);
case 'o':
offscreen = 1;
}
}
if (optind == argc) {
printf("no filename given\n");
return 1;
}
image_file = argv[optind];
fd = open(fbdev, O_RDWR);
if (fd < 0) {
perror("open");
return 1;
}
fb = memmap(fd, PROT_READ | PROT_WRITE);
if (fb == (void *)-1) {
perror("memmap");
goto failed_memmap;
}
ret = ioctl(fd, FBIOGET_SCREENINFO, &info);
if (ret) {
perror("ioctl");
goto failed_memmap;
}
xres = info.xres;
yres = info.yres;
if (offscreen) {
int fbsize;
/* Don't fail if malloc fails, just continue rendering directly
* on the framebuffer
*/
fbsize = xres * yres * (info.bits_per_pixel >> 3);
offscreenbuf = malloc(fbsize);
if (offscreenbuf) {
if (do_bg)
memset_pixel(&info, offscreenbuf, bg_color, xres * yres);
else
memcpy(offscreenbuf, fb, fbsize);
}
} else if (do_bg) {
memset_pixel(&info, fb, bg_color, xres * yres);
}
if (image_renderer_file(&info, image_file, fb, startx, starty,
offscreenbuf) < 0)
ret = 1;
if (offscreenbuf)
free(offscreenbuf);
close(fd);
return ret;
failed_memmap:
close(fd);
return 1;
}
BAREBOX_CMD_HELP_START(splash)
BAREBOX_CMD_HELP_USAGE("splash [OPTIONS] FILE\n")
BAREBOX_CMD_HELP_SHORT("Show the bitmap FILE on the framebuffer.\n")
BAREBOX_CMD_HELP_OPT ("-f <fb>", "framebuffer device (/dev/fb0)\n")
BAREBOX_CMD_HELP_OPT ("-x <xofs>", "x offset (default center)\n")
BAREBOX_CMD_HELP_OPT ("-y <yofs>", "y offset (default center)\n")
BAREBOX_CMD_HELP_OPT ("-b <color>", "background color in 0xttrrggbb\n")
BAREBOX_CMD_HELP_OPT ("-o", "render offscreen\n")
BAREBOX_CMD_HELP_END
/**
* @page bmp_command
This command displays a graphics in the bitmap (.bmp) format on the
framebuffer. Currently the bmp command supports images with 8 and 24 bit
color depth.
\todo What does the -o (offscreen) option do?
*/
BAREBOX_CMD_START(splash)
.cmd = do_splash,
.usage = "show a bmp image",
BAREBOX_CMD_HELP(cmd_splash_help)
BAREBOX_CMD_END

View File

@ -44,6 +44,8 @@ static const char *filetype_str[] = {
[filetype_mips_barebox] = "MIPS barebox image",
[filetype_fat] = "FAT filesytem",
[filetype_mbr] = "MBR sector",
[filetype_bmp] = "BMP image",
[filetype_png] = "PNG image",
};
const char *file_type_to_string(enum filetype f)
@ -97,6 +99,7 @@ enum filetype is_fat_or_mbr(const unsigned char *sector, unsigned long *bootsec)
enum filetype file_detect_type(void *_buf)
{
u32 *buf = _buf;
u64 *buf64 = _buf;
u8 *buf8 = _buf;
enum filetype type;
@ -129,6 +132,10 @@ enum filetype file_detect_type(void *_buf)
type = is_fat_or_mbr(buf8, NULL);
if (type != filetype_unknown)
return type;
if (strncmp(buf8, "BM", 2) == 0)
return filetype_bmp;
if (buf64[0] == le64_to_cpu(0x0a1a0a0d474e5089ull))
return filetype_png;
return filetype_unknown;
}

View File

@ -20,6 +20,8 @@ enum filetype {
filetype_mips_barebox,
filetype_fat,
filetype_mbr,
filetype_bmp,
filetype_png,
};
const char *file_type_to_string(enum filetype f);

17
include/graphic_utils.h Normal file
View File

@ -0,0 +1,17 @@
/*
* Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
*
* GPL v2
*/
#ifndef __GRAPHIC_UTILS_H__
#define __GRAPHIC_UTILS_H__
void rgba_blend(struct fb_info *info, void *image, void* dest, int height,
int width, int startx, int starty, bool is_rgba);
void set_pixel(struct fb_info *info, void *adr, u32 px);
void set_rgb_pixel(struct fb_info *info, void *adr, u8 r, u8 g, u8 b);
void set_rgba_pixel(struct fb_info *info, void *adr, u8 r, u8 g, u8 b, u8 a);
void memset_pixel(struct fb_info *info, void* buf, u32 color, size_t size);
#endif /* __GRAPHIC_UTILS_H__ */

85
include/image_renderer.h Normal file
View File

@ -0,0 +1,85 @@
/*
* Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
*
* GPL v2
*/
#ifndef __IMAGE_RENDER_H__
#define __IMAGE_RENDER_H__
#include <filetype.h>
#include <linux/list.h>
#include <errno.h>
#include <linux/err.h>
#include <fb.h>
struct image {
void *data;
struct image_renderer *ir;
int height;
int width;
int bits_per_pixel;
};
struct image_renderer {
enum filetype type;
struct image *(*open)(char *data, int size);
void (*close)(struct image *img);
int (*renderer)(struct fb_info *info, struct image *img, void* fb,
int startx, int starty, void* offscreenbuf);
/*
* do not free the data read from the file
* needed by bmp support
*/
int keep_file_data;
struct list_head list;
};
#ifdef CONFIG_IMAGE_RENDERER
int image_renderer_register(struct image_renderer *ir);
void image_render_unregister(struct image_renderer *ir);
int image_renderer_image(struct fb_info *info, struct image *img, void* fb,
int startx, int starty, void* offscreenbuf);
struct image *image_renderer_open(const char* file);
void image_renderer_close(struct image *img);
#else
static inline int image_renderer_register(struct image_renderer *ir)
{
return -EINVAL;
}
static inline void image_renderer_unregister(struct image_renderer *ir) {}
static inline struct image *image_renderer_open(const char* file)
{
return ERR_PTR(-EINVAL);
}
static inline void image_renderer_close(struct image *img) {}
int image_renderer_image(struct fb_info *info, struct image *img, void* fb,
int startx, int starty, void* offscreenbuf);
#endif
static inline int image_renderer_file(struct fb_info *info, const char* file, void* fb,
int startx, int starty, void* offscreenbuf)
{
struct image* img = image_renderer_open(file);
int ret;
if (IS_ERR(img))
return PTR_ERR(img);
ret = image_renderer_image(info, img, fb, startx, starty,
offscreenbuf);
image_renderer_close(img);
return ret;
}
#endif /* __IMAGE_RENDERER_H__ */

View File

@ -38,4 +38,40 @@ config BITREV
config QSORT
bool
config IMAGE_RENDERER
bool
depends on VIDEO
select FILETYPE
if IMAGE_RENDERER
config BMP
bool "bmp"
config PNG
bool "png"
select ZLIB
if PNG
choice
prompt "PNG Lib"
config LODEPNG
bool "lodePNG"
help
This PNG library supports most PNG formats.
config PICOPNG
bool "picoPNG"
help
This PNG library only supports RGBA PNG8 but is much smaller
in binary size than lodepng.
endchoice
endif
endif
endmenu

View File

@ -34,3 +34,8 @@ obj-$(CONFIG_UNCOMPRESS) += uncompress.o
obj-$(CONFIG_BCH) += bch.o
obj-$(CONFIG_BITREV) += bitrev.o
obj-$(CONFIG_QSORT) += qsort.o
obj-$(CONFIG_BMP) += bmp.o
obj-$(CONFIG_IMAGE_RENDERER) += image_renderer.o graphic_utils.o
obj-$(CONFIG_PNG) += png.o
obj-$(CONFIG_LODEPNG) += png_lode.o lodepng.o
obj-$(CONFIG_PICOPNG) += png_pico.o picopng.o

134
lib/bmp.c Normal file
View File

@ -0,0 +1,134 @@
#include <common.h>
#include <errno.h>
#include <malloc.h>
#include <fb.h>
#include "bmp_layout.h"
#include <asm/byteorder.h>
#include <graphic_utils.h>
#include <init.h>
#include <image_renderer.h>
struct image *bmp_open(char *inbuf, int insize)
{
struct image *img = calloc(1, sizeof(struct image));
struct bmp_image *bmp = (struct bmp_image*)inbuf;
if (!img) {
free(bmp);
return ERR_PTR(-ENOMEM);
}
img->data = inbuf;
img->height = le32_to_cpu(bmp->header.height);;
img->width = le32_to_cpu(bmp->header.width);;
img->bits_per_pixel = le16_to_cpu(bmp->header.bit_count);
pr_debug("bmp: %d x %d x %d data@0x%p\n", img->width, img->height,
img->bit_per_pixel, img->data);
return img;
}
void bmp_close(struct image *img)
{
free(img->data);
}
static int bmp_renderer(struct fb_info *info, struct image *img, void* fb,
int startx, int starty, void* offscreenbuf)
{
struct bmp_image *bmp = img->data;
int width, height;
int bits_per_pixel, fbsize;
void *adr, *buf;
char *image;
int xres, yres;
xres = info->xres;
yres = info->yres;
if (startx < 0) {
startx = (xres - img->width) / 2;
if (startx < 0)
startx = 0;
}
if (starty < 0) {
starty = (yres - img->height) / 2;
if (starty < 0)
starty = 0;
}
width = min(img->width, xres - startx);
height = min(img->height, yres - starty);
bits_per_pixel = img->bits_per_pixel;
fbsize = xres * yres * (info->bits_per_pixel >> 3);
buf = offscreenbuf ? offscreenbuf : fb;
if (bits_per_pixel == 8) {
int x, y;
struct bmp_color_table_entry *color_table = bmp->color_table;
for (y = 0; y < height; y++) {
image = (char *)bmp +
le32_to_cpu(bmp->header.data_offset);
image += (img->height - y - 1) * img->width * (bits_per_pixel >> 3);
adr = buf + ((y + starty) * xres + startx) *
(info->bits_per_pixel >> 3);
for (x = 0; x < width; x++) {
int pixel;
pixel = *image;
set_rgb_pixel(info, adr, color_table[pixel].red,
color_table[pixel].green,
color_table[pixel].blue);
adr += info->bits_per_pixel >> 3;
image += bits_per_pixel >> 3;
}
}
} else if (bits_per_pixel == 24) {
int x, y;
for (y = 0; y < height; y++) {
image = (char *)bmp +
le32_to_cpu(bmp->header.data_offset);
image += (img->height - y - 1) * img->width * (bits_per_pixel >> 3);
adr = buf + ((y + starty) * xres + startx) *
(info->bits_per_pixel >> 3);
for (x = 0; x < width; x++) {
char *pixel;
pixel = image;
set_rgb_pixel(info, adr, pixel[2], pixel[1],
pixel[0]);
adr += info->bits_per_pixel >> 3;
image += bits_per_pixel >> 3;
}
}
} else
printf("bmp: illegal bits per pixel value: %d\n", bits_per_pixel);
if (offscreenbuf)
memcpy(fb, offscreenbuf, fbsize);
return img->height;
}
static struct image_renderer bmp = {
.type = filetype_bmp,
.open = bmp_open,
.close = bmp_close,
.renderer = bmp_renderer,
};
static int bmp_init(void)
{
return image_renderer_register(&bmp);
}
fs_initcall(bmp_init);

View File

@ -74,4 +74,15 @@ struct bmp_image {
#define BMP_BI_RLE8 1
#define BMP_BI_RLE4 2
#ifdef CONFIG_BMP
int bmp_render_file(struct fb_info *info, const char* bmpfile, void* fb,
int startx, int starty, int xres, int yres, void* offscreenbuf);
#else
static inline int bmp_render_file(struct fb_info *info, const char* bmpfile, void* fb,
int startx, int starty, int xres, int yres, void* offscreenbuf)
{
return -ENOSYS;
}
#endif
#endif /* _BMP_H_ */

191
lib/graphic_utils.c Normal file
View File

@ -0,0 +1,191 @@
#include <common.h>
#include <fb.h>
#include <graphic_utils.h>
static u32 get_pixel(struct fb_info *info, u32 color)
{
u32 px;
u8 t = (color >> 24) & 0xff;
u8 r = (color >> 16) & 0xff;
u8 g = (color >> 8 ) & 0xff;
u8 b = (color >> 0 ) & 0xff;
if (info->grayscale) {
px = (r | g | b) ? 0xffffffff : 0x0;
return px;
}
px = (t >> (8 - info->transp.length)) << info->transp.offset |
(r >> (8 - info->red.length)) << info->red.offset |
(g >> (8 - info->green.length)) << info->green.offset |
(b >> (8 - info->blue.length)) << info->blue.offset;
return px;
}
static void memsetw(void *s, u16 c, size_t n)
{
size_t i;
u16* tmp = s;
for (i = 0; i < n; i++)
*tmp++ = c;
}
static void memsetl(void *s, u32 c, size_t n)
{
size_t i;
u32* tmp = s;
for (i = 0; i < n; i++)
*tmp++ = c;
}
void memset_pixel(struct fb_info *info, void* buf, u32 color, size_t size)
{
u32 px;
u8 *screen = buf;
px = get_pixel(info, color);
switch (info->bits_per_pixel) {
case 8:
memset(screen, (uint8_t)px, size);
break;
case 16:
memsetw(screen, (uint16_t)px, size);
break;
case 32:
case 24:
memsetl(screen, px, size);
break;
}
}
static void get_rgb_pixel(struct fb_info *info, void *adr, u8 *r ,u8 *g, u8 *b)
{
u32 px;
u32 rmask, gmask, bmask;
switch (info->bits_per_pixel) {
case 16:
px = *(u16 *)adr;
break;
case 32:
px = *(u32 *)adr;
break;
case 8:
default:
return;
}
rmask = (0xff >> (8 - info->blue.length)) << info->blue.offset |
(0xff >> (8 - info->green.length)) << info->green.offset;
gmask = (0xff >> (8 - info->red.length)) << info->red.offset |
(0xff >> (8 - info->blue.length)) << info->blue.offset;
bmask = (0xff >> (8 - info->red.length)) << info->red.offset |
(0xff >> (8 - info->green.length)) << info->green.offset;
*r = ((px & ~rmask) >> info->red.offset) << (8 - info->red.length);
*g = ((px & ~gmask) >> info->green.offset) << (8 - info->green.length);
*b = ((px & ~bmask) >> info->blue.offset) << (8 - info->blue.length);
}
void set_pixel(struct fb_info *info, void *adr, u32 px)
{
switch (info->bits_per_pixel) {
case 8:
break;
case 16:
*(u16 *)adr = px;
break;
case 32:
*(u32 *)adr = px;
break;
}
}
void set_rgb_pixel(struct fb_info *info, void *adr, u8 r, u8 g, u8 b)
{
u32 px;
px = (r >> (8 - info->red.length)) << info->red.offset |
(g >> (8 - info->green.length)) << info->green.offset |
(b >> (8 - info->blue.length)) << info->blue.offset;
set_pixel(info, adr, px);
}
static u8 alpha_mux(int s, int d, int a)
{
return (d * a + s * (255 - a)) >> 8;
}
void set_rgba_pixel(struct fb_info *info, void *adr, u8 r, u8 g, u8 b, u8 a)
{
u32 px = 0x0;
if (!a)
return;
if (a != 0xff) {
if (info->transp.length) {
px |= (a >> (8 - info->transp.length)) << info->transp.offset;
} else {
u8 sr = 0;
u8 sg = 0;
u8 sb = 0;
get_rgb_pixel(info, adr, &sr, &sg, &sb);
r = alpha_mux(sr, r, a);
g = alpha_mux(sg, g, a);
b = alpha_mux(sb, b, a);
set_rgb_pixel(info, adr, r, g, b);
return;
}
}
px |= (r >> (8 - info->red.length)) << info->red.offset |
(g >> (8 - info->green.length)) << info->green.offset |
(b >> (8 - info->blue.length)) << info->blue.offset;
set_pixel(info, adr, px);
}
void rgba_blend(struct fb_info *info, void *image, void* buf, int height,
int width, int startx, int starty, bool is_rgba)
{
unsigned char *adr;
int x, y;
int xres;
int img_byte_per_pixel = 3;
if (is_rgba)
img_byte_per_pixel++;
xres = info->xres;
for (y = 0; y < height; y++) {
adr = buf + ((y + starty) * xres + startx) *
(info->bits_per_pixel >> 3);
for (x = 0; x < width; x++) {
char *pixel;
pixel = image;
if (is_rgba)
set_rgba_pixel(info, adr, pixel[0], pixel[1],
pixel[2], pixel[3]);
else
set_rgb_pixel(info, adr, pixel[0], pixel[1],
pixel[2]);
adr += info->bits_per_pixel >> 3;
image += img_byte_per_pixel;
}
}
}

96
lib/image_renderer.c Normal file
View File

@ -0,0 +1,96 @@
/*
* Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
*
* GPL v2
*/
#include <common.h>
#include <fb.h>
#include <image_renderer.h>
#include <errno.h>
#include <fs.h>
#include <malloc.h>
static LIST_HEAD(image_renderers);
static struct image_renderer *get_renderer(void* buf)
{
struct image_renderer *ir;
enum filetype type = file_detect_type(buf);
list_for_each_entry(ir, &image_renderers, list) {
if (ir->type == type)
return ir;
}
return NULL;
}
struct image *image_renderer_open(const char* file)
{
void *data;
int size;
struct image_renderer *ir;
struct image *img;
int ret;
data = read_file(file, &size);
if (!data) {
printf("unable to read %s\n", file);
return ERR_PTR(-ENOMEM);
}
ir = get_renderer(data);
if (!ir) {
ret = -ENOENT;
goto out;
}
img = ir->open(data, size);
if (IS_ERR(img)) {
ret = PTR_ERR(img);
goto out;
}
img->ir = ir;
if (!ir->keep_file_data)
free(data);
return img;
out:
free(data);
return ERR_PTR(ret);
}
void image_renderer_close(struct image *img)
{
if (!img)
return;
img->ir->close(img);
free(img);
}
int image_renderer_image(struct fb_info *info, struct image *img, void* fb,
int startx, int starty, void* offscreenbuf)
{
return img->ir->renderer(info, img, fb, startx, starty, offscreenbuf);
}
int image_renderer_register(struct image_renderer *ir)
{
if (!ir || !ir->type || !ir->renderer || !ir->open || !ir->close)
return -EIO;
list_add_tail(&ir->list, &image_renderers);
return 0;
}
void image_renderer_unregister(struct image_renderer *ir)
{
if (!ir)
return;
list_del(&ir->list);
}

5928
lib/lodepng.c Normal file

File diff suppressed because it is too large Load Diff

1640
lib/lodepng.h Normal file

File diff suppressed because it is too large Load Diff

810
lib/picopng.c Normal file
View File

@ -0,0 +1,810 @@
// picoPNG version 20080503 (cleaned up and ported to c by kaitek)
// Copyright (c) 2005-2008 Lode Vandevenne
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
// 3. This notice may not be removed or altered from any source distribution.
#include <common.h>
#include <malloc.h>
#include "picopng.h"
/*************************************************************************************************/
typedef struct png_alloc_node {
struct png_alloc_node *prev, *next;
void *addr;
size_t size;
} png_alloc_node_t;
png_alloc_node_t *png_alloc_head = NULL;
png_alloc_node_t *png_alloc_tail = NULL;
png_alloc_node_t *png_alloc_find_node(void *addr)
{
png_alloc_node_t *node;
for (node = png_alloc_head; node; node = node->next)
if (node->addr == addr)
break;
return node;
}
void png_alloc_add_node(void *addr, size_t size)
{
png_alloc_node_t *node;
if (png_alloc_find_node(addr))
return;
node = malloc(sizeof (png_alloc_node_t));
node->addr = addr;
node->size = size;
node->prev = png_alloc_tail;
node->next = NULL;
png_alloc_tail = node;
if (node->prev)
node->prev->next = node;
if (!png_alloc_head)
png_alloc_head = node;
}
void png_alloc_remove_node(png_alloc_node_t *node)
{
if (node->prev)
node->prev->next = node->next;
if (node->next)
node->next->prev = node->prev;
if (node == png_alloc_head)
png_alloc_head = node->next;
if (node == png_alloc_tail)
png_alloc_tail = node->prev;
node->prev = node->next = node->addr = NULL;
free(node);
}
void *png_alloc_malloc(size_t size)
{
void *addr = malloc(size);
png_alloc_add_node(addr, size);
return addr;
}
void *png_alloc_realloc(void *addr, size_t size)
{
void *new_addr;
if (!addr)
return png_alloc_malloc(size);
new_addr = realloc(addr, size);
if (new_addr != addr) {
png_alloc_node_t *old_node;
old_node = png_alloc_find_node(addr);
png_alloc_remove_node(old_node);
png_alloc_add_node(new_addr, size);
}
return new_addr;
}
void png_alloc_free(void *addr)
{
png_alloc_node_t *node = png_alloc_find_node(addr);
if (!node)
return;
png_alloc_remove_node(node);
free(addr);
}
void png_alloc_free_all()
{
while (png_alloc_tail) {
void *addr = png_alloc_tail->addr;
png_alloc_remove_node(png_alloc_tail);
free(addr);
}
}
/*************************************************************************************************/
__maybe_unused void vector32_cleanup(vector32_t *p)
{
p->size = p->allocsize = 0;
if (p->data)
png_alloc_free(p->data);
p->data = NULL;
}
uint32_t vector32_resize(vector32_t *p, size_t size)
{ // returns 1 if success, 0 if failure ==> nothing done
if (size * sizeof (uint32_t) > p->allocsize) {
size_t newsize = size * sizeof (uint32_t) * 2;
void *data = png_alloc_realloc(p->data, newsize);
if (data) {
p->allocsize = newsize;
p->data = (uint32_t *) data;
p->size = size;
} else
return 0;
} else
p->size = size;
return 1;
}
uint32_t vector32_resizev(vector32_t *p, size_t size, uint32_t value)
{ // resize and give all new elements the value
size_t oldsize = p->size, i;
if (!vector32_resize(p, size))
return 0;
for (i = oldsize; i < size; i++)
p->data[i] = value;
return 1;
}
void vector32_init(vector32_t *p)
{
p->data = NULL;
p->size = p->allocsize = 0;
}
vector32_t *vector32_new(size_t size, uint32_t value)
{
vector32_t *p = png_alloc_malloc(sizeof (vector32_t));
vector32_init(p);
if (size && !vector32_resizev(p, size, value))
return NULL;
return p;
}
/*************************************************************************************************/
__maybe_unused void vector8_cleanup(vector8_t *p)
{
p->size = p->allocsize = 0;
if (p->data)
png_alloc_free(p->data);
p->data = NULL;
}
uint32_t vector8_resize(vector8_t *p, size_t size)
{ // returns 1 if success, 0 if failure ==> nothing done
// xxx: the use of sizeof uint32_t here seems like a bug (this descends from the lodepng vector
// compatibility functions which do the same). without this there is corruption in certain cases,
// so this was probably done to cover up allocation bug(s) in the original picopng code!
if (size * sizeof (uint32_t) > p->allocsize) {
size_t newsize = size * sizeof (uint32_t) * 2;
void *data = png_alloc_realloc(p->data, newsize);
if (data) {
p->allocsize = newsize;
p->data = (uint8_t *) data;
p->size = size;
} else
return 0; // error: not enough memory
} else
p->size = size;
return 1;
}
uint32_t vector8_resizev(vector8_t *p, size_t size, uint8_t value)
{ // resize and give all new elements the value
size_t oldsize = p->size, i;
if (!vector8_resize(p, size))
return 0;
for (i = oldsize; i < size; i++)
p->data[i] = value;
return 1;
}
void vector8_init(vector8_t *p)
{
p->data = NULL;
p->size = p->allocsize = 0;
}
vector8_t *vector8_new(size_t size, uint8_t value)
{
vector8_t *p = png_alloc_malloc(sizeof (vector8_t));
vector8_init(p);
if (size && !vector8_resizev(p, size, value))
return NULL;
return p;
}
vector8_t *vector8_copy(vector8_t *p)
{
vector8_t *q = vector8_new(p->size, 0);
uint32_t n;
for (n = 0; n < q->size; n++)
q->data[n] = p->data[n];
return q;
}
/*************************************************************************************************/
int Zlib_decompress(vector8_t *out, const vector8_t *in) // returns error value
{
return picopng_zlib_decompress(out->data, out->size, in->data, in->size);
}
/*************************************************************************************************/
#define PNG_SIGNATURE 0x0a1a0a0d474e5089ull
#define CHUNK_IHDR 0x52444849
#define CHUNK_IDAT 0x54414449
#define CHUNK_IEND 0x444e4549
#define CHUNK_PLTE 0x45544c50
#define CHUNK_tRNS 0x534e5274
int PNG_error;
uint32_t PNG_readBitFromReversedStream(size_t *bitp, const uint8_t *bits)
{
uint32_t result = (bits[*bitp >> 3] >> (7 - (*bitp & 0x7))) & 1;
(*bitp)++;
return result;
}
uint32_t PNG_readBitsFromReversedStream(size_t *bitp, const uint8_t *bits, uint32_t nbits)
{
uint32_t i, result = 0;
for (i = nbits - 1; i < nbits; i--)
result += ((PNG_readBitFromReversedStream(bitp, bits)) << i);
return result;
}
void PNG_setBitOfReversedStream(size_t *bitp, uint8_t *bits, uint32_t bit)
{
bits[*bitp >> 3] |= (bit << (7 - (*bitp & 0x7)));
(*bitp)++;
}
uint32_t PNG_read32bitInt(const uint8_t *buffer)
{
return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
}
int PNG_checkColorValidity(uint32_t colorType, uint32_t bd) // return type is a LodePNG error code
{
if ((colorType == 2 || colorType == 4 || colorType == 6)) {
if (!(bd == 8 || bd == 16))
return 37;
else
return 0;
} else if (colorType == 0) {
if (!(bd == 1 || bd == 2 || bd == 4 || bd == 8 || bd == 16))
return 37;
else
return 0;
} else if (colorType == 3) {
if (!(bd == 1 || bd == 2 || bd == 4 || bd == 8))
return 37;
else
return 0;
} else
return 31; // nonexistent color type
}
uint32_t PNG_getBpp(const PNG_info_t *info)
{
uint32_t bitDepth, colorType;
bitDepth = info->bitDepth;
colorType = info->colorType;
if (colorType == 2)
return (3 * bitDepth);
else if (colorType >= 4)
return (colorType - 2) * bitDepth;
else
return bitDepth;
}
void PNG_readPngHeader(PNG_info_t *info, const uint8_t *in, size_t inlength)
{ // read the information from the header and store it in the Info
if (inlength < 29) {
PNG_error = 27; // error: the data length is smaller than the length of the header
return;
}
if (*(uint64_t *) in != PNG_SIGNATURE) {
PNG_error = 28; // no PNG signature
return;
}
if (*(uint32_t *) &in[12] != CHUNK_IHDR) {
PNG_error = 29; // error: it doesn't start with a IHDR chunk!
return;
}
info->width = PNG_read32bitInt(&in[16]);
info->height = PNG_read32bitInt(&in[20]);
info->bitDepth = in[24];
info->colorType = in[25];
info->compressionMethod = in[26];
if (in[26] != 0) {
PNG_error = 32; // error: only compression method 0 is allowed in the specification
return;
}
info->filterMethod = in[27];
if (in[27] != 0) {
PNG_error = 33; // error: only filter method 0 is allowed in the specification
return;
}
info->interlaceMethod = in[28];
if (in[28] > 1) {
PNG_error = 34; // error: only interlace methods 0 and 1 exist in the specification
return;
}
PNG_error = PNG_checkColorValidity(info->colorType, info->bitDepth);
}
int PNG_paethPredictor(int a, int b, int c) // Paeth predicter, used by PNG filter type 4
{
int p, pa, pb, pc;
p = a + b - c;
pa = p > a ? (p - a) : (a - p);
pb = p > b ? (p - b) : (b - p);
pc = p > c ? (p - c) : (c - p);
return (pa <= pb && pa <= pc) ? a : (pb <= pc ? b : c);
}
void PNG_unFilterScanline(uint8_t *recon, const uint8_t *scanline, const uint8_t *precon,
size_t bytewidth, uint32_t filterType, size_t length)
{
size_t i;
switch (filterType) {
case 0:
for (i = 0; i < length; i++)
recon[i] = scanline[i];
break;
case 1:
for (i = 0; i < bytewidth; i++)
recon[i] = scanline[i];
for (i = bytewidth; i < length; i++)
recon[i] = scanline[i] + recon[i - bytewidth];
break;
case 2:
if (precon)
for (i = 0; i < length; i++)
recon[i] = scanline[i] + precon[i];
else
for (i = 0; i < length; i++)
recon[i] = scanline[i];
break;
case 3:
if (precon) {
for (i = 0; i < bytewidth; i++)
recon[i] = scanline[i] + precon[i] / 2;
for (i = bytewidth; i < length; i++)
recon[i] = scanline[i] + ((recon[i - bytewidth] + precon[i]) / 2);
} else {
for (i = 0; i < bytewidth; i++)
recon[i] = scanline[i];
for (i = bytewidth; i < length; i++)
recon[i] = scanline[i] + recon[i - bytewidth] / 2;
}
break;
case 4:
if (precon) {
for (i = 0; i < bytewidth; i++)
recon[i] = (uint8_t) (scanline[i] + PNG_paethPredictor(0, precon[i], 0));
for (i = bytewidth; i < length; i++)
recon[i] = (uint8_t) (scanline[i] + PNG_paethPredictor(recon[i - bytewidth],
precon[i], precon[i - bytewidth]));
} else {
for (i = 0; i < bytewidth; i++)
recon[i] = scanline[i];
for (i = bytewidth; i < length; i++)
recon[i] = (uint8_t) (scanline[i] + PNG_paethPredictor(recon[i - bytewidth], 0, 0));
}
break;
default:
PNG_error = 36; // error: nonexistent filter type given
return;
}
}
void PNG_adam7Pass(uint8_t *out, uint8_t *linen, uint8_t *lineo, const uint8_t *in, uint32_t w,
size_t passleft, size_t passtop, size_t spacex, size_t spacey, size_t passw, size_t passh,
uint32_t bpp)
{
size_t bytewidth, linelength;
uint32_t y;
uint8_t *temp;
// filter and reposition the pixels into the output when the image is Adam7 interlaced. This
// function can only do it after the full image is already decoded. The out buffer must have
// the correct allocated memory size already.
if (passw == 0)
return;
bytewidth = (bpp + 7) / 8;
linelength = 1 + ((bpp * passw + 7) / 8);
for (y = 0; y < passh; y++) {
size_t i, b;
uint8_t filterType = in[y * linelength], *prevline = (y == 0) ? 0 : lineo;
PNG_unFilterScanline(linen, &in[y * linelength + 1], prevline, bytewidth, filterType,
(w * bpp + 7) / 8);
if (PNG_error)
return;
if (bpp >= 8)
for (i = 0; i < passw; i++)
for (b = 0; b < bytewidth; b++) // b = current byte of this pixel
out[bytewidth * w * (passtop + spacey * y) + bytewidth *
(passleft + spacex * i) + b] = linen[bytewidth * i + b];
else
for (i = 0; i < passw; i++) {
size_t obp, bp;
obp = bpp * w * (passtop + spacey * y) + bpp * (passleft + spacex * i);
bp = i * bpp;
for (b = 0; b < bpp; b++)
PNG_setBitOfReversedStream(&obp, out, PNG_readBitFromReversedStream(&bp, linen));
}
temp = linen;
linen = lineo;
lineo = temp; // swap the two buffer pointers "line old" and "line new"
}
}
int PNG_convert(const PNG_info_t *info, vector8_t *out, const uint8_t *in)
{ // converts from any color type to 32-bit. return value = LodePNG error code
size_t i, c;
uint32_t bitDepth, colorType;
size_t numpixels, bp;
uint8_t *out_data;
bitDepth = info->bitDepth;
colorType = info->colorType;
numpixels = info->width * info->height;
bp = 0;
vector8_resize(out, numpixels * 4);
out_data = out->size ? out->data : 0;
if (bitDepth == 8 && colorType == 0) // greyscale
for (i = 0; i < numpixels; i++) {
out_data[4 * i + 0] = out_data[4 * i + 1] = out_data[4 * i + 2] = in[i];
out_data[4 * i + 3] = (info->key_defined && (in[i] == info->key_r)) ? 0 : 255;
}
else if (bitDepth == 8 && colorType == 2) // RGB color
for (i = 0; i < numpixels; i++) {
for (c = 0; c < 3; c++)
out_data[4 * i + c] = in[3 * i + c];
out_data[4 * i + 3] = (info->key_defined && (in[3 * i + 0] == info->key_r) &&
(in[3 * i + 1] == info->key_g) && (in[3 * i + 2] == info->key_b)) ? 0 : 255;
}
else if (bitDepth == 8 && colorType == 3) // indexed color (palette)
for (i = 0; i < numpixels; i++) {
if (4U * in[i] >= info->palette->size)
return 46;
for (c = 0; c < 4; c++) // get rgb colors from the palette
out_data[4 * i + c] = info->palette->data[4 * in[i] + c];
}
else if (bitDepth == 8 && colorType == 4) // greyscale with alpha
for (i = 0; i < numpixels; i++) {
out_data[4 * i + 0] = out_data[4 * i + 1] = out_data[4 * i + 2] = in[2 * i + 0];
out_data[4 * i + 3] = in[2 * i + 1];
}
else if (bitDepth == 8 && colorType == 6)
for (i = 0; i < numpixels; i++)
for (c = 0; c < 4; c++)
out_data[4 * i + c] = in[4 * i + c]; // RGB with alpha
else if (bitDepth == 16 && colorType == 0) // greyscale
for (i = 0; i < numpixels; i++) {
out_data[4 * i + 0] = out_data[4 * i + 1] = out_data[4 * i + 2] = in[2 * i];
out_data[4 * i + 3] = (info->key_defined && (256U * in[i] + in[i + 1] == info->key_r))
? 0 : 255;
}
else if (bitDepth == 16 && colorType == 2) // RGB color
for (i = 0; i < numpixels; i++) {
for (c = 0; c < 3; c++)
out_data[4 * i + c] = in[6 * i + 2 * c];
out_data[4 * i + 3] = (info->key_defined &&
(256U * in[6 * i + 0] + in[6 * i + 1] == info->key_r) &&
(256U * in[6 * i + 2] + in[6 * i + 3] == info->key_g) &&
(256U * in[6 * i + 4] + in[6 * i + 5] == info->key_b)) ? 0 : 255;
}
else if (bitDepth == 16 && colorType == 4) // greyscale with alpha
for (i = 0; i < numpixels; i++) {
out_data[4 * i + 0] = out_data[4 * i + 1] = out_data[4 * i + 2] = in[4 * i]; // msb
out_data[4 * i + 3] = in[4 * i + 2];
}
else if (bitDepth == 16 && colorType == 6)
for (i = 0; i < numpixels; i++)
for (c = 0; c < 4; c++)
out_data[4 * i + c] = in[8 * i + 2 * c]; // RGB with alpha
else if (bitDepth < 8 && colorType == 0) // greyscale
for (i = 0; i < numpixels; i++) {
uint32_t value = (PNG_readBitsFromReversedStream(&bp, in, bitDepth) * 255) /
((1 << bitDepth) - 1); // scale value from 0 to 255
out_data[4 * i + 0] = out_data[4 * i + 1] = out_data[4 * i + 2] = (uint8_t) value;
out_data[4 * i + 3] = (info->key_defined && value &&
(((1U << bitDepth) - 1U) == info->key_r) && ((1U << bitDepth) - 1U)) ? 0 : 255;
}
else if (bitDepth < 8 && colorType == 3) // palette
for (i = 0; i < numpixels; i++) {
uint32_t value = PNG_readBitsFromReversedStream(&bp, in, bitDepth);
if (4 * value >= info->palette->size)
return 47;
for (c = 0; c < 4; c++) // get rgb colors from the palette
out_data[4 * i + c] = info->palette->data[4 * value + c];
}
return 0;
}
PNG_info_t *PNG_info_new(void)
{
PNG_info_t *info = png_alloc_malloc(sizeof (PNG_info_t));
uint32_t i;
for (i = 0; i < sizeof (PNG_info_t); i++)
((uint8_t *) info)[i] = 0;
info->palette = vector8_new(0, 0);
info->image = vector8_new(0, 0);
return info;
}
PNG_info_t *PNG_decode(const uint8_t *in, uint32_t size)
{
PNG_info_t *info;
size_t pos;
vector8_t *idat;
bool IEND, known_type;
uint32_t bpp;
vector8_t *scanlines; // now the out buffer will be filled
size_t bytewidth, outlength;
uint8_t *out_data;
PNG_error = 0;
if (size == 0 || in == 0) {
PNG_error = 48; // the given data is empty
return NULL;
}
info = PNG_info_new();
PNG_readPngHeader(info, in, size);
if (PNG_error)
return NULL;
pos = 33; // first byte of the first chunk after the header
idat = NULL; // the data from idat chunks
IEND = false;
known_type = true;
info->key_defined = false;
// loop through the chunks, ignoring unknown chunks and stopping at IEND chunk. IDAT data is
// put at the start of the in buffer
while (!IEND) {
size_t i, j;
size_t chunkLength;
uint32_t chunkType;
if (pos + 8 >= size) {
PNG_error = 30; // error: size of the in buffer too small to contain next chunk
return NULL;
}
chunkLength = PNG_read32bitInt(&in[pos]);
pos += 4;
if (chunkLength > 0x7fffffff) {
PNG_error = 63;
return NULL;
}
if (pos + chunkLength >= size) {
PNG_error = 35; // error: size of the in buffer too small to contain next chunk
return NULL;
}
chunkType = *(uint32_t *) &in[pos];
if (chunkType == CHUNK_IDAT) { // IDAT: compressed image data chunk
size_t offset = 0;
if (idat) {
offset = idat->size;
vector8_resize(idat, offset + chunkLength);
} else
idat = vector8_new(chunkLength, 0);
for (i = 0; i < chunkLength; i++)
idat->data[offset + i] = in[pos + 4 + i];
pos += (4 + chunkLength);
} else if (chunkType == CHUNK_IEND) { // IEND
pos += 4;
IEND = true;
} else if (chunkType == CHUNK_PLTE) { // PLTE: palette chunk
pos += 4; // go after the 4 letters
vector8_resize(info->palette, 4 * (chunkLength / 3));
if (info->palette->size > (4 * 256)) {
PNG_error = 38; // error: palette too big
return NULL;
}
for (i = 0; i < info->palette->size; i += 4) {
for (j = 0; j < 3; j++)
info->palette->data[i + j] = in[pos++]; // RGB
info->palette->data[i + 3] = 255; // alpha
}
} else if (chunkType == CHUNK_tRNS) { // tRNS: palette transparency chunk
pos += 4; // go after the 4 letters
if (info->colorType == 3) {
if (4 * chunkLength > info->palette->size) {
PNG_error = 39; // error: more alpha values given than there are palette entries
return NULL;
}
for (i = 0; i < chunkLength; i++)
info->palette->data[4 * i + 3] = in[pos++];
} else if (info->colorType == 0) {
if (chunkLength != 2) {
PNG_error = 40; // error: this chunk must be 2 bytes for greyscale image
return NULL;
}
info->key_defined = true;
info->key_r = info->key_g = info->key_b = 256 * in[pos] + in[pos + 1];
pos += 2;
} else if (info->colorType == 2) {
if (chunkLength != 6) {
PNG_error = 41; // error: this chunk must be 6 bytes for RGB image
return NULL;
}
info->key_defined = true;
info->key_r = 256 * in[pos] + in[pos + 1];
pos += 2;
info->key_g = 256 * in[pos] + in[pos + 1];
pos += 2;
info->key_b = 256 * in[pos] + in[pos + 1];
pos += 2;
} else {
PNG_error = 42; // error: tRNS chunk not allowed for other color models
return NULL;
}
} else { // it's not an implemented chunk type, so ignore it: skip over the data
if (!(in[pos + 0] & 32)) {
// error: unknown critical chunk (5th bit of first byte of chunk type is 0)
PNG_error = 69;
return NULL;
}
pos += (chunkLength + 4); // skip 4 letters and uninterpreted data of unimplemented chunk
known_type = false;
}
pos += 4; // step over CRC (which is ignored)
}
bpp = PNG_getBpp(info);
scanlines = vector8_new(((info->width * (info->height * bpp + 7)) / 8) + info->height, 0);
PNG_error = Zlib_decompress(scanlines, idat);
if (PNG_error)
return NULL; // stop if the zlib decompressor returned an error
bytewidth = (bpp + 7) / 8;
outlength = (info->height * info->width * bpp + 7) / 8;
vector8_resize(info->image, outlength); // time to fill the out buffer
out_data = outlength ? info->image->data : 0;
if (info->interlaceMethod == 0) { // no interlace, just filter
size_t y, obp, bp;
size_t linestart, linelength;
linestart = 0;
// length in bytes of a scanline, excluding the filtertype byte
linelength = (info->width * bpp + 7) / 8;
if (bpp >= 8) // byte per byte
for (y = 0; y < info->height; y++) {
uint32_t filterType = scanlines->data[linestart];
const uint8_t *prevline;
prevline = (y == 0) ? 0 : &out_data[(y - 1) * info->width * bytewidth];
PNG_unFilterScanline(&out_data[linestart - y], &scanlines->data[linestart + 1],
prevline, bytewidth, filterType, linelength);
if (PNG_error)
return NULL;
linestart += (1 + linelength); // go to start of next scanline
} else { // less than 8 bits per pixel, so fill it up bit per bit
vector8_t *templine; // only used if bpp < 8
templine = vector8_new((info->width * bpp + 7) >> 3, 0);
for (y = 0, obp = 0; y < info->height; y++) {
uint32_t filterType = scanlines->data[linestart];
const uint8_t *prevline;
prevline = (y == 0) ? 0 : &out_data[(y - 1) * info->width * bytewidth];
PNG_unFilterScanline(templine->data, &scanlines->data[linestart + 1], prevline,
bytewidth, filterType, linelength);
if (PNG_error)
return NULL;
for (bp = 0; bp < info->width * bpp;)
PNG_setBitOfReversedStream(&obp, out_data, PNG_readBitFromReversedStream(&bp,
templine->data));
linestart += (1 + linelength); // go to start of next scanline
}
}
} else { // interlaceMethod is 1 (Adam7)
int i;
vector8_t *scanlineo, *scanlinen; // "old" and "new" scanline
size_t passw[7] = {
(info->width + 7) / 8, (info->width + 3) / 8, (info->width + 3) / 4,
(info->width + 1) / 4, (info->width + 1) / 2, (info->width + 0) / 2,
(info->width + 0) / 1
};
size_t passh[7] = {
(info->height + 7) / 8, (info->height + 7) / 8, (info->height + 3) / 8,
(info->height + 3) / 4, (info->height + 1) / 4, (info->height + 1) / 2,
(info->height + 0) / 2
};
size_t passstart[7] = { 0 };
size_t pattern[28] = { 0, 4, 0, 2, 0, 1, 0, 0, 0, 4, 0, 2, 0, 1, 8, 8, 4, 4, 2, 2, 1, 8, 8,
8, 4, 4, 2, 2 }; // values for the adam7 passes
for (i = 0; i < 6; i++)
passstart[i + 1] = passstart[i] + passh[i] * ((passw[i] ? 1 : 0) + (passw[i] * bpp + 7) / 8);
scanlineo = vector8_new((info->width * bpp + 7) / 8, 0);
scanlinen = vector8_new((info->width * bpp + 7) / 8, 0);
for (i = 0; i < 7; i++)
PNG_adam7Pass(out_data, scanlinen->data, scanlineo->data, &scanlines->data[passstart[i]],
info->width, pattern[i], pattern[i + 7], pattern[i + 14], pattern[i + 21],
passw[i], passh[i], bpp);
}
if (info->colorType != 6 || info->bitDepth != 8) { // conversion needed
vector8_t *copy = vector8_copy(info->image); // xxx: is this copy necessary?
PNG_error = PNG_convert(info, info->image, copy->data);
}
return info;
}
/*************************************************************************************************/
#ifdef TEST
#include <stdio.h>
#include <sys/stat.h>
int main(int argc, char **argv)
{
char *fname = (argc > 1) ? argv[1] : "test.png";
PNG_info_t *info;
struct stat statbuf;
uint32_t insize, outsize;
FILE *infp, *outfp;
uint8_t *inbuf;
uint32_t n;
if (stat(fname, &statbuf) != 0) {
perror("stat");
return 1;
} else if (!statbuf.st_size) {
printf("file empty\n");
return 1;
}
insize = (uint32_t) statbuf.st_size;
inbuf = malloc(insize);
infp = fopen(fname, "rb");
if (!infp) {
perror("fopen");
return 1;
} else if (fread(inbuf, 1, insize, infp) != insize) {
perror("fread");
return 1;
}
fclose(infp);
printf("input file: %s (size: %d)\n", fname, insize);
info = PNG_decode(inbuf, insize);
free(inbuf);
printf("PNG_error: %d\n", PNG_error);
if (PNG_error != 0)
return 1;
printf("width: %d, height: %d\nfirst 16 bytes: ", info->width, info->height);
for (n = 0; n < 16; n++)
printf("%02x ", info->image->data[n]);
printf("\n");
outsize = info->width * info->height * 4;
printf("image size: %d\n", outsize);
if (outsize != info->image->size) {
printf("error: image size doesn't match dimensions\n");
return 1;
}
outfp = fopen("out.bin", "wb");
if (!outfp) {
perror("fopen");
return 1;
} else if (fwrite(info->image->data, 1, outsize, outfp) != outsize) {
perror("fwrite");
return 1;
}
fclose(outfp);
#ifdef ALLOC_DEBUG
png_alloc_node_t *node;
for (node = png_alloc_head, n = 1; node; node = node->next, n++)
printf("node %d (%p) addr = %p, size = %ld\n", n, node, node->addr, node->size);
#endif
png_alloc_free_all(); // also frees info and image data from PNG_decode
return 0;
}
#endif

34
lib/picopng.h Normal file
View File

@ -0,0 +1,34 @@
#ifndef _PICOPNG_H
#define _PICOPNG_H
typedef struct {
uint32_t *data;
size_t size;
size_t allocsize;
} vector32_t;
typedef struct {
uint8_t *data;
size_t size;
size_t allocsize;
} vector8_t;
typedef struct {
uint32_t width, height;
uint32_t colorType, bitDepth;
uint32_t compressionMethod, filterMethod, interlaceMethod;
uint32_t key_r, key_g, key_b;
bool key_defined; // is a transparent color key given?
vector8_t *palette;
vector8_t *image;
} PNG_info_t;
PNG_info_t *PNG_decode(const uint8_t *in, uint32_t size);
void png_alloc_free_all(void);
unsigned picopng_zlib_decompress(unsigned char* out, size_t outsize,
const unsigned char* in, size_t insize);
extern int PNG_error;
#endif

89
lib/png.c Normal file
View File

@ -0,0 +1,89 @@
#include <common.h>
#include <errno.h>
#include <malloc.h>
#include <fb.h>
#include <asm/byteorder.h>
#include <init.h>
#include <image_renderer.h>
#include <graphic_utils.h>
#include <linux/zlib.h>
#include "png.h"
z_stream png_stream;
static int initialized;
int png_uncompress_init(void)
{
if (!initialized++) {
png_stream.workspace = malloc(zlib_inflate_workspacesize());
if (!png_stream.workspace) {
initialized = 0;
return -ENOMEM;
}
png_stream.next_in = NULL;
png_stream.avail_in = 0;
zlib_inflateInit(&png_stream);
}
return 0;
}
void png_uncompress_exit(void)
{
if (!--initialized) {
zlib_inflateEnd(&png_stream);
vfree(png_stream.workspace);
}
}
static int png_renderer(struct fb_info *info, struct image *img, void* fb,
int startx, int starty, void* offscreenbuf)
{
int width, height;
void *buf;
int xres, yres;
xres = info->xres;
yres = info->yres;
if (startx < 0) {
startx = (xres - img->width) / 2;
if (startx < 0)
startx = 0;
}
if (starty < 0) {
starty = (yres - img->height) / 2;
if (starty < 0)
starty = 0;
}
width = min(img->width, xres - startx);
height = min(img->height, yres - starty);
buf = offscreenbuf ? offscreenbuf : fb;
rgba_blend(info, img->data, buf, height, width, startx, starty, true);
if (offscreenbuf) {
int fbsize;
fbsize = xres * yres * (info->bits_per_pixel >> 3);
memcpy(fb, offscreenbuf, fbsize);
}
return img->height;
}
static struct image_renderer png = {
.type = filetype_png,
.open = png_open,
.close = png_close,
.renderer = png_renderer,
};
static int png_init(void)
{
return image_renderer_register(&png);
}
fs_initcall(png_init);

21
lib/png.h Normal file
View File

@ -0,0 +1,21 @@
/*
* Copyright (C) 2012 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
*
* GPL v2
*/
#ifndef __PNG_H__
#define __PNG_H__
#include <filetype.h>
#include <linux/list.h>
#include <errno.h>
#include <linux/err.h>
int png_uncompress_init(void);
void png_uncompress_exit(void);
void png_close(struct image *img);
struct image *png_open(char *inbuf, int insize);
extern z_stream png_stream;
#endif /* __PNG_H__ */

90
lib/png_lode.c Normal file
View File

@ -0,0 +1,90 @@
#include <common.h>
#include <errno.h>
#include <malloc.h>
#include <fb.h>
#include <asm/byteorder.h>
#include <init.h>
#include <image_renderer.h>
#include <graphic_utils.h>
#include <linux/zlib.h>
#include "lodepng.h"
#include "png.h"
unsigned lodepng_custom_zlib_decompress(unsigned char** out, size_t* outsize,
const unsigned char* in, size_t insize,
const LodePNGDecompressSettings* settings)
{
int err;
png_stream.next_in = in;
png_stream.avail_in = insize;
png_stream.next_out = *out;
png_stream.avail_out = *outsize;
err = zlib_inflateReset(&png_stream);
if (err != Z_OK) {
printk("zlib_inflateReset error %d\n", err);
zlib_inflateEnd(&png_stream);
zlib_inflateInit(&png_stream);
}
err = zlib_inflate(&png_stream, Z_FINISH);
if (err != Z_STREAM_END)
goto err;
return 0;
err:
printk("Error %d while decompressing!\n", err);
printk("%p(%zd)->%p(%zd)\n", in, insize, *out, *outsize);
return -EIO;
}
struct image *png_open(char *inbuf, int insize)
{
LodePNGState state;
int ret;
unsigned error;
struct image *img = calloc(1, sizeof(struct image));
unsigned char *png;
if (!img)
return ERR_PTR(-ENOMEM);
ret = png_uncompress_init();
if (ret)
goto err;
lodepng_state_init(&state);
state.info_raw.colortype = LCT_RGBA;
state.info_raw.bitdepth = 8;
error = lodepng_decode(&png, &img->width, &img->height, &state, inbuf, insize);
if(error) {
printf("error %u: %s\n", error, lodepng_error_text(error));
ret = -EINVAL;
goto err;
}
img->bits_per_pixel = 4 << 3;
img->data = png;
pr_debug("png: %d x %d data@0x%p\n", img->width, img->height, img->data);
lodepng_state_cleanup(&state);
return img;
err:
free(png);
free(img);
return ERR_PTR(ret);
}
void png_close(struct image *img)
{
free(img->data);
png_uncompress_exit();
}

85
lib/png_pico.c Normal file
View File

@ -0,0 +1,85 @@
#include <common.h>
#include <errno.h>
#include <malloc.h>
#include <fb.h>
#include <asm/byteorder.h>
#include <init.h>
#include <image_renderer.h>
#include <graphic_utils.h>
#include <linux/zlib.h>
#include "picopng.h"
#include "png.h"
unsigned picopng_zlib_decompress(unsigned char* out, size_t outsize,
const unsigned char* in, size_t insize)
{
int err;
png_stream.next_in = in;
png_stream.avail_in = insize;
png_stream.next_out = out;
png_stream.avail_out = outsize;
err = zlib_inflateReset(&png_stream);
if (err != Z_OK) {
printk("zlib_inflateReset error %d\n", err);
zlib_inflateEnd(&png_stream);
zlib_inflateInit(&png_stream);
}
err = zlib_inflate(&png_stream, Z_FINISH);
if (err != Z_STREAM_END)
goto err;
return 0;
err:
printk("Error %d while decompressing!\n", err);
printk("%p(%zd)->%p(%zd)\n", in, insize, out, outsize);
return -EIO;
}
struct image *png_open(char *inbuf, int insize)
{
PNG_info_t *png_info;
int ret;
struct image *img = calloc(1, sizeof(struct image));
if (!img)
return ERR_PTR(-ENOMEM);
ret = png_uncompress_init();
if (ret)
goto err;
/* rgba */
png_info = PNG_decode(inbuf, insize);
if(PNG_error) {
printf("error %u:\n", PNG_error);
ret = -EINVAL;
goto err;
}
img->width = png_info->width;
img->height = png_info->height;
img->bits_per_pixel = 4 << 3;
img->data = png_info->image->data;
pr_debug("png: %d x %d data@0x%p\n", img->width, img->height, img->data);
png_alloc_free_all();
return img;
err:
png_alloc_free_all();
free(img);
return ERR_PTR(ret);
}
void png_close(struct image *img)
{
free(img->data);
png_alloc_free_all();
}