A C library for creating and drawing images using the PPM image format.
at main 4.7 kB view raw
1#include "ppm.h" 2#include <inttypes.h> 3#include <math.h> 4#include <stdint.h> 5#include <stdio.h> 6#include <stdlib.h> 7 8ppm_image *ppm_create(uint64_t height, uint64_t width) { 9 return ppm_create_with_background_color(height, width, PPM_BLACK); 10} 11 12ppm_image *ppm_create_with_background_color(uint64_t height, uint64_t width, 13 ppm_rgb background_color) { 14 ppm_image *image = (ppm_image *)malloc(sizeof(ppm_image)); 15 image->height = height; 16 image->width = width; 17 18 ppm_rgb *data = (ppm_rgb *)malloc(sizeof(ppm_rgb) * width * height); 19 20 for (uint64_t y = 0; y < height; y++) { 21 for (uint64_t x = 0; x < width; x++) { 22 uint64_t position = (y * width) + x; 23 24 data[position] = background_color; 25 } 26 } 27 28 image->data = data; 29 30 return image; 31} 32 33int ppm_destroy(ppm_image *image) { 34 free(image->data); 35 free(image); 36 37 return EXIT_SUCCESS; 38} 39 40int ppm_is_in_bounds(ppm_image *image, uint64_t x, uint64_t y) { 41 if (x <= 0) 42 return EXIT_FAILURE; 43 44 if (x > image->width) 45 return EXIT_FAILURE; 46 47 if (y <= 0) 48 return EXIT_FAILURE; 49 50 if (y > image->height) 51 return EXIT_FAILURE; 52 53 return EXIT_SUCCESS; 54} 55 56int ppm_to_ppm3_file(ppm_image *image, const char *file_path) { 57 FILE *file = fopen(file_path, "w"); 58 59 fprintf(file, "P3\n"); 60 fprintf(file, "%" PRIu64 " %" PRIu64 "\n", image->height, image->width); 61 fprintf(file, "255\n"); 62 63 for (uint64_t y = 0; y < image->height; y++) { 64 for (uint64_t x = 0; x < image->width; x++) { 65 uint64_t position = (y * image->width) + x; 66 67 ppm_rgb rgb = image->data[position]; 68 fprintf(file, "%" PRIu8 " %" PRIu8 " %" PRIu8, rgb.r, rgb.g, rgb.b); 69 70 if (x != image->width - 1) { 71 fprintf(file, " "); 72 } 73 } 74 75 if (y != image->height - 1) { 76 fprintf(file, "\n"); 77 } 78 } 79 80 fclose(file); 81 82 return EXIT_SUCCESS; 83} 84 85int ppm_to_ppm6_file(ppm_image *image, const char *file_path) { 86 FILE *file = fopen(file_path, "w"); 87 88 fprintf(file, "P6\n"); 89 fprintf(file, "%" PRIu64 " %" PRIu64 "\n", image->height, image->width); 90 fprintf(file, "255\n"); 91 92 for (uint64_t y = 0; y < image->height; y++) { 93 for (uint64_t x = 0; x < image->width; x++) { 94 uint64_t position = (y * image->width) + x; 95 96 ppm_rgb rgb = image->data[position]; 97 fprintf(file, "%c%c%c", rgb.r, rgb.g, rgb.b); 98 } 99 } 100 101 fclose(file); 102 103 return EXIT_SUCCESS; 104} 105 106int ppm_draw_point(ppm_image *image, uint64_t x, uint64_t y, ppm_rgb color) { 107 if (ppm_is_in_bounds(image, x, y) == EXIT_FAILURE) 108 return EXIT_FAILURE; 109 110 uint64_t position = ((y - 1) * image->width) + x - 1; 111 112 image->data[position] = color; 113 114 return EXIT_SUCCESS; 115} 116 117int ppm_draw_circle(ppm_image *image, int x, int y, uint64_t radius, 118 ppm_rgb color) { 119 for (int local_y = 0; local_y <= radius * 2; local_y++) { 120 for (int local_x = 0; local_x <= radius * 2; local_x++) { 121 int local_centered_x = local_x - radius; 122 int local_centered_y = local_y - radius; 123 124 uint64_t length = sqrt((local_centered_x * local_centered_x) + 125 (local_centered_y * local_centered_y)); 126 127 if (length > radius) 128 continue; 129 130 uint64_t global_x = local_x + x - radius; 131 uint64_t global_y = local_y + y - radius; 132 133 ppm_draw_point(image, global_x, global_y, color); 134 } 135 } 136 137 return EXIT_SUCCESS; 138} 139 140int ppm_draw_rectangle(ppm_image *image, int x, int y, uint64_t height, 141 uint64_t width, ppm_rgb color) { 142 for (int local_y = 0; local_y <= height; local_y++) { 143 for (int local_x = 0; local_x <= width; local_x++) { 144 145 uint64_t global_x = local_x + x; 146 uint64_t global_y = local_y + y; 147 148 ppm_draw_point(image, global_x, global_y, color); 149 } 150 } 151 152 return EXIT_SUCCESS; 153} 154 155/** 156 * Draw a line using Bresenham's line algorithm. 157 */ 158int ppm_draw_line(ppm_image *image, int x1, int y1, int x2, int y2, 159 ppm_rgb color) { 160 161 int dx = x2 - x1; 162 int dy = y2 - y1; 163 164 int d = 2 * dy - dx; 165 166 int y = y1; 167 168 for (int x = x1; x < x2; x++) { 169 ppm_draw_point(image, x, y, color); 170 171 if (d > 0) { 172 y++; 173 d -= 2 * dx; 174 } 175 176 d += 2 * dy; 177 } 178 179 return EXIT_SUCCESS; 180} 181 182int ppm_clear(ppm_image *image) { 183 ppm_clear_with_background_color(image, PPM_BLACK); 184 185 return EXIT_SUCCESS; 186} 187 188int ppm_clear_with_background_color(ppm_image *image, 189 ppm_rgb background_color) { 190 for (uint64_t y = 0; y < image->height; y++) { 191 for (uint64_t x = 0; x < image->width; x++) { 192 uint64_t position = (y * image->width) + x; 193 194 image->data[position] = background_color; 195 } 196 } 197 198 return EXIT_SUCCESS; 199}