A C library for creating and drawing images using the PPM image format.
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}