Merge branch 'for-next/png'
Conflicts: common/filetype.c include/filetype.h
This commit is contained in:
commit
cd323c0224
|
@ -18,7 +18,6 @@ available in @a Barebox:
|
||||||
@li @subpage _name
|
@li @subpage _name
|
||||||
@li @subpage addpart_command
|
@li @subpage addpart_command
|
||||||
@li @subpage alternate
|
@li @subpage alternate
|
||||||
@li @subpage bmp_command
|
|
||||||
@li @subpage bootm_command
|
@li @subpage bootm_command
|
||||||
@li @subpage bootu
|
@li @subpage bootu
|
||||||
@li @subpage bootz
|
@li @subpage bootz
|
||||||
|
@ -95,6 +94,7 @@ available in @a Barebox:
|
||||||
@li @subpage sh
|
@li @subpage sh
|
||||||
@li @subpage sleep
|
@li @subpage sleep
|
||||||
@li @subpage source
|
@li @subpage source
|
||||||
|
@li @subpage splash_command
|
||||||
@li @subpage test
|
@li @subpage test
|
||||||
@li @subpage timeout
|
@li @subpage timeout
|
||||||
@li @subpage true
|
@li @subpage true
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
if [ -f /env/logo.bmp ]; then
|
if [ -f /env/logo.bmp ]; then
|
||||||
bmp /env/logo.bmp
|
splash /env/logo.bmp
|
||||||
fb0.enable=1
|
fb0.enable=1
|
||||||
elif [ -f /env/logo.bmp.lzo ]; then
|
elif [ -f /env/logo.bmp.lzo ]; then
|
||||||
uncompress /env/logo.bmp.lzo /logo.bmp
|
uncompress /env/logo.bmp.lzo /logo.bmp
|
||||||
bmp /logo.bmp
|
splash /logo.bmp
|
||||||
fb0.enable=1
|
fb0.enable=1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
@ -17,11 +17,11 @@ if [ -e /dev/nand0 ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -f /env/logo.bmp ]; then
|
if [ -f /env/logo.bmp ]; then
|
||||||
bmp /env/logo.bmp
|
splash /env/logo.bmp
|
||||||
fb0.enable=1
|
fb0.enable=1
|
||||||
elif [ -f /env/logo.bmp.lzo ]; then
|
elif [ -f /env/logo.bmp.lzo ]; then
|
||||||
uncompress /env/logo.bmp.lzo /logo.bmp
|
uncompress /env/logo.bmp.lzo /logo.bmp
|
||||||
bmp /logo.bmp
|
splash /logo.bmp
|
||||||
fb0.enable=1
|
fb0.enable=1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
if [ -f /env/logo.bmp ]; then
|
if [ -f /env/logo.bmp ]; then
|
||||||
bmp /env/logo.bmp
|
splash /env/logo.bmp
|
||||||
fb0.enable=1
|
fb0.enable=1
|
||||||
gpio_set_value 1 1
|
gpio_set_value 1 1
|
||||||
elif [ -f /env/logo.bmp.lzo ]; then
|
elif [ -f /env/logo.bmp.lzo ]; then
|
||||||
uncompress /env/logo.bmp.lzo /logo.bmp
|
uncompress /env/logo.bmp.lzo /logo.bmp
|
||||||
bmp /logo.bmp
|
splash /logo.bmp
|
||||||
fb0.enable=1
|
fb0.enable=1
|
||||||
gpio_set_value 1 1
|
gpio_set_value 1 1
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
if [ -f /env/logo.bmp ]; then
|
if [ -f /env/logo.bmp ]; then
|
||||||
bmp /env/logo.bmp
|
splash /env/logo.bmp
|
||||||
fb0.enable=1
|
fb0.enable=1
|
||||||
gpio_set_value 1 1
|
gpio_set_value 1 1
|
||||||
elif [ -f /env/logo.bmp.lzo ]; then
|
elif [ -f /env/logo.bmp.lzo ]; then
|
||||||
uncompress /env/logo.bmp.lzo /logo.bmp
|
uncompress /env/logo.bmp.lzo /logo.bmp
|
||||||
bmp /logo.bmp
|
splash /logo.bmp
|
||||||
fb0.enable=1
|
fb0.enable=1
|
||||||
gpio_set_value 1 1
|
gpio_set_value 1 1
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
|
||||||
if [ -e /dev/fb0 -a -e /env/splash.bmp ]; then
|
if [ -e /dev/fb0 -a -e /env/splash.bmp ]; then
|
||||||
bmp /env/splash.bmp
|
splash /env/splash.bmp
|
||||||
fb0.enable=1
|
fb0.enable=1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ led keyboard 0
|
||||||
sdcard_override
|
sdcard_override
|
||||||
|
|
||||||
fb0.enable=1
|
fb0.enable=1
|
||||||
bmp /dev/mtd0.barebox-logo
|
splash /dev/mtd0.barebox-logo
|
||||||
|
|
||||||
mtd_env_override
|
mtd_env_override
|
||||||
if [ $? = 0 ]; then
|
if [ $? = 0 ]; then
|
||||||
|
|
|
@ -30,7 +30,7 @@ CONFIG_CMD_RESET=y
|
||||||
CONFIG_CMD_GO=y
|
CONFIG_CMD_GO=y
|
||||||
CONFIG_CMD_TIMEOUT=y
|
CONFIG_CMD_TIMEOUT=y
|
||||||
CONFIG_CMD_PARTITION=y
|
CONFIG_CMD_PARTITION=y
|
||||||
CONFIG_CMD_BMP=y
|
CONFIG_CMD_SPLASH=y
|
||||||
CONFIG_CMD_GPIO=y
|
CONFIG_CMD_GPIO=y
|
||||||
CONFIG_NET=y
|
CONFIG_NET=y
|
||||||
CONFIG_NET_DHCP=y
|
CONFIG_NET_DHCP=y
|
||||||
|
|
|
@ -45,7 +45,7 @@ CONFIG_CMD_TIMEOUT=y
|
||||||
CONFIG_CMD_PARTITION=y
|
CONFIG_CMD_PARTITION=y
|
||||||
CONFIG_CMD_MAGICVAR=y
|
CONFIG_CMD_MAGICVAR=y
|
||||||
CONFIG_CMD_MAGICVAR_HELP=y
|
CONFIG_CMD_MAGICVAR_HELP=y
|
||||||
CONFIG_CMD_BMP=y
|
CONFIG_CMD_SPLASH=y
|
||||||
CONFIG_CMD_GPIO=y
|
CONFIG_CMD_GPIO=y
|
||||||
CONFIG_CMD_UNCOMPRESS=y
|
CONFIG_CMD_UNCOMPRESS=y
|
||||||
CONFIG_NET=y
|
CONFIG_NET=y
|
||||||
|
|
|
@ -43,7 +43,7 @@ CONFIG_CMD_TIMEOUT=y
|
||||||
CONFIG_CMD_PARTITION=y
|
CONFIG_CMD_PARTITION=y
|
||||||
CONFIG_CMD_MAGICVAR=y
|
CONFIG_CMD_MAGICVAR=y
|
||||||
CONFIG_CMD_MAGICVAR_HELP=y
|
CONFIG_CMD_MAGICVAR_HELP=y
|
||||||
CONFIG_CMD_BMP=y
|
CONFIG_CMD_SPLASH=y
|
||||||
CONFIG_CMD_GPIO=y
|
CONFIG_CMD_GPIO=y
|
||||||
CONFIG_CMD_UNCOMPRESS=y
|
CONFIG_CMD_UNCOMPRESS=y
|
||||||
CONFIG_CMD_I2C=y
|
CONFIG_CMD_I2C=y
|
||||||
|
|
|
@ -31,7 +31,7 @@ CONFIG_CMD_RESET=y
|
||||||
CONFIG_CMD_GO=y
|
CONFIG_CMD_GO=y
|
||||||
CONFIG_CMD_TIMEOUT=y
|
CONFIG_CMD_TIMEOUT=y
|
||||||
CONFIG_CMD_PARTITION=y
|
CONFIG_CMD_PARTITION=y
|
||||||
CONFIG_CMD_BMP=y
|
CONFIG_CMD_SPLASH=y
|
||||||
CONFIG_CMD_GPIO=y
|
CONFIG_CMD_GPIO=y
|
||||||
CONFIG_CMD_UNCOMPRESS=y
|
CONFIG_CMD_UNCOMPRESS=y
|
||||||
CONFIG_CMD_I2C=y
|
CONFIG_CMD_I2C=y
|
||||||
|
|
|
@ -44,7 +44,7 @@ CONFIG_CMD_TIMEOUT=y
|
||||||
CONFIG_CMD_PARTITION=y
|
CONFIG_CMD_PARTITION=y
|
||||||
CONFIG_CMD_MAGICVAR=y
|
CONFIG_CMD_MAGICVAR=y
|
||||||
CONFIG_CMD_MAGICVAR_HELP=y
|
CONFIG_CMD_MAGICVAR_HELP=y
|
||||||
CONFIG_CMD_BMP=y
|
CONFIG_CMD_SPLASH=y
|
||||||
CONFIG_CMD_GPIO=y
|
CONFIG_CMD_GPIO=y
|
||||||
CONFIG_CMD_UNCOMPRESS=y
|
CONFIG_CMD_UNCOMPRESS=y
|
||||||
CONFIG_CMD_I2C=y
|
CONFIG_CMD_I2C=y
|
||||||
|
|
|
@ -42,7 +42,7 @@ CONFIG_CMD_TIMEOUT=y
|
||||||
CONFIG_CMD_PARTITION=y
|
CONFIG_CMD_PARTITION=y
|
||||||
CONFIG_CMD_MAGICVAR=y
|
CONFIG_CMD_MAGICVAR=y
|
||||||
CONFIG_CMD_MAGICVAR_HELP=y
|
CONFIG_CMD_MAGICVAR_HELP=y
|
||||||
CONFIG_CMD_BMP=y
|
CONFIG_CMD_SPLASH=y
|
||||||
CONFIG_CMD_GPIO=y
|
CONFIG_CMD_GPIO=y
|
||||||
CONFIG_CMD_UNCOMPRESS=y
|
CONFIG_CMD_UNCOMPRESS=y
|
||||||
CONFIG_CMD_I2C=y
|
CONFIG_CMD_I2C=y
|
||||||
|
|
|
@ -33,7 +33,7 @@ CONFIG_CMD_RESET=y
|
||||||
CONFIG_CMD_GO=y
|
CONFIG_CMD_GO=y
|
||||||
CONFIG_CMD_TIMEOUT=y
|
CONFIG_CMD_TIMEOUT=y
|
||||||
CONFIG_CMD_PARTITION=y
|
CONFIG_CMD_PARTITION=y
|
||||||
CONFIG_CMD_BMP=y
|
CONFIG_CMD_SPLASH=y
|
||||||
CONFIG_CMD_GPIO=y
|
CONFIG_CMD_GPIO=y
|
||||||
CONFIG_NET=y
|
CONFIG_NET=y
|
||||||
CONFIG_NET_DHCP=y
|
CONFIG_NET_DHCP=y
|
||||||
|
|
|
@ -38,7 +38,7 @@ CONFIG_CMD_BOOTM_INITRD=y
|
||||||
CONFIG_CMD_RESET=y
|
CONFIG_CMD_RESET=y
|
||||||
CONFIG_CMD_TIMEOUT=y
|
CONFIG_CMD_TIMEOUT=y
|
||||||
CONFIG_CMD_PARTITION=y
|
CONFIG_CMD_PARTITION=y
|
||||||
CONFIG_CMD_BMP=y
|
CONFIG_CMD_SPLASH=y
|
||||||
CONFIG_CMD_GPIO=y
|
CONFIG_CMD_GPIO=y
|
||||||
CONFIG_CMD_UNCOMPRESS=y
|
CONFIG_CMD_UNCOMPRESS=y
|
||||||
CONFIG_CMD_LED=y
|
CONFIG_CMD_LED=y
|
||||||
|
|
|
@ -45,7 +45,7 @@ CONFIG_CMD_TIMEOUT=y
|
||||||
CONFIG_CMD_PARTITION=y
|
CONFIG_CMD_PARTITION=y
|
||||||
CONFIG_CMD_MAGICVAR=y
|
CONFIG_CMD_MAGICVAR=y
|
||||||
CONFIG_CMD_MAGICVAR_HELP=y
|
CONFIG_CMD_MAGICVAR_HELP=y
|
||||||
CONFIG_CMD_BMP=y
|
CONFIG_CMD_SPLASH=y
|
||||||
CONFIG_CMD_GPIO=y
|
CONFIG_CMD_GPIO=y
|
||||||
CONFIG_CMD_UNCOMPRESS=y
|
CONFIG_CMD_UNCOMPRESS=y
|
||||||
CONFIG_NET=y
|
CONFIG_NET=y
|
||||||
|
|
|
@ -43,7 +43,7 @@ CONFIG_CMD_TIMEOUT=y
|
||||||
CONFIG_CMD_PARTITION=y
|
CONFIG_CMD_PARTITION=y
|
||||||
CONFIG_CMD_MAGICVAR=y
|
CONFIG_CMD_MAGICVAR=y
|
||||||
CONFIG_CMD_MAGICVAR_HELP=y
|
CONFIG_CMD_MAGICVAR_HELP=y
|
||||||
CONFIG_CMD_BMP=y
|
CONFIG_CMD_SPLASH=y
|
||||||
CONFIG_CMD_GPIO=y
|
CONFIG_CMD_GPIO=y
|
||||||
CONFIG_CMD_UNCOMPRESS=y
|
CONFIG_CMD_UNCOMPRESS=y
|
||||||
CONFIG_NET=y
|
CONFIG_NET=y
|
||||||
|
|
|
@ -49,7 +49,7 @@ CONFIG_CMD_TIMEOUT=y
|
||||||
CONFIG_CMD_PARTITION=y
|
CONFIG_CMD_PARTITION=y
|
||||||
CONFIG_CMD_MAGICVAR=y
|
CONFIG_CMD_MAGICVAR=y
|
||||||
CONFIG_CMD_MAGICVAR_HELP=y
|
CONFIG_CMD_MAGICVAR_HELP=y
|
||||||
CONFIG_CMD_BMP=y
|
CONFIG_CMD_SPLASH=y
|
||||||
CONFIG_CMD_GPIO=y
|
CONFIG_CMD_GPIO=y
|
||||||
CONFIG_CMD_UNCOMPRESS=y
|
CONFIG_CMD_UNCOMPRESS=y
|
||||||
CONFIG_NET=y
|
CONFIG_NET=y
|
||||||
|
|
|
@ -45,7 +45,7 @@ CONFIG_CMD_TIMEOUT=y
|
||||||
CONFIG_CMD_PARTITION=y
|
CONFIG_CMD_PARTITION=y
|
||||||
CONFIG_CMD_MAGICVAR=y
|
CONFIG_CMD_MAGICVAR=y
|
||||||
CONFIG_CMD_MAGICVAR_HELP=y
|
CONFIG_CMD_MAGICVAR_HELP=y
|
||||||
CONFIG_CMD_BMP=y
|
CONFIG_CMD_SPLASH=y
|
||||||
CONFIG_CMD_GPIO=y
|
CONFIG_CMD_GPIO=y
|
||||||
CONFIG_CMD_UNCOMPRESS=y
|
CONFIG_CMD_UNCOMPRESS=y
|
||||||
CONFIG_NET=y
|
CONFIG_NET=y
|
||||||
|
|
|
@ -41,7 +41,7 @@ CONFIG_CMD_TIMEOUT=y
|
||||||
CONFIG_CMD_PARTITION=y
|
CONFIG_CMD_PARTITION=y
|
||||||
CONFIG_CMD_MAGICVAR=y
|
CONFIG_CMD_MAGICVAR=y
|
||||||
CONFIG_CMD_MAGICVAR_HELP=y
|
CONFIG_CMD_MAGICVAR_HELP=y
|
||||||
CONFIG_CMD_BMP=y
|
CONFIG_CMD_SPLASH=y
|
||||||
CONFIG_CMD_GPIO=y
|
CONFIG_CMD_GPIO=y
|
||||||
CONFIG_CMD_UNCOMPRESS=y
|
CONFIG_CMD_UNCOMPRESS=y
|
||||||
CONFIG_NET=y
|
CONFIG_NET=y
|
||||||
|
|
|
@ -545,10 +545,11 @@ config CMD_LSMOD
|
||||||
depends on MODULES
|
depends on MODULES
|
||||||
prompt "lsmod"
|
prompt "lsmod"
|
||||||
|
|
||||||
config CMD_BMP
|
config CMD_SPLASH
|
||||||
bool
|
bool
|
||||||
depends on VIDEO
|
depends on VIDEO
|
||||||
prompt "bmp"
|
select IMAGE_RENDERER
|
||||||
|
prompt "splash"
|
||||||
help
|
help
|
||||||
show bmp files on framebuffer devices
|
show bmp files on framebuffer devices
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ obj-$(CONFIG_CMD_VERSION) += version.o
|
||||||
obj-$(CONFIG_CMD_HELP) += help.o
|
obj-$(CONFIG_CMD_HELP) += help.o
|
||||||
obj-$(CONFIG_CMD_LSMOD) += lsmod.o
|
obj-$(CONFIG_CMD_LSMOD) += lsmod.o
|
||||||
obj-$(CONFIG_CMD_INSMOD) += insmod.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_DFU) += dfu.o
|
||||||
obj-$(CONFIG_USB_GADGET_SERIAL) += usbserial.o
|
obj-$(CONFIG_USB_GADGET_SERIAL) += usbserial.o
|
||||||
obj-$(CONFIG_CMD_GPIO) += gpio.o
|
obj-$(CONFIG_CMD_GPIO) += gpio.o
|
||||||
|
|
221
commands/bmp.c
221
commands/bmp.c
|
@ -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
|
|
|
@ -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
|
|
@ -44,6 +44,8 @@ static const char *filetype_str[] = {
|
||||||
[filetype_mips_barebox] = "MIPS barebox image",
|
[filetype_mips_barebox] = "MIPS barebox image",
|
||||||
[filetype_fat] = "FAT filesytem",
|
[filetype_fat] = "FAT filesytem",
|
||||||
[filetype_mbr] = "MBR sector",
|
[filetype_mbr] = "MBR sector",
|
||||||
|
[filetype_bmp] = "BMP image",
|
||||||
|
[filetype_png] = "PNG image",
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *file_type_to_string(enum filetype f)
|
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)
|
enum filetype file_detect_type(void *_buf)
|
||||||
{
|
{
|
||||||
u32 *buf = _buf;
|
u32 *buf = _buf;
|
||||||
|
u64 *buf64 = _buf;
|
||||||
u8 *buf8 = _buf;
|
u8 *buf8 = _buf;
|
||||||
enum filetype type;
|
enum filetype type;
|
||||||
|
|
||||||
|
@ -129,6 +132,10 @@ enum filetype file_detect_type(void *_buf)
|
||||||
type = is_fat_or_mbr(buf8, NULL);
|
type = is_fat_or_mbr(buf8, NULL);
|
||||||
if (type != filetype_unknown)
|
if (type != filetype_unknown)
|
||||||
return type;
|
return type;
|
||||||
|
if (strncmp(buf8, "BM", 2) == 0)
|
||||||
|
return filetype_bmp;
|
||||||
|
if (buf64[0] == le64_to_cpu(0x0a1a0a0d474e5089ull))
|
||||||
|
return filetype_png;
|
||||||
|
|
||||||
return filetype_unknown;
|
return filetype_unknown;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,8 @@ enum filetype {
|
||||||
filetype_mips_barebox,
|
filetype_mips_barebox,
|
||||||
filetype_fat,
|
filetype_fat,
|
||||||
filetype_mbr,
|
filetype_mbr,
|
||||||
|
filetype_bmp,
|
||||||
|
filetype_png,
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *file_type_to_string(enum filetype f);
|
const char *file_type_to_string(enum filetype f);
|
||||||
|
|
|
@ -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__ */
|
|
@ -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__ */
|
36
lib/Kconfig
36
lib/Kconfig
|
@ -38,4 +38,40 @@ config BITREV
|
||||||
config QSORT
|
config QSORT
|
||||||
bool
|
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
|
endmenu
|
||||||
|
|
|
@ -34,3 +34,8 @@ obj-$(CONFIG_UNCOMPRESS) += uncompress.o
|
||||||
obj-$(CONFIG_BCH) += bch.o
|
obj-$(CONFIG_BCH) += bch.o
|
||||||
obj-$(CONFIG_BITREV) += bitrev.o
|
obj-$(CONFIG_BITREV) += bitrev.o
|
||||||
obj-$(CONFIG_QSORT) += qsort.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
|
||||||
|
|
|
@ -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);
|
|
@ -74,4 +74,15 @@ struct bmp_image {
|
||||||
#define BMP_BI_RLE8 1
|
#define BMP_BI_RLE8 1
|
||||||
#define BMP_BI_RLE4 2
|
#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_ */
|
#endif /* _BMP_H_ */
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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
|
|
@ -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);
|
|
@ -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__ */
|
|
@ -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();
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
Loading…
Reference in New Issue