A very small library for reading image files
1#include "img.h"
2#include <stdio.h>
3#include <stdlib.h>
4
5struct Ctx {
6 FILE *file;
7};
8
9static ImgStatus ctxRead(ImgAny user, ImgAny buf, ImgSz bufSz)
10{
11 struct Ctx *ctx = user;
12 if(fread(buf, bufSz, 1, ctx->file) != 1) {
13 return ImgErrIO;
14 }
15 return ImgOK;
16}
17
18static ImgStatus ctxSeek(ImgAny user, ImgOff off)
19{
20 struct Ctx *ctx = user;
21 fseek(ctx->file, off, SEEK_CUR);
22 return ImgOK;
23}
24
25static ImgStatus ctxClose(ImgAny user)
26{
27 struct Ctx *ctx = user;
28 fclose(ctx->file);
29 return ImgOK;
30}
31
32static void saveToPPM_RGB(const Img *img, const ImgU8 *pixels, const char *filename)
33{
34 FILE *file = fopen(filename, "wb");
35 if(file == NULL) {
36 perror("Could not open output file");
37 return;
38 }
39
40 fprintf(file, "P6\n%u %u\n255\n", img->width, img->height);
41 fwrite(pixels, 3, (ImgSz)img->width * img->height, file);
42 fclose(file);
43}
44
45static void saveToPPM_RGBA(const Img *img, const ImgU8 *pixels, const char *filename)
46{
47 FILE *file = fopen(filename, "wb");
48 if(file == NULL) {
49 perror("Could not open output file");
50 return;
51 }
52
53 fprintf(file, "P6\n%u %u\n255\n", img->width, img->height);
54 for(ImgSz i = 0; i < (ImgSz)img->width * img->height; ++i) {
55 fwrite(&pixels[i * 4], 1, 3, file);
56 }
57 fclose(file);
58}
59
60int main(int argc, char **argv)
61{
62 if(argc < 3) {
63 printf("Usage: %s <input file> <output PPM file>\n", argv[0]);
64 return 1;
65 }
66
67 FILE *file = fopen(argv[1], "rb");
68 if(file == NULL) {
69 perror("Could not open file");
70 return 1;
71 }
72
73 struct Ctx ctx;
74 ctx.file = file;
75 ImgFuncs funcs;
76 funcs.user = &ctx;
77 funcs.read = &ctxRead;
78 funcs.seek = &ctxSeek;
79 funcs.close = &ctxClose;
80
81 Img img;
82 ImgStatus status = imgOpen(&img, &funcs);
83 if(status != ImgOK) {
84 printf("Could not open image: %s\n", imgStatusMessage(status));
85 return 1;
86 }
87
88 printf(
89 "Detected %s\n"
90 "Size: %ux%u\n"
91 "Channel count: %u\n",
92 imgFormatName(img.format),
93 img.width, img.height,
94 img.channelCount);
95
96 ImgSz size = (ImgSz)img.width * img.height * img.channelCount;
97 ImgU8 *pixels = (ImgU8*)malloc(size);
98 status = imgRead(&img, pixels, size);
99 if(status != ImgOK) {
100 printf("Could not decode image: %s\n", imgStatusMessage(status));
101 /* return 1; */
102 }
103
104 if(img.channelCount == 3) {
105 saveToPPM_RGB(&img, pixels, argv[2]);
106 } else if(img.channelCount == 4) {
107 saveToPPM_RGBA(&img, pixels, argv[2]);
108 } else {
109 printf("Image must have 3 or 4 channels. Not converting.\n");
110 }
111
112 status = imgClose(&img);
113 if(status != ImgOK) {
114 printf("Could not close image: %s\n", imgStatusMessage(status));
115 return 1;
116 }
117
118 return 0;
119}