141bool pam_read(
const char *filename,
struct pam_metadata *info,
unsigned char **data,
void *(*allocator)(
size_t)) {
144 FILE *file = fopen(filename,
"rb");
146 fprintf(stderr,
"Failed to open %s: %s\n", filename, strerror(errno));
149 memset(info, 0,
sizeof *info);
150 if (fgets(line, 4, file) == NULL) {
151 fprintf(stderr,
"File '%s' read error: %s\n", filename, strerror(errno));
153 bool parse_rc =
false;
154 if (strcmp(line,
"P7\n") == 0) {
156 }
else if (strlen(line) == 3 && line[0] ==
'P' && isspace(line[2])) {
157 parse_rc =
parse_pnm(file, line[1], info);
159 fprintf(stderr,
"File '%s' doesn't seem to be valid PAM or PNM.\n", filename);
165 if (info->width <= 0 || info->height <= 0) {
166 fprintf(stderr,
"Unspecified/incorrect size %dx%d!\n", info->width, info->height);
169 if (info->depth <= 0) {
170 fprintf(stderr,
"Unspecified/incorrect depth %d!\n", info->depth);
173 if (info->maxval <= 0 || info->maxval > 65535) {
174 fprintf(stderr,
"Unspecified/incorrect maximal value %d!\n", info->maxval);
177 if (data == NULL || allocator == NULL || !parse_rc) {
181 size_t datalen = (size_t) info->depth * info->width * info->height;
182 if (info->maxval == 1 && info->bitmap_pbm) {
183 datalen = (info->width + 7) / 8 * info->height;
184 }
else if (info->maxval > 255) {
187 *data = (
unsigned char *) allocator(datalen);
189 fprintf(stderr,
"Unspecified depth header field!\n");
193 size_t bytes_read = fread((
char *) *data, 1, datalen, file);
194 if (bytes_read != datalen) {
195 fprintf(stderr,
"Unable to load PAM/PNM data from file - read %zu B, expected %zu B: %s\n",
196 bytes_read, datalen, strerror(errno));
204bool pam_write(
const char *filename,
unsigned int width,
unsigned int height,
int depth,
int maxval,
const unsigned char *data,
bool pnm) {
206 FILE *file = fopen(filename,
"wb");
208 fprintf(stderr,
"Failed to open %s for writing: %s\n", filename, strerror(errno));
213 fprintf(stderr,
"Only 1 or 3 channels supported for PNM!\n");
217 fprintf(file,
"P%d\n"
221 width, height, maxval);
223 const char *tuple_type =
"INVALID";
225 case 4: tuple_type =
"RGB_ALPHA";
break;
226 case 3: tuple_type =
"RGB";
break;
227 case 2: tuple_type =
"GRAYSCALE_ALPHA";
break;
228 case 1: tuple_type =
"GRAYSCALE";
break;
229 default: fprintf(stderr,
"Wrong depth: %d\n",
depth);
238 width, height,
depth, maxval, tuple_type);
240 size_t len = (size_t) width * height *
depth * (maxval <= 255 ? 1 : 2);
242 size_t bytes_written = fwrite((
const char *) data, 1,
len, file);
243 if (bytes_written !=
len) {
244 fprintf(stderr,
"Unable to write PAM/PNM data - length %zd, written %zd: %s\n",
245 len, bytes_written, strerror(errno));
248 return bytes_written ==
len;
bool pam_write(const char *filename, unsigned int width, unsigned int height, int depth, int maxval, const unsigned char *data, bool pnm)