Advertisement
jcdkiki

Untitled

Apr 29th, 2024
47
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 16.95 KB | None | 0 0
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <getopt.h>
  4. #include <string.h>
  5. #include <limits.h>
  6.  
  7. #pragma pack(push, 1)
  8.  
  9. #define CW_OK 0
  10. #define CW_ERROR 40
  11.  
  12. enum {
  13.     EXCHANGE_UNKNOWN = -1,
  14.     EXCHANGE_CLOCKWISE = 0,
  15.     EXCHANGE_COUNTERCLOCKWISE,
  16.     EXCHANGE_DIAGONALS
  17. };
  18.  
  19. typedef struct {
  20.     unsigned short signature;
  21.     unsigned int filesize;
  22.     unsigned short reserved1;
  23.     unsigned short reserved2;
  24.     unsigned int data_offset;
  25. } bmpfile_header_t;
  26.  
  27. typedef struct {
  28.     unsigned int header_size;
  29.     unsigned int width;
  30.     unsigned int height;
  31.     unsigned short planes;
  32.     unsigned short bits_per_pixel;
  33.     unsigned int compression;
  34.     unsigned int image_size;
  35.     unsigned int xresolution;
  36.     unsigned int yresolution;
  37.     unsigned int n_colors;
  38.     unsigned int n_important_colors;
  39. } bmpfile_info_t;
  40.  
  41. typedef struct {
  42.     unsigned char b;
  43.     unsigned char g;
  44.     unsigned char r;
  45. } rgb_t;
  46.  
  47. #pragma pack(pop)
  48.  
  49. typedef struct {
  50.     int x, y;
  51. } point_t;
  52.  
  53. typedef struct {
  54.     bmpfile_header_t header;
  55.     bmpfile_info_t   info;
  56.     rgb_t**          data;
  57. } bmp_t;
  58.  
  59. int load_bmp(bmp_t *bmp, char *filename)
  60. {
  61.     FILE *fp = fopen(filename, "rb");
  62.     if (fp == NULL) {
  63.         fputs("Cannot open input file\n", stderr);
  64.         return CW_ERROR;
  65.     }
  66.  
  67.     fread(&bmp->header, 1, sizeof(bmpfile_header_t), fp);
  68.     fread(&bmp->info, 1, sizeof(bmpfile_info_t), fp);
  69.  
  70.     if (bmp->header.signature!= 0x4D42) {
  71.         fputs("Invalid file signature\n", stderr);
  72.         fclose(fp);
  73.         return CW_ERROR;
  74.     }
  75.  
  76.     if (bmp->info.bits_per_pixel != 24 || bmp->info.compression != 0 || bmp->info.planes != 1) {
  77.         fputs("Unsupported BMP format\n", stderr);
  78.         fclose(fp);
  79.         return CW_ERROR;
  80.     }
  81.  
  82.     bmp->data = (rgb_t**)malloc(bmp->info.height * sizeof(rgb_t*));
  83.     if (bmp->data == NULL) {
  84.         fputs("Memory allocation error\n", stderr);
  85.         fclose(fp);
  86.         return CW_ERROR;
  87.     }
  88.  
  89.     size_t padding = (4 - (sizeof(bmp_t) * bmp->info.width) % 4) % 4;
  90.    
  91.     for (int i = bmp->info.height - 1; i >= 0; i--) {
  92.         bmp->data[i] = (rgb_t*)malloc(bmp->info.width * sizeof(rgb_t));
  93.         if (bmp->data[i] == NULL) {
  94.             fputs("Memory allocation error\n", stderr);
  95.             fclose(fp);
  96.  
  97.             for (size_t j = bmp->info.height - 1; j > i; j--)
  98.                 free(bmp->data[j]);
  99.             free(bmp->data);
  100.             return CW_ERROR;
  101.         }
  102.  
  103.         fread(bmp->data[i], 1, bmp->info.width * sizeof(rgb_t), fp);
  104.         fseek(fp, padding, SEEK_CUR);
  105.     }
  106.  
  107.     fclose(fp);
  108.     return CW_OK;
  109. }
  110.  
  111. int save_bmp(bmp_t *bmp, char *filename)
  112. {
  113.     FILE *fp = fopen(filename, "wb");
  114.     if (fp == NULL) {
  115.         fputs("Cannot open output file\n", stderr);
  116.         return CW_ERROR;
  117.     }
  118.  
  119.     fwrite(&bmp->header, 1, sizeof(bmpfile_header_t), fp);
  120.     fwrite(&bmp->info, 1, sizeof(bmpfile_info_t), fp);
  121.     fseek(fp, bmp->header.data_offset, SEEK_SET);
  122.  
  123.     size_t padding = (4 - (4 * bmp->info.width) % 4) % 4;
  124.     for (int i = bmp->info.height - 1; i >= 0; i--) {
  125.         fwrite(bmp->data[i], 1, bmp->info.width * sizeof(rgb_t), fp);
  126.         fseek(fp, padding, SEEK_CUR);
  127.     }
  128.  
  129.     fclose(fp);
  130.     return CW_OK;
  131. }
  132.  
  133. void free_bmp(bmp_t *bmp)
  134. {
  135.     for (size_t i = 0; i < bmp->info.height; i++) {
  136.         free(bmp->data[i]);
  137.     }
  138.     free(bmp->data);
  139. }
  140.  
  141. const char shortopts[] = "hil:s:t:c:fF:r:x:I:O:";
  142.  
  143. enum {
  144.     FUNCTION_SQUARE = 1,
  145.     FUNCTION_EXCHANGE,
  146.     FUNCTION_FREQ_COLOR
  147. };
  148.  
  149. struct option longopts[] = {
  150.     { "help", 0, NULL, 'h' },
  151.     { "info", 0, NULL, 'i' },
  152.     { "square", 0, NULL, FUNCTION_SQUARE },
  153.     { "exchange", 0, NULL, FUNCTION_EXCHANGE },
  154.     { "freq_color", 0, NULL, FUNCTION_FREQ_COLOR },
  155.  
  156.     { "left_up", 1, NULL, 'l' },
  157.     { "side_size", 1, NULL,'s' },
  158.     { "thickness", 1, NULL, 't' },
  159.     { "color", 1, NULL, 'c'},
  160.     { "fill", 0, NULL, 'f' },
  161.     { "fill_color", 1, NULL, 'F' },
  162.  
  163.     { "right_down", 1, NULL, 'r' },
  164.     { "exchange_type", 1, NULL, 'x' },
  165.  
  166.     { "input", 1, NULL, 'I' },
  167.     { "output", 1, NULL, 'O' },
  168.  
  169.     { NULL, 0, NULL, 0 }
  170. };
  171.  
  172. typedef struct {
  173.     point_t left_up;
  174.     int side_size;
  175.     int thickness;
  176.     rgb_t color;
  177.     char is_color_set;
  178.     char fill;
  179.     rgb_t fill_color;
  180.     char is_fill_color_set;
  181.     point_t right_down;
  182.     int exchange_type;
  183.     char *input;
  184.     char *output;
  185. } args_t;
  186.  
  187. void init_args(args_t *args)
  188. {
  189.     args->left_up = (point_t) { INT_MAX, INT_MAX };
  190.     args->side_size = INT_MAX;
  191.     args->thickness = INT_MAX;
  192.     args->color = (rgb_t) { 0, 0, 0 };
  193.     args->is_color_set = 0;
  194.     args->fill = 0;
  195.     args->right_down = (point_t) { INT_MAX, INT_MAX };
  196.     args->exchange_type = EXCHANGE_UNKNOWN;
  197.     args->input = NULL;
  198.     args->output = "out.bmp";
  199. }
  200.  
  201. int read_color(rgb_t *rgb, char *str)
  202. {
  203.     int r, g, b;
  204.     int n = sscanf(str, "%d.%d.%d", &r, &g, &b);
  205.  
  206.     if (n != 3) {
  207.         fputs("Invalid color format\n", stderr);
  208.         return CW_ERROR;
  209.     }
  210.  
  211.     if (r < 0 || g < 0 || b < 0 || r > 255 || g > 255 || b > 255) {
  212.         fputs("Invalid color value\n", stderr);
  213.         return CW_ERROR;
  214.     }
  215.  
  216.     rgb->r = r;
  217.     rgb->g = g;
  218.     rgb->b = b;
  219.     return CW_OK;
  220. }
  221.  
  222. int read_int(int *val, char *str)
  223. {
  224.     int n = sscanf(str, "%d", val);
  225.  
  226.     if (n != 1) {
  227.         fputs("Invalid integer\n", stderr);
  228.         return CW_ERROR;
  229.     }
  230.  
  231.     return CW_OK;
  232. }
  233.  
  234. int read_point(point_t *pt, char *str)
  235. {
  236.     int n = sscanf(str, "%d.%d", &pt->x, &pt->y);
  237.    
  238.     if (n!= 2) {
  239.         fputs("Invalid point format\n", stderr);
  240.         return CW_ERROR;
  241.     }
  242.  
  243.     return CW_OK;
  244. }
  245.  
  246. int read_exchange_type(int *exchange_type, char *str)
  247. {
  248.     if (strcmp(str, "clockwise") == 0) {
  249.         *exchange_type = EXCHANGE_CLOCKWISE;
  250.         return CW_OK;
  251.     }
  252.     if (strcmp(str, "counterclockwise") == 0) {
  253.         *exchange_type = EXCHANGE_COUNTERCLOCKWISE;
  254.         return CW_OK;
  255.     }
  256.     if (strcmp(str, "diagonals") == 0) {
  257.         *exchange_type = EXCHANGE_DIAGONALS;
  258.         return CW_OK;
  259.     }
  260.  
  261.     fputs("Invalid exchange type\n", stderr);
  262.     return CW_ERROR;  
  263. }
  264.  
  265. void print_help()
  266. {
  267.     puts(
  268.         "./cw <function> [options]\n"
  269.         "Functions:\n"
  270.         " -h, --help\n"
  271.         " -i, --info     print info about image\n"
  272.         " --square       draw square\n"
  273.         " --exchange     exchange four pieces of the image\n"
  274.         " --freq_color   replace most frequent color\n"
  275.         "Options:\n"
  276.         " -I, --input <file>\n"
  277.         " -O, --output <file>\n"
  278.         "Options for square:\n"
  279.         " -l, --left_up X.Y\n"
  280.         " -s, --side_size X\n"
  281.         " -t, --thickness X\n"
  282.         " -c, --color R.G.B\n"
  283.         " -f, --fill (flag to fill the square)\n"
  284.         " -F, --fill_color R.G.B\n"
  285.         "Options for exchange:\n"
  286.         "  -e, --exchange_type (clockwise, counterclockwise, diagonals)\n"
  287.         "  -l, --left_up X.Y\n"
  288.         "  -r, --right_down X.Y\n"
  289.         "Options for freq_color:\n"
  290.         "  -c, --color R.G.B"
  291.     );
  292. }
  293.  
  294. rgb_t get_pixel(bmp_t *bmp, int x, int y)
  295. {
  296.     if (x < 0 || y < 0 || x >= (int)bmp->info.width || y >= (int)bmp->info.height) {
  297.         return (rgb_t) { 0, 0, 0 };
  298.     }
  299.     return bmp->data[y][x];
  300. }
  301.  
  302. rgb_t set_pixel(bmp_t *bmp, int x, int y, rgb_t rgb)
  303. {
  304.     if (x < 0 || y < 0 || x >= (int)bmp->info.width || y >= (int)bmp->info.height) {
  305.         return (rgb_t) { 0, 0, 0 };
  306.     }
  307.     bmp->data[y][x] = rgb;
  308. }
  309.  
  310. int print_image_info_option(bmp_t *bmp)
  311. {
  312.     printf("Width: %d\n", (int)bmp->info.width);
  313.     printf("Height: %d\n", (int)bmp->info.height);
  314.     printf("Planes: %d\n", (int)bmp->info.planes);
  315.     printf("Bits per pixel: %d\n", (int)bmp->info.bits_per_pixel);
  316.     printf("Compression: %d\n", (int)bmp->info.compression);
  317.     printf("Image size: %d\n", (int)bmp->info.image_size);
  318.     printf("X resolution: %d\n", (int)bmp->info.xresolution);
  319.     printf("Y resolution: %d\n", (int)bmp->info.yresolution);
  320.     printf("Number of colors: %d\n", (int)bmp->info.n_colors);
  321.     printf("Number of important colors: %d\n", (int)bmp->info.n_important_colors);
  322.  
  323.     return CW_OK;
  324. }
  325.  
  326. int draw_square_option(bmp_t *bmp, args_t *args)
  327. {
  328.     if (args->left_up.x == INT_MAX && args->left_up.y == INT_MAX) {
  329.         fputs("Left up corner not specified\n", stderr);
  330.         return CW_ERROR;
  331.     }
  332.     if (args->side_size == INT_MAX) {
  333.         fputs("Side size not specified\n", stderr);
  334.         return CW_ERROR;
  335.     }
  336.     if (args->thickness == INT_MAX) {
  337.         fputs("Thickness not specified\n", stderr);
  338.         return CW_ERROR;
  339.     }
  340.     if (args->is_color_set == 0) {
  341.         fputs("Color not specified\n", stderr);
  342.         return CW_ERROR;
  343.     }
  344.     if (args->fill == 1 && args->is_fill_color_set == 0) {
  345.         fputs("Fill color not specified\n", stderr);
  346.         return CW_ERROR;
  347.     }
  348.  
  349.     int x0 = args->left_up.x;
  350.     int y0 = args->left_up.y;
  351.     int x1 = args->left_up.x + args->side_size;
  352.     int y1 = args->left_up.y + args->side_size;
  353.  
  354.     args->thickness = (args->thickness + 1) / 2;
  355.  
  356.     if (args->fill) {
  357.         int fx0 = (x0 < 0) ? 0 : x0;
  358.         int fy0 = (y0 < 0) ? 0 : y0;
  359.         int fx1 = (x1 > bmp->info.width) ? bmp->info.width : x1;
  360.         int fy1 = (y1 > bmp->info.height)? bmp->info.height : y1;
  361.  
  362.         for (int x = fx0; x < fx1; x++) {
  363.             for (int y = fy0; y < fy1; y++) {
  364.                 set_pixel(bmp, x, y, args->fill_color);
  365.             }
  366.         }
  367.     }
  368.  
  369.     for (int s = -args->thickness+1; s < args->side_size + args->thickness; s++) {
  370.         for (int t = 0; t < args->thickness; t++) {
  371.             set_pixel(bmp, x0 + s, y0 + t, args->color);
  372.             set_pixel(bmp, x0 + s, y0 - t, args->color);
  373.             set_pixel(bmp, x0 + t, y0 + s, args->color);
  374.             set_pixel(bmp, x0 - t, y0 + s, args->color);
  375.             set_pixel(bmp, x0 + s, y1 + t, args->color);
  376.             set_pixel(bmp, x0 + s, y1 - t, args->color);
  377.             set_pixel(bmp, x1 + t, y0 + s, args->color);
  378.             set_pixel(bmp, x1 - t, y0 + s, args->color);
  379.         }
  380.     }
  381.  
  382.     return CW_OK;
  383. }
  384.  
  385. void swap_regions(bmp_t *bmp, int x0, int y0, int x1, int y1, int dx, int dy)
  386. {
  387.     for (int x = 0; x < dx; x++) {
  388.         for (int y = 0; y < dy; y++) {
  389.             rgb_t tmp = get_pixel(bmp, x0 + x, y0 + y);
  390.             set_pixel(bmp, x0 + x, y0 + y, get_pixel(bmp, x1 + x, y1 + y));
  391.             set_pixel(bmp, x1 + x, y1 + y, tmp);
  392.         }
  393.     }
  394. }
  395.  
  396. int exchange_opion(bmp_t *bmp, args_t *args)
  397. {
  398.     if (args->exchange_type == EXCHANGE_UNKNOWN) {
  399.         fputs("Exchange type is not specified\n", stderr);
  400.         return CW_ERROR;
  401.     }
  402.     if (args->left_up.x == INT_MAX && args->left_up.y == INT_MAX) {
  403.         fputs("Left up point is not specified\n", stderr);
  404.         return CW_ERROR;
  405.     }
  406.     if (args->right_down.x == INT_MAX && args->right_down.y == INT_MAX) {
  407.         fputs("Right down point is not specified\n", stderr);
  408.         return CW_ERROR;
  409.     }
  410.  
  411.     int x0 = args->left_up.x;
  412.     int y0 = args->left_up.y;
  413.     int x1 = args->right_down.x;
  414.     int y1 = args->right_down.y;
  415.     int dx = (x1 - x0) / 2;
  416.     int dy = (y1 - y0) / 2;
  417.  
  418.     if (args->exchange_type == EXCHANGE_DIAGONALS) {
  419.         swap_regions(bmp, x0, y0, x0 + dx, y0 + dx, dx, dy);
  420.         swap_regions(bmp, x0 + dx, y0, x0, y0 + dx, dx, dy);    
  421.     }
  422.     else if (args->exchange_type == EXCHANGE_CLOCKWISE) {
  423.         swap_regions(bmp, x0, y0, x0, y0 + dy, dx, dy);
  424.         swap_regions(bmp, x0 + dx, y0, x0, y0 + dy, dx, dy);
  425.         swap_regions(bmp, x0 + dx, y0 + dy, x0, y0 + dy, dx, dy);
  426.     }
  427.     else {
  428.         swap_regions(bmp, x0, y0, x0 + dx, y0, dx, dy);
  429.         swap_regions(bmp, x0 + dx, y0, x0 + dx, y0 + dy, dx, dy);
  430.         swap_regions(bmp, x0 + dx, y0 + dy, x0, y0 + dy, dx, dy);
  431.     }
  432.  
  433.     return CW_OK;
  434. }
  435.  
  436. typedef struct {
  437.     rgb_t color;
  438.     size_t freq;
  439. } colorinfo_t;
  440.  
  441. #define BASE_CAPACITY 8
  442.  
  443. int find_color(colorinfo_t *colors, size_t size, rgb_t color)
  444. {
  445.     for (size_t i = 0; i < size; i++) {
  446.         if (colors[i].color.r == color.r &&
  447.             colors[i].color.g == color.g &&
  448.             colors[i].color.b == color.b) {
  449.             return i;
  450.         }
  451.     }
  452.     return -1;
  453. }
  454.  
  455. int freq_color_option(bmp_t *bmp, args_t *args)
  456. {
  457.     if (!args->is_color_set) {
  458.         fputs("Color is not specified\n", stderr);
  459.         return CW_ERROR;
  460.     }
  461.  
  462.     colorinfo_t *colors = malloc(sizeof(colorinfo_t) * BASE_CAPACITY);
  463.     if (colors == NULL) {
  464.         fputs("Memory allocation failed\n", stderr);
  465.         return CW_ERROR;
  466.     }
  467.  
  468.     size_t capacity = BASE_CAPACITY;
  469.     size_t size = 0;
  470.  
  471.     for (int y = 0; y < bmp->info.height; y++) {
  472.         for (int x = 0; x < bmp->info.width; x++) {
  473.             int index = find_color(colors, size, bmp->data[y][x]);
  474.             if (index < 0) {
  475.                 if (size == capacity) {
  476.                     capacity *= 2;
  477.                     colors = realloc(colors, sizeof(colorinfo_t) * capacity);
  478.                     if (colors == NULL) {
  479.                         fputs("Memory allocation failed\n", stderr);
  480.                         return CW_ERROR;
  481.                     }
  482.                 }
  483.                 colors[size].color = bmp->data[y][x];
  484.                 colors[size].freq = 1;
  485.                 size++;
  486.             }
  487.             else {
  488.                 colors[index].freq++;
  489.             }
  490.         }
  491.     }
  492.  
  493.     int best_i = 0;
  494.     for (size_t i = 0; i < size; i++) {
  495.         if (colors[i].freq > colors[best_i].freq)
  496.             best_i = i;
  497.     }
  498.  
  499.     rgb_t color = colors[best_i].color;
  500.     for (int y = 0; y < bmp->info.height; y++) {
  501.         for (int x = 0; x < bmp->info.width; x++) {
  502.             if (bmp->data[y][x].r == color.r &&
  503.                 bmp->data[y][x].g == color.g &&
  504.                 bmp->data[y][x].b == color.b) {
  505.                 bmp->data[y][x] = args->color;
  506.             }
  507.         }
  508.     }
  509.  
  510.     free(colors);
  511.     return CW_OK;
  512. }
  513.  
  514. int main(int argc, char **argv)
  515. {
  516.     puts("Course work for option 4.4, created by Kulach Daniil");
  517.  
  518.     args_t args;
  519.     int function = '\0';
  520.  
  521.     init_args(&args);
  522.  
  523.     int opt = getopt_long(argc, argv, shortopts, longopts, NULL);
  524.     while (opt!= -1) {
  525.         if (opt == '?') {
  526.             fputs("Invalid option\n", stderr);
  527.             return CW_ERROR;
  528.         }
  529.  
  530.         int ret = CW_OK;
  531.         switch (opt) {
  532.             case 'h':
  533.                 print_help();
  534.                 return CW_OK;
  535.             case 'i':
  536.             case FUNCTION_SQUARE:
  537.             case FUNCTION_EXCHANGE:
  538.             case FUNCTION_FREQ_COLOR:
  539.                 function = opt;
  540.                 break;
  541.             case 'l':
  542.                 ret = read_point(&args.left_up, optarg);
  543.                 break;
  544.             case 's':
  545.                 ret = read_int(&args.side_size, optarg);
  546.                 break;
  547.             case 't':
  548.                 ret = read_int(&args.thickness, optarg);
  549.                 break;
  550.             case 'c':
  551.                 ret = read_color(&args.color, optarg);
  552.                 args.is_color_set = 1;
  553.                 break;
  554.             case 'f':
  555.                 args.fill = 1;
  556.                 break;
  557.             case 'F':
  558.                 ret = read_color(&args.fill_color, optarg);
  559.                 args.is_fill_color_set = 1;
  560.             case 'r':
  561.                 ret = read_point(&args.right_down, optarg);
  562.                 break;
  563.             case 'x':
  564.                 ret = read_exchange_type(&args.exchange_type, optarg);
  565.                 break;
  566.             case 'I':
  567.                 args.input = optarg;
  568.                 break;
  569.             case 'O':
  570.                 args.output = optarg;
  571.                 break;
  572.         }
  573.  
  574.         if (ret != CW_OK) {
  575.             return CW_ERROR;
  576.         }
  577.  
  578.         opt = getopt_long(argc, argv, shortopts, longopts, NULL);
  579.     }
  580.  
  581.     if (function == '\0') {
  582.         fputs("No function specified\n", stderr);
  583.         return CW_ERROR;
  584.     }
  585.  
  586.     if (args.input == NULL) {
  587.         if (optind >= argc) {
  588.             fputs("No image specified\n", stderr);
  589.             return CW_ERROR;
  590.         }
  591.         args.input = argv[optind];
  592.     }
  593.  
  594.     bmp_t bmp;
  595.     if (load_bmp(&bmp, args.input) != CW_OK) {
  596.         return CW_ERROR;
  597.     }
  598.  
  599.     int ret = CW_OK;
  600.     switch (function) {
  601.         case 'i':
  602.             ret = print_image_info_option(&bmp);
  603.             break;
  604.         case FUNCTION_SQUARE:
  605.             ret = draw_square_option(&bmp, &args);
  606.             break;
  607.         case FUNCTION_EXCHANGE:
  608.             ret = exchange_opion(&bmp, &args);
  609.             break;
  610.         case FUNCTION_FREQ_COLOR:
  611.             ret = freq_color_option(&bmp, &args);
  612.             break;
  613.     }
  614.  
  615.     if (ret != CW_OK) {
  616.         free_bmp(&bmp);
  617.         return CW_ERROR;
  618.     }
  619.  
  620.     if (function != 'i') {
  621.         int ret = save_bmp(&bmp, args.output);
  622.         if (ret != CW_OK) {
  623.             return CW_ERROR;
  624.         }
  625.     }
  626.  
  627.     free_bmp(&bmp);
  628. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement