Skip to content

Instantly share code, notes, and snippets.

@Costava
Last active October 15, 2021 01:26
Show Gist options
  • Save Costava/4c85cce606d9d09c8161fdb12fe9a801 to your computer and use it in GitHub Desktop.
Save Costava/4c85cce606d9d09c8161fdb12fe9a801 to your computer and use it in GitHub Desktop.
Print to stdout a P6 .ppm image of a grid
/*
* 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