1 /*
2 * Copyright 2008 Sean Fox <dyntryx@gmail.com>
3 * Copyright 2008 James Bursa <james@netsurf-browser.org>
4 *
5 * This file is part of NetSurf's libnsbmp, http://www.netsurf-browser.org/
6 * Licenced under the MIT License,
7 * http://www.opensource.org/licenses/mit-license.php
8 */
9
10 /**
11 * \file
12 * Use libnsbmp to decode icons into ppm or pam files for testing
13 */
14
15 #include <assert.h>
16 #include <errno.h>
17 #include <stdbool.h>
18 #include <stdlib.h>
19 #include <stdint.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <sys/stat.h>
23 #include "../include/libnsbmp.h"
24
25 /* Currently the library returns the data in RGBA format,
26 * so there are 4 bytes per pixel */
27 #define BYTES_PER_PIXEL 4
28
29 /* White with alpha masking. */
30 #define TRANSPARENT_COLOR 0xffffffff
31
bitmap_create(int width,int height,unsigned int state)32 static void *bitmap_create(int width, int height, unsigned int state)
33 {
34 (void) state; /* unused */
35 return calloc(width * height, BYTES_PER_PIXEL);
36 }
37
38
bitmap_get_buffer(void * bitmap)39 static unsigned char *bitmap_get_buffer(void *bitmap)
40 {
41 assert(bitmap);
42 return bitmap;
43 }
44
45
bitmap_get_bpp(void * bitmap)46 static size_t bitmap_get_bpp(void *bitmap)
47 {
48 (void) bitmap; /* unused */
49 return BYTES_PER_PIXEL;
50 }
51
52
bitmap_destroy(void * bitmap)53 static void bitmap_destroy(void *bitmap)
54 {
55 assert(bitmap);
56 free(bitmap);
57 }
58
load_file(const char * path,size_t * data_size)59 static unsigned char *load_file(const char *path, size_t *data_size)
60 {
61 FILE *fd;
62 struct stat sb;
63 unsigned char *buffer;
64 size_t size;
65 size_t n;
66
67 fd = fopen(path, "rb");
68 if (!fd) {
69 perror(path);
70 exit(EXIT_FAILURE);
71 }
72
73 if (stat(path, &sb)) {
74 perror(path);
75 exit(EXIT_FAILURE);
76 }
77 size = sb.st_size;
78
79 buffer = malloc(size);
80 if (!buffer) {
81 fprintf(stderr, "Unable to allocate %lld bytes\n",
82 (long long) size);
83 exit(EXIT_FAILURE);
84 }
85
86 n = fread(buffer, 1, size, fd);
87 if (n != size) {
88 perror(path);
89 exit(EXIT_FAILURE);
90 }
91
92 fclose(fd);
93
94 *data_size = size;
95 return buffer;
96 }
97
98
warning(const char * context,bmp_result code)99 static void warning(const char *context, bmp_result code)
100 {
101 fprintf(stderr, "%s failed: ", context);
102 switch (code) {
103 case BMP_INSUFFICIENT_MEMORY:
104 fprintf(stderr, "BMP_INSUFFICIENT_MEMORY");
105 break;
106 case BMP_INSUFFICIENT_DATA:
107 fprintf(stderr, "BMP_INSUFFICIENT_DATA");
108 break;
109 case BMP_DATA_ERROR:
110 fprintf(stderr, "BMP_DATA_ERROR");
111 break;
112 default:
113 fprintf(stderr, "unknown code %i", code);
114 break;
115 }
116 fprintf(stderr, "\n");
117 }
118
119
write_pam(FILE * fh,const char * name,struct bmp_image * bmp)120 static void write_pam(FILE* fh, const char *name, struct bmp_image *bmp)
121 {
122 uint16_t row, col;
123 uint8_t *image;
124
125 fprintf(fh, "P7\n");
126 fprintf(fh, "# %s\n", name);
127 fprintf(fh, "WIDTH %u\n", bmp->width);
128 fprintf(fh, "HEIGHT %u\n", bmp->height);
129 fprintf(fh, "DEPTH 4\n");
130 fprintf(fh, "MAXVAL 255\n");
131 fprintf(fh, "TUPLTYPE RGB_ALPHA\n");
132 fprintf(fh, "ENDHDR\n");
133
134
135 image = (uint8_t *) bmp->bitmap;
136 for (row = 0; row != bmp->height; row++) {
137 for (col = 0; col != bmp->width; col++) {
138 size_t z = (row * bmp->width + col) * BYTES_PER_PIXEL;
139 putc(image[z], fh);
140 putc(image[z + 1], fh);
141 putc(image[z + 2], fh);
142 putc(image[z + 3], fh);
143 }
144 }
145
146 }
147
write_ppm(FILE * fh,const char * name,struct bmp_image * bmp)148 static void write_ppm(FILE* fh, const char *name, struct bmp_image *bmp)
149 {
150 uint16_t row, col;
151 uint8_t *image;
152
153 fprintf(fh, "P3\n");
154 fprintf(fh, "# %s\n", name);
155 fprintf(fh, "# width %u \n", bmp->width);
156 fprintf(fh, "# height %u \n", bmp->height);
157 fprintf(fh, "%u %u 256\n", bmp->width, bmp->height);
158
159 image = (uint8_t *) bmp->bitmap;
160 for (row = 0; row != bmp->height; row++) {
161 for (col = 0; col != bmp->width; col++) {
162 size_t z = (row * bmp->width + col) * BYTES_PER_PIXEL;
163 fprintf(fh, "%u %u %u ",
164 image[z],
165 image[z + 1],
166 image[z + 2]);
167 }
168 fprintf(fh, "\n");
169 }
170 }
171
main(int argc,char * argv[])172 int main(int argc, char *argv[])
173 {
174 bmp_bitmap_callback_vt bitmap_callbacks = {
175 bitmap_create,
176 bitmap_destroy,
177 bitmap_get_buffer,
178 bitmap_get_bpp
179 };
180 uint16_t width, height;
181 ico_collection ico;
182 bmp_result code;
183 struct bmp_image *bmp;
184 size_t size;
185 unsigned short res = 0;
186 unsigned char *data;
187 FILE *outf = stdout;
188
189 if ((argc < 2) || (argc > 5)) {
190 fprintf(stderr, "Usage: %s collection.ico [width=255] [height=255] [outfile]\n", argv[0]);
191 return 1;
192 }
193 width = (argc >= 3) ? atoi(argv[2]) : 255;
194 height = (argc >= 4) ? atoi(argv[3]) : 255;
195
196 if (argc >= 5) {
197 outf = fopen(argv[4], "w+");
198 if (outf == NULL) {
199 fprintf(stderr, "Unable to open %s for writing\n", argv[2]);
200 return 2;
201 }
202 }
203
204 /* create our bmp image */
205 ico_collection_create(&ico, &bitmap_callbacks);
206
207 /* load file into memory */
208 data = load_file(argv[1], &size);
209
210 /* analyse the BMP */
211 code = ico_analyse(&ico, size, data);
212 if (code != BMP_OK) {
213 warning("ico_analyse", code);
214 res = 3;
215 goto cleanup;
216 }
217
218 /* decode the image */
219 bmp = ico_find(&ico, width, height);
220 assert(bmp);
221
222 code = bmp_decode(bmp);
223 /* code = bmp_decode_trans(bmp, TRANSPARENT_COLOR); */
224 if (code != BMP_OK) {
225 warning("bmp_decode", code);
226 /* allow partially decoded images */
227 if ((code != BMP_INSUFFICIENT_DATA) &&
228 (code != BMP_DATA_ERROR)) {
229 res = 1;
230 goto cleanup;
231 }
232
233 /* skip if the decoded image would be ridiculously large */
234 if ((bmp->width * bmp->height) > 200000) {
235 res = 1;
236 goto cleanup;
237 }
238 }
239
240 if (bmp->opaque) {
241 write_ppm(outf, argv[1], bmp);
242 } else {
243 write_pam(outf, argv[1], bmp);
244 }
245
246 if (argc >= 5) {
247 fclose(outf);
248 }
249
250 cleanup:
251 /* clean up */
252 ico_finalise(&ico);
253 free(data);
254
255 return res;
256 }
257