• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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