#include /* using fopen, fprintf, fclose, fputs, perror */ #include /* using strcmp, memset */ #include /* using errno */ /** * Array of fixed size representing a pixel row */ typedef int image_line[10]; /** * Draws a horizontal line in the image * * \param line points to the pixel row that is to be filled * \param left offset of the line from the left border * \param length number of pixels in the line */ static void draw_horizontal_line(image_line* line, int left, int length) { int i; for(i = left; i < length; ++i) (*line)[i] = 1; } /** * Draws a vertical line in the image * * \param top_line points to the row in the image where the line starts * \param horizontal_offset distance of the line from the left border * \param length number of pixels in the line */ static void draw_vertical_line(image_line* top_line, int horizontal_offset, int length) { int i; for(i = 0; i < length; ++i) top_line[i][horizontal_offset] = 1; } /** * Draws a diagonal line in the image * * TODO: Use Bresenham's line algorithm * * \param top_line points to the row in the image where the line starts * \param horizontal_offset distance of the top point of the line from the * left border * \param length number of pixels in the line * \param slope direction of the diagonal. +1 is from top left to bottom right, * -1 is from top right to bottom left */ static void draw_diagonal_line(image_line* top_line, int horizontal_offset, int length, int slope) { int i; for(i = 0; i < length; ++i) { top_line[i][horizontal_offset] = 1; horizontal_offset += slope; } } static void draw_rectangle(image_line* pixels, int image_dimensions) { /* centered 8 x 4 rectangle */ const int vertical_size = 4; const int horizontal_size = 8; const int top = image_dimensions / 2 - vertical_size / 2; const int left = image_dimensions / 2 - horizontal_size / 2; draw_horizontal_line(pixels + top, left, horizontal_size + 1); draw_horizontal_line(pixels + top + vertical_size - 1, left, horizontal_size + 1); draw_vertical_line(pixels + top + 1, left, vertical_size - 2); draw_vertical_line(pixels + top + 1, left + horizontal_size - 1, vertical_size - 2); } static int print_image(image_line* pixels, int image_dimensions, const char* filename, const char* pattern_name) { int tmp_errno; FILE* output; if(! (output = fopen(filename, "w"))) goto err_rtrn; if(fprintf(output, "P1\n" "# This is a %1$s\n" "%2$d %2$d\n", pattern_name, image_dimensions) < 0) goto err_fclose; int i; for(i = 0; i < image_dimensions; ++i) { int j; for(j = 0; j < image_dimensions; ++j) { const int separator = j == image_dimensions - 1 ? '\n' : ' '; if(fprintf(output, "%d%c", pixels[i][j], separator) < 0) goto err_fclose; } } if(fclose(output)) goto err_rtrn; return 0; err_fclose: tmp_errno = errno; fclose(output); errno = tmp_errno; err_rtrn: return 1; } int main(int argc, char** argv) { if(argc != 3) goto err_usage; enum pattern_t { _INVALID_, RECTANGLE, TRIANGLE, CIRCLE, SQUARE }; static const char* const pattern_names[] = { "rectangle", "triangle", "circle", "square" }; const int pattern_n = sizeof(pattern_names) / sizeof(*pattern_names); const char* pattern_name = argv[1]; enum pattern_t pattern = _INVALID_; int i; for(i = 0; i < pattern_n; ++i) { if(! strcmp(pattern_name, pattern_names[i])) { pattern = i + 1; break; } } const int image_dimensions = 10; image_line pixels[10]; memset(pixels, 0, sizeof(pixels)); switch(pattern) { case _INVALID_: goto err_usage; case RECTANGLE: draw_rectangle(pixels, image_dimensions); break; case TRIANGLE: case CIRCLE: case SQUARE: default: goto err_unsupported; } if(print_image(pixels, image_dimensions, argv[2], pattern_name)) { perror("Saving image"); goto err_rtrn; } return 0; err_rtrn: return 1; err_unsupported: fputs("Operation not implemented, yet\n", stderr); return 2; err_usage: fprintf(stderr, "Usage: %s [rectangle|triangle|circle|square] OUTPUT.pbm\n", argv[0]); return 3; }