1 /* sane - Scanner Access Now Easy.
2
3 Copyright (C) 2019 Touboul Nathane
4 Copyright (C) 2019 Thierry HUCHARD <thierry@ordissimo.com>
5
6 This file is part of the SANE package.
7
8 SANE is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
12
13 SANE is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with sane; see the file COPYING.
20 If not, see <https://www.gnu.org/licenses/>.
21
22 This file implements a SANE backend for eSCL scanners. */
23
24 #define DEBUG_DECLARE_ONLY
25 #include "../include/sane/config.h"
26
27 #include "escl.h"
28
29 #include "../include/sane/sanei.h"
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 #if(defined HAVE_LIBPNG)
36 #include <png.h>
37 #endif
38
39 #include <setjmp.h>
40
41
42 #if(defined HAVE_LIBPNG)
43
44 /**
45 * \fn SANE_Status escl_sane_decompressor(escl_sane_t *handler)
46 * \brief Function that aims to decompress the png image to SANE be able to read the image.
47 * This function is called in the "sane_read" function.
48 *
49 * \return SANE_STATUS_GOOD (if everything is OK, otherwise, SANE_STATUS_NO_MEM/SANE_STATUS_INVAL)
50 */
51 SANE_Status
get_PNG_data(capabilities_t * scanner,int * width,int * height,int * bps)52 get_PNG_data(capabilities_t *scanner, int *width, int *height, int *bps)
53 {
54 unsigned int w = 0;
55 unsigned int h = 0;
56 int components = 3;
57 unsigned char *surface = NULL; /* Image data */
58 unsigned int i = 0;
59 png_byte magic[8];
60 SANE_Status status = SANE_STATUS_GOOD;
61
62 // read magic number
63 fread (magic, 1, sizeof (magic), scanner->tmp);
64 // check for valid magic number
65 if (!png_check_sig (magic, sizeof (magic)))
66 {
67 DBG( 1, "Escl Png : PNG error is not a valid PNG image!\n");
68 status = SANE_STATUS_INVAL;
69 goto close_file;
70 }
71 // create a png read struct
72 png_structp png_ptr = png_create_read_struct
73 (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
74 if (!png_ptr)
75 {
76 DBG( 1, "Escl Png : PNG error create a png read struct\n");
77 status = SANE_STATUS_INVAL;
78 goto close_file;
79 }
80 // create a png info struct
81 png_infop info_ptr = png_create_info_struct (png_ptr);
82 if (!info_ptr)
83 {
84 DBG( 1, "Escl Png : PNG error create a png info struct\n");
85 png_destroy_read_struct (&png_ptr, NULL, NULL);
86 status = SANE_STATUS_INVAL;
87 goto close_file;
88 }
89 // initialize the setjmp for returning properly after a libpng
90 // error occurred
91 if (setjmp (png_jmpbuf (png_ptr)))
92 {
93 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
94 if (surface)
95 free (surface);
96 DBG( 1, "Escl Png : PNG read error.\n");
97 status = SANE_STATUS_INVAL;
98 goto close_file;
99 }
100 // setup libpng for using standard C fread() function
101 // with our FILE pointer
102 png_init_io (png_ptr, scanner->tmp);
103 // tell libpng that we have already read the magic number
104 png_set_sig_bytes (png_ptr, sizeof (magic));
105
106 // read png info
107 png_read_info (png_ptr, info_ptr);
108
109 int bit_depth, color_type;
110 // get some useful information from header
111 bit_depth = png_get_bit_depth (png_ptr, info_ptr);
112 color_type = png_get_color_type (png_ptr, info_ptr);
113 // convert index color images to RGB images
114 if (color_type == PNG_COLOR_TYPE_PALETTE)
115 png_set_palette_to_rgb (png_ptr);
116 else if (color_type != PNG_COLOR_TYPE_RGB && color_type != PNG_COLOR_TYPE_RGB_ALPHA)
117 {
118 DBG(1, "PNG format not supported.\n");
119 status = SANE_STATUS_NO_MEM;
120 goto close_file;
121 }
122
123 if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
124 components = 4;
125 else
126 components = 3;
127
128 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
129 png_set_tRNS_to_alpha (png_ptr);
130 if (bit_depth == 16)
131 png_set_strip_16 (png_ptr);
132 else if (bit_depth < 8)
133 png_set_packing (png_ptr);
134 // update info structure to apply transformations
135 png_read_update_info (png_ptr, info_ptr);
136 // retrieve updated information
137 png_get_IHDR (png_ptr, info_ptr,
138 (png_uint_32*)(&w),
139 (png_uint_32*)(&h),
140 &bit_depth, &color_type,
141 NULL, NULL, NULL);
142
143 *bps = components;
144 // we can now allocate memory for storing pixel data
145 surface = (unsigned char *)malloc (sizeof (unsigned char) * w
146 * h * components);
147 if (!surface) {
148 DBG( 1, "Escl Png : texels Memory allocation problem\n");
149 status = SANE_STATUS_NO_MEM;
150 goto close_file;
151 }
152 png_bytep *row_pointers;
153 // setup a pointer array. Each one points at the begening of a row.
154 row_pointers = (png_bytep *)malloc (sizeof (png_bytep) * h);
155 if (!row_pointers) {
156 DBG( 1, "Escl Png : row_pointers Memory allocation problem\n");
157 free(surface);
158 status = SANE_STATUS_NO_MEM;
159 goto close_file;
160 }
161 for (i = 0; i < h; ++i)
162 {
163 row_pointers[i] = (png_bytep)(surface +
164 ((h - (i + 1)) * w * components));
165 }
166 // read pixel data using row pointers
167 png_read_image (png_ptr, row_pointers);
168
169 // If necessary, trim the image.
170 surface = escl_crop_surface(scanner, surface, w, h, components, width, height);
171 if (!surface) {
172 DBG( 1, "Escl Png : Surface Memory allocation problem\n");
173 status = SANE_STATUS_NO_MEM;
174 goto close_file;
175 }
176
177 free (row_pointers);
178
179 close_file:
180 if (scanner->tmp)
181 fclose(scanner->tmp);
182 scanner->tmp = NULL;
183 return (status);
184 }
185 #else
186
187 SANE_Status
get_PNG_data(capabilities_t __sane_unused__ * scanner,int __sane_unused__ * width,int __sane_unused__ * height,int __sane_unused__ * bps)188 get_PNG_data(capabilities_t __sane_unused__ *scanner,
189 int __sane_unused__ *width,
190 int __sane_unused__ *height,
191 int __sane_unused__ *bps)
192 {
193 return (SANE_STATUS_INVAL);
194 }
195
196 #endif
197