1#include <stdio.h>
2#include <stdlib.h>
3#include <math.h>
4#include <time.h>
5#include <string.h>
6
7typedef struct {
8 int width;
9 int height;
10 unsigned char *data;
11} Ppm;
12
13void
14rotate_image(Ppm *src, Ppm *dst, double degrees)
15{
16 double radians = degrees * (3.1415926 / 180.0);
17 double cos_t = cos(radians);
18 double sin_t = sin(radians);
19 int cx = src->width / 2;
20 int cy = src->height / 2;
21 int dst_y, dst_x;
22 int dx, dy, src_x, src_y, dst_idx;
23
24 for (dst_y = 0; dst_y < dst->height; dst_y++) {
25 for (dst_x = 0; dst_x < dst->width; dst_x++) {
26
27 /* make the center be 0,0 */
28 dx = dst_x - cx;
29 dy = dst_y - cy;
30
31 /* calulate rotation */
32 src_x = (int)floor(dx * cos_t + dy * sin_t + 0.5) + cx;
33 src_y = (int)floor(-dx * sin_t + dy * cos_t + 0.5) + cy;
34
35 /* 2d image to 1d array */
36 dst_idx = (dst_y * dst->width + dst_x) * 3;
37
38 if (src_x >= 0 && src_x < src->width &&
39 src_y >= 0 && src_y < src->height) {
40
41 int src_idx = (src_y * src->width + src_x) * 3;
42
43 dst->data[dst_idx] = src->data[src_idx];
44 dst->data[dst_idx + 1] = src->data[src_idx + 1];
45 dst->data[dst_idx + 2] = src->data[src_idx + 2];
46
47 } else {
48 dst->data[dst_idx] = 255;
49 dst->data[dst_idx + 1] = 255;
50 dst->data[dst_idx + 2] = 255;
51 }
52 }
53 }
54}
55
56void
57place_tile(Ppm *tile, Ppm *grid, int tile_col, int tile_row)
58{
59 int x, y, src_idx, dst_idx, dst_x, dst_y;
60 unsigned char palette[9][3] = {
61 {213, 62, 79}, {244, 109, 67}, {253, 174, 97},
62 {254, 224, 139}, {255, 255, 191}, {230, 245, 152},
63 {171, 221, 164}, {102, 194, 165}, {50, 136, 189}
64 };
65 unsigned char *color = palette[rand() % 9];
66
67 for (y = 0; y < tile->height; y++) {
68 for (x = 0; x < tile->width; x++) {
69 /* calculate index starting in the given col and row */
70 dst_x = tile_col * tile->width + x;
71 dst_y = tile_row * tile->height + y;
72 /* 2d image to 1d array in the current image*/
73 src_idx = (y * tile->width + x) * 3;
74 /* 2d image to 1d array in the whole grid*/
75 dst_idx = (dst_y * grid->width + dst_x) * 3;
76
77 /* move the pixels over */
78 if (tile->data[src_idx] < 250 || tile->data[src_idx+1] < 250 || tile->data[src_idx+2] < 250) {
79 grid->data[dst_idx] = color[0];
80 grid->data[dst_idx + 1] = color[1];
81 grid->data[dst_idx + 2] = color[2];
82 } else {
83 grid->data[dst_idx] = 255;
84 grid->data[dst_idx + 1] = 255;
85 grid->data[dst_idx + 2] = 255;
86 }
87 }
88 }
89}
90
91int
92main(void)
93{
94 FILE *in, *out;
95 char magic[3];
96 int width, height, max_val;
97 int i, val, cell;
98 double degrees[9];
99 Ppm src, rotated, grid;
100
101 srand((unsigned int)time(NULL));
102
103 for (cell = 0; cell < 9; cell++)
104 degrees[cell] = (double)(rand() % 3600) / 10.0;
105
106 in = fopen("pjw.ppm", "r");
107 if (!in) {
108 perror("failed to open file, pjw.ppm");
109 return 1;
110 }
111
112 fscanf(in, "%2s %d %d %d", magic, &width, &height, &max_val);
113
114 if (magic[0] != 'P' || magic[1] != '3') {
115 fprintf(stderr, "only P3 plx(ascii)\n");
116 fclose(in);
117 return 1;
118 }
119
120 src.width = width;
121 src.height = height;
122 src.data = (unsigned char *)malloc(width * height * 3);
123
124 rotated.width = width;
125 rotated.height = height;
126 rotated.data = (unsigned char *)malloc(width * height * 3);
127
128 grid.width = width * 3;
129 grid.height = height * 3;
130
131 size_t src_size = (size_t)width * height * 3;
132 size_t grid_size = (size_t)grid.width * grid.height * 3;
133
134 grid.data = (unsigned char *)malloc(grid_size);
135
136 if (!src.data || !rotated.data || !grid.data) {
137 fprintf(stderr, "Memory allocation failed.\n");
138 return 1;
139 }
140
141 /* avoid garbage pixels */
142 memset(grid.data, 255, grid_size);
143
144 for (i = 0; i < src_size; i++) {
145 fscanf(in, "%d", &val);
146 src.data[i] = (unsigned char)val;
147 }
148 fclose(in);
149
150 for (cell = 0; cell < 9; cell++) {
151 rotate_image(&src, &rotated, degrees[cell]);
152 place_tile(&rotated, &grid, cell%3, cell/3);
153 }
154
155 out = fopen("output.ppm", "w");
156 if (!out) {
157 perror("failed to open the file output.ppm");
158 return 1;
159 }
160
161 /* write the header */
162 fprintf(out, "P3\n%d %d\n255\n", grid.width, grid.height);
163 /* write the rest */
164 for (i = 0; i < (int)grid_size; i+=3) {
165 if (grid.data[i] == 0 && grid.data[i + 1] == 0 && grid.data[i + 2] == 0)
166 switch (rand() % 4) {
167 case 0: fprintf(out, "0 0 0 "); break;
168 case 1: fprintf(out, "255 0 0 "); break;
169 case 2: fprintf(out, "0 255 0 "); break;
170 case 3: fprintf(out, "0 0 255 "); break;
171 }
172 else {
173 fprintf(out, "%d %d %d ",
174 grid.data[i],
175 grid.data[i + 1],
176 grid.data[i + 2]);
177 }
178
179 if ((i + 1) % (grid.width * 3) == 0) {
180 fprintf(out, "\n");
181 }
182 }
183
184 fclose(out);
185
186 free(src.data);
187 free(rotated.data);
188 free(grid.data);
189
190 printf("done %s (%dx%d)\n", "output.ppm", grid.width, grid.height);
191 return 0;
192}