1 /* sane - Scanner Access Now Easy.
2
3 pieusb_buffer.c
4
5 Copyright (C) 2012-2015 Jan Vleeshouwers, Michael Rickmann, Klaus Kaempf
6
7 This file is part of the SANE package.
8
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License as
11 published by the Free Software Foundation; either version 2 of the
12 License, or (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <https://www.gnu.org/licenses/>.
21
22 As a special exception, the authors of SANE give permission for
23 additional uses of the libraries contained in this release of SANE.
24
25 The exception is that, if you link a SANE library with other files
26 to produce an executable, this does not by itself cause the
27 resulting executable to be covered by the GNU General Public
28 License. Your use of that executable is in no way restricted on
29 account of linking the SANE library code into it.
30
31 This exception does not, however, invalidate any other reasons why
32 the executable file might be covered by the GNU General Public
33 License.
34
35 If you submit changes to SANE to the maintainers to be included in
36 a subsequent release, you agree by submitting the changes that
37 those changes may be distributed with this exception intact.
38
39 If you write modifications of your own for SANE, it is your choice
40 whether to permit this exception to apply to your modifications.
41 If you do not wish that, delete this exception notice. */
42
43 /* =========================================================================
44 *
45 * Read buffer
46 *
47 * Data obtained from the scanner cannot be presented to the frontend immediately.
48 * The scanner returns data in the 'index' or 'line' color format, which means it
49 * returns data in batches which contain a single color of a scan line.
50 *
51 * These must finally be converted into the SANE data format (data for a single
52 * pixel in consecutive bytes). Apart from that, sane_read() must be able to
53 * return any amount of data bytes.
54 *
55 * In between, data processing may be necessary, usually requiring the whole
56 * image to be available.
57 *
58 * To accommodate all this, the buffer stores all samples as 16-bit values, even
59 * if the original values are 8-bit or even 1 bit. This is a waste of space, but
60 * makes processing much easier, and it is only temporary.
61 *
62 * The read buffer is constructed by a call to buffer_create(), which initializes
63 * the buffer based on width, height, number of colors and depth. The buffer
64 * contains data organized in color planes, with each plane consisting of lines,
65 * each line of a fixed number of (single color) pixels, and each pixel of a fixed
66 * number of bits (or bytes).
67 *
68 * The buffer maintains read and write pointers.
69 *
70 * Multi-color data with a bit depth of 1 are packed in single color bytes, so
71 * the data obtained from the scanner does not need conversion.
72 *
73 * ========================================================================= */
74
75 #define DEBUG_DECLARE_ONLY
76
77 /* Configuration defines */
78 #include "../include/sane/config.h"
79
80 /* SANE includes */
81 #include "../include/sane/sane.h"
82 #include "../include/sane/saneopts.h"
83 #include "../include/sane/sanei_usb.h"
84 #include "../include/sane/sanei_config.h"
85
86 /* Backend includes */
87 #define BACKEND_NAME pieusb
88 #include "../include/sane/sanei_backend.h"
89 #include "pieusb.h"
90
91 #include "pieusb_specific.h"
92 #include "pieusb_buffer.h"
93
94 #ifdef HAVE_ALLOCA_H
95 #include <alloca.h>
96 #endif
97
98 #include <stdio.h>
99 #include <fcntl.h>
100 #include <sys/mman.h>
101
102 #include "byteorder.h"
103
104 static void buffer_update_read_index(struct Pieusb_Read_Buffer* buffer, int increment);
105
106 /* READER */
107
108 /**
109 * Initialize the buffer.
110 * A scanner has a Pieusb_Read_Buffer struct as one of its members.
111 *
112 * @param buffer the buffer to initialize
113 * @param width number of pixels on a line (row)
114 * @param height number of lines in the buffer (pixels in a column)
115 * @param colors bitmap specifying the colors in the scanned data (bitmap: 0000 IBGR)
116 * @param depth number of bits of a color
117 * @param bigendian how to store multi-byte values: bigendian if true
118 * @param maximum_size maximum size of buffer (-1 = size of image)
119 */
120
121 SANE_Status
sanei_pieusb_buffer_create(struct Pieusb_Read_Buffer* buffer, SANE_Int width, SANE_Int height, SANE_Byte color_spec, SANE_Byte depth)122 sanei_pieusb_buffer_create(struct Pieusb_Read_Buffer* buffer, SANE_Int width, SANE_Int height, SANE_Byte color_spec, SANE_Byte depth)
123 {
124 int k, result;
125 unsigned int buffer_size_bytes;
126 unsigned char g;
127
128 /* Base parameters */
129 buffer->width = width;
130 buffer->height = height;
131 buffer->colors = 0;
132 if (color_spec & 0x01) { buffer->color_index_red = 0; buffer->colors++; } else { buffer->color_index_red = -1; }
133 if (color_spec & 0x02) { buffer->color_index_green = 1; buffer->colors++; } else { buffer->color_index_green = -1; }
134 if (color_spec & 0x04) { buffer->color_index_blue = 2; buffer->colors++; } else { buffer->color_index_blue = -1; }
135 if (color_spec & 0x08) { buffer->color_index_infrared = 3; buffer->colors++; } else { buffer->color_index_infrared = -1; }
136 if (buffer->colors == 0) {
137 DBG(DBG_error, "sanei_pieusb_buffer_create(): no colors specified\n");
138 return SANE_STATUS_INVAL;
139 }
140 buffer->depth = depth;
141 if (depth < 1 || depth > 16) {
142 DBG(DBG_error, "sanei_pieusb_buffer_create(): unsupported depth %d\n", depth);
143 return SANE_STATUS_INVAL;
144 }
145 buffer->packing_density = (depth == 1) ? 8 : 1; /* These are all the situations we have */
146
147 /* Derived*/
148 buffer->packet_size_bytes = (buffer->depth * buffer->packing_density + 7) / 8;
149 buffer->line_size_packets = (buffer->width + buffer->packing_density -1) / buffer->packing_density;
150 buffer->line_size_bytes = buffer->line_size_packets * buffer->packet_size_bytes;
151 buffer->image_size_bytes = buffer->colors * buffer->height * buffer->line_size_bytes;
152
153 /* Create empty file */
154 snprintf(buffer->buffer_name, L_tmpnam, "/tmp/sane.XXXXXX");
155 if (buffer->data_file != 0) /* might still be open from previous invocation */
156 close(buffer->data_file);
157 buffer->data_file = mkstemp(buffer->buffer_name);
158 if (buffer->data_file == -1) {
159 buffer->data_file = 0;
160 buffer->data = NULL;
161 perror("sanei_pieusb_buffer_create(): error opening image buffer file");
162 return SANE_STATUS_IO_ERROR;
163 }
164 /* Stretch the file size */
165 buffer_size_bytes = buffer->width * buffer->height * buffer->colors * sizeof(SANE_Uint);
166 if (buffer_size_bytes == 0) {
167 close(buffer->data_file);
168 buffer->data_file = 0;
169 DBG(DBG_error, "sanei_pieusb_buffer_create(): buffer_size is zero: width %d, height %d, colors %d\n", buffer->width, buffer->height, buffer->colors);
170 return SANE_STATUS_INVAL;
171 }
172 result = lseek(buffer->data_file, buffer_size_bytes-1, SEEK_SET);
173 if (result == -1) {
174 close(buffer->data_file);
175 buffer->data_file = 0;
176 buffer->data = NULL;
177 DBG(DBG_error, "sanei_pieusb_buffer_create(): error calling lseek() to 'stretch' the file to %d bytes\n", buffer_size_bytes-1);
178 perror("sanei_pieusb_buffer_create(): error calling lseek()");
179 return SANE_STATUS_INVAL;
180 }
181 /* Write one byte at the end */
182 g = 0x00;
183 result = write(buffer->data_file, &g, 1);
184 if (result < 0) {
185 close(buffer->data_file);
186 buffer->data_file = 0;
187 buffer->data = NULL;
188 perror("sanei_pieusb_buffer_create(): error writing a byte at the end of the file");
189 return SANE_STATUS_IO_ERROR;
190 }
191 #ifdef HAVE_MMAP
192 /* Create memory map */
193 buffer->data = mmap(NULL, buffer_size_bytes, PROT_WRITE | PROT_READ, MAP_SHARED, buffer->data_file, 0);
194 if (buffer->data == MAP_FAILED) {
195 close(buffer->data_file);
196 buffer->data = NULL;
197 perror("sanei_pieusb_buffer_create(): error mapping file");
198 return SANE_STATUS_INVAL;
199 }
200 #else
201 #error mmap(2) not available, aborting
202 #endif
203 buffer->data_size = buffer_size_bytes;
204 /* Reading and writing */
205 buffer->p_read = calloc(buffer->colors, sizeof(SANE_Uint*));
206 if (buffer->p_read == NULL)
207 return SANE_STATUS_NO_MEM;
208 buffer->p_write = calloc(buffer->colors, sizeof(SANE_Uint*));
209 if (buffer->p_write == NULL)
210 return SANE_STATUS_NO_MEM;
211 for (k = 0; k < buffer->colors; k++) {
212 buffer->p_write[k] = buffer->data + k * buffer->height * buffer->width;
213 buffer->p_read[k] = buffer->p_write[k];
214 }
215 buffer->read_index[0] = 0;
216 buffer->read_index[1] = 0;
217 buffer->read_index[2] = 0;
218 buffer->read_index[3] = 0;
219
220 /* Statistics */
221 buffer->bytes_read = 0;
222 buffer->bytes_written = 0;
223 buffer->bytes_unread = 0;
224
225 DBG(DBG_info,"pieusb: Read buffer created: w=%d h=%d ncol=%d depth=%d in file %s\n",
226 buffer->width, buffer->height, buffer->colors, buffer->depth, buffer->buffer_name);
227 return SANE_STATUS_GOOD;
228 }
229
230 /**
231 * Delete buffer and free its resources
232 *
233 * @param buffer
234 */
235 void
sanei_pieusb_buffer_delete(struct Pieusb_Read_Buffer* buffer)236 sanei_pieusb_buffer_delete(struct Pieusb_Read_Buffer* buffer)
237 {
238 #ifdef HAVE_MMAP
239 munmap(buffer->data, buffer->data_size);
240 #else
241 #error mmap(2) not available, aborting
242 #endif
243 /* ftruncate(buffer->data_file,0); Can we delete given a file-descriptor? */
244 close(buffer->data_file);
245 /* remove fs entry */
246 unlink(buffer->buffer_name);
247 buffer->data_file = 0;
248 buffer->data_size = 0;
249 free(buffer->p_read);
250 free(buffer->p_write);
251 buffer->data = 0;
252 buffer->width = 0;
253 buffer->height = 0;
254 buffer->depth = 0;
255 buffer->colors = 0;
256 buffer->packing_density = 0;
257
258 DBG(DBG_info,"pieusb: Read buffer deleted\n");
259 }
260
261 /**
262 * Add a line to the reader buffer, for the given color.
263 * The buffer checks and decides how to interpret the data.
264 *
265 * @param buffer
266 * @param color Color code for line
267 * @param line
268 * @param size Number of bytes in line
269 * @return 1 if successful, 0 if not
270 */
271 SANE_Int
sanei_pieusb_buffer_put_single_color_line(struct Pieusb_Read_Buffer* buffer, SANE_Byte color, void* line, SANE_Int size)272 sanei_pieusb_buffer_put_single_color_line(struct Pieusb_Read_Buffer* buffer, SANE_Byte color, void* line, SANE_Int size)
273 {
274
275 SANE_Int c, k, m, n;
276
277 /* Check index code */
278 c = -1;
279 switch (color) {
280 case 'R':
281 c = buffer->color_index_red;
282 break;
283 case 'G':
284 c = buffer->color_index_green;
285 break;
286 case 'B':
287 c = buffer->color_index_blue;
288 break;
289 case 'I':
290 c = buffer->color_index_infrared;
291 break;
292 }
293 if (c == -1) {
294 DBG(DBG_error, "sanei_pieusb_buffer_put_single_color_line(): color '%c' not specified when buffer was created\n", color);
295 return 0;
296 }
297 DBG(DBG_info_buffer, "sanei_pieusb_buffer_put_single_color_line() line color = %d (0=R, 1=G, 2=B, 3=I)\n",c);
298
299 /* Check line size (for a line with a single color) */
300 if (buffer->line_size_bytes != size) {
301 DBG(DBG_error, "sanei_pieusb_buffer_put_single_color_line(): incorrect line size, expecting %d, got %d\n", buffer->line_size_bytes, size);
302 return 0;
303 }
304
305 /* The general approach for all densities and packet sizes
306 * - process packet_size_bytes at a time
307 * - use packing_density to decode the full packet into separate values
308 * - now save these values as neighbouring pixels on the current line
309 * Use custom code for the 1-byte and 2-byte single sample cases,
310 * because the general approach is a bit overkill for them.
311 */
312
313 if (buffer->packet_size_bytes == 1 && buffer->packing_density == 1) {
314 uint8_t* p_packet = (uint8_t*)line;
315 n = 0;
316 while (n < size) {
317 /* Get next packet data & store in buffer */
318 *buffer->p_write[c]++ = *p_packet++;
319 n++;
320 }
321 } else if (buffer->packet_size_bytes == 2 && buffer->packing_density == 1) {
322 uint16_t* p_packet = (uint16_t*)line;
323 n = 0;
324 while (n < size) {
325 /* Get next packet data & store in buffer */
326 *buffer->p_write[c]++ = le16toh (*p_packet++);
327 n += 2;
328 }
329 } else {
330 uint8_t* p_packet = (uint8_t*)line;
331 uint8_t *packet = (uint8_t *)alloca(buffer->packet_size_bytes * sizeof(uint8_t));
332 SANE_Uint val;
333 uint8_t mask = ~(0xFF >> buffer->depth); /* byte with depth most significant bits set */
334 n = 0;
335 while (n < size) {
336 /* Get next packet data */
337 for (k = 0; k < buffer->packet_size_bytes; k++) packet[k] = *p_packet++;
338 /* Unpack packing_density samples from packet. Of course,
339 * buffer->depth * packing_density <= # bits in packet.
340 * That is checked at buffer creation. */
341 for (k = 0; k < buffer->packing_density; k++) {
342 /* Take 1st depth bits and store in val */
343 val = (packet[0] & mask) >> (8-buffer->depth);
344 /* Now shift packet bytes depth bits left */
345 for (m = 0; m < buffer->packet_size_bytes; m++) {
346 /* Shift left one sample */
347 packet[m] <<= buffer->depth;
348 if (m < buffer->packet_size_bytes-1) {
349 /* If there are more bytes, insert 1st depth bits of next byte */
350 packet[m] |= (packet[m+1] >> (8-buffer->depth));
351 }
352 }
353 /* Store in buffer */
354 *buffer->p_write[c]++ = val;
355 }
356 n += buffer->packet_size_bytes;
357 }
358 }
359
360 /* Update state & statistics */
361 buffer->bytes_written += size;
362 buffer->bytes_unread += size;
363
364 /* Output current buffer state */
365 /* buffer_output_state(buffer); */
366
367 return 1;
368 }
369
370 /**
371 * Write line of full color pixels to the buffer.
372 *
373 * @param buffer Read buffer
374 * @param pixel array of full color pixel data
375 * @param size Number of bytes in the line
376 * @return 1 if successful, 0 if not
377 */
378 /**
379 *
380 */
381 SANE_Int
sanei_pieusb_buffer_put_full_color_line(struct Pieusb_Read_Buffer* buffer, void* line, int size)382 sanei_pieusb_buffer_put_full_color_line(struct Pieusb_Read_Buffer* buffer, void* line, int size)
383 {
384 int k, c, m, n;
385
386 DBG(DBG_info_buffer, "sanei_pieusb_buffer_put_full_color_line() entered\n");
387
388 /* Check line size */
389 if (buffer->line_size_bytes * buffer->colors != size) {
390 DBG(DBG_error, "sanei_pieusb_buffer_put_full_color_line(): incorrect line size, expecting %d, got %d\n", buffer->line_size_bytes * buffer->colors, size);
391 return 0;
392 }
393
394 /* The general approach for all densities and packet sizes
395 * - process packet_size_bytes at a time
396 * - use packing_density to decode the full packet into separate values
397 * - now save these values as neighbouring pixels on the current line
398 * Use custom code for the 1-byte and 2-byte single sample cases,
399 * because the general approach is a bit overkill for them.
400 */
401
402 if (buffer->packet_size_bytes == 1 && buffer->packing_density == 1) {
403 uint8_t* p_packet = (uint8_t*)line;
404 n = 0;
405 while (n < size) {
406 /* Get next packet data & store in buffer */
407 for (c = 0; c < buffer->colors; c++) {
408 *buffer->p_write[c]++ = *p_packet++;
409 n++;
410 }
411 }
412 } else if (buffer->packet_size_bytes == 2 && buffer->packing_density == 1) {
413 uint16_t* p_packet = (uint16_t*)line;
414 n = 0;
415 while (n < size) {
416 /* Get next packet data & store in buffer */
417 for (c = 0; c < buffer->colors; c++) {
418 *buffer->p_write[c]++ = le16toh (*p_packet++);
419 n += 2;
420 }
421 }
422 } else {
423 uint8_t* p_packet = (uint8_t*)line;
424 uint8_t *packet = (uint8_t *)alloca(buffer->packet_size_bytes * sizeof(uint8_t));
425 SANE_Uint val;
426 uint8_t mask = ~(0xFF >> buffer->depth); /* byte with depth most significant bits set */
427 /* DBG(DBG_info,"buffer_put_full_color_line(): mask %02x\n",mask); */
428 n = 0;
429 while (n < size) {
430 /* Get next packet data */
431 for (c = 0; c < buffer->colors; c++) {
432 for (k = 0; k < buffer->packet_size_bytes; k++) {
433 packet[k] = *p_packet++;
434 /* DBG(DBG_info,"buffer_put_full_color_line(): packet[%d] = %02x\n",k,packet[k]); */
435 }
436 /* Unpack packing_density samples from packet. Of course,
437 * buffer->depth * packing_density <= # bits in packet.
438 * That is checked at buffer creation. */
439 for (k = 0; k < buffer->packing_density; k++) {
440 /* Take 1st depth bits and store in val */
441 val = (packet[0] & mask) >> (8-buffer->depth);
442 /* DBG(DBG_info,"buffer_put_full_color_line(): val[%d] = %02x\n",k,val); */
443 /* Now shift packet bytes depth bits left */
444 for (m = 0; m < buffer->packet_size_bytes; m++) {
445 /* Shift left one sample */
446 packet[m] <<= buffer->depth;
447 /* DBG(DBG_info,"buffer_put_full_color_line(): shift packet[%d] = %02x\n",m,packet[m]); */
448 if (m < buffer->packet_size_bytes-1) {
449 /* If there are more bytes, insert 1st depth bits of next byte */
450 packet[m] |= (packet[m+1] >> (8-buffer->depth));
451 /* DBG(DBG_info,"buffer_put_full_color_line(): shift packet[%d] = %02x\n",m,packet[m]); */
452 }
453 }
454 /* Store in buffer */
455 *buffer->p_write[c]++ = val;
456 }
457 n += buffer->packet_size_bytes;
458 }
459 }
460 }
461
462 /* Update state & statistics */
463 buffer->bytes_written += size;
464 buffer->bytes_unread += size;
465
466 /* Output current buffer state */
467 /* buffer_output_state(buffer); */
468
469 return 1;
470 }
471
472 /**
473 * Return bytes from the buffer. Do not mind pixel boundaries.
474 * Since the image data is organized in color planes, return bytes from the
475 * planes in the defined order. Take care to return multi-byte values after
476 * each other. Pack unpacked values.
477 *
478 * @param buffer Buffer to return bytes from.
479 * @param data Byte array to return bytes in
480 * @param max_len Maximum number of bytes returned
481 * @param len Actual number of bytes returned
482 */
483 void
sanei_pieusb_buffer_get(struct Pieusb_Read_Buffer* buffer, SANE_Byte* data, SANE_Int max_len, SANE_Int* len)484 sanei_pieusb_buffer_get(struct Pieusb_Read_Buffer* buffer, SANE_Byte* data, SANE_Int max_len, SANE_Int* len)
485 {
486 SANE_Byte *pdata;
487 SANE_Int n, i, n_bits, N;
488
489 DBG(DBG_info_buffer, "sanei_pieusb_buffer_get() entered\n");
490
491 /* Read from the p_read locations */
492 pdata = data;
493 n = 0;
494 N = buffer->width * buffer->height;
495 /* Determine bytes to return */
496 if (buffer->packet_size_bytes == 1 && buffer->packing_density == 1) {
497 /* Single byte values in buffer */
498 while (n < max_len && buffer->bytes_read < buffer->image_size_bytes) {
499 /* Return byte*/
500 *pdata++ = *(buffer->data + N*buffer->read_index[0] + buffer->width*buffer->read_index[1] + buffer->read_index[2]) & 0xFF;
501 /* Update read indices */
502 buffer_update_read_index(buffer,1);
503 /* Update number of bytes read */
504 buffer->bytes_read++;
505 n++;
506 }
507 } else if (buffer->packet_size_bytes == 1 && buffer->packing_density == 8) {
508 /* Unpacked bits in buffer: repack */
509 while (n < max_len && buffer->bytes_read < buffer->image_size_bytes) {
510 uint8_t val = 0;
511 /* How many bits to pack? At the end of a line it may be less than 8 */
512 n_bits = 8;
513 if (buffer->width - buffer->read_index[2] < 8) {
514 n_bits = buffer->width - buffer->read_index[2];
515 }
516 /* Pack n_bits samples from same color plane */
517 for (i = 0; i < n_bits; i++) {
518 if (*(buffer->data + N*buffer->read_index[0] + buffer->width*buffer->read_index[1] + buffer->read_index[2] + i) > 0) {
519 val |= (0x80 >> i);
520 }
521 }
522 /* Return byte */
523 *pdata++ = val;
524 /* Update read indices */
525 buffer_update_read_index(buffer,n_bits);
526 /* Update number of bytes read */
527 buffer->bytes_read++;
528 n++;
529 }
530 } else if (buffer->packet_size_bytes == 2) {
531 /* Two-byte values in buffer */
532 while (n < max_len && buffer->bytes_read < buffer->image_size_bytes) {
533 /* Pointer to byte to return */
534 SANE_Uint val = *(buffer->data + N*buffer->read_index[0] + buffer->width*buffer->read_index[1] + buffer->read_index[2]);
535 /* Return byte */
536 if (buffer->read_index[3] == 0) {
537 *pdata++ = *((SANE_Byte*)(&val));
538 } else {
539 *pdata++ = *((SANE_Byte*)(&val)+1);
540 }
541 /* Update read indices */
542 buffer_update_read_index(buffer,1);
543 /* Update number of bytes read */
544 buffer->bytes_read++;
545 n++;
546 }
547 } else {
548 /* not implemented */
549 DBG(DBG_error, "buffer_put(): paccket size & density of %d/%d not implemented\n", buffer->packet_size_bytes, buffer->packing_density);
550 return;
551 }
552 *len = n;
553
554 /* Update statistics */
555 buffer->bytes_unread -= n;
556
557 /* Output current buffer state */
558 /* buffer_output_state(buffer); */
559 }
560
561 /**
562 * Update read index to point a given number of bytes past the current position.
563 *
564 * @param buffer the buffer to initialize
565 * @param increment the amount of bytes to move the index
566 */
buffer_update_read_index(struct Pieusb_Read_Buffer* buffer, int increment)567 static void buffer_update_read_index(struct Pieusb_Read_Buffer* buffer, int increment)
568 {
569 /* Update read indices
570 * [3] = byte-index in 2-byte value: increased first, if we have 2-byte data
571 * [2] = index of pixel on line: increased after color plane
572 * [1] = index of line: increased after line is complete
573 * [0] = color index: increased first since SANE requires full color pixels */
574 if (buffer->read_index[3] == 0 && buffer->packet_size_bytes == 2) {
575 buffer->read_index[3] = 1;
576 } else {
577 buffer->read_index[3] = 0;
578 buffer->read_index[0]++;
579 if (buffer->read_index[0] == buffer->colors) {
580 buffer->read_index[0] = 0;
581 buffer->read_index[2] += increment;
582 if (buffer->read_index[2] >= buffer->width) {
583 buffer->read_index[2] = 0;
584 buffer->read_index[1]++;
585 }
586 }
587 }
588 }
589
590 #if 0
591 /**
592 * Display the buffer state.
593 *
594 * @param buffer the buffer to initialize
595 */
596
597 static void buffer_output_state(struct Pieusb_Read_Buffer* buffer)
598 {
599 SANE_Int line_size;
600 SANE_Int N, k, loc[4];
601
602 line_size = buffer->line_size_bytes * buffer->colors; /* Full line size in bytes */
603
604 DBG(DBG_info_buffer, "Buffer data\n");
605 DBG(DBG_info_buffer," width/height/colors/depth = %d %d %d %d (buffer size %d)\n",
606 buffer->width, buffer->height, buffer->colors, buffer->depth, buffer->image_size_bytes);
607
608 /* Summary */
609 N = buffer->width * buffer->height;
610 for (k = 0; k < buffer->colors; k++) {
611 loc[k] = buffer->p_read[k] - buffer->data - k*N;
612 }
613 for (k = buffer->colors; k < 4; k++) {
614 loc[k] = 0;
615 }
616 DBG(DBG_info_buffer, " reading at: lines = %d:%d:%d:%d\n", loc[0], loc[1], loc[2], loc[3]);
617 for (k = 0; k < buffer->colors; k++) {
618 loc[k] = buffer->p_write[k] - buffer->data - k*N;
619 }
620 for (k = buffer->colors; k < 4; k++) {
621 loc[k] = 0;
622 }
623 DBG(DBG_info_buffer, " writing at: lines = %d:%d:%d:%d\n", loc[0], loc[1], loc[2], loc[3]);
624
625 /* Progress */
626 double fdata = (double)buffer->bytes_unread/buffer->image_size_bytes*100;
627 double fread = (double)buffer->bytes_read/buffer->image_size_bytes*100;
628 double fwritten = (double)buffer->bytes_written/buffer->image_size_bytes*100;
629 DBG(DBG_info_buffer, " byte counts: image = %d, data = %d (%.0f%%), read = %d (%.0f%%), written = %d (%.0f%%)\n",
630 buffer->image_size_bytes, buffer->bytes_unread, fdata, buffer->bytes_read, fread, buffer->bytes_written, fwritten);
631 DBG(DBG_info_buffer, " line counts: image = %.1f, data = %.1f, read = %.1f, written = %.1f\n",
632 (double)buffer->image_size_bytes/line_size, (double)buffer->bytes_unread/line_size, (double)buffer->bytes_read/line_size, (double)buffer->bytes_written/line_size);
633
634 }
635 #endif
636