1 /* sane-airscan image decoders test
2 *
3 * Copyright (C) 2019 and up by Alexander Pevzner (pzz@apevzner.com)
4 * See LICENSE for license terms and conditions
5 */
6
7 #include "airscan.h"
8
9 #include <errno.h>
10 #include <stdarg.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14
15 #include <png.h>
16
17 /* save_file represents a PNG output file, used for
18 * saving decoded image
19 */
20 typedef struct {
21 const char *name; /* Output file name */
22 FILE *fp; /* Output file handle */
23 png_struct *png_ptr; /* Underlying libpng encoder */
24 png_info *info_ptr; /* libpng info struct */
25 } save_file;
26
27 /* Print error message and exit
28 */
29 void __attribute__((noreturn))
die(const char * format,...)30 die (const char *format, ...)
31 {
32 va_list ap;
33
34 va_start(ap, format);
35 vprintf(format, ap);
36 printf("\n");
37 va_end(ap);
38
39 exit(1);
40 }
41
42 /* libpng write callback
43 */
44 void
png_write_fn(png_struct * png_ptr,png_bytep data,size_t size)45 png_write_fn (png_struct *png_ptr, png_bytep data, size_t size)
46 {
47 save_file *file = png_get_io_ptr(png_ptr);
48
49 if (size != fwrite(data, 1, size, file->fp)) {
50 die("%s: %s", file->name, strerror(errno));
51 }
52 }
53
54 /* libpng error callback
55 */
56 void
png_error_fn(png_struct * png_ptr,const char * message)57 png_error_fn (png_struct *png_ptr, const char *message)
58 {
59 save_file *file = png_get_error_ptr(png_ptr);
60 die("%s: %s", file->name, message);
61 }
62
63 /* Open the save_file
64 */
65 save_file*
save_open(const char * name,const SANE_Parameters * params)66 save_open (const char *name, const SANE_Parameters *params)
67 {
68 save_file *save = mem_new(save_file, 1);
69 int color_type;
70
71 save->name = str_dup(name);
72 save->fp = fopen(name, "wb");
73 if (save->fp == NULL) {
74 die("%s: %s", name, strerror(errno));
75 }
76
77 save->png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
78 NULL, NULL, NULL);
79 if (save->png_ptr == NULL) {
80 die("%s: png_create_write_struct() failed", name);
81 }
82
83 png_set_write_fn(save->png_ptr, save, png_write_fn, NULL);
84 png_set_error_fn(save->png_ptr, save, png_error_fn, NULL);
85
86 save->info_ptr = png_create_info_struct(save->png_ptr);
87 if (save->info_ptr == NULL) {
88 die("%s: png_create_info_struct() failed", name);
89 }
90
91 if (params->format == SANE_FRAME_GRAY) {
92 color_type = PNG_COLOR_TYPE_GRAY;
93 } else {
94 color_type = PNG_COLOR_TYPE_RGB;
95 }
96
97 png_set_IHDR(save->png_ptr, save->info_ptr,
98 params->pixels_per_line, params->lines, params->depth,
99 color_type, PNG_INTERLACE_NONE,
100 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
101
102 png_set_sRGB(save->png_ptr, save->info_ptr, PNG_sRGB_INTENT_PERCEPTUAL);
103
104 png_write_info(save->png_ptr, save->info_ptr);
105
106 return save;
107 }
108
109 /* Close the save file
110 */
111 void
save_close(save_file * save)112 save_close (save_file *save)
113 {
114 png_write_end(save->png_ptr, NULL);
115 png_destroy_write_struct(&save->png_ptr, &save->info_ptr);
116 fclose(save->fp);
117 mem_free((char*) save->name);
118 mem_free(save);
119 }
120
121 /* Write a row of image data
122 */
123 void
save_write(save_file * save,void * data)124 save_write (save_file *save, void *data)
125 {
126 png_write_row(save->png_ptr, data);
127 }
128
129 /* The main function
130 */
131 int
main(int argc,char ** argv)132 main (int argc, char **argv)
133 {
134 const char *file, *ext;
135 image_decoder *decoder = NULL;
136 FILE *fp;
137 long size;
138 int rc;
139 void *data, *line;
140 error err;
141 SANE_Parameters params;
142 int i;
143 save_file *save;
144
145 /* Parse command-line arguments */
146 if (argc != 2) {
147 die("usage: %s file", argv[0]);
148 }
149
150 file = argv[1];
151 ext = strrchr(file, '.');
152 ext = ext ? ext + 1 : "";
153
154 /* Create decoder */
155 if (!strcmp(ext, "jpeg") || !strcmp(ext, "jpg")) {
156 decoder = image_decoder_jpeg_new();
157 } else if (!strcmp(ext, "png")) {
158 decoder = image_decoder_png_new();
159 } else if (!strcmp(ext, "bmp")) {
160 decoder = image_decoder_bmp_new();
161 }
162
163 if (decoder == NULL) {
164 die("can't guess image format");
165 }
166
167 /* Load the file */
168 fp = fopen(file, "rb");
169 if (fp == NULL) {
170 die("%s: %s", file, strerror(errno));
171 }
172
173 rc = fseek(fp, 0, SEEK_END);
174 if (rc < 0) {
175 die("%s: %s", file, strerror(errno));
176 }
177
178 size = ftell(fp);
179 if (size < 0) {
180 die("%s: %s", file, strerror(errno));
181 }
182
183 rc = fseek(fp, 0, SEEK_SET);
184 if (rc < 0) {
185 die("%s: %s", file, strerror(errno));
186 }
187
188 data = mem_new(char, size);
189 if ((size_t) size != fread(data, 1, size, fp)) {
190 die("%s: read error", file);
191 }
192
193 fclose(fp);
194
195 /* Decode the image */
196 err = image_decoder_begin(decoder, data, size);
197 if (err != NULL) {
198 die("%s", err);
199 }
200
201
202 image_decoder_get_params(decoder, ¶ms);
203 printf("format: %s\n", image_content_type(decoder));
204 printf("width: %d\n", params.pixels_per_line);
205 printf("height: %d\n", params.lines);
206 printf("bytes/line: %d\n", params.bytes_per_line);
207 printf("bytes/pixel: %d\n", params.bytes_per_line / params.pixels_per_line);
208
209 save = save_open("decoded.png", ¶ms);
210
211 line = mem_new(char, params.bytes_per_line);
212 for (i = 0; i < params.lines; i ++) {
213 err = image_decoder_read_line(decoder, line);
214 if (err != NULL) {
215 die("line %d: %s", i, err);
216 }
217
218 save_write(save, line);
219 }
220
221 mem_free(line);
222 save_close(save);
223
224 return 0;
225 }
226
227 /* vim:ts=8:sw=4:et
228 */
229