#include <stdio.h>
/* using fopen, fprintf, fclose, fputs, perror */
#include <string.h>
/* using strcmp, memset */
#include <errno.h>
/* 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;
}
Comments