#include <stdio.h>
#include <stdlib.h>
#include <math.h>

/*
 - Troy Muehlhausen
 - tjmuehlh
 - This program reads a text file and reads its content, converting that content
 - into generated "ASCII Art." It is capable of executing point, rectangle, line,
 - and fill commands.
*/

// Function to initialize the image with default color
void initImage(int width, int height, double image[width][height]) {
	for (int x = 0; x < width; x++) {
		for (int y = 0; y < height; y++) {
			image[x][y] = 0.0;
		}
	}
} 

// Function to print the image as ASCII art
void printImage(int width, int height, double image[width][height]) {
	// Top row border
	printf("+");
	for (int x = 0; x <width; x++) {
		printf("-");
	}
	printf("+\n");

	// Middle rows, including both image and right and left borders
	for (int y = 0; y < height; y++) {
		printf("|");
		for (int x = 0; x < width; x++) {
			char pixelChar;

			// Determine the character based on the color value
			double color = image[x][y];
			int range = (int)(color * 10);

			switch (range) {
				case 0: pixelChar = ' '; break;
				case 1: pixelChar = '.'; break;
				case 2: pixelChar = ':'; break;
				case 3: pixelChar = '-'; break;
				case 4: pixelChar = '='; break;
				case 5: pixelChar = '+'; break;
				case 6: pixelChar = '*'; break;
				case 7: pixelChar = '#'; break;
				case 8: pixelChar = '%'; break;
				default: pixelChar = '@'; break;
			}

			printf("%c", pixelChar);
		}
		printf("|\n");
	}

	// Bottom row border
	printf("+");
	for (int x = 0; x < width; x++) {
		printf("-");
	}
	printf("+\n");
}   

// Function to draw a point at the specified location with the specified color
void drawPoint(int width, int height, double image[width][height],
	       	int x, int y, double color) {
	if (x >= 0 && x < width && y >= 0 && y < height) { // Check bounds
		image[x][y] = color;
	}
}  

// Function to draw a filled rectangle
void drawRectangle(int width, int height, double image[width][height], 
		int left, int top, int rectangleWidth, int rectangleHeight, double color) {
	for (int x = left; x < left + rectangleWidth; x++) {
		for (int y = top; y < top + rectangleHeight; y++) {
			drawPoint(width, height, image, x, y, color); // Checking for bounds is done within drawPoint already
		}
	}
} 

// Function to draw a line using DDA algorithm
void drawLine(int width, int height, double image[width][height],
	       	int x1, int y1, int x2, int y2, double color) {
	int dx = abs(x2 - x1);
	int dy = abs(y2 - y1);
	int steps = dx > dy ? dx : dy;
	
	// I like to think of this as finding the slope of the line function (i.e. 1/4x is a line where 1/4 is the slope)
	double xIncrement = (double)(x2 - x1) / steps;
	double yIncrement = (double)(y2 - y1) / steps;

	double x = x1;
	double y = y1;

	// Incrementing by the "slope" we found earlier between pixels results in a pretty convincing line!
	// (i.e. moving across 1 and up 4 for last example)
	for (int i = 0; i <= steps; i++) {
		drawPoint(width, height, image, round(x), round(y), color);
		x += xIncrement;
		y += yIncrement;
	}
}

// Function to calculate image statistics
void getImageStats(int width, int height, double image[width][height],
	       	double *minColor, double *maxColor, double *avgColor) {
	*minColor = 1.0; // Initialize minColor to maximum value
	*maxColor = 0.0; // Initialize maxColor to minimum value
	double totalColor = 0.0;

	for (int x = 0; x < width; x++) {
		for (int y = 0; y < height; y++) {
			double color = image[x][y];
			totalColor += color;

			if (color < *minColor) {
				*minColor = color;
			}

			if (color > *maxColor) {
				*maxColor = color;
			}
		}
	}

	*avgColor = totalColor / (width * height);
}   

// Function to "flood fill" an area
void floodFill(int width, int height, double image[width][height], int x, int y, double color) {
	if (x < 0 || x >= width || y < 0 || y >= height) {
		return; // Outside the image bounds
	}

	if (image[x][y] >= color) {
		return; // Stop if the current pixel is darker or equal to the fill color
	}

	image[x][y] = color; // Fill the current pixel

	// Recursive flood fill in all four directions
	floodFill(width, height, image, x + 1, y, color);
	floodFill(width, height, image, x - 1, y, color);
	floodFill(width, height, image, x, y + 1, color);
	floodFill(width, height, image, x, y - 1, color);
}  

// Print the resulting greyscale image as ASCII art.
int main(void)
{
    // Read in the size of the drawing canvas
    int width = 0;
    int height = 0;
    
    // Read the width and height
    int result = scanf("%d %d", &width, &height);
        
    // Program only supports images that are 1x1 or bigger
    if ((width <= 0) || (height <= 0) || (result != 2))
    {
        printf("Failed to read a valid width and height from standard input!\n");
        return 0;
    }
    
    // Create the 2D array and initialize all the greyscale values to 0.0
    double image[width][height];
    initImage(width, height, image);
    
    char command = '\0';
    double color = 0.0;
    
    // Keep reading in drawing commands until we reach the end of the input
    while (scanf(" %c", &command) == 1) {
        switch (command) {
            case 'p': {
                // Draw a point, read in: x, y, color
                int x = 0;
                int y = 0;
				// Read point parameters
                result = scanf("%d %d %lf", &x, &y, &color);

                if (result != 3) {
                    printf("Invalid point command!\n");
                    return 0;
                }

                drawPoint(width, height, image, x, y, color);
                break;
            }

            case 'r': {
                // Draw a rectangle, read in: x, y, w, h, color
                int left = 0;
                int top = 0;
                int rectangleWidth = 0;
                int rectangleHeight = 0;
				// Read rectangle parameters
                result = scanf("%d %d %d %d %lf", &left, &top, &rectangleWidth, &rectangleHeight, &color);

                if (result != 5) {
                    printf("Invalid rectangle command!\n");
                    return 0;
                }
                
                drawRectangle(width, height, image, left, top, rectangleWidth, rectangleHeight, color);
                break;
            }
		      
            case 'l': {
                // Draw a line, read in x1, y1, x2, y2, color
                int x1 = 0; 
                int y1 = 0;  
                int x2 = 0;   
                int y2 = 0;
	      		// Read line parameters	
                result = scanf("%d %d %d %d %lf", &x1, &y1, &x2, &y2, &color);

                if (result != 5) {
                    printf("Invalid line command!\n");
                    return 0;
                }

                drawLine(width, height, image, x1, y1, x2, y2, color);
                break;
            }

            case 'f': {
                // Flood fill a color in, read in: x, y, color
                int x = 0;
                int y = 0;
				// Read fill parameters
                result = scanf("%d %d %lf", &x, &y, &color);

                if (result != 3) {
                    printf("Invalid flood fill command!\n");
		    return 0;
                }
                
                floodFill(width, height, image, x, y, color);
                break;
            }

            default: {
                printf("Unknown command!\n");
                return 0;
            }
        }
    }
                            
    // Print the final image
    printImage(width, height, image);
    
    // Finally display some statistics about the image
    double minColor = 0.0;
    double maxColor = 0.0;
    double avgColor = 0.0;
    getImageStats(width, height, image, &minColor, &maxColor, &avgColor);
    printf("Color range [%.2f, %.2f], average %.4f\n", minColor, maxColor, avgColor);
}

Embed on website

To embed this project on your website, copy the following code and paste it into your website's HTML: