Skip to content

Commit 7342ee9

Browse files
authored
Merge pull request #125 from saxbophone/josh/114-pbm-image-output
Implement pbm image output
2 parents 4d76491 + 9626074 commit 7342ee9

File tree

2 files changed

+189
-0
lines changed

2 files changed

+189
-0
lines changed
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
/*
2+
* This source file forms part of libsaxbospiral, a library which generates
3+
* experimental 2D spiral-like shapes based on input binary data.
4+
*
5+
* This compilation unit provides functionality to render a bitmap struct to a
6+
* PBM image (binary version, stored in a buffer).
7+
*
8+
* Reference materials used for the PBM format are located at
9+
* <http://netpbm.sourceforge.net/doc/pbm.html>
10+
*
11+
*
12+
*
13+
* Copyright (C) 2016, Joshua Saxby [email protected]
14+
*
15+
* This program is free software: you can redistribute it and/or modify
16+
* it under the terms of the GNU Affero General Public License (version 3),
17+
* as published by the Free Software Foundation.
18+
*
19+
* This program is distributed in the hope that it will be useful,
20+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
21+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22+
* GNU Affero General Public License for more details.
23+
*
24+
* You should have received a copy of the GNU Affero General Public License
25+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
26+
*/
27+
#include <assert.h>
28+
#include <inttypes.h>
29+
#include <math.h>
30+
#include <stddef.h>
31+
#include <stdint.h>
32+
#include <stdio.h>
33+
#include <stdlib.h>
34+
#include <string.h>
35+
36+
#include "../saxbospiral.h"
37+
#include "../render.h"
38+
#include "backend_pbm.h"
39+
40+
41+
#ifdef __cplusplus
42+
extern "C"{
43+
#endif
44+
45+
/*
46+
* given a bitmap_t struct and a pointer to a blank buffer_t, write the bitmap
47+
* data as a PBM image to the buffer
48+
* returns a status struct containing error information, if any
49+
*
50+
* Asserts:
51+
* - That bitmap.pixels is not NULL
52+
* - That buffer->bytes is NULL
53+
*/
54+
sxbp_status_t sxbp_render_backend_pbm(
55+
sxbp_bitmap_t bitmap, sxbp_buffer_t* buffer
56+
) {
57+
// preconditional assertsions
58+
assert(bitmap.pixels != NULL);
59+
assert(buffer->bytes == NULL);
60+
/*
61+
* allocate two char arrays for the width and height strings - these may be
62+
* up to 19 characters each (max uint64_t is 19 digits long), so allocate 2
63+
* char arrays of 20 chars each (1 extra char for null-terminator)
64+
*/
65+
char width_string[20], height_string[20];
66+
// these are used to keep track of how many digits each is
67+
int width_string_length, height_string_length = 0;
68+
// convert width and height to a decimal string, store lengths
69+
width_string_length = sprintf(width_string, "%" PRIu64, bitmap.width);
70+
height_string_length = sprintf(height_string, "%" PRIu64, bitmap.height);
71+
/*
72+
* now that we know the length of the image dimension strings, we can now
73+
* calculate how much memory we'll have to allocate for the image buffer
74+
*/
75+
// calculate number of bytes per row - this is ceiling(width / 8)
76+
size_t bytes_per_row = (size_t)ceil((double)bitmap.width / 8.0);
77+
// calculate number of bytes for the entire image pixels (rows and columns)
78+
size_t image_bytes = bytes_per_row * bitmap.height;
79+
// finally put it all together to get total image buffer size
80+
size_t image_buffer_size = (
81+
3 // "P4" magic number + whitespace
82+
+ width_string_length + 1 // width of image in decimal + whitespace
83+
+ height_string_length + 1 // height of image in decimal + whitespace
84+
+ image_bytes // lastly, the bytes which make up the image pixels
85+
);
86+
// try and allocate the data for the buffer
87+
buffer->bytes = calloc(image_buffer_size, sizeof(uint8_t));
88+
// check fo memory allocation failure
89+
if(buffer->bytes == NULL) {
90+
return SXBP_MALLOC_REFUSED;
91+
} else {
92+
// set buffer size
93+
buffer->size = image_buffer_size;
94+
// otherwise carry on
95+
size_t index = 0; // this index is used to index the buffer
96+
// construct magic number + whitespace
97+
memcpy(buffer->bytes + index, "P4\n", 3);
98+
index += 3;
99+
// image width
100+
memcpy(buffer->bytes + index, width_string, width_string_length);
101+
index += width_string_length;
102+
// whitespace
103+
memcpy(buffer->bytes + index, "\n", 1);
104+
index += 1;
105+
// image height
106+
memcpy(buffer->bytes + index, height_string, height_string_length);
107+
index += height_string_length;
108+
// whitespace
109+
memcpy(buffer->bytes + index, "\n", 1);
110+
index += 1;
111+
// now for the image data, packed into rows to the nearest byte
112+
for(size_t y = 0; y < bitmap.height; y++) { // row loop
113+
for(size_t x = 0; x < bitmap.width; x++) {
114+
// byte index is index + floor(x / 8)
115+
size_t byte_index = index + (x / 8);
116+
// bit index is x mod 8
117+
uint8_t bit_index = x % 8;
118+
// write bits most-significant-bit first
119+
buffer->bytes[byte_index] |= (
120+
// black pixel = bool true = 1, just like in PBM format
121+
bitmap.pixels[x][y] << (7 - bit_index)
122+
);
123+
}
124+
// increment index so next row is written in the correct place
125+
index += bytes_per_row;
126+
}
127+
return SXBP_OPERATION_OK;
128+
}
129+
}
130+
131+
#ifdef __cplusplus
132+
} // extern "C"
133+
#endif
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* This source file forms part of libsaxbospiral, a library which generates
3+
* experimental 2D spiral-like shapes based on input binary data.
4+
*
5+
* This compilation unit provides functionality to render a bitmap struct to a
6+
* PBM image (binary version, stored in a buffer).
7+
*
8+
* Reference materials used for the PBM format are located at
9+
* <http://netpbm.sourceforge.net/doc/pbm.html>
10+
*
11+
*
12+
*
13+
* Copyright (C) 2016, Joshua Saxby [email protected]
14+
*
15+
* This program is free software: you can redistribute it and/or modify
16+
* it under the terms of the GNU Affero General Public License (version 3),
17+
* as published by the Free Software Foundation.
18+
*
19+
* This program is distributed in the hope that it will be useful,
20+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
21+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22+
* GNU Affero General Public License for more details.
23+
*
24+
* You should have received a copy of the GNU Affero General Public License
25+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
26+
*/
27+
#ifndef SAXBOPHONE_SAXBOSPIRAL_BACKEND_PBM_H
28+
#define SAXBOPHONE_SAXBOSPIRAL_BACKEND_PBM_H
29+
30+
#include "../saxbospiral.h"
31+
#include "../render.h"
32+
33+
34+
#ifdef __cplusplus
35+
extern "C"{
36+
#endif
37+
38+
/*
39+
* given a bitmap_t struct and a pointer to a blank buffer_t, write the bitmap
40+
* data as a PBM image to the buffer
41+
* returns a status struct containing error information, if any
42+
*
43+
* Asserts:
44+
* - That bitmap.pixels is not NULL
45+
* - That buffer->bytes is NULL
46+
*/
47+
sxbp_status_t sxbp_render_backend_pbm(
48+
sxbp_bitmap_t bitmap, sxbp_buffer_t* buffer
49+
);
50+
51+
#ifdef __cplusplus
52+
} // extern "C"
53+
#endif
54+
55+
// end of header file
56+
#endif

0 commit comments

Comments
 (0)