Update solution/include/bmp.h, solution/include/file.h,...

Update solution/include/bmp.h, solution/include/file.h, solution/include/image.h, solution/include/rotation.h, solution/src/bmp.c, solution/src/file.c, solution/src/image.c, solution/src/rotation.c, solution/src/main.c files
parent e5752400
//
// Created by ricar on 16.12.2022.
//
#ifndef IMAGE_ROTATION_BMP_H
#define IMAGE_ROTATION_BMP_H
#include<malloc.h>
#include<stdint.h>
#include<stdio.h>
#include "image.h"
#define PLANES 1
#define HEADER_SIZE 40
#define TYPE (19778)
#define BIT_COUNT (24)
#pragma pack(push,1)
// bmp_header represents the header for a BMP file
struct bmp_header
{
uint16_t bfType; // type of BMP file (0x4d42 | 0x4349 | 0x5450)
uint32_t bfileSize; // size of the file
uint32_t bfReserved; // reserved field, should be 0
uint32_t bOffBits; // offset to data field
uint32_t biSize; // size of the structure in bytes (40 for BITMAPINFOHEADER, 108 for BITMAPV4HEADER, 124 for BITMAPV5HEADER)
uint32_t biWidth; // width in pixels
uint32_t biHeight; // height in pixels
uint16_t biPlanes; // should always be 1
uint16_t biBitCount; // number of bits per pixel (0, 1, 4, 8, 16, 24, 32)
uint32_t biCompression; // type of compression (BI_RGB, BI_RLE8, BI_RLE4, BI_BITFIELDS, BI_JPEG, BI_PNG) (only BI_RGB is commonly used)
uint32_t biSizeImage; // size of data field in bytes (usually set to 0)
uint32_t biXPelsPerMeter; // horizontal resolution, pixels per inch
uint32_t biYPelsPerMeter; // vertical resolution, pixels per inch
uint32_t biClrUsed; // number of colors used (if there is a color table)
uint32_t biClrImportant; // number of significant colors (can be considered 0)
};
#pragma pack(pop)
enum read_status {
READ_OK = 0,
READ_INVALID_SIGNATURE,
READ_INVALID_BITS,
READ_INVALID_HEADER,
READ_ERROR
/* code for other errors */
};
// This function reads a BMP file from the given input buffer and stores the image data in the given image structure.
enum read_status from_bmp( char* in, struct image *img );
/* serializer */
enum write_status {
WRITE_OK = 0,
WRITE_ERROR
/* code for other errors */
};
// This function writes an image to a BMP file in the given output buffer.
enum write_status to_bmp( char* out, struct image const* img );
#endif //IMAGE_ROTATION_BMP_H
//
// Created by ricar on 16.12.2022.
//
#ifndef IMAGE_ROTATION_FILE_H
#define IMAGE_ROTATION_FILE_H
#include <stdbool.h>
#include <stdio.h>
// This function attempts to open a file with the given name and mode.
bool check_file_opened(FILE **file,const char *name, const char *mode);
// This function closes a file that was previously opened with check_file_opened().
bool check_file_closed(FILE **file);
#endif //IMAGE_ROTATION_FILE_H
//
// Created by ricar on 16.12.2022.
//
#ifndef IMAGE_ROTATION_IMAGE_H
#define IMAGE_ROTATION_IMAGE_H
#include<malloc.h>
#include<stdint.h>
#include<stdio.h>
// This directive tells the compiler to pack the structure members
// tightly together, without adding any padding bytes between them
#pragma pack(push,1)
// This structure represents an image, with a width and height
struct image{
uint64_t width;
uint64_t height;
struct pixel* data;
};
// This structure represents a pixel, with 8-bit red, green, and blue values.
struct pixel{
__attribute__((unused))
uint8_t b;
uint8_t g;
uint8_t r;
};
// This directive tells the compiler to revert to its default packing of structure members
#pragma pack(pop)
// This function configures an image structure with the given width and height.
void configure_image(struct image *img,uint32_t width, uint32_t height);
// This function frees the memory allocated for the image data in the given image structure.
void free_img (struct image const* image );
#endif //IMAGE_ROTATION_IMAGE_H
//
// Created by ricar on 16.12.2022.
//
#include"bmp.h"
#ifndef IMAGE_ROTATION_ROTATION_H
#define IMAGE_ROTATION_ROTATION_H
// This function rotates an image by 90 degrees clockwise.
// The input "source" is the image to be rotated.
struct image rotation(struct image source);
#endif //IMAGE_ROTATION_ROTATION_H
//
// Created by ricar on 16.12.2022.
//
#include "bmp.h"
#include "file.h"
#include<string.h>
// find_padding calculates the number of padding bytes needed at the end of each row of pixels in the BMP file
uint32_t find_padding(uint64_t a) {
// the number of bytes in each row of pixels must be a multiple of 4
if (a % 4 == 0) {
return 0;
} else {
return (a % 4);
}
}
// from_bmp reads a BMP file and stores its data in the given image struct
// it returns a read_status enum value indicating the success or failure of the operation
enum read_status from_bmp( char* input_name, struct image *img ){
// create a file pointer and open the input file
FILE *in= NULL;
if(check_file_opened(&in,input_name,"rb") == false) return READ_ERROR;
// create a variable to store the BMP file header
struct bmp_header header;
// read the BMP file header from the input file
size_t res = fread(&header,1,sizeof(struct bmp_header),in);
// if the header is not the expected size, return an error status
if(res != sizeof (struct bmp_header)){
printf("%s","The header is invalid");
return READ_INVALID_HEADER;
}
// check the signature of the BMP file to ensure it is a valid BMP file
if(header.bfType != 0x4d42 && header.bfType != 0x4349 && header.bfType != 0x5450) {
printf("%d",header.bfType);
printf("%s","The type is invalid");
return READ_INVALID_SIGNATURE;
}
// check the header fields to ensure they are valid
bool invalidHeader = (header.bfileSize != header.biSizeImage + res) ||
(header.bfReserved != 0) ||
(header.biPlanes != 1) ||
((header.biSize != 40) && (header.biSize != 25) && (header.biSize != 124)) ||
(header.bOffBits != 14 + header.biSize) ||
(header.biWidth < 1) || (header.biWidth > 10000) ||
(header.biHeight < 1) || (header.biHeight > 10000) ||
(header.biBitCount != 24) ||
(header.biCompression != 0);
// if any of the header fields are invalid, return an error status
if (invalidHeader) {
printf("%s","The header is invalid");
return READ_INVALID_HEADER;
}
// the BMP file header has been read and checked, and the image is a BGR-24 format with known width and height
configure_image(img,header.biWidth,header.biHeight);
// if the image data could not be allocated, return an error status
if(((*img).data) == NULL) {return READ_INVALID_BITS;}
// read the pixel data from the input file and store it in the image struct
size_t i = 0;
while (i < ((*img).height)) {
// read a row of pixels from the input file
res = fread(&(((*img).data)[i * ((*img).width)]), sizeof(struct pixel), (*img).width, in);
// if the number of pixels read is not equal to the image width, return an error status
if (res != ((*img).width)) return READ_ERROR;
// skip the padding bytes at the end of the row
fseek(in, find_padding((*img).width), SEEK_CUR);
++i;
}
// close the input file and return a status indicating success or failure
if(check_file_closed(&in) == false){return READ_ERROR;}
return READ_OK;
}
struct bmp_header create_new_header(struct image const* img){
struct bmp_header bmpHeader;
bmpHeader.bfType = TYPE;
//Find the length of the line in the fine
unsigned long width_full = (3* ((*img).width) +3) &(-4);
bmpHeader.biSizeImage = ((*img).height) * width_full;
bmpHeader.bfileSize = sizeof (struct bmp_header) + bmpHeader.biSizeImage;
bmpHeader.bfReserved = 0;
bmpHeader.biPlanes = PLANES;
bmpHeader.biSize = HEADER_SIZE;
bmpHeader.bOffBits = sizeof (struct bmp_header);
bmpHeader.biWidth = (*img).width;
bmpHeader.biHeight = (*img).height;
bmpHeader.biBitCount = BIT_COUNT;
bmpHeader.biCompression = 0;
bmpHeader.biYPelsPerMeter = 0;
bmpHeader.biXPelsPerMeter = 0;
bmpHeader.biClrImportant = 0;
bmpHeader.biClrUsed = 0;
return bmpHeader;
}
// to_bmp writes the data from the given image struct to a BMP file
// it returns a write_status enum value indicating the success or failure of the operation
enum write_status to_bmp( char* output_name, struct image const* img ){
// create a file pointer and open the output file
FILE *out = NULL;
if(check_file_opened(&out,output_name,"wb") == false) return WRITE_ERROR;
// create a BMP file header for the output file
struct bmp_header bmpHeader = create_new_header(img);
// write the BMP file header to the output file
size_t res = fwrite(&bmpHeader, 1,sizeof(struct bmp_header), out);
// if the header is not the expected size, return an error status
if(res != sizeof (struct bmp_header)) {return WRITE_ERROR;}
// write the pixel data to the output file
size_t i = 0;
while (i < ((*img).height)) {
// write a row of pixels to the output file
res = fwrite(&(((*img).data)[i * ((*img).width)]), sizeof(struct pixel), ((*img).width), out);
// if the number of pixels written is not equal to the image width, return an error status
if (res != ((*img).width)) return WRITE_ERROR;
// add padding bytes to the end of the row to make it a multiple of 4 bytes
uint32_t padding = find_padding((*img).width);
uint32_t j = 0;
while (j < padding) {
fputc(0, out);
++j;
}
++i;
}
// close the output file and return a status indicating success or failure
if(check_file_closed(&out) == false){return WRITE_ERROR;}
return WRITE_OK;
}
//
// Created by ricar on 16.12.2022.
//
#include "file.h"
// check_file_opened opens a file and returns a boolean indicating success or failure
bool check_file_opened(FILE** file, const char* filename, const char* mode) {
// open the file with the given filename and mode and assign the result to the file pointer
*file = fopen(filename, mode);
// if the file could not be opened, print an error message and return false
if (!*file) {
printf("%s","Error opening file");
return false;
}
// return true if the file was successfully opened
return true;
}
// check_file_closed closes a file and returns a boolean indicating success or failure
bool check_file_closed(FILE **file){
// if the file pointer is null, return false
if(!*file){
return false;
}
// close the file and return true if the operation was successful, or false otherwise
return (fclose(*file) == 0);
}
//
// Created by ricar on 16.12.2022.
//
#include "image.h"
#include <inttypes.h>
#include <malloc.h>
#include <stdlib.h>
// configure_image sets the width, height, and data fields of the input image struct
void configure_image(struct image *img,uint32_t width, uint32_t height){
// set the width and height fields of the image struct
(*img).width = width;
(*img).height = height;
// allocate memory for the image data array and assign it to the data field of the image struct
(*img).data = malloc(sizeof (struct pixel) * width * height);
}
// free_img frees the memory allocated for the data field of the input image struct
void free_img (struct image const* image ){
// free the memory allocated for the image data array
free((*image).data);
}
#include <stdio.h>
//
// Created by ricar on 16.12.2022.
//
int main( int argc, char** argv ) {
(void) argc; (void) argv; // supress 'unused parameters' warning
#include "bmp.h"
#include "file.h"
#include "image.h"
#include "rotation.h"
int main(int argc, char** argv) {
// Check if there are enough arguments
if (argc != 3) {
return 1;
}
// Get the input and output filenames from the command line arguments
char *input_name = argv[1];
char *output_name = argv[2];
// Initialize the image structure
struct image image = {0};
// Read the input file and check for errors
int read_result = from_bmp(input_name, &image);
if (read_result != READ_OK) {
free_img(&image);
return 1;
}
// Rotate the image and check for errors
struct image rotated_image = rotation(image);
int write_result = to_bmp(output_name, &rotated_image);
if (write_result != WRITE_OK) {
free_img(&image);
free_img(&rotated_image);
return 1;
}
// Free the image data
free_img(&image);
free_img(&rotated_image);
// Return success
return 0;
}
//
// Created by ricar on 16.12.2022.
//
#include "image.h"
#include "rotation.h"
// location_PIXEL returns a pointer to the pixel at the specified location in the image
struct pixel* location_PIXEL(struct image src, uint32_t h, uint32_t w){
// calculate the location of the pixel in the image data array and return a pointer to it
return src.data + src.width*h + w;
}
// rotation rotates the input image by 90 degrees clockwise
struct image rotation(struct image const source){
// create a new image to store the rotated result
struct image result = {0};
// configure the result image with the rotated dimensions of the source image
configure_image(&result,source.height,source.width);
// loop through the result image pixels
uint32_t i = 0;
while (i < result.height) {
uint32_t j = 0;
while (j < result.width) {
// set the result pixel to the source pixel at the corresponding rotated location
*(location_PIXEL(result,i,j)) = *(location_PIXEL(source,result.width-j-1,i));
j++;
}
i++;
}
// return the rotated result image
return result;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment