Last active
October 15, 2021 01:26
-
-
Save Costava/4c85cce606d9d09c8161fdb12fe9a801 to your computer and use it in GitHub Desktop.
Print to stdout a P6 .ppm image of a grid
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* output_grid_image.c | |
* | |
* Print to stdout a P6 .ppm image of a grid. | |
* Specify the sizing and color of the grid in the user-defined values section, | |
* then compile and run. | |
* Program returns 0 on success. | |
* 1 if error allocating memory or outputting to stdout. | |
* | |
* Example compilation: | |
* gcc output_grid_image.c -o output_grid_image -std=c99 -Wall -Wextra | |
* | |
* Example usage: | |
* ./output_grid_image > out.ppm | |
* | |
* Info on .ppm format: https://en.wikipedia.org/wiki/Netpbm | |
* | |
* License: | |
* | |
* BSD Zero Clause License | |
* | |
* Copyright (C) 2021 by Costava | |
* | |
* Permission to use, copy, modify, and/or distribute this software for any | |
* purpose with or without fee is hereby granted. | |
* | |
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY | |
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION | |
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN | |
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
*/ | |
/////////////////////////////////////////////////////////////////////////////// | |
/* INCLUDES */ | |
/////////////////////////////////////////////////////////////////////////////// | |
#include <stdint.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
/////////////////////////////////////////////////////////////////////////////// | |
/* USER-DEFINED VALUES */ | |
/////////////////////////////////////////////////////////////////////////////// | |
// Values are not validated by program. | |
// Size assumptions made in the program are commented with "Assume:" | |
// but in general: program may produce unexpected results if: | |
// (Number of pixels in image) * 3 is >= SIZE_MAX | |
/* Size of grid. */ | |
const size_t NUM_COLS = 6; | |
const size_t NUM_ROWS = 4; | |
/* Unit is pixels. */ | |
const size_t LINE_WIDTH_PX = 1; | |
const size_t CELL_WIDTH_PX = 4; | |
const size_t CELL_HEIGHT_PX = 2; | |
/* Cell color components. */ | |
const uint8_t CELL_R = 88; | |
const uint8_t CELL_G = 129; | |
const uint8_t CELL_B = 87; | |
/* Line color components. */ | |
const uint8_t LINE_R = 44; | |
const uint8_t LINE_G = 44; | |
const uint8_t LINE_B = 44; | |
/////////////////////////////////////////////////////////////////////////////// | |
/* NON-USER-DEFINED CONSTANTS */ | |
/////////////////////////////////////////////////////////////////////////////// | |
const size_t NUM_COLOR_COMPONENTS = 3; | |
const size_t IMAGE_WIDTH_PX = | |
(NUM_COLS * (LINE_WIDTH_PX + CELL_WIDTH_PX ) + LINE_WIDTH_PX); | |
const size_t IMAGE_HEIGHT_PX = | |
(NUM_ROWS * (LINE_WIDTH_PX + CELL_HEIGHT_PX) + LINE_WIDTH_PX); | |
const size_t NUM_PIXELS = (IMAGE_WIDTH_PX * IMAGE_HEIGHT_PX); | |
const size_t FRAMEBUF_LEN = (NUM_PIXELS * NUM_COLOR_COMPONENTS); | |
/////////////////////////////////////////////////////////////////////////////// | |
/* MAIN */ | |
/////////////////////////////////////////////////////////////////////////////// | |
int main(void) { | |
uint8_t *const framebuf = malloc(sizeof(framebuf[0]) * FRAMEBUF_LEN); | |
if (framebuf == NULL) { | |
return 1; | |
} | |
// Make all pixels the cell color. | |
{ | |
size_t i = 0; | |
// Assume: NUM_PIXELS < SIZE_MAX | |
for (size_t px = 0; px < NUM_PIXELS; px += 1) { | |
framebuf[i] = CELL_R; i += 1; | |
framebuf[i] = CELL_G; i += 1; | |
framebuf[i] = CELL_B; i += 1; | |
} | |
} | |
// Draw the horizontal borders. | |
// Assume: IMAGE_HEIGHT_PX < SIZE_MAX | |
// Assume: LINE_WIDTH_PX < SIZE_MAX | |
// Assume: IMAGE_WIDTH_PX < SIZE_MAX | |
{ | |
size_t i = 0; | |
for (size_t h = 0; h < IMAGE_HEIGHT_PX; | |
h += LINE_WIDTH_PX + CELL_HEIGHT_PX) | |
{ | |
for (size_t w = 0; w < LINE_WIDTH_PX; w += 1) { | |
for (size_t c = 0; c < IMAGE_WIDTH_PX; c += 1) { | |
framebuf[i] = LINE_R; i += 1; | |
framebuf[i] = LINE_G; i += 1; | |
framebuf[i] = LINE_B; i += 1; | |
} | |
} | |
i += CELL_HEIGHT_PX * IMAGE_WIDTH_PX * NUM_COLOR_COMPONENTS; | |
} | |
} | |
// Draw the vertical borders. | |
// Assume: IMAGE_HEIGHT_PX < SIZE_MAX | |
// Assume: IMAGE_WIDTH_PX < SIZE_MAX | |
// Assume: LINE_WIDTH_PX < SIZE_MAX | |
{ | |
size_t i = 0; | |
for (size_t h = 0; h < IMAGE_HEIGHT_PX; h += 1) { | |
for (size_t iw = 0; iw < IMAGE_WIDTH_PX; | |
iw += LINE_WIDTH_PX + CELL_WIDTH_PX) | |
{ | |
for (size_t lw = 0; lw < LINE_WIDTH_PX; lw += 1) { | |
framebuf[i] = LINE_R; i += 1; | |
framebuf[i] = LINE_G; i += 1; | |
framebuf[i] = LINE_B; i += 1; | |
} | |
i += CELL_WIDTH_PX * NUM_COLOR_COMPONENTS; | |
} | |
// We moved down to the next row of pixels. | |
// There is no cell to 'jump across' at the end of a row of pixels. | |
i -= CELL_WIDTH_PX * NUM_COLOR_COMPONENTS; | |
} | |
} | |
// Output the image file. | |
// Output the header. | |
if (printf("P6\n%zu %zu\n255\n", IMAGE_WIDTH_PX, IMAGE_HEIGHT_PX) < 0) { | |
return 1; | |
} | |
// Output the image data. | |
{ | |
const size_t num_written = | |
fwrite(framebuf, sizeof(framebuf[0]), FRAMEBUF_LEN, stdout); | |
if (num_written != FRAMEBUF_LEN) { | |
return 1; | |
} | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment