1 /* sane - Scanner Access Now Easy.
2
3 Copyright (C) 2019 Thierry HUCHARD <thierry@ordissimo.com>
4
5 This file is part of the SANE package.
6
7 SANE is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11
12 SANE is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with sane; see the file COPYING.
19 If not, see <https://www.gnu.org/licenses/>.
20
21 This file implements a SANE backend for eSCL scanners. */
22
23 #define DEBUG_DECLARE_ONLY
24 #include "../include/sane/config.h"
25
26 #include "escl.h"
27
28 #include "../include/sane/sanei.h"
29
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <stddef.h>
34 #include <math.h>
35
36 #include <errno.h>
37
38 #if HAVE_POPPLER_GLIB
39 #include <poppler/glib/poppler.h>
40 #endif
41
42 #include <setjmp.h>
43
44
45 #if HAVE_POPPLER_GLIB
46
47 #define ESCL_PDF_USE_MAPPED_FILE POPPLER_CHECK_VERSION(0,82,0)
48
49 #if ! ESCL_PDF_USE_MAPPED_FILE
50 static unsigned char*
set_file_in_buffer(FILE * fp,int * size)51 set_file_in_buffer(FILE *fp, int *size)
52 {
53 char buffer[1024] = { 0 };
54 unsigned char *data = (unsigned char *)calloc(1, sizeof(char));
55 int nx = 0;
56
57 while(!feof(fp))
58 {
59 int n = fread(buffer,sizeof(char),1024,fp);
60 unsigned char *t = realloc(data, nx + n + 1);
61 if (t == NULL) {
62 DBG(10, "not enough memory (realloc returned NULL)");
63 free(data);
64 return NULL;
65 }
66 data = t;
67 memcpy(&(data[nx]), buffer, n);
68 nx = nx + n;
69 data[nx] = 0;
70 }
71 *size = nx;
72 return data;
73 }
74 #endif
75
76 static unsigned char *
cairo_surface_to_pixels(cairo_surface_t * surface,int bps)77 cairo_surface_to_pixels (cairo_surface_t *surface, int bps)
78 {
79 int cairo_width, cairo_height, cairo_rowstride;
80 unsigned char *data, *dst, *cairo_data;
81 unsigned int *src;
82 int x, y;
83
84 cairo_width = cairo_image_surface_get_width (surface);
85 cairo_height = cairo_image_surface_get_height (surface);
86 cairo_rowstride = cairo_image_surface_get_stride (surface);
87 cairo_data = cairo_image_surface_get_data (surface);
88 data = (unsigned char*)calloc(1, sizeof(unsigned char) * (cairo_height * cairo_width * bps));
89
90 for (y = 0; y < cairo_height; y++)
91 {
92 src = (unsigned int *) (cairo_data + y * cairo_rowstride);
93 dst = data + y * (cairo_width * bps);
94 for (x = 0; x < cairo_width; x++)
95 {
96 dst[0] = (*src >> 16) & 0xff;
97 dst[1] = (*src >> 8) & 0xff;
98 dst[2] = (*src >> 0) & 0xff;
99 dst += bps;
100 src++;
101 }
102 }
103 return data;
104 }
105
106 SANE_Status
get_PDF_data(capabilities_t * scanner,int * width,int * height,int * bps)107 get_PDF_data(capabilities_t *scanner, int *width, int *height, int *bps)
108 {
109 cairo_surface_t *cairo_surface = NULL;
110 cairo_t *cr;
111 PopplerPage *page;
112 PopplerDocument *doc;
113 double dw, dh;
114 int w, h;
115 unsigned char* surface = NULL;
116 SANE_Status status = SANE_STATUS_GOOD;
117
118 #if ESCL_PDF_USE_MAPPED_FILE
119 GMappedFile *file;
120 GBytes *bytes;
121
122 file = g_mapped_file_new_from_fd (fileno (scanner->tmp), 0, NULL);
123 if (!file) {
124 DBG(1, "Error : g_mapped_file_new_from_fd");
125 status = SANE_STATUS_INVAL;
126 goto close_file;
127 }
128
129 bytes = g_mapped_file_get_bytes (file);
130 if (!bytes) {
131 DBG(1, "Error : g_mapped_file_get_bytes");
132 status = SANE_STATUS_INVAL;
133 goto free_file;
134 }
135
136 doc = poppler_document_new_from_bytes (bytes, NULL, NULL);
137 if (!doc) {
138 DBG(1, "Error : poppler_document_new_from_bytes");
139 status = SANE_STATUS_INVAL;
140 goto free_bytes;
141 }
142 #else
143 int size = 0;
144 char *data = NULL;
145
146 data = (char*)set_file_in_buffer(scanner->tmp, &size);
147 if (!data) {
148 DBG(1, "Error : set_file_in_buffer");
149 status = SANE_STATUS_INVAL;
150 goto close_file;
151 }
152
153 doc = poppler_document_new_from_data (data, size, NULL, NULL);
154 if (!doc) {
155 DBG(1, "Error : poppler_document_new_from_data");
156 status = SANE_STATUS_INVAL;
157 goto free_data;
158 }
159 #endif
160
161 page = poppler_document_get_page (doc, 0);
162 if (!page) {
163 DBG(1, "Error : poppler_document_get_page");
164 status = SANE_STATUS_INVAL;
165 goto free_doc;
166 }
167
168 poppler_page_get_size (page, &dw, &dh);
169 dw = (double)scanner->caps[scanner->source].default_resolution * dw / 72.0;
170 dh = (double)scanner->caps[scanner->source].default_resolution * dh / 72.0;
171 w = (int)ceil(dw);
172 h = (int)ceil(dh);
173 cairo_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w, h);
174 if (!cairo_surface) {
175 DBG(1, "Error : cairo_image_surface_create");
176 status = SANE_STATUS_INVAL;
177 goto free_page;
178 }
179
180 cr = cairo_create (cairo_surface);
181 if (!cairo_surface) {
182 DBG(1, "Error : cairo_create");
183 status = SANE_STATUS_INVAL;
184 goto free_surface;
185 }
186 cairo_scale (cr, (double)scanner->caps[scanner->source].default_resolution / 72.0,
187 (double)scanner->caps[scanner->source].default_resolution / 72.0);
188 cairo_save (cr);
189 poppler_page_render (page, cr);
190 cairo_restore (cr);
191
192 cairo_set_operator (cr, CAIRO_OPERATOR_DEST_OVER);
193 cairo_set_source_rgb (cr, 1, 1, 1);
194 cairo_paint (cr);
195
196 int st = cairo_status(cr);
197 if (st)
198 {
199 DBG(1, "%s", cairo_status_to_string (st));
200 status = SANE_STATUS_INVAL;
201 goto destroy_cr;
202 }
203
204 *bps = 3;
205
206 DBG(1, "Escl Pdf : Image Size [%dx%d]\n", w, h);
207
208 surface = cairo_surface_to_pixels (cairo_surface, *bps);
209 if (!surface) {
210 status = SANE_STATUS_NO_MEM;
211 DBG(1, "Escl Pdf : Surface Memory allocation problem");
212 goto destroy_cr;
213 }
214
215 // If necessary, trim the image.
216 surface = escl_crop_surface(scanner, surface, w, h, *bps, width, height);
217 if (!surface) {
218 DBG(1, "Escl Pdf Crop: Surface Memory allocation problem");
219 status = SANE_STATUS_NO_MEM;
220 }
221
222 destroy_cr:
223 cairo_destroy (cr);
224 free_surface:
225 cairo_surface_destroy (cairo_surface);
226 free_page:
227 g_object_unref (page);
228 free_doc:
229 g_object_unref (doc);
230 #if ESCL_PDF_USE_MAPPED_FILE
231 free_bytes:
232 g_bytes_unref (bytes);
233 free_file:
234 g_mapped_file_unref (file);
235 #else
236 free_data:
237 free(data);
238 #endif
239 close_file:
240 if (scanner->tmp)
241 fclose(scanner->tmp);
242 scanner->tmp = NULL;
243 return status;
244 }
245 #else
246
247 SANE_Status
get_PDF_data(capabilities_t __sane_unused__ * scanner,int __sane_unused__ * width,int __sane_unused__ * height,int __sane_unused__ * bps)248 get_PDF_data(capabilities_t __sane_unused__ *scanner,
249 int __sane_unused__ *width,
250 int __sane_unused__ *height,
251 int __sane_unused__ *bps)
252 {
253 return (SANE_STATUS_INVAL);
254 }
255
256 #endif
257