#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../inc/mcip_bmp_utils.h"

/*#define BMP_UTILS_DEBUG*/

/* BMP Gray image default header */
static bmp_header_t default_grayscale_bmp_header = {
		{
			{'B', 'M'} /*signature*/
		},
		{
			263222,  /*file_size*/
			0, 0,    /*reserved1, reserved2*/
			1078     /*bitmap_offset*/
		},
		{
			40,      /*header_size*/
			512,     /*width*/
			512,     /*height*/
			1,       /*nplanes*/
			8,       /*bitspp*/
			0,       /*compress_type*/
			262144,  /*bmp_bytesz*/
			0,       /*hres*/
			0,       /*vres*/
			256,     /*ncolors*/
			0        /*nimpcolors*/
		}
};

/****************************************************************************/
/* Bitmap header reading routine                                            */
/****************************************************************************/
int bmp_read_header (raw_image_data_t * image, bmp_header_t * hdr)
{
    if (image->length < 
        sizeof(bmpfile_signature_t) + sizeof(bmpfile_header_t) + sizeof(bmpfile_dib_header_t)) {
        printf ("Insufficient Image Buffer Length %d\n", image->length);
        return -1;
    }

	memcpy(&(hdr->signature), image->data, sizeof(bmpfile_signature_t));
	memcpy(&(hdr->file), image->data + sizeof(bmpfile_signature_t),
			sizeof(bmpfile_header_t));
	memcpy(&(hdr->dib), image->data + sizeof(bmpfile_signature_t) + sizeof(bmpfile_header_t),
			sizeof(bmpfile_dib_header_t));
#if BMP_UTILS_DEBUG
	printf("signature = %c%c\n", hdr->signature.signature[0], hdr->signature.signature[1]);

	printf("header.file_size = %d\n", hdr->file.file_size);
	printf("header.reserved1 = %d\n", hdr->file.reserved1);
	printf("header.reserved2 = %d\n", hdr->file.reserved2);
	printf("header.bitmap_offset = %d\n", hdr->file.bitmap_offset);

	printf("info_header.header_size = %d\n", hdr->dib.header_size);
	printf("info_header.width = %d\n", hdr->dib.image_width);
	printf("info_header.height = %d\n", hdr->dib.image_height);
	printf("info_header.nplanes = %d\n", hdr->dib.number_of_planes);
	printf("info_header.bitspp = %d\n", hdr->dib.bits_per_pixel);
	printf("info_header.compress_type = %d\n", hdr->dib.compression_type);
	printf("info_header.bmp_bytesz = %d\n", hdr->dib.image_size);
	printf("info_header.hres = %d\n", hdr->dib.horizontal_resolution);
	printf("info_header.vres = %d\n", hdr->dib.vertical_resolution);
	printf("info_header.ncolors = %d\n", hdr->dib.number_of_colors);
	printf("info_header.nimpcolors = %d\n", hdr->dib.important_color_count);
#endif
	if((hdr->signature.signature[0] != 'B') || (hdr->signature.signature[1] != 'M')) {
		printf("Incorrect MAGIC number 0x%x 0x%x\n", hdr->signature.signature[0], hdr->signature.signature[1]);
		return -1;
	}

	if((hdr->dib.bits_per_pixel != 8) &&  (hdr->dib.bits_per_pixel != 24)) {
		printf("Only 8 or 24 bits per pixel supported, the image bpp is %d\n", hdr->dib.bits_per_pixel);
		return -1;
	}

	if(hdr->dib.compression_type != BMP_RGB) {
		printf("Need a RGB type image, the image type is %d\n", hdr->dib.compression_type);
		return -1;
	}
	
	return 0;
}

/****************************************************************************/
/* Bitmap colormap reading routine                                          */
/****************************************************************************/
int bmp_read_colormap (raw_image_data_t * image, bmp_header_t * hdr,
						bmp_color_table_t * color_table)
{
	int index;

	if(hdr->dib.number_of_colors == 0) {
		printf("Color table can't be read, ncolors = %d\n", hdr->dib.number_of_colors);
		return -1;
	}

	index = sizeof(bmpfile_signature_t) + sizeof(bmpfile_header_t) + hdr->dib.header_size;

	memcpy(color_table, image->data + index, sizeof(bmp_color_table_t) * hdr->dib.number_of_colors);

#if BMP_UTILS_DEBUG
	{
		int i;
		printf("Color Table:\nindex:\tblue\tgreen\tred\n");
		for (i = 0; i < hdr->dib.number_of_colors; i++){
			printf("%d:\t0x%02x\t0x%02x\t0x%02x\n",
				i,  color_table[i].blue, color_table[i].green, color_table[i].red);
		}
	}
#endif
	return 0;
}

/****************************************************************************/
/* Bitmap image row reading routine                                         */
/****************************************************************************/
int bmp_read_image (raw_image_data_t * image, bmp_header_t * hdr, uint8_t * pixel_array_rgb)
{ 
	int i;
	int index;
	int pixel_size = hdr->dib.bits_per_pixel / 8;
	int row_width  = hdr->dib.image_width * pixel_size;
	int row_width_with_pad = ((row_width) + 3) & (~3);

	for(i = 0; i < hdr->dib.image_height; i++) {
		index = hdr->file.bitmap_offset + (row_width_with_pad * (hdr->dib.image_height - i - 1));
		memcpy(pixel_array_rgb + (i * row_width), image->data + index, row_width);
#if BMP_UTILS_DEBUG
		if (i == 0) {
			int j, k;
			printf("Pixel Value (0): ");
			for(j = 0; j < 512; j++){
				for(k = 0; k < pixel_size; k++) {
					printf("%x", (uint8_t)*(pixel_array_rgb + (i * row_width) + (j * pixel_size) + k));
				}
				printf(" ");
			}
			printf("\n");
		}
#endif
	}
	return 0;
}

/****************************************************************************/
/* Write a gray scale image file                                            */
/****************************************************************************/
int bmp_write_gray_bmpfile (raw_image_data_t * image, uint8_t * pixel_array,
		                    uint32_t width, uint32_t height)
{
	int i;
	int index = 0;
	int row_width_with_pad = (width + 3) & (~3);
	int pad_size = row_width_with_pad - width;
	bmp_color_table_t * color_table = 0;
	uint8_t * pad_array = 0;
	bmp_header_t hdr = default_grayscale_bmp_header;
    int ret_val = 0;

	if(pad_size) {
		pad_array = calloc(pad_size, 1);
	}

	hdr.dib.image_height     = height;
	hdr.dib.image_width      = width;
	hdr.dib.image_size = (row_width_with_pad * hdr.dib.image_height);

	color_table = calloc(sizeof(bmp_color_table_t), hdr.dib.number_of_colors);

	for(i = 0; i < hdr.dib.number_of_colors; i++) {
		color_table[i].blue  = i;
		color_table[i].green = i;
		color_table[i].red   = i;
	}

	hdr.file.file_size =
			sizeof(bmpfile_signature_t) + sizeof(bmpfile_header_t)
			+ hdr.dib.header_size
			+ (sizeof(bmp_color_table_t) * hdr.dib.number_of_colors)
			+ (row_width_with_pad * hdr.dib.image_height);
	hdr.file.bitmap_offset =
			sizeof(bmpfile_signature_t)
			+ sizeof(bmpfile_header_t) + hdr.dib.header_size
			+ (sizeof(bmp_color_table_t) * hdr.dib.number_of_colors);

    if (image->length < hdr.file.file_size) {
		printf("Insufficient image array size %d (expected %d)", 
            image->length, hdr.file.file_size);
		ret_val = -1;
        goto close_n_exit;
    }

	memcpy(image->data, &hdr.signature, sizeof(bmpfile_signature_t));
	index = sizeof(bmpfile_signature_t);
	memcpy(image->data + index, &hdr.file, sizeof(bmpfile_header_t));
	index += sizeof(bmpfile_header_t);
	memcpy(image->data + index, &hdr.dib, sizeof(bmpfile_dib_header_t));
	index += sizeof(bmpfile_dib_header_t);
	memcpy(image->data + index, color_table, sizeof(bmp_color_table_t) * hdr.dib.number_of_colors);
	index += sizeof(bmp_color_table_t) * hdr.dib.number_of_colors;

	for(i = hdr.dib.image_height - 1; i >= 0; i--) {
		memcpy(image->data + index, pixel_array + (hdr.dib.image_width * i), hdr.dib.image_width);
		index += hdr.dib.image_width;
		if (pad_size) {
			memcpy(image->data + index, pad_array, pad_size);
			index += pad_size;
		}
	}

    ret_val = 0;

close_n_exit:
	if(color_table) free(color_table);
    if(pad_array)   free(pad_array);

	return ret_val;
}

/****************************************************************************/
/* Get a gray scale image file file size                                    */
/****************************************************************************/
uint32_t bmp_get_gray_bmpfile_size (uint32_t width, uint32_t height)
{
	int row_width_with_pad = (width + 3) & (~3);
	bmp_header_t hdr = default_grayscale_bmp_header;

	return(sizeof(bmpfile_signature_t) + sizeof(bmpfile_header_t)
			+ hdr.dib.header_size
			+ (sizeof(bmp_color_table_t) * hdr.dib.number_of_colors)
			+ (row_width_with_pad * height));
}

#ifndef BMP_UTILS_H
#define BMP_UTILS_H

#include <stdint.h>

/****************************************************************************/
/* Bitmap header structure                                                  */
/****************************************************************************/
#ifdef _HOST_BUILD
#pragma pack(1)
#endif

typedef struct bmpfile_signature {
  uint8_t signature[2];      /* Signature - 'BM' */
} bmpfile_signature_t;

typedef struct bmpfile_header {
  uint32_t file_size;       /* File size in bytes */
  uint16_t reserved1;
  uint16_t reserved2;
  uint32_t bitmap_offset;   /* Offset to bitmap */
} bmpfile_header_t;

typedef struct bmpfile_dib_header {
  uint32_t header_size;    /* Size of this struct */
  int32_t  image_width;        /* Image width in pixels */
  int32_t  image_height;       /* Image image_height in pixels */
  uint16_t number_of_planes;      /* Number of planes */
  uint16_t bits_per_pixel;       /* Bits per pixel */
  uint32_t compression_type;/* Compression flag */
  uint32_t image_size;   /* Image size in bytes */
  int32_t  horizontal_resolution;         /* Horizontal resolution */
  int32_t  vertical_resolution;         /* Vertical resolution */
  uint32_t number_of_colors;      /* Color map size */
  uint32_t important_color_count;   /* Important color count */
} bmpfile_dib_header_t;

typedef struct bmp_header {
	bmpfile_signature_t  signature;
	bmpfile_header_t     file;
	bmpfile_dib_header_t dib;
} bmp_header_t;

/****************************************************************************/
/* Bitmap RGB colormap entry structure                                      */
/****************************************************************************/
typedef struct {
  uint8_t red;
  uint8_t green;
  uint8_t blue;
  uint8_t reserved;
} bmp_color_table_t;

#ifdef _HOST_BUILD
#pragma pack()
#endif

typedef enum {
  BMP_RGB = 0,
  BMP_RLE8,
  BMP_RLE4,
  BMP_BITFIELDS,
  BMP_JPEG,
  BMP_PNG
} bmp_compression_method_e;

/* Raw image data
 */

typedef struct raw_image_data {
	uint8_t * data;
	uint32_t  length;
} raw_image_data_t;

/* This function reads the header information from a bitmap file.
 * Note: It also does some preliminary checking if the file is valid.
 * It would return 0 for success and < 0 if file read or check fails.
 */

extern int bmp_read_header (raw_image_data_t * image, bmp_header_t * hdr);

/* This function reads the color table from the file.
 * It should be called if info_header.ncolors > 0.
 * The color_table structure should be an array of bmp_color_table_t size
 * length hdr->dib.ncolors.
 */
extern int bmp_read_colormap (raw_image_data_t * image, bmp_header_t * hdr,
									bmp_color_table_t * color_table);

/* This function reads the image (or pixel value). It expects the pixel_array_rgb should
 * be of size [hdr->dib.height * (hdr->dib.width * hdr->dib.bitspp / 8)], i.e., image size
 * in bytes.
 */
extern int bmp_read_image (raw_image_data_t * image, bmp_header_t * hdr, uint8_t * pixel_array_rgb);

/* This function creates and writes a gray scale image to system.
 * It expects the pixel_array should be of size
 * [hdr->dib.height * (hdr->dib.width * hdr->dib.bitspp / 8)],
 * i.e., image size in bytes.
 */
extern int bmp_write_gray_bmpfile (raw_image_data_t * image, uint8_t * pixel_array,
		                           uint32_t width, uint32_t height);

/*
 * Get a gray scale image file file size
 */
extern uint32_t bmp_get_gray_bmpfile_size (uint32_t width, uint32_t height);

#endif /*BMP_UTILS_H*/

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐