Jump to content

BMP File Processor


WarFox
 Share

Recommended Posts

Feel free to ask questions about the code. It reads and writes BMP Files. The PixelProcessor can be used to manipulate pixels in the image.

 

File format specification for reference: http://www.ece.ualberta.ca/~elliott/ee552/studentAppNotes/2003_w/misc/bmp_file_format/bmp_file_format.htm

Note that the BMP file format is in binary. This processor targets 24 bit images with pixel data 4 byte aligned. So the fseek is going to round out each "row" by advancing the file pointer by an amount to keep the "row" size some multiple of 4.

 

BmpProcessor.h

Spoiler

#include <stdio.h>
#include "PixelProcessor.h"

#ifndef BMP_HEADER
#define BMP_HEADER

typedef struct BMP_Header {
	char signature[2];
	int file_size;
	short reserve1;
	short reserve2;
	int file_offset;
} BMP_Header;

typedef struct DIB_Header{
	int DIB_size;
	int image_width;
	int image_height;
	short planes;
	short bits_per_pixel;
	int compression;
	int image_size;
	int x_pixels;
	int y_pixels;
	int colors;
	int important_colors;
} DIB_Header;


/**
 * read BMP header of a file. Useful for converting files from PPM to BMP.
 *
 * @param  file: A pointer to the file being read or written
 * @param  header: Pointer to the destination BMP header
 */
void readBMPHeader(FILE* file, struct BMP_Header* header);

/**
 * write BMP header of a file. Useful for converting files from PPM to BMP.
 *
 * @param  file: A pointer to the file being read or written
 * @param  header: The header made by makeBMPHeader function
 */
void writeBMPHeader(FILE* file, struct BMP_Header* header);

/**
 * read DIB header from a file. Useful for converting files from PPM to BMP.
 *
 * @param  file: A pointer to the file being read or written
 * @param  header: Pointer to the destination DIB header
 */
void readDIBHeader(FILE* file, struct DIB_Header* header);

/**
 * write DIB header of a file. Useful for converting files from PPM to BMP.
 *
 * @param  file: A pointer to the file being read or written
 * @param  header: The header made by makeDIBHeader function
 */
void writeDIBHeader(FILE* file, struct DIB_Header* header);

/**
 * make BMP header based on width and height. 
 * The purpose of this is to create a new BMPHeader struct using the information 
 * from a PPMHeader when converting from PPM to BMP.
 *
 * @param  header: Pointer to the destination DIB header
 * @param  width: Width of the image that this header is for
 * @param  height: Height of the image that this header is for
 */
void makeBMPHeader(struct BMP_Header* header, int width, int height);


 /**
 * Makes new DIB header based on width and height. Useful for converting files from PPM to BMP.
 *
 * @param  header: Pointer to the destination DIB header
 * @param  width: Width of the image that this header is for
 * @param  height: Height of the image that this header is for
 */
void makeDIBHeader(struct DIB_Header* header, int width, int height);


/**
 * read Pixels from BMP file based on width and height.
 *
 * @param  file: A pointer to the file being read or written
 * @param  pArr: Pixel array of the image that this header is for
 * @param  width: Width of the image that this header is for
 * @param  height: Height of the image that this header is for
 */
void readPixelsBMP(FILE* file, struct Pixel** pArr, int width, int height);


/**
 * write Pixels from BMP file based on width and height.
 *
 * @param  file: A pointer to the file being read or written
 * @param  pArr: Pixel array of the image that this header is for
 * @param  width: Width of the image that this header is for
 * @param  height: Height of the image that this header is for
 */
void writePixelsBMP(FILE* file, struct Pixel** pArr, int width, int height);

#endif

 

BmpProcessor.c

Spoiler

#include "BmpProcessor.h"
#include "PixelProcessor.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/**
 * read BMP header of a file. Useful for converting files from PPM to BMP.
 *
 * @param  file: A pointer to the file being read or written
 * @param  header: Pointer to the destination BMP header
 */
void readBMPHeader(FILE* file, struct BMP_Header* header) {
    fread(&header->signature, sizeof(char)*2, 1, file);
    fread(&header->file_size, sizeof(int), 1, file);
    fread(&header->reserve1, sizeof(short), 1, file);
    fread(&header->reserve2, sizeof(short), 1, file);
    fread(&header->file_offset, sizeof(int), 1, file);
}

/**
 * write BMP header of a file. Useful for converting files from PPM to BMP.
 *
 * @param  file: A pointer to the file being read or written
 * @param  header: The header made by makeBMPHeader function
 */
void writeBMPHeader(FILE* file, struct BMP_Header* header) {
    fwrite(&header->signature, sizeof(short), 1, file);
    fwrite(&header->file_size, sizeof(int), 1, file);
    fwrite(&header->reserve1, sizeof(short), 1, file);
    fwrite(&header->reserve2, sizeof(short), 1, file);
    fwrite(&header->file_offset, sizeof(int), 1, file);
}

/**
 * read DIB header from a file. Useful for converting files from PPM to BMP.
 *
 * @param  file: A pointer to the file being read or written
 * @param  header: Pointer to the destination DIB header
 */
void readDIBHeader(FILE* file, struct DIB_Header* header) {
    fread(&header->DIB_size, sizeof(int), 1, file);
    fread(&header->image_width, sizeof(int), 1, file);
    fread(&header->image_height, sizeof(int), 1, file);
    fread(&header->planes, sizeof(short), 1, file);
    fread(&header->bits_per_pixel, sizeof(short), 1, file);
    fread(&header->compression, sizeof(int), 1, file);
    fread(&header->image_size, sizeof(int), 1, file);
    fread(&header->x_pixels, sizeof(int), 1, file);
    fread(&header->y_pixels, sizeof(int), 1, file);
    fread(&header->colors, sizeof(int), 1, file);
    fread(&header->important_colors, sizeof(int), 1, file);
}

/**
 * write DIB header of a file. Useful for converting files from PPM to BMP.
 *
 * @param  file: A pointer to the file being read or written
 * @param  header: The header made by makeDIBHeader function
 */
void writeDIBHeader(FILE* file, struct DIB_Header* header) {
    fwrite(&header->DIB_size, sizeof(int), 1, file);
    fwrite(&header->image_width, sizeof(int), 1, file);
    fwrite(&header->image_height, sizeof(int), 1, file);
    fwrite(&header->planes, sizeof(short), 1, file);
    fwrite(&header->bits_per_pixel, sizeof(short), 1, file);
    fwrite(&header->compression, sizeof(int), 1, file);
    fwrite(&header->image_size, sizeof(int), 1, file);
    fwrite(&header->x_pixels, sizeof(int), 1, file);
    fwrite(&header->y_pixels, sizeof(int), 1, file);
    fwrite(&header->colors, sizeof(int), 1, file);
    fwrite(&header->important_colors, sizeof(int), 1, file);
}

/**
 * make BMP header based on width and height.
 * The purpose of this is to create a new BMPHeader struct using the information
 * from a PPMHeader when converting from PPM to BMP.
 *
 * @param  header: Pointer to the destination DIB header
 * @param  width: Width of the image that this header is for
 * @param  height: Height of the image that this header is for
 */
void makeBMPHeader(struct BMP_Header* header, int width, int height) {
    header->signature[0] = 0x42;
    header->signature[1] = 0x4D;
    header->reserve1 = 0x00;
    header->reserve2 = 0x00;
    header->file_offset = 54;
    //int file_size = (14+40+(height*(width+(width%4))));
    header->file_size = (54+(height*(width+(width%4)))*3);
}


 /**
 * Makes new DIB header based on width and height. Useful for converting files from PPM to BMP.
 *
 * @param  header: Pointer to the destination DIB header
 * @param  width: Width of the image that this header is for
 * @param  height: Height of the image that this header is for
 */
void makeDIBHeader(struct DIB_Header* header, int width, int height) {
    header->DIB_size = 40;
    header->image_width = width;
    header->image_height = height;
    header->planes = 1;
    header->bits_per_pixel = 24;
    header->compression = 0;
    header->image_size = height*(width+(width%4))*(3);
    header->x_pixels = 0;
    header->y_pixels = 0;
    header->colors = 0;
    header->important_colors = 0;
}


/**
 * read Pixels from BMP file based on width and height.
 *
 * @param  file: A pointer to the file being read or written
 * @param  pArr: Pixel array of the image that this header is for
 * @param  width: Width of the image that this header is for
 * @param  height: Height of the image that this header is for
 */
void readPixelsBMP(FILE* file, struct Pixel** pArr, int width, int height) {
    //pArr = (struct Pixel**) malloc(sizeof(struct Pixel*)*width);
    //for (int i = 0; i < width; i++) {
    //    pArr = (struct Pixel*) malloc(sizeof(struct Pixel) * height);
    //}
    int padding_length = (width%4);
    //fread(&padding, sizeof(char), 1, file);
    for (int w = 0; w < width; w++) {
        for (int h = 0; h < height; h++) {
            unsigned char b,g,r;
            fread(&b, sizeof(unsigned char), 1, file);
            fread(&g, sizeof(unsigned char), 1, file);
            fread(&r, sizeof(unsigned char), 1, file);
            //printf("%d %d %d\n", b,g,r);
            pArr[w][h].b = b;
            pArr[w][h].g = g;
            pArr[w][h].r = r;
            if (h == height-1) {
                fseek(file, sizeof(char)*padding_length, SEEK_CUR);
            }
        }
    }
} // b, g, r


/**
 * write Pixels from BMP file based on width and height.
 *
 * @param  file: A pointer to the file being read or written
 * @param  pArr: Pixel array of the image that this header is for
 * @param  width: Width of the image that this header is for
 * @param  height: Height of the image that this header is for
 */
void writePixelsBMP(FILE* file, struct Pixel** pArr, int width, int height) {
    int padding_length = width%4;
    for (int r = 0; r < width; r++) {
        for (int c = 0; c < height; c++) {
            //struct Pixel temp = pArr[r][c];
            //printf("|%c |%c |%c|", temp.b, temp.g, temp.r);
            fwrite(&pArr[r][c].b, sizeof(char), 1, file);
            fwrite(&pArr[r][c].g, sizeof(char), 1, file);
            fwrite(&pArr[r][c].r, sizeof(char), 1, file);
            if (c == (height-1)) {
                fseek(file, sizeof(char)*padding_length, SEEK_CUR);
            }
        }
    }
    char end_of_file = 0x00;
    fwrite(&end_of_file, sizeof(char), 1, file);
}

 

PixelProcessor.h

Spoiler

#ifndef PIXEL_HEADER
#define PIXEL_HEADER

struct Pixel{
	unsigned char r, b, g;	
};

/**
 * Shift color of Pixel array. The dimension of the array is width * height. The shift value of RGB is 
 * rShift, gShift,bShift. Useful for color shift.
 *
 * @param  pArr: Pixel array of the image that this header is for
 * @param  width: Width of the image that this header is for
 * @param  height: Height of the image that this header is for
 * @param  rShift: the shift value of color r shift
 * @param  gShift: the shift value of color g shift 
 * @param  bShift: the shift value of color b shift 
 */
void colorShiftPixels(struct Pixel** pArr, int width, int height, int rShift, int gShift, int bShift);

#endif

 

PixelProcessor.c

Spoiler

#include <stdio.h>
#include "PixelProcessor.h"

void colorShiftPixels (struct Pixel** pArr, int width, int height, int rShift, int gShift, int bShift) {
	for (int i = 0; i < width; i++) {
		for (int j = 0; j < height; j++) {
			pArr[i][j].r += rShift;
			pArr[i][j].b += bShift;
			pArr[i][j].g += gShift;
		}
	}
}

 

 

Edited by WarFox
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...