Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <math.h>
- #include <ctype.h>
- #include <getopt.h>
- void printHelp(){
- printf("\tThe program processes the V3 version of BMP files.\n");
- printf("-n --name - filename to open (necessarily)\n");
- printf("-o --outpname - filename to save\n");
- printf("-h --help - option to call a list of available commands\n");
- printf("-i --info - option to print information about the processed file\n");
- printf("\tTo draw a rectangle\n");
- printf("-r --rectangle - option sets the coordinates of the rectangle - upper left and lower right corners in format /x_1 y_1 x_2 y_2/\n");
- printf("-w --width - boundary line width in format /w/\n");
- printf("-L --linecolor - color of boundary line in format /R G B/\n");
- printf("-f --fill - fill color in format /R G B/\n");
- printf("\tTo draw a hexagon\n");
- printf("-S --sqarehex - to draw a hexagon, using square: upper left and lower right corners in format /x_1 y_1 x_2 y_2/\n");
- printf("-C --circlehex - to draw hexagon, using circle: circle center coordinates and radius in format /x_c y_c r/\n");
- printf("-w --width - boundary line width in format /w/\n");
- printf("-L --linecolor - color of boundary line in format /R G B/\n");
- printf("-f --fill - fill color in format /R G B/\n");
- printf("\tTo copy part of an image\n");
- printf("-c --copy - coordinates of the source area and the coordinate of the upper left corner of the destination area\n");
- }
- struct Configs{
- int cfg_error_flag;
- int infoFlag;
- int rectangleFlag;
- int squarehexFlag;
- int circlehexFlag;
- int copyFlag;
- int fillFlag;
- char* name;
- char* output_name;
- int rectangle[4];
- int width;
- int linecolor[3];
- int fill[3];
- int square_hexagon[4];
- int circle_hexagon[3];
- int copy[6];
- };
- void optsProcess(int argc, char* argv[], struct Configs *config){
- char* opts = "hin:o:r:w:L:f:S:C:c:";
- struct option longOpts[]={
- {"help", no_argument, NULL, 'h'},
- {"info", no_argument, NULL, 'i'},
- {"name", required_argument, 0, 'n'},
- {"outpname", required_argument, 0, 'o'},
- {"rectangle", required_argument, 0, 'r'},
- {"width", required_argument, 0, 'w'},
- {"linecolor", required_argument, 0, 'L'},
- {"fill", required_argument, 0, 'f'},
- {"squarehex", required_argument, 0, 'S'},
- {"circlehex", required_argument, 0, 'C'},
- {"copy", required_argument, 0, 'c'},
- {0, 0, 0, 0}
- };
- int opt;
- int longIngex;
- opt = getopt_long(argc, argv, opts, longOpts, &longIngex);
- while(opt != -1){
- switch(opt){
- case 'h':
- printHelp();
- break;
- case 'i':
- config->infoFlag = 1;
- break;
- case 'n':
- config->name = optarg;
- break;
- case 'o':
- config->output_name = optarg;
- case 'r':
- longIngex = optind - 1;
- config->rectangleFlag = 1;
- int counter = 0;
- while(longIngex < argc){
- char *next = strdup(argv[longIngex]);
- longIngex++;
- if(strstr(next, "-") == NULL){
- if(counter < 4){
- config->rectangle[counter++] = atoi(next);
- }
- }
- else{
- if(counter<4){
- config->cfg_error_flag = 1;
- }
- break;
- }
- }
- if(counter<4){
- config->cfg_error_flag = 1;
- }
- break;
- case 'w':
- config->width = atoi(optarg);
- break;
- case 'L':
- longIngex = optind - 1;
- counter = 0;
- while(longIngex < argc) {
- char *next = strdup(argv[longIngex]);
- longIngex++;
- if(strstr(next, "-") == NULL){
- if(counter < 3){
- config->linecolor[counter++] = atoi(next);
- }
- }
- else{
- if(counter<3){
- config->cfg_error_flag = 1;
- }
- break;
- }
- }
- if(counter<3){
- config->cfg_error_flag = 1;
- }
- break;
- case 'f':
- config->fillFlag = 1;
- longIngex = optind - 1;
- counter = 0;
- while(longIngex < argc) {
- char *next = strdup(argv[longIngex]);
- longIngex++;
- if(strstr(next, "-") == NULL){
- if(counter < 3){
- config->fill[counter++] = atoi(next);
- }
- }
- else{
- if(counter<3){
- config->cfg_error_flag = 1;
- }
- break;
- }
- }
- if(counter<3){
- config->cfg_error_flag = 1;
- }
- break;
- case 'S':
- longIngex = optind - 1;
- config->squarehexFlag = 1;
- counter = 0;
- while(longIngex < argc) {
- char *next = strdup(argv[longIngex]);
- longIngex++;
- if(strstr(next, "-") == NULL){
- if(counter < 4){
- config->square_hexagon[counter++] = atoi(next);
- }
- }
- else{
- if(counter<4){
- config->cfg_error_flag = 1;
- }
- break;
- }
- }
- if(counter<4){
- config->cfg_error_flag = 1;
- }
- break;
- case 'C':
- longIngex = optind - 1;
- config->circlehexFlag = 1;
- counter = 0;
- while(longIngex < argc) {
- char *next = strdup(argv[longIngex]);
- longIngex++;
- if(strstr(next, "-") == NULL){
- if(counter < 3){
- config->circle_hexagon[counter++] = atoi(next);
- }
- }
- else{
- if(counter<3){
- config->cfg_error_flag = 1;
- }
- break;
- }
- }
- if(counter<3){
- config->cfg_error_flag = 1;
- }
- break;
- case 'c':
- longIngex = optind - 1;
- config->copyFlag = 1;
- counter = 0;
- while(longIngex < argc) {
- char *next = strdup(argv[longIngex]);
- longIngex++;
- if(strstr(next, "-") == NULL){
- if(counter < 6){
- config->copy[counter++] = atoi(next);
- }
- }
- else{
- if(counter<6){
- config->cfg_error_flag = 1;
- }
- break;
- }
- }
- if(counter<6){
- config->cfg_error_flag = 1;
- }
- break;
- default:
- printHelp();
- config->cfg_error_flag = 1;
- return;
- }
- opt = getopt_long(argc, argv, opts, longOpts, &longIngex);
- }
- argc -= optind;
- argv += optind;
- }
- #pragma pack (push, 1)
- typedef struct
- {
- unsigned short signature;
- unsigned int filesize;
- unsigned short reserved1;
- unsigned short reserved2;
- unsigned int pixelArrOffset;
- } BitmapFileHeader;
- typedef struct
- {
- unsigned int headerSize;
- unsigned int width;
- unsigned int height;
- unsigned short planes;
- unsigned short bitsPerPixel;
- unsigned int compression;
- unsigned int imageSize;
- unsigned int xPixelsPerMeter;
- unsigned int yPixelsPerMeter;
- unsigned int colorsInColorTable;
- unsigned int importantColorCount;
- } BitmapInfoHeader;
- typedef struct
- {
- unsigned char b;
- unsigned char g;
- unsigned char r;
- } Rgb;
- #pragma pack(pop)
- void printFileHeader(BitmapFileHeader header){
- printf("signature:\t%x (%hu)\n", header.signature, header.signature);
- printf("filesize:\t%x (%u)\n", header.filesize, header.filesize);
- printf("reserved1:\t%x (%hu)\n", header.reserved1, header.reserved1);
- printf("reserved2:\t%x (%hu)\n", header.reserved2, header.reserved2);
- printf("pixelArrOffset:\t%x (%u)\n", header.pixelArrOffset, header.pixelArrOffset);
- }
- void printInfoHeader(BitmapInfoHeader header){
- printf("headerSize:\t%x (%u)\n", header.headerSize, header.headerSize);
- printf("width: \t%x (%u)\n", header.width, header.width);
- printf("height: \t%x (%u)\n", header.height, header.height);
- printf("planes: \t%x (%hu)\n", header.planes, header.planes);
- printf("bitsPerPixel:\t%x (%hu)\n", header.bitsPerPixel, header.bitsPerPixel);
- printf("compression:\t%x (%u)\n", header.compression, header.compression);
- printf("imageSize:\t%x (%u)\n", header.imageSize, header.imageSize);
- printf("xPixelsPerMeter:\t%x (%u)\n", header.xPixelsPerMeter, header.xPixelsPerMeter);
- printf("yPixelsPerMeter:\t%x (%u)\n", header.yPixelsPerMeter, header.yPixelsPerMeter);
- printf("colorsInColorTable:\t%x (%u)\n", header.colorsInColorTable, header.colorsInColorTable);
- printf("importantColorCount:\t%x (%u)\n", header.importantColorCount, header.importantColorCount);
- }
- void drawPixel(Rgb** arr, BitmapInfoHeader bih, int x, int y, int color_r, int color_g, int color_b){
- if(x>=0 && y>=0 && x<bih.width && y<bih.height){
- arr[y][x].r = color_r;
- arr[y][x].g = color_g;
- arr[y][x].b = color_b;
- }
- }
- /* Drawing a line using Bresenham's algorithm */
- void drawLine(Rgb** arr, BitmapInfoHeader bih, int x_st, int y_st, int x_end, int y_end, int color_r, int color_g, int color_b){
- int dx = abs(x_end - x_st), sx = x_st < x_end ? 1 : -1;
- int dy = -abs(y_end - y_st), sy = y_st < y_end ? 1 : -1;
- int err = dx + dy, e2; /* error value e_xy */
- for (;;){
- drawPixel(arr, bih, x_st, y_st, color_r, color_g, color_b);
- if(x_st == x_end && y_st == y_end){
- break;
- }
- e2 = 2 * err;
- if(e2 >= dy){
- err += dy; x_st += sx; /* e_xy+e_x > 0 */
- }
- if(e2 <= dx){
- err += dx; y_st += sy; /* e_xy+e_y < 0 */
- }
- }
- }
- /* Recursive fill function */
- void shapeFill(Rgb** arr, BitmapInfoHeader bih, int x, int y, int fill_r, int fill_g, int fill_b, int line_r, int line_g, int line_b){
- if(x>=0 && x<bih.width && y>=0 && y<bih.height && (arr[y][x].r != line_r || arr[y][x].g != line_g || arr[y][x].b != line_b) && (arr[y][x].r != fill_r || arr[y][x].g != fill_g || arr[y][x].b != fill_b)){
- drawPixel(arr, bih, x, y,fill_r, fill_g, fill_b);
- shapeFill(arr, bih, x+1, y, fill_r, fill_g, fill_b, line_r, line_g, line_b);
- shapeFill(arr, bih, x-1, y, fill_r, fill_g, fill_b, line_r, line_g, line_b);
- shapeFill(arr, bih, x, y+1, fill_r, fill_g, fill_b, line_r, line_g, line_b);
- shapeFill(arr, bih, x, y-1, fill_r, fill_g, fill_b, line_r, line_g, line_b);
- }
- }
- void drawRectangle(Rgb** arr, BitmapInfoHeader bih, struct Configs cfg){
- int x_st = cfg.rectangle[0];
- int y_st = bih.height - cfg.rectangle[1] - 1;
- int x_end = cfg.rectangle[2];
- int y_end = bih.height - cfg.rectangle[3] - 1;
- int color_r = cfg.linecolor[0];
- int color_g = cfg.linecolor[1];
- int color_b = cfg.linecolor[2];
- int fill_r = cfg.fill[0];
- int fill_g = cfg.fill[1];
- int fill_b = cfg.fill[2];
- /* Validity check of entered coordinates and colours */
- if(x_st < 0 || x_st >= bih.width || y_st < 0 || y_st >= bih.height || x_end < 0 || x_end >= bih.width || y_end < 0 || y_end >= bih.height){
- printf("Rectangle drawing error\n");
- printf("Coordinates of rectangle are out of bounds!\n");
- return;
- }
- if(x_st >= x_end || y_st <= y_end){
- printf("Invalid input format!\n");
- return;
- }
- if(color_r < 0 || color_r > 255 || color_g < 0 || color_g > 255 || color_b < 0 || color_b > 255 || fill_r < 0 || fill_r > 255 || fill_g < 0 || fill_g > 255|| fill_b < 0 || fill_b > 255){
- printf("Invalid color value!\n");
- return;
- }
- /* Rectangle drawing */
- for(int w = 0; w < cfg.width; w++){
- drawLine(arr, bih, x_st+w, y_st, x_st+w, y_end, color_r, color_g, color_b);
- drawLine(arr, bih, x_st, y_st-w, x_end, y_st-w, color_r, color_g, color_b);
- drawLine(arr, bih, x_end-w, y_st, x_end-w, y_end, color_r, color_g, color_b);
- drawLine(arr, bih, x_st, y_end+w, x_end, y_end+w, color_r, color_g, color_b);
- }
- /* Rectangle fill */
- if(cfg.fillFlag == 1){
- shapeFill(arr, bih, (x_st+x_end)/2, (y_st+y_end)/2, fill_r, fill_g, fill_b, color_r, color_g, color_b);
- }
- }
- void drawHexagon(Rgb** arr, BitmapInfoHeader bih, struct Configs cfg){
- int x_c, y_c, R;
- int color_r = cfg.linecolor[0];
- int color_g = cfg.linecolor[1];
- int color_b = cfg.linecolor[2];
- int fillFlag = cfg.fillFlag;
- int fill_r = cfg.fill[0];
- int fill_g = cfg.fill[1];
- int fill_b = cfg.fill[2];
- /* Getting the coordinates of the center of a hexagon */
- if(cfg.squarehexFlag == 1){
- int a = cfg.square_hexagon[2] - cfg.square_hexagon[0];
- int b = cfg.square_hexagon[3] - cfg.square_hexagon[1];
- if(a < 0 || b < 0){
- printf("Invalid input format!\n");
- return;
- }
- if(a != b) {
- printf("Please enter square coordinates for option -S/--squarehex\n");
- return;
- }
- R = a/2;
- x_c = (cfg.square_hexagon[2] + cfg.square_hexagon[0])/2;
- y_c = (2*bih.height - cfg.square_hexagon[1] - cfg.square_hexagon[3] - 2)/2;
- }
- else if(cfg.circlehexFlag == 1){
- x_c = cfg.circle_hexagon[0];
- y_c = bih.height - cfg.circle_hexagon[1] - 1;
- R = cfg.circle_hexagon[2];
- }
- if(x_c < 0 || x_c >= bih.width || y_c < 0 || y_c >= bih.height){
- printf("Hexagon drawing error\n");
- printf("Coordinates of hexagon center are out of bounds!\n");
- return;
- }
- if(color_r < 0 || color_r > 255 || color_g < 0 || color_g > 255 || color_b < 0 || color_b > 255 || fill_r < 0 || fill_r > 255 || fill_g < 0 || fill_g > 255|| fill_b < 0 || fill_b > 255){
- printf("Invalid color value!\n");
- return;
- }
- /* Hexagon drawing */
- float Pi = 3.141593;
- int dx = R * sin(Pi / 6);
- int dy = R * cos(Pi / 6);
- for (int w = 0; w < cfg.width; w++){
- drawLine(arr, bih, x_c + R - w, y_c, x_c + dx - w, y_c + dy, color_r, color_g, color_b);
- drawLine(arr, bih, x_c + dx, y_c + dy - w, x_c - dx, y_c + dy - w, color_r, color_g, color_b);
- drawLine(arr, bih, x_c - dx + w, y_c + dy, x_c - R + w, y_c, color_r, color_g, color_b);
- drawLine(arr, bih, x_c - R + w, y_c, x_c - dx + w, y_c - dy, color_r, color_g, color_b);
- drawLine(arr, bih, x_c - dx, y_c - dy + w, x_c + dx, y_c - dy + w, color_r, color_g, color_b);
- drawLine(arr, bih, x_c + dx - w, y_c - dy, x_c + R - w, y_c, color_r, color_g, color_b);
- }
- /* Hexagon fill */
- if(fillFlag == 1){
- shapeFill(arr, bih, x_c, y_c, fill_r, fill_g, fill_b, color_r, color_g, color_b);
- }
- }
- void copy(Rgb** arr, BitmapInfoHeader bih, struct Configs cfg){
- int x_st = cfg.copy[0], y_st = bih.height - cfg.copy[1] - 1, x_end = cfg.copy[2], y_end = bih.height - cfg.copy[3] - 1, x_c = cfg.copy[4], y_c = bih.height - cfg.copy[5] - 1;
- /* Validity check of entered coordinates */
- if(x_st < 0 || x_st >= bih.width || y_st < 0 || y_st >= bih.height || x_end < 0 || x_end >= bih.width || y_end < 0 || y_end >= bih.height || x_c < 0 || x_c >= bih.width || y_c < 0 || y_c >= bih.height){
- printf("Error in option -c/--copy\n");
- printf("Coordinates are out of bounds!\n");
- return;
- }
- int dx = x_end - x_st + 1;
- int dy = y_st - y_end + 1;
- if(x_c+dx-1 < 0 || x_c+dx-1 >= bih.width || y_c-dx-1 < 0 || y_c-dx-1 >= bih.height){
- printf("Area copying error\n");
- printf("Coordinates are out of bounds!\n");
- return;
- }
- /* Creating a buffer array of pixels */
- Rgb** buf_arr = malloc(dy*sizeof(Rgb*));
- for(int i = 0; i<dy; i++) {
- buf_arr[i] = malloc(dx * sizeof(Rgb));
- for(int j = 0; j<dx; j++){
- buf_arr[i][j].r = arr[y_st - i][x_st + j].r;
- buf_arr[i][j].g = arr[y_st - i][x_st + j].g;
- buf_arr[i][j].b = arr[y_st - i][x_st + j].b;
- }
- }
- /* Place the copied area in the resulting location */
- for(int i = 0; i<dy; i++){
- for(int j = 0; j<dx; j++){
- arr[y_c - i][x_c + j].r = buf_arr[i][j].r;
- arr[y_c - i][x_c + j].g = buf_arr[i][j].g;
- arr[y_c - i][x_c + j].b = buf_arr[i][j].b;
- }
- }
- for(int u = 0; u<dy; u++){
- free(buf_arr[u]);
- }
- free(buf_arr);
- }
- int main(int argc, char* argv[]) {
- struct Configs opts = {0, 0, 0, 0, 0, 0, 0, "", "output.bmp", 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- optsProcess(argc, argv, &opts);
- if (!strcmp(opts.name, "")) {
- puts("No file on input!\nPlease enter -h for more information");
- return 0;
- }
- if(opts.cfg_error_flag == 1){
- puts("Invalid input format!");
- return 0;
- }
- /* Validation of the file type being processed */
- if(strstr(opts.name, ".bmp") == NULL){
- puts("Invalid file format");
- return 0;
- }
- FILE *f = fopen(opts.name, "rb");
- if(f == NULL){
- puts("No such file!");
- return 0;
- }
- BitmapFileHeader bfh;
- BitmapInfoHeader bih;
- /* Reading file headers and pixel map */
- fread(&bfh, 1, sizeof(BitmapFileHeader), f);
- fread(&bih, 1, sizeof(BitmapInfoHeader), f);
- if(bih.headerSize != 40 || bih.bitsPerPixel != 24){
- puts("Invalid file version! Please use V3 version");
- return 0;
- }
- unsigned int H = bih.height;
- unsigned int W = bih.width;
- Rgb **arr = malloc(H * sizeof(Rgb *));
- int offset = (W * sizeof(Rgb)) % 4;
- offset = offset ? 4 - offset : 0;
- for (int i = 0; i < H; i++) {
- arr[i] = malloc(W * sizeof(Rgb) + offset);
- fread(arr[i], 1, W * sizeof(Rgb) + offset, f);
- }
- /* Opening the resulting file */
- FILE *ff = fopen(opts.output_name, "wb");
- /* Calling functions by option flags */
- if(opts.infoFlag == 1){
- printFileHeader(bfh);
- printInfoHeader(bih);
- }
- if(opts.rectangleFlag == 1){
- drawRectangle(arr, bih, opts);
- }
- if(opts.squarehexFlag == 1 || opts.circlehexFlag == 1){
- drawHexagon(arr, bih, opts);
- }
- if(opts.copyFlag == 1){
- copy(arr, bih, opts);
- }
- /* Writing headers and pixel maps to the resulting file */
- fwrite(&bfh, 1, sizeof(BitmapFileHeader), ff);
- fwrite(&bih, 1, sizeof(BitmapInfoHeader), ff);
- unsigned int w = (W) * sizeof(Rgb) + offset;
- for (int i = 0; i < H; i++) {
- fwrite(arr[i], 1, w, ff);
- }
- for (int i = 0; i < H; i++) {
- free(arr[i]);
- }
- free(arr);
- fclose(ff);
- fclose(f);
- return 0;
- }
Add Comment
Please, Sign In to add comment