ss928_framework/ss928sdk/common/loadbmp.c
2024-12-16 13:31:45 +08:00

721 lines
21 KiB
C
Executable File

/*
Copyright (c), 2001-2022, Shenshu Tech. Co., Ltd.
*/
#include "loadbmp.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "securec.h"
#include <limits.h>
#include "sample_comm.h"
#define BITS_NUM_PER_BYTE 8
#define BYTE_PER_PIX_1555 2
#define BYTE_PER_PIX_8888 4
#define PIX_PER_BYTE_CLUT2 4
#define PIX_PER_BYTE_CLUT4 2
#define STRIDE_ALIGN 4
#define MAX_BIT_COUNT 32
#define MAX_OFF_BITS 118
#define MAX_WIDTH 16384
#define MAX_HEIGHT 8192
#ifndef align_up
#define align_up(x, a) ((((x) + ((a) - 1)) / (a)) * (a))
#endif
osd_component_info g_osd_comp_info[OSD_COLOR_FORMAT_BUTT] = {
{ 0, 4, 4, 4 }, /* RGB444 */
{ 4, 4, 4, 4 }, /* ARGB4444 */
{ 0, 5, 5, 5 }, /* RGB555 */
{ 0, 5, 6, 5 }, /* RGB565 */
{ 1, 5, 5, 5 }, /* ARGB1555 */
{ 0, 0, 0, 0 }, /* RESERVED */
{ 0, 8, 8, 8 }, /* RGB888 */
{ 8, 8, 8, 8 } /* ARGB8888 */
};
td_u16 osd_make_color_u16(td_u8 r, td_u8 g, td_u8 b, osd_component_info comp_info)
{
td_u8 r1, g1, b1;
td_u16 pixel = 0;
td_u32 tmp = 15; /* 15bit color data */
r1 = r >> (BITS_NUM_PER_BYTE - comp_info.r_len);
g1 = g >> (BITS_NUM_PER_BYTE - comp_info.g_len);
b1 = b >> (BITS_NUM_PER_BYTE - comp_info.b_len);
while (comp_info.a_len) {
pixel |= (1 << tmp);
tmp--;
comp_info.a_len--;
}
pixel |= (r1 | (g1 << comp_info.b_len) | (b1 << (comp_info.b_len + comp_info.g_len)));
return pixel;
}
td_s32 get_bmp_info(const td_char *filename, osd_bit_map_file_header *bmp_file_header, osd_bit_map_info *bmp_info)
{
FILE *file = TD_NULL;
td_u16 bf_type;
td_char *path = TD_NULL;
check_null_ptr_return(filename);
check_null_ptr_return(bmp_file_header);
check_null_ptr_return(bmp_info);
if (strlen(filename) > PATH_MAX - 1) {
printf("file name Extra long\n");
return TD_FAILURE;
}
path = realpath(filename, TD_NULL);
if (path == TD_NULL) {
return TD_FAILURE;
}
file = fopen(path, "rb");
if (file == TD_NULL) {
printf("Open file failed:%s!\n", filename);
goto read_bmp_failed;
}
(td_void)fread(&bf_type, 1, sizeof(bf_type), file);
if (bf_type != 0x4d42) { /* BM */
printf("not bitmap file\n");
fclose(file);
goto read_bmp_failed;
}
(td_void)fread(bmp_file_header, 1, sizeof(osd_bit_map_file_header), file);
(td_void)fread(bmp_info, 1, sizeof(osd_bit_map_info), file);
fclose(file);
free(path);
return TD_SUCCESS;
read_bmp_failed:
free(path);
return TD_FAILURE;
}
static td_bool is_support_bmp_file(const osd_bit_map_info *bmp_info, td_u16 bpp_threshold)
{
td_u16 bpp;
bpp = bmp_info->bmp_header.bi_bit_count / BITS_NUM_PER_BYTE;
if (bpp_threshold != 0 && bpp < bpp_threshold) {
printf("bitmap format not supported!\n");
return TD_FALSE;
}
if (bmp_info->bmp_header.bi_compression != 0) {
printf("not support compressed bitmap file!\n");
return TD_FALSE;
}
if (bmp_info->bmp_header.bi_height < 0) {
printf("bmp_info.bmp_header.bi_height < 0\n");
return TD_FALSE;
}
return TD_TRUE;
}
static td_s32 read_bmp_data(const osd_bit_map_file_header *bmp_file_header, const osd_bit_map_info *bmp_info,
FILE *file, osd_logo *video_logo)
{
td_u8 *rgb_buf = video_logo->rgb_buf;
td_u8 *orig_bmp_buf = NULL;
td_u32 bmp_data_stride;
td_u32 bmp_data_size;
td_u16 bpp, dst_bpp;
td_u16 i, j;
td_s32 ret;
bpp = bmp_info->bmp_header.bi_bit_count / BITS_NUM_PER_BYTE;
dst_bpp = (bpp > 2) ? 4 : 2; /* RGB1555: 2byte, RGB8888: 4byte */
video_logo->width = bmp_info->bmp_header.bi_width;
video_logo->height = bmp_info->bmp_header.bi_height;
if (video_logo->stride == 0) {
video_logo->stride = video_logo->width * dst_bpp;
}
bmp_data_stride = video_logo->width * bpp;
bmp_data_stride = align_up(bmp_data_stride, STRIDE_ALIGN);
bmp_data_size = video_logo->height * bmp_data_stride;
/* RGB8888 or RGB1555 */
orig_bmp_buf = (td_u8 *)malloc(bmp_data_size);
if (orig_bmp_buf == NULL) {
printf("not enough memory to malloc!\n");
return TD_FAILURE;
}
fseek(file, bmp_file_header->bf_off_bits, 0);
if (fread(orig_bmp_buf, 1, bmp_data_size, file) != bmp_data_size) {
printf("fread error!line:%d\n", __LINE__);
perror("fread:");
}
for (i = 0; i < video_logo->height; i++) {
for (j = 0; j < video_logo->width; ++j) {
ret = memcpy_s(rgb_buf + i * video_logo->stride + j * dst_bpp, bpp,
orig_bmp_buf + ((video_logo->height - 1) - i) * bmp_data_stride + j * bpp, bpp);
if (ret != EOK) {
free(orig_bmp_buf);
printf("copy bmp failed!line:%d\n", __LINE__);
return TD_FAILURE;
}
if (dst_bpp == 4) { /* 4: RGB8888 */
*(rgb_buf + i * video_logo->stride + j * dst_bpp + 3) = 0x80; /* 3: alpha offset */
}
}
}
free(orig_bmp_buf);
return TD_SUCCESS;
}
td_s32 load_bmp(const td_char *filename, osd_logo *video_logo)
{
osd_bit_map_file_header bmp_file_header;
osd_bit_map_info bmp_info;
FILE *file = TD_NULL;
td_char *path = TD_NULL;
if (filename == TD_NULL || video_logo == TD_NULL) {
printf("load_bmp: null ptr args!\n");
return TD_FAILURE;
}
if (strlen(filename) > PATH_MAX - 1) {
printf("file name Extra long\n");
return TD_FAILURE;
}
path = realpath(filename, TD_NULL);
if (path == TD_NULL) {
return TD_FAILURE;
}
if (get_bmp_info(path, &bmp_file_header, &bmp_info) < 0) {
goto read_bmp_failed;
}
if (bmp_info.bmp_header.bi_bit_count > MAX_BIT_COUNT || bmp_info.bmp_header.bi_width > MAX_WIDTH ||
bmp_info.bmp_header.bi_height > MAX_HEIGHT || bmp_file_header.bf_off_bits > MAX_OFF_BITS) {
printf("bmp info error!");
goto read_bmp_failed;
}
if (is_support_bmp_file(&bmp_info, 2) != TD_TRUE) { /* each pixel should takes 2 (or more) bytes */
goto read_bmp_failed;
}
file = fopen(path, "rb");
if (file == TD_NULL) {
printf("Open file failed:%s!\n", filename);
goto read_bmp_failed;
}
if (read_bmp_data(&bmp_file_header, &bmp_info, file, video_logo) != TD_SUCCESS) {
fclose(file);
goto read_bmp_failed;
}
fclose(file);
free(path);
return TD_SUCCESS;
read_bmp_failed:
free(path);
return TD_FAILURE;
}
static td_void updata_osd_logo_size_info(const osd_bit_map_info *bmp_info, osd_color_format fmt, osd_logo *video_logo)
{
video_logo->width = bmp_info->bmp_header.bi_width;
video_logo->height = bmp_info->bmp_header.bi_height;
switch (fmt) {
case OSD_COLOR_FORMAT_RGB444:
case OSD_COLOR_FORMAT_RGB555:
case OSD_COLOR_FORMAT_RGB565:
case OSD_COLOR_FORMAT_RGB1555:
case OSD_COLOR_FORMAT_RGB4444:
video_logo->stride = video_logo->width * BYTE_PER_PIX_1555;
return;
case OSD_COLOR_FORMAT_RGB888:
case OSD_COLOR_FORMAT_RGB8888:
video_logo->stride = video_logo->width * BYTE_PER_PIX_8888;
return;
case OSD_COLOR_FORMAT_CLUT2:
video_logo->stride = video_logo->width / PIX_PER_BYTE_CLUT2;
return;
case OSD_COLOR_FORMAT_CLUT4:
video_logo->stride = video_logo->width / PIX_PER_BYTE_CLUT4;
return;
default:
printf("file(%s), line(%d), no such format!\n", __FILE__, __LINE__);
return;
}
}
static td_s32 copy_original_bmp_data(td_u16 bpp, const td_u8 *data, const bmp_data_size_info *data_size_info,
osd_logo *video_logo)
{
td_u32 i, j;
td_s32 ret;
td_u8 *rgb_buf = video_logo->rgb_buf;
for (i = 0; i < data_size_info->height; ++i) {
for (j = 0; j < data_size_info->width; ++j) {
ret = memcpy_s(rgb_buf + i * video_logo->stride + j * bpp, bpp,
data + ((data_size_info->height - 1) - i) * data_size_info->stride + j * bpp, bpp);
if (ret != EOK) {
printf("copy bmp failed!line:%d\n", __LINE__);
return TD_FAILURE;
}
}
}
return TD_SUCCESS;
}
static td_s32 copy_clut_bmp_data(td_u16 bpp, osd_color_format fmt, const td_u8 *data,
const bmp_data_size_info *data_size_info, osd_logo *video_logo)
{
td_u32 i, j;
td_s32 ret;
td_u8 *rgb_buf = video_logo->rgb_buf;
td_u32 width = data_size_info->width;
if (fmt == OSD_COLOR_FORMAT_CLUT4) {
width /= PIX_PER_BYTE_CLUT4;
} else if (fmt == OSD_COLOR_FORMAT_CLUT2) {
width /= PIX_PER_BYTE_CLUT2;
} else {
}
for (i = 0; i < data_size_info->height; ++i) {
for (j = 0; j < width; ++j) {
ret = memcpy_s(rgb_buf + i * video_logo->stride + j, bpp,
data + ((data_size_info->height - 1) - i) * data_size_info->stride + j, bpp);
if (ret != EOK) {
printf("copy bmp failed!line:%d\n", __LINE__);
return TD_FAILURE;
}
}
}
return TD_SUCCESS;
}
static td_s32 copy_2byte_bmp(td_u16 bpp, osd_color_format fmt, const td_u8 *data,
const bmp_data_size_info *data_size_info, osd_logo *video_logo)
{
td_u32 i, j;
td_u8 *rgb_buf = video_logo->rgb_buf;
td_u8 r, g, b;
td_u8 *start = TD_NULL;
td_u16 *dst = TD_NULL;
/* start color convert */
for (i = 0; i < data_size_info->height; ++i) {
for (j = 0; j < data_size_info->width; ++j) {
start = (td_u8 *)(data + ((data_size_info->height - 1) - i) * data_size_info->stride + j * bpp);
dst = (td_u16 *)(rgb_buf + i * video_logo->stride + j * 2); /* 2 bytes */
r = *(start);
g = *(start + 1);
b = *(start + 2); /* 2 bytes offset */
*dst = osd_make_color_u16(r, g, b, g_osd_comp_info[fmt]);
}
}
return TD_SUCCESS;
}
static td_s32 copy_4byte_bmp(td_u16 bpp, const td_u8 *data, const bmp_data_size_info *data_size_info,
osd_logo *video_logo)
{
td_u32 i, j;
td_s32 ret;
td_u8 *rgb_buf = video_logo->rgb_buf;
for (i = 0; i < data_size_info->height; ++i) {
for (j = 0; j < data_size_info->width; ++j) {
ret = memcpy_s(rgb_buf + i * video_logo->stride + j * 4, bpp, /* offset 4 bytes */
data + ((data_size_info->height - 1) - i) * data_size_info->stride + j * bpp, bpp);
if (ret != EOK) {
printf("copy bmp failed!line:%d\n", __LINE__);
return TD_FAILURE;
}
*(rgb_buf + i * video_logo->stride + j * 4 + 3) = 0xff; /* 4 bytes data, alpha offset is 3 */
}
}
return TD_SUCCESS;
}
static td_s32 copy_original_bmp_data_and_fill_alpha(td_u16 bpp, osd_color_format fmt, const td_u8 *data,
const bmp_data_size_info *data_size_info, osd_logo *video_logo)
{
switch (fmt) {
case OSD_COLOR_FORMAT_RGB444:
case OSD_COLOR_FORMAT_RGB555:
case OSD_COLOR_FORMAT_RGB565:
case OSD_COLOR_FORMAT_RGB1555:
case OSD_COLOR_FORMAT_RGB4444:
return copy_2byte_bmp(bpp, fmt, data, data_size_info, video_logo);
case OSD_COLOR_FORMAT_RGB888:
case OSD_COLOR_FORMAT_RGB8888:
return copy_4byte_bmp(bpp, data, data_size_info, video_logo);
default:
printf("file(%s), line(%d), no such format!\n", __FILE__, __LINE__);
return TD_FAILURE;
}
}
static td_s32 read_bmp_data_ex(const osd_bit_map_file_header *bmp_file_header, const osd_bit_map_info *bmp_info,
FILE *file, osd_logo *video_logo, osd_color_format fmt)
{
td_u8 *orig_bmp_buf = NULL;
td_u16 bpp = bmp_info->bmp_header.bi_bit_count / BITS_NUM_PER_BYTE;
td_u32 bmp_data_stride;
td_u32 bmp_data_size;
td_s32 ret = TD_SUCCESS;
bmp_data_size_info data_size_info;
updata_osd_logo_size_info(bmp_info, fmt, video_logo);
bmp_data_stride = (bpp == 0) ? video_logo->stride : (video_logo->width * bpp);
bmp_data_stride = align_up(bmp_data_stride, STRIDE_ALIGN);
bmp_data_size = video_logo->height * bmp_data_stride;
data_size_info.width = video_logo->width;
data_size_info.height = video_logo->height;
data_size_info.stride = bmp_data_stride;
orig_bmp_buf = (td_u8 *)malloc(bmp_data_size);
if (orig_bmp_buf == NULL) {
printf("not enough memory to malloc!\n");
return TD_FAILURE;
}
fseek(file, bmp_file_header->bf_off_bits, 0);
if (fread(orig_bmp_buf, 1, bmp_data_size, file) != bmp_data_size) {
printf("fread error!line:%d\n", __LINE__);
perror("fread:");
}
/* copy bmp data to rgb_buf according bpp (and fmt) */
if (bpp == 2 || bpp == 4) { /* each pixel takes 2 (or 4) bytes */
ret = copy_original_bmp_data(bpp, orig_bmp_buf, &data_size_info, video_logo);
goto copy_over_exit;
}
if (bpp <= 1) { /* such as clut2 or clut 4, or 2BPP... */
ret = copy_clut_bmp_data(bpp, fmt, orig_bmp_buf, &data_size_info, video_logo);
goto copy_over_exit;
}
/* bpp should equal to 3 here */
ret = copy_original_bmp_data_and_fill_alpha(bpp, fmt, orig_bmp_buf, &data_size_info, video_logo);
copy_over_exit:
free(orig_bmp_buf);
return ret;
}
td_s32 load_bmp_ex(const td_char *filename, osd_logo *video_logo, osd_color_format fmt)
{
osd_bit_map_file_header bmp_file_header;
osd_bit_map_info bmp_info;
FILE *file = TD_NULL;
td_char *path = TD_NULL;
if (filename == TD_NULL || video_logo == TD_NULL) {
printf("load_bmp_ex: null ptr args!\n");
return TD_FAILURE;
}
if (strlen(filename) > PATH_MAX - 1) {
printf("file name Extra long\n");
return TD_FAILURE;
}
path = realpath(filename, TD_NULL);
if (path == TD_NULL) {
return TD_FAILURE;
}
if (get_bmp_info(path, &bmp_file_header, &bmp_info) < 0) {
goto read_bmp_failed;
}
if (bmp_info.bmp_header.bi_bit_count > MAX_BIT_COUNT || bmp_info.bmp_header.bi_width > MAX_WIDTH ||
bmp_info.bmp_header.bi_height > MAX_HEIGHT || bmp_file_header.bf_off_bits > MAX_OFF_BITS) {
printf("bmp info error!");
goto read_bmp_failed;
}
if (is_support_bmp_file(&bmp_info, 0) != TD_TRUE) {
goto read_bmp_failed;
}
file = fopen(path, "rb");
if (file == TD_NULL) {
printf("Open file failed:%s!\n", filename);
goto read_bmp_failed;
}
if (read_bmp_data_ex(&bmp_file_header, &bmp_info, file, video_logo, fmt) != TD_SUCCESS) {
fclose(file);
goto read_bmp_failed;
}
fclose(file);
free(path);
return TD_SUCCESS;
read_bmp_failed:
free(path);
return TD_FAILURE;
}
static td_s32 read_bmp_canvas(const osd_bit_map_file_header *bmp_file_header, const osd_bit_map_info *bmp_info,
FILE *file, osd_logo *video_logo, osd_color_format fmt)
{
td_u8 *orig_bmp_buf = NULL;
td_u16 bpp = bmp_info->bmp_header.bi_bit_count / BITS_NUM_PER_BYTE;
td_u32 bmp_data_size;
td_s32 ret = TD_SUCCESS;
bmp_data_size_info data_size_info;
data_size_info.width = bmp_info->bmp_header.bi_width;
data_size_info.height = bmp_info->bmp_header.bi_height;
if (bpp == 0) {
if (fmt == OSD_COLOR_FORMAT_CLUT2) {
data_size_info.stride = data_size_info.width / PIX_PER_BYTE_CLUT2;
} else if (fmt == OSD_COLOR_FORMAT_CLUT4) {
data_size_info.stride = data_size_info.width / PIX_PER_BYTE_CLUT4;
} else {
data_size_info.stride = video_logo->stride;
}
} else {
data_size_info.stride = data_size_info.width * bpp;
data_size_info.stride = align_up(data_size_info.stride, STRIDE_ALIGN);
}
bmp_data_size = data_size_info.height * data_size_info.stride;
orig_bmp_buf = (td_u8 *)malloc(bmp_data_size);
if (orig_bmp_buf == NULL) {
printf("not enough memory to malloc!\n");
return TD_FAILURE;
}
fseek(file, bmp_file_header->bf_off_bits, 0);
if (fread(orig_bmp_buf, 1, bmp_data_size, file) != bmp_data_size) {
printf("fread error!line:%d\n", __LINE__);
perror("fread:");
}
/* copy bmp data to rgb_buf according bpp (and fmt) */
if (bpp == 2 || bpp == 4) { /* each pixel takes 2 (or 4) bytes */
ret = copy_original_bmp_data(bpp, orig_bmp_buf, &data_size_info, video_logo);
goto copy_over_exit;
}
if (bpp <= 1) { /* such as clut2 or clut 4, or 2BPP... */
ret = copy_clut_bmp_data(bpp, fmt, orig_bmp_buf, &data_size_info, video_logo);
goto copy_over_exit;
}
/* bpp should equal to 3 here */
ret = copy_original_bmp_data_and_fill_alpha(bpp, fmt, orig_bmp_buf, &data_size_info, video_logo);
copy_over_exit:
free(orig_bmp_buf);
return ret;
}
td_s32 load_bmp_canvas(const td_char *filename, osd_logo *video_logo, osd_color_format fmt)
{
osd_bit_map_file_header bmp_file_header;
osd_bit_map_info bmp_info;
FILE *file = TD_NULL;
td_char *path = TD_NULL;
if (filename == TD_NULL || video_logo == TD_NULL) {
printf("load_bmp_canvas: null ptr args!\n");
return TD_FAILURE;
}
if (strlen(filename) > PATH_MAX - 1) {
printf("file name Extra long\n");
return TD_FAILURE;
}
path = realpath(filename, TD_NULL);
if (path == TD_NULL) {
return TD_FAILURE;
}
if (get_bmp_info(path, &bmp_file_header, &bmp_info) < 0) {
goto read_bmp_failed;
}
if (bmp_info.bmp_header.bi_bit_count > MAX_BIT_COUNT || bmp_info.bmp_header.bi_width > MAX_WIDTH ||
bmp_info.bmp_header.bi_height > MAX_HEIGHT || bmp_file_header.bf_off_bits > MAX_OFF_BITS) {
printf("bmp info error!");
goto read_bmp_failed;
}
if (is_support_bmp_file(&bmp_info, 0) != TD_TRUE) {
goto read_bmp_failed;
}
file = fopen(path, "rb");
if (file == TD_NULL) {
printf("Open file failed:%s!\n", filename);
goto read_bmp_failed;
}
if (read_bmp_canvas(&bmp_file_header, &bmp_info, file, video_logo, fmt) != TD_SUCCESS) {
fclose(file);
goto read_bmp_failed;
}
fclose(file);
free(path);
return TD_SUCCESS;
read_bmp_failed:
free(path);
return TD_FAILURE;
}
td_char *get_ext_name(const td_char *filename)
{
td_char *pret = TD_NULL;
size_t len;
if (filename == TD_NULL) {
printf("filename can't be null!");
return TD_NULL;
}
len = strlen(filename);
while (len) {
pret = (td_char *)(filename + len);
if (*pret == '.') {
return (pret + 1);
}
len--;
}
return pret;
}
td_s32 load_image(const td_char *filename, osd_logo *video_logo)
{
td_char *ext = get_ext_name(filename);
if (ext == TD_NULL) {
printf("get_ext_name error!\n");
return -1;
}
if (strcmp(ext, "bmp") == 0) {
if (load_bmp(filename, video_logo) != 0) {
printf("load_bmp error!\n");
return -1;
}
} else {
printf("not supported image file!\n");
return -1;
}
return 0;
}
td_s32 load_image_ex(const td_char *filename, osd_logo *video_logo, osd_color_format fmt)
{
td_char *ext = get_ext_name(filename);
if (ext == TD_NULL) {
printf("load_image_ex error!\n");
return -1;
}
if (strcmp(ext, "bmp") == 0) {
if (load_bmp_ex(filename, video_logo, fmt) != 0) {
printf("load_bmp_ex error!\n");
return -1;
}
} else {
printf("not supported image file!\n");
return -1;
}
return 0;
}
td_s32 load_canvas_ex(const td_char *filename, osd_logo *video_logo, osd_color_format fmt)
{
td_char *ext = get_ext_name(filename);
if (ext == TD_NULL) {
printf("load_canvas_ex error!\n");
return -1;
}
if (strcmp(ext, "bmp") == 0) {
if (load_bmp_canvas(filename, video_logo, fmt) != 0) {
printf("OSD_LoadBMP error!\n");
return -1;
}
} else {
printf("not supported image file!\n");
return -1;
}
return 0;
}
td_s32 load_bit_map_to_surface(const td_char *file_name, const osd_surface *surface, td_u8 *virt)
{
osd_logo logo;
check_null_ptr_return(file_name);
check_null_ptr_return(surface);
logo.stride = surface->stride;
logo.rgb_buf = virt;
return load_image(file_name, &logo);
}
td_s32 create_surface_by_bit_map(const td_char *file_name, osd_surface *surface, td_u8 *virt)
{
osd_logo logo;
check_null_ptr_return(file_name);
check_null_ptr_return(surface);
logo.rgb_buf = virt;
if (load_image_ex(file_name, &logo, surface->color_format) < 0) {
printf("load bmp error!\n");
return -1;
}
surface->height = logo.height;
surface->width = logo.width;
surface->stride = logo.stride;
return 0;
}
td_s32 create_surface_by_canvas(const td_char *file_name, osd_surface *surface, td_u8 *virt,
const canvas_size_info *canvas_size)
{
osd_logo logo;
check_null_ptr_return(file_name);
check_null_ptr_return(surface);
check_null_ptr_return(canvas_size);
logo.rgb_buf = virt;
logo.width = canvas_size->width;
logo.height = canvas_size->height;
logo.stride = canvas_size->stride;
if (load_canvas_ex(file_name, &logo, surface->color_format) < 0) {
printf("load bmp error!\n");
return -1;
}
surface->height = canvas_size->height;
surface->width = canvas_size->width;
surface->stride = canvas_size->stride;
return 0;
}