1/*************************************************************************** 2 * SANE - Scanner Access Now Easy. 3 4 dc25.c 5 6 This file (C) 1998 Peter Fales 7 8 This file is part of the SANE package. 9 10 This program is free software; you can redistribute it and/or 11 modify it under the terms of the GNU General Public License as 12 published by the Free Software Foundation; either version 2 of the 13 License, or (at your option) any later version. 14 15 This program is distributed in the hope that it will be useful, but 16 WITHOUT ANY WARRANTY; without even the implied warranty of 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 General Public License for more details. 19 20 You should have received a copy of the GNU General Public License 21 along with this program. If not, see <https://www.gnu.org/licenses/>. 22 23 As a special exception, the authors of SANE give permission for 24 additional uses of the libraries contained in this release of SANE. 25 26 The exception is that, if you link a SANE library with other files 27 to produce an executable, this does not by itself cause the 28 resulting executable to be covered by the GNU General Public 29 License. Your use of that executable is in no way restricted on 30 account of linking the SANE library code into it. 31 32 This exception does not, however, invalidate any other reasons why 33 the executable file might be covered by the GNU General Public 34 License. 35 36 If you submit changes to SANE to the maintainers to be included in 37 a subsequent release, you agree by submitting the changes that 38 those changes may be distributed with this exception intact. 39 40 If you write modifications of your own for SANE, it is your choice 41 whether to permit this exception to apply to your modifications. 42 If you do not wish that, delete this exception notice. 43 44 *************************************************************************** 45 46 This file implements a SANE backend for the Kodak DC-25 (and 47 probably the DC-20) digital cameras. THIS IS EXTREMELY ALPHA CODE! 48 USE AT YOUR OWN RISK!! 49 50 (feedback to: dc25-devel@fales-lorenz.net) 51 52 This backend is based heavily on the dc20ctrl package by Ugo 53 Paternostro <paterno@dsi.unifi.it>. I've attached his header below: 54 55 *************************************************************************** 56 57 * Copyright (C) 1998 Ugo Paternostro <paterno@dsi.unifi.it> 58 * 59 * This file is part of the dc20ctrl package. The complete package can be 60 * downloaded from: 61 * http://aguirre.dsi.unifi.it/~paterno/binaries/dc20ctrl.tar.gz 62 * 63 * This package is derived from the dc20 package, built by Karl Hakimian 64 * <hakimian@aha.com> that you can find it at ftp.eecs.wsu.edu in the 65 * /pub/hakimian directory. The complete URL is: 66 * ftp://ftp.eecs.wsu.edu/pub/hakimian/dc20.tar.gz 67 * 68 * This package also includes a slightly modified version of the Comet to ppm 69 * conversion routine written by YOSHIDA Hideki <hideki@yk.rim.or.jp> 70 * 71 * This program is free software; you can redistribute it and/or modify 72 * it under the terms of the GNU General Public License as published 73 * the Free Software Foundation; either version 2 of the License, or 74 * (at your option) any later version. 75 * 76 * This program is distributed in the hope that it will be useful, 77 * but WITHOUT ANY WARRANTY; without even the implied warranty of 78 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 79 * GNU General Public License for more details. 80 * 81 * You should have received a copy of the GNU General Public License 82 * along with this program; if not, write to the Free Software 83 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 84 * 85 86 ***************************************************************************/ 87 88#include "../include/sane/config.h" 89 90#include <stdlib.h> 91#include <string.h> 92#include <stdio.h> 93#include <unistd.h> 94#include <fcntl.h> 95#include <limits.h> 96 97#include "../include/sane/sane.h" 98#include "../include/sane/sanei.h" 99#include "../include/sane/saneopts.h" 100 101#define BACKEND_NAME dc25 102#include "../include/sane/sanei_backend.h" 103 104#include "dc25.h" 105 106#ifndef PATH_MAX 107# define PATH_MAX 1024 108#endif 109 110#define MAGIC (void *)0xab730324 111#define DC25_CONFIG_FILE "dc25.conf" 112#define THUMBSIZE ( (CameraInfo.model == 0x25 ) ? 14400 : 5120 ) 113 114static SANE_Bool is_open = 0; 115 116static SANE_Byte dc25_opt_image_number = 1; /* Image to load */ 117static SANE_Bool dc25_opt_thumbnails; /* Load thumbnails */ 118static SANE_Bool dc25_opt_snap; /* Take new picture */ 119static SANE_Bool dc25_opt_lowres; /* Use low resoluiton */ 120#define DC25_OPT_CONTRAST_DEFAULT 1.6 121 /* Contrast enhancement */ 122static SANE_Fixed dc25_opt_contrast = SANE_FIX (DC25_OPT_CONTRAST_DEFAULT); 123#define DC25_OPT_GAMMA_DEFAULT 4.5 124 /* Gamma correction (10x) */ 125static SANE_Fixed dc25_opt_gamma = SANE_FIX (DC25_OPT_GAMMA_DEFAULT); 126static SANE_Bool dc25_opt_erase; /* Erase all after download */ 127static SANE_Bool dc25_opt_erase_one; /* Erase one after download */ 128static SANE_Bool dumpinquiry; 129 130static SANE_Int info_flags; 131 132static int tfd; /* Camera File Descriptor */ 133static char tty_name[PATH_MAX]; 134#define DEF_TTY_NAME "/dev/ttyS0" 135 136static speed_t tty_baud = DEFAULT_TTY_BAUD; 137#define TMPFILE_PATTERN "/tmp/dc25XXXXXX"; 138 139static Dc20Info *dc20_info; 140static Dc20Info CameraInfo; 141 142static SANE_Byte contrast_table[256]; 143 144static struct pixmap *pp; 145 146static const SANE_Range contrast_range = { 147 0 << SANE_FIXED_SCALE_SHIFT, /* minimum */ 148 3 << SANE_FIXED_SCALE_SHIFT, /* maximum */ 149 16384 /* quantization ~ 0.025 */ 150}; 151 152static const SANE_Range gamma_range = { 153 0 << SANE_FIXED_SCALE_SHIFT, /* minimum */ 154 10 << SANE_FIXED_SCALE_SHIFT, /* maximum */ 155 16384 /* quantization ~ 0.025 */ 156}; 157 158static SANE_Range image_range = { 159 0, 160 14, 161 0 162}; 163 164static SANE_Option_Descriptor sod[] = { 165 { 166 SANE_NAME_NUM_OPTIONS, 167 SANE_TITLE_NUM_OPTIONS, 168 SANE_DESC_NUM_OPTIONS, 169 SANE_TYPE_INT, 170 SANE_UNIT_NONE, 171 sizeof (SANE_Word), 172 SANE_CAP_SOFT_DETECT, 173 SANE_CONSTRAINT_NONE, 174 {NULL} 175 } 176 , 177 178#define D25_OPT_IMAGE_SELECTION 1 179 { 180 "", 181 "Image Selection", 182 "Selection of the image to load.", 183 SANE_TYPE_GROUP, 184 SANE_UNIT_NONE, 185 0, 186 0, 187 SANE_CONSTRAINT_NONE, 188 {NULL} 189 } 190 , 191 192#define DC25_OPT_IMAGE_NUMBER 2 193 { 194 "image", 195 "Image Number", 196 "Select Image Number to load from camera", 197 SANE_TYPE_INT, 198 SANE_UNIT_NONE, 199 4, 200 SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT, 201 SANE_CONSTRAINT_RANGE, 202 {(SANE_String_Const *) & image_range} /* this is ANSI conformant! */ 203 } 204 , 205 206#define DC25_OPT_THUMBS 3 207 { 208 "thumbs", 209 "Load Thumbnail", 210 "Load the image as thumbnail.", 211 SANE_TYPE_BOOL, 212 SANE_UNIT_NONE, 213 sizeof (SANE_Word), 214 SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT, 215 SANE_CONSTRAINT_NONE, 216 {NULL} 217 } 218 , 219#define DC25_OPT_SNAP 4 220 { 221 "snap", 222 "Snap new picture", 223 "Take new picture and download it", 224 SANE_TYPE_BOOL, 225 SANE_UNIT_NONE, 226 sizeof (SANE_Word), 227 SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED, 228 SANE_CONSTRAINT_NONE, 229 {NULL} 230 } 231 , 232#define DC25_OPT_LOWRES 5 233 { 234 "lowres", 235 "Low Resolution", 236 "New pictures taken in low resolution", 237 SANE_TYPE_BOOL, 238 SANE_UNIT_NONE, 239 sizeof (SANE_Word), 240 SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_INACTIVE | 241 SANE_CAP_ADVANCED, 242 SANE_CONSTRAINT_NONE, 243 {NULL} 244 } 245 , 246 247#define DC25_OPT_ERASE 6 248 { 249 "erase", 250 "Erase", 251 "Erase all pictures after downloading", 252 SANE_TYPE_BOOL, 253 SANE_UNIT_NONE, 254 sizeof (SANE_Word), 255 SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT, 256 SANE_CONSTRAINT_NONE, 257 {NULL} 258 } 259 , 260 261#define DC25_OPT_ERASE_ONE 7 262 { 263 "erase-one", 264 "Erase One", 265 "Erase downloaded picture after downloading", 266 SANE_TYPE_BOOL, 267 SANE_UNIT_NONE, 268 sizeof (SANE_Word), 269 SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT, 270 SANE_CONSTRAINT_NONE, 271 {NULL} 272 } 273 , 274 275#define DC25_OPT_ENHANCE 8 276 { 277 "", 278 "Image Parameters", 279 "Modifications to image parameters", 280 SANE_TYPE_GROUP, 281 SANE_UNIT_NONE, 282 0, 283 0, 284 SANE_CONSTRAINT_NONE, 285 {NULL} 286 } 287 , 288 289#define DC25_OPT_CONTRAST 9 290 { 291 "contrast", 292 "Contrast Adjustment", 293 "Values > 1 enhance contrast", 294 SANE_TYPE_FIXED, 295 SANE_UNIT_NONE, 296 sizeof (SANE_Word), 297 SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT, 298 SANE_CONSTRAINT_RANGE, 299 {(const SANE_String_Const *) &contrast_range} /* this is ANSI conformant! */ 300 }, 301 302#define DC25_OPT_GAMMA 10 303 { 304 "gamma", 305 "Gamma Adjustment", 306 "Larger values make image darker", 307 SANE_TYPE_FIXED, 308 SANE_UNIT_NONE, 309 sizeof (SANE_Word), 310 SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT, 311 SANE_CONSTRAINT_RANGE, 312 {(const SANE_String_Const *) &gamma_range} /* this is ANSI conformant! */ 313 }, 314 315#define DC25_OPT_DEFAULT 11 316 { 317 "default-enhancements", 318 "Defaults", 319 "Set default values for enhancement controls (i.e. contrast).", 320 SANE_TYPE_BUTTON, 321 SANE_UNIT_NONE, 322 0, 323 SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT, 324 SANE_CONSTRAINT_NONE, 325 {NULL} 326 } 327}; 328 329static SANE_Parameters parms = { 330 SANE_FRAME_RGB, 331 1, 332 500, /* Number of bytes returned per scan line: */ 333 500, /* Number of pixels per scan line. */ 334 373, /* Number of lines for the current scan. */ 335 8, /* Number of bits per sample. */ 336}; 337 338 339 340 341static unsigned char init_pck[] = INIT_PCK; 342 343/* 344 * List of speeds to try to establish connection with the camera. 345 * Check 9600 first, as it's the speed the camera comes up in, then 346 * 115200, as that is the one most likely to be configured from a 347 * previous run 348 */ 349static struct pkt_speed speeds[] = { {B9600, {0x96, 0x00}}, 350#ifdef B115200 351{B115200, {0x11, 0x52}}, 352#endif 353#ifdef B57600 354{B57600, {0x57, 0x60}}, 355#endif 356{B38400, {0x38, 0x40}}, 357{B19200, {0x19, 0x20}}, 358}; 359#define NUM_OF_SPEEDS ((int)(sizeof(speeds) / sizeof(struct pkt_speed))) 360 361static struct termios tty_orig; 362 363static int 364send_pck (int fd, unsigned char *pck) 365{ 366 int n; 367 unsigned char r; 368 369 /* 370 * Not quite sure why we need this, but the program works a whole 371 * lot better (at least on the DC25) with this short delay. 372 */ 373#ifdef HAVE_USLEEP 374 usleep (10); 375#else 376 sleep (1); 377#endif 378 if (write (fd, (char *) pck, 8) != 8) 379 { 380 DBG (2, "send_pck: error: write returned -1\n"); 381 return -1; 382 } 383 384 if ((n = read (fd, (char *) &r, 1)) != 1) 385 { 386 DBG (2, "send_pck: error: read returned -1\n"); 387 return -1; 388 } 389 390 return (r == 0xd1) ? 0 : -1; 391} 392 393static int 394init_dc20 (char *device, speed_t speed) 395{ 396 struct termios tty_new; 397 int speed_index; 398 399 DBG (1, "DC-20/25 Backend 05/07/01\n"); 400 401 for (speed_index = 0; speed_index < NUM_OF_SPEEDS; speed_index++) 402 { 403 if (speeds[speed_index].baud == speed) 404 { 405 init_pck[2] = speeds[speed_index].pkt_code[0]; 406 init_pck[3] = speeds[speed_index].pkt_code[1]; 407 break; 408 } 409 } 410 411 if (init_pck[2] == 0) 412 { 413 DBG (2, "unsupported baud rate.\n"); 414 return -1; 415 } 416 417 /* 418 Open device file. 419 */ 420 if ((tfd = open (device, O_RDWR)) == -1) 421 { 422 DBG (2, "init_dc20: error: could not open %s for read/write\n", device); 423 return -1; 424 } 425 /* 426 Save old device information to restore when we are done. 427 */ 428 if (tcgetattr (tfd, &tty_orig) == -1) 429 { 430 DBG (2, "init_dc20: error: could not get attributes\n"); 431 return -1; 432 } 433 434 memcpy ((char *) &tty_new, (char *) &tty_orig, sizeof (struct termios)); 435 /* 436 We need the device to be raw. 8 bits even parity on 9600 baud to start. 437 */ 438#ifdef HAVE_CFMAKERAW 439 cfmakeraw (&tty_new); 440#else 441 tty_new.c_lflag &= ~(ICANON | ECHO | ISIG); 442#endif 443 tty_new.c_oflag &= ~CSTOPB; 444 tty_new.c_cflag |= PARENB; 445 tty_new.c_cflag &= ~PARODD; 446 tty_new.c_cc[VMIN] = 0; 447 tty_new.c_cc[VTIME] = 50; 448 cfsetospeed (&tty_new, B9600); 449 cfsetispeed (&tty_new, B9600); 450 451 if (tcsetattr (tfd, TCSANOW, &tty_new) == -1) 452 { 453 DBG (2, "init_dc20: error: could not set attributes\n"); 454 return -1; 455 } 456 457 if (send_pck (tfd, init_pck) == -1) 458 { 459 /* 460 * The camera always powers up at 9600, so we try 461 * that first. However, it may be already set to 462 * a different speed. Try the entries in the table: 463 */ 464 465 for (speed_index = NUM_OF_SPEEDS - 1; speed_index > 0; speed_index--) 466 { 467 DBG (3, "init_dc20: changing speed to %d\n", 468 (int) speeds[speed_index].baud); 469 470 cfsetospeed (&tty_new, speeds[speed_index].baud); 471 cfsetispeed (&tty_new, speeds[speed_index].baud); 472 473 if (tcsetattr (tfd, TCSANOW, &tty_new) == -1) 474 { 475 DBG (2, "init_dc20: error: could not set attributes\n"); 476 return -1; 477 } 478 if (send_pck (tfd, init_pck) != -1) 479 break; 480 } 481 482 if (speed_index == 0) 483 { 484 tcsetattr (tfd, TCSANOW, &tty_orig); 485 DBG (2, "init_dc20: error: no suitable baud rate\n"); 486 return -1; 487 } 488 } 489 /* 490 Set speed to requested speed. Also, make a long timeout (we need this for 491 erase and shoot operations) 492 */ 493 tty_new.c_cc[VTIME] = 150; 494 cfsetospeed (&tty_new, speed); 495 cfsetispeed (&tty_new, speed); 496 497 if (tcsetattr (tfd, TCSANOW, &tty_new) == -1) 498 { 499 DBG (2, "init_dc20: error: could not set attributes\n"); 500 return -1; 501 } 502 503 return tfd; 504} 505 506static void 507close_dc20 (int fd) 508{ 509 DBG (127, "close_dc20() called\n"); 510 /* 511 * Put the camera back to 9600 baud 512 */ 513 514 init_pck[2] = speeds[0].pkt_code[0]; 515 init_pck[3] = speeds[0].pkt_code[1]; 516 if (send_pck (fd, init_pck) == -1) 517 { 518 DBG (4, "close_dc20: error: could not set attributes\n"); 519 } 520 521 /* 522 Restore original device settings. 523 */ 524 if (tcsetattr (fd, TCSANOW, &tty_orig) == -1) 525 { 526 DBG (4, "close_dc20: error: could not set attributes\n"); 527 } 528 529 if (close (fd) == -1) 530 { 531 DBG (4, "close_dc20: error: could not close device\n"); 532 } 533} 534 535static unsigned char info_pck[] = INFO_PCK; 536 537static Dc20Info * 538get_info (int fd) 539{ 540 unsigned char buf[256]; 541 542 if (send_pck (fd, info_pck) == -1) 543 { 544 DBG (2, "get_info: error: send_pck returned -1\n"); 545 return NULL; 546 } 547 548 DBG (9, "get_info: read info packet\n"); 549 550 if (read_data (fd, buf, 256) == -1) 551 { 552 DBG (2, "get_info: error: read_data returned -1\n"); 553 return NULL; 554 } 555 556 if (end_of_data (fd) == -1) 557 { 558 DBG (2, "get_info: error: end_of_data returned -1\n"); 559 return NULL; 560 } 561 562 CameraInfo.model = buf[1]; 563 CameraInfo.ver_major = buf[2]; 564 CameraInfo.ver_minor = buf[3]; 565 CameraInfo.pic_taken = buf[8] << 8 | buf[9]; 566 if (CameraInfo.model == 0x25) 567 { 568 569 /* Not sure where the previous line came from. All the 570 * information I have says that even on the DC20 the number of 571 * standard res pics is in byte 17 and the number of high res pics 572 * is in byte 19. This is definitely true on my DC25. 573 */ 574 CameraInfo.pic_taken = buf[17] + buf[19]; 575 } 576 577 image_range.max = CameraInfo.pic_taken; 578 image_range.min = CameraInfo.pic_taken ? 1 : 0; 579 580 CameraInfo.pic_left = buf[10] << 8 | buf[11]; 581 582 if (CameraInfo.model == 0x25) 583 { 584 /* Not sure where the previous line came from. All the 585 * information I have says that even on the DC20 the number of 586 * standard res pics left is in byte 23 and the number of high res 587 * pics left is in byte 21. It seems to me that the conservative 588 * approach is to report the number of high res pics left. 589 */ 590 CameraInfo.pic_left = buf[21]; 591 } 592 CameraInfo.flags.low_res = buf[23]; 593 594 if (CameraInfo.model == 0x25) 595 { 596 /* Not sure where the previous line came from. All the 597 * information I have says that even on the DC20 the low_res 598 * byte is 11. 599 */ 600 CameraInfo.flags.low_res = buf[11]; 601 } 602 CameraInfo.flags.low_batt = buf[29]; 603 604 return &CameraInfo; 605} 606 607static int 608read_data (int fd, unsigned char *buf, int sz) 609{ 610 unsigned char ccsum; 611 unsigned char rcsum; 612 unsigned char c; 613 int retries = 0; 614 int n; 615 int r = 0; 616 int i; 617 618 while (retries++ < 5) 619 { 620 621 /* 622 * If this is not the first time through, then it must be 623 * a retry - signal the camera that we didn't like what 624 * we got. In either case, start filling the packet 625 */ 626 if (retries != 1) 627 { 628 629 DBG (2, "Attempt retry %d\n", retries); 630 c = 0xe3; 631 if (write (fd, (char *) &c, 1) != 1) 632 { 633 DBG (2, "read_data: error: write ack\n"); 634 return -1; 635 } 636 637 } 638 639 for (n = 0; n < sz && (r = read (fd, (char *) &buf[n], sz - n)) > 0; 640 n += r) 641 ; 642 643 if (r <= 0) 644 { 645 DBG (2, "read_data: error: read returned -1\n"); 646 continue; 647 } 648 649 if (n < sz || read (fd, &rcsum, 1) != 1) 650 { 651 DBG (2, "read_data: error: buffer underrun or no checksum\n"); 652 continue; 653 } 654 655 for (i = 0, ccsum = 0; i < n; i++) 656 ccsum ^= buf[i]; 657 658 if (ccsum != rcsum) 659 { 660 DBG (2, "read_data: error: bad checksum (%02x != %02x)\n", rcsum, 661 ccsum); 662 continue; 663 } 664 665 /* If we got this far, then the packet is OK */ 666 break; 667 } 668 669 c = 0xd2; 670 671 if (write (fd, (char *) &c, 1) != 1) 672 { 673 DBG (2, "read_data: error: write ack\n"); 674 return -1; 675 } 676 677 return 0; 678} 679 680static int 681end_of_data (int fd) 682{ 683 char c; 684 685 if (read (fd, &c, 1) != 1) 686 { 687 DBG (2, "end_of_data: error: read returned -1\n"); 688 return -1; 689 } 690 691 if (c != 0) 692 { 693 DBG (2, "end_of_data: error: bad EOD from camera (%02x)\n", 694 (unsigned) c); 695 return -1; 696 } 697 698 return 0; 699} 700 701#include <math.h> 702 703#define BIDIM_ARRAY(name, x, y, width) (name[((x) + ((y) * (width)))]) 704 705/* 706 * These definitions depend on the resolution of the image 707 */ 708 709#define MY_LOW_RIGHT_MARGIN 6 710 711/* 712 * These definitions are constant with resolution 713 */ 714 715#define MY_LEFT_MARGIN 2 716 717#define NET_COLUMNS (columns - MY_LEFT_MARGIN - right_margin) 718#define NET_LINES (HEIGHT - TOP_MARGIN - BOTTOM_MARGIN) 719#define NET_PIXELS (NET_COLUMNS * NET_LINES) 720 721 722#define SCALE 64 723#define SMAX (256 * SCALE - 1) 724#define HORIZONTAL_INTERPOLATIONS 3 725#define HISTOGRAM_STEPS 4096 726 727#define RFACTOR 0.64 728#define GFACTOR 0.58 729#define BFACTOR 1.00 730#define RINTENSITY 0.476 731#define GINTENSITY 0.299 732#define BINTENSITY 0.175 733 734#define SATURATION 1.0 735#define NORM_PERCENTAGE 3 736 737static int columns = HIGH_WIDTH, 738 right_margin = HIGH_RIGHT_MARGIN, camera_header_size = HIGH_CAMERA_HEADER; 739static int low_i = -1, high_i = -1, norm_percentage = NORM_PERCENTAGE; 740static float saturation = SATURATION, 741 rfactor = RFACTOR, gfactor = GFACTOR, bfactor = BFACTOR; 742 743static void 744set_initial_interpolation (const unsigned char ccd[], 745 short horizontal_interpolation[]) 746{ 747 int column, line; 748 for (line = 0; line < HEIGHT; line++) 749 { 750 BIDIM_ARRAY (horizontal_interpolation, MY_LEFT_MARGIN, line, columns) = 751 BIDIM_ARRAY (ccd, MY_LEFT_MARGIN + 1, line, columns) * SCALE; 752 BIDIM_ARRAY (horizontal_interpolation, columns - right_margin - 1, line, 753 columns) = 754 BIDIM_ARRAY (ccd, columns - right_margin - 2, line, columns) * SCALE; 755 for (column = MY_LEFT_MARGIN + 1; column < columns - right_margin - 1; 756 column++) 757 { 758 BIDIM_ARRAY (horizontal_interpolation, column, line, columns) = 759 (BIDIM_ARRAY (ccd, column - 1, line, columns) + 760 BIDIM_ARRAY (ccd, column + 1, line, columns)) * (SCALE / 2); 761 } 762 } 763} 764 765static void 766interpolate_horizontally (const unsigned char ccd[], 767 short horizontal_interpolation[]) 768{ 769 int column, line, i, initial_column; 770 for (line = TOP_MARGIN - 1; line < HEIGHT - BOTTOM_MARGIN + 1; line++) 771 { 772 for (i = 0; i < HORIZONTAL_INTERPOLATIONS; i++) 773 { 774 for (initial_column = MY_LEFT_MARGIN + 1; 775 initial_column <= MY_LEFT_MARGIN + 2; initial_column++) 776 { 777 for (column = initial_column; 778 column < columns - right_margin - 1; column += 2) 779 { 780 BIDIM_ARRAY (horizontal_interpolation, column, line, 781 columns) = 782 ((float) BIDIM_ARRAY (ccd, column - 1, line, columns) / 783 BIDIM_ARRAY (horizontal_interpolation, column - 1, line, 784 columns) + (float) BIDIM_ARRAY (ccd, 785 column + 1, 786 line, 787 columns) / 788 BIDIM_ARRAY (horizontal_interpolation, column + 1, line, 789 columns)) * BIDIM_ARRAY (ccd, column, line, 790 columns) * (SCALE * 791 SCALE / 792 2) + 793 0.5; 794 } 795 } 796 } 797 } 798} 799 800static void 801interpolate_vertically (const unsigned char ccd[], 802 const short horizontal_interpolation[], 803 short red[], short green[], short blue[]) 804{ 805 int column, line; 806 for (line = TOP_MARGIN; line < HEIGHT - BOTTOM_MARGIN; line++) 807 { 808 for (column = MY_LEFT_MARGIN; column < columns - right_margin; column++) 809 { 810 int r2gb, g2b, rg2, rgb2, r, g, b; 811 int this_ccd = BIDIM_ARRAY (ccd, column, line, columns) * SCALE; 812 int up_ccd = BIDIM_ARRAY (ccd, column, line - 1, columns) * SCALE; 813 int down_ccd = BIDIM_ARRAY (ccd, column, line + 1, columns) * SCALE; 814 int this_horizontal_interpolation = 815 BIDIM_ARRAY (horizontal_interpolation, column, line, columns); 816 int this_intensity = this_ccd + this_horizontal_interpolation; 817 int up_intensity = 818 BIDIM_ARRAY (horizontal_interpolation, column, line - 1, 819 columns) + up_ccd; 820 int down_intensity = 821 BIDIM_ARRAY (horizontal_interpolation, column, line + 1, 822 columns) + down_ccd; 823 int this_vertical_interpolation; 824 825 /* 826 * PSF: I don't understand all this code, but I've found pictures 827 * where up_intensity or down_intensity are zero, resulting in a 828 * divide by zero error. It looks like this only happens when 829 * up_ccd or down_ccd are also zero, so we just set the intensity 830 * value to non-zero to prevent the error. 831 */ 832 if (down_ccd == 0) 833 DBG (10, "down_ccd==0 at %d,%d\n", line, column); 834 if (up_ccd == 0) 835 DBG (10, "up_ccd==0 at %d,%d\n", line, column); 836 if (down_intensity == 0) 837 { 838 DBG (9, "Found down_intensity==0 at %d,%d down_ccd=%d\n", line, 839 column, down_ccd); 840 down_intensity = 1; 841 } 842 if (up_intensity == 0) 843 { 844 DBG (9, "Found up_intensity==0 at %d,%d up_ccd=%d\n", line, 845 column, up_ccd); 846 up_intensity = 1; 847 } 848 849 if (line == TOP_MARGIN) 850 { 851 this_vertical_interpolation = 852 (float) down_ccd / down_intensity * this_intensity + 0.5; 853 } 854 else if (line == HEIGHT - BOTTOM_MARGIN - 1) 855 { 856 this_vertical_interpolation = 857 (float) up_ccd / up_intensity * this_intensity + 0.5; 858 } 859 else 860 { 861 this_vertical_interpolation = 862 ((float) up_ccd / up_intensity + 863 (float) down_ccd / down_intensity) * this_intensity / 2.0 + 864 0.5; 865 } 866 if (line & 1) 867 { 868 if (column & 1) 869 { 870 r2gb = this_ccd; 871 g2b = this_horizontal_interpolation; 872 rg2 = this_vertical_interpolation; 873 r = (2 * (r2gb - g2b) + rg2) / 5; 874 g = (rg2 - r) / 2; 875 b = g2b - 2 * g; 876 } 877 else 878 { 879 g2b = this_ccd; 880 r2gb = this_horizontal_interpolation; 881 rgb2 = this_vertical_interpolation; 882 r = (3 * r2gb - g2b - rgb2) / 5; 883 g = 2 * r - r2gb + g2b; 884 b = g2b - 2 * g; 885 } 886 } 887 else 888 { 889 if (column & 1) 890 { 891 rg2 = this_ccd; 892 rgb2 = this_horizontal_interpolation; 893 r2gb = this_vertical_interpolation; 894 b = (3 * rgb2 - r2gb - rg2) / 5; 895 g = (rgb2 - r2gb + rg2 - b) / 2; 896 r = rg2 - 2 * g; 897 } 898 else 899 { 900 rgb2 = this_ccd; 901 rg2 = this_horizontal_interpolation; 902 g2b = this_vertical_interpolation; 903 b = (g2b - 2 * (rg2 - rgb2)) / 5; 904 g = (g2b - b) / 2; 905 r = rg2 - 2 * g; 906 } 907 } 908 if (r < 0) 909 r = 0; 910 if (g < 0) 911 g = 0; 912 if (b < 0) 913 b = 0; 914 BIDIM_ARRAY (red, column, line, columns) = r; 915 BIDIM_ARRAY (green, column, line, columns) = g; 916 BIDIM_ARRAY (blue, column, line, columns) = b; 917 } 918 } 919} 920 921static void 922adjust_color_and_saturation (short red[], short green[], short blue[]) 923{ 924 int line, column; 925 int r_min = SMAX, g_min = SMAX, b_min = SMAX; 926 int r_max = 0, g_max = 0, b_max = 0; 927 float sqr_saturation = sqrt (saturation); 928 for (line = TOP_MARGIN; line < HEIGHT - BOTTOM_MARGIN; line++) 929 { 930 for (column = MY_LEFT_MARGIN; column < columns - right_margin; column++) 931 { 932 float r = BIDIM_ARRAY (red, column, line, columns) * rfactor; 933 float g = BIDIM_ARRAY (green, column, line, columns) * gfactor; 934 float b = BIDIM_ARRAY (blue, column, line, columns) * bfactor; 935 if (saturation != 1.0) 936 { 937 float *min, *mid, *max, new_intensity; 938 float intensity = 939 r * RINTENSITY + g * GINTENSITY + b * BINTENSITY; 940 if (r > g) 941 { 942 if (r > b) 943 { 944 max = &r; 945 if (g > b) 946 { 947 min = &b; 948 mid = &g; 949 } 950 else 951 { 952 min = &g; 953 mid = &b; 954 } 955 } 956 else 957 { 958 min = &g; 959 mid = &r; 960 max = &b; 961 } 962 } 963 else 964 { 965 if (g > b) 966 { 967 max = &g; 968 if (r > b) 969 { 970 min = &b; 971 mid = &r; 972 } 973 else 974 { 975 min = &r; 976 mid = &b; 977 } 978 } 979 else 980 { 981 min = &r; 982 mid = &g; 983 max = &b; 984 } 985 } 986 *mid = *min + sqr_saturation * (*mid - *min); 987 *max = *min + saturation * (*max - *min); 988 new_intensity = 989 r * RINTENSITY + g * GINTENSITY + b * BINTENSITY; 990 r *= intensity / new_intensity; 991 g *= intensity / new_intensity; 992 b *= intensity / new_intensity; 993 } 994 r += 0.5; 995 g += 0.5; 996 b += 0.5; 997 if (r_min > r) 998 r_min = r; 999 if (g_min > g) 1000 g_min = g; 1001 if (b_min > b) 1002 b_min = b; 1003 if (r_max < r) 1004 r_max = r; 1005 if (g_max < g) 1006 g_max = g; 1007 if (b_max < b) 1008 b_max = b; 1009 BIDIM_ARRAY (red, column, line, columns) = r; 1010 BIDIM_ARRAY (green, column, line, columns) = g; 1011 BIDIM_ARRAY (blue, column, line, columns) = b; 1012 } 1013 } 1014} 1015 1016static int 1017min3 (int x, int y, int z) 1018{ 1019 return (x < y ? (x < z ? x : z) : (y < z ? y : z)); 1020} 1021 1022static int 1023max3 (int x, int y, int z) 1024{ 1025 return (x > y ? (x > z ? x : z) : (y > z ? y : z)); 1026} 1027 1028static void 1029determine_limits (const short red[], 1030 const short green[], 1031 const short blue[], int *low_i_ptr, int *high_i_ptr) 1032{ 1033 unsigned int histogram[HISTOGRAM_STEPS + 1]; 1034 int column, line, i, s; 1035 int low_i = *low_i_ptr, high_i = *high_i_ptr; 1036 int max_i = 0; 1037 for (line = TOP_MARGIN; line < HEIGHT - BOTTOM_MARGIN; line++) 1038 { 1039 for (column = MY_LEFT_MARGIN; column < columns - right_margin; column++) 1040 { 1041 i = max3 (BIDIM_ARRAY (red, column, line, columns), 1042 BIDIM_ARRAY (green, column, line, columns), 1043 BIDIM_ARRAY (blue, column, line, columns)); 1044 if (i > max_i) 1045 max_i = i; 1046 } 1047 } 1048 if (low_i == -1) 1049 { 1050 for (i = 0; i <= HISTOGRAM_STEPS; i++) 1051 histogram[i] = 0; 1052 for (line = TOP_MARGIN; line < HEIGHT - BOTTOM_MARGIN; line++) 1053 { 1054 for (column = MY_LEFT_MARGIN; column < columns - right_margin; 1055 column++) 1056 { 1057 i = min3 (BIDIM_ARRAY (red, column, line, columns), 1058 BIDIM_ARRAY (green, column, line, columns), 1059 BIDIM_ARRAY (blue, column, line, columns)); 1060 histogram[i * HISTOGRAM_STEPS / max_i]++; 1061 } 1062 } 1063 for (low_i = 0, s = 0; 1064 low_i <= HISTOGRAM_STEPS && s < NET_PIXELS * norm_percentage / 100; 1065 low_i++) 1066 { 1067 s += histogram[low_i]; 1068 } 1069 low_i = (low_i * max_i + HISTOGRAM_STEPS / 2) / HISTOGRAM_STEPS; 1070 *low_i_ptr = low_i; 1071 } 1072 if (high_i == -1) 1073 { 1074 for (i = 0; i <= HISTOGRAM_STEPS; i++) 1075 histogram[i] = 0; 1076 for (line = TOP_MARGIN; line < HEIGHT - BOTTOM_MARGIN; line++) 1077 { 1078 for (column = MY_LEFT_MARGIN; column < columns - right_margin; 1079 column++) 1080 { 1081 i = max3 (BIDIM_ARRAY (red, column, line, columns), 1082 BIDIM_ARRAY (green, column, line, columns), 1083 BIDIM_ARRAY (blue, column, line, columns)); 1084 histogram[i * HISTOGRAM_STEPS / max_i]++; 1085 } 1086 } 1087 for (high_i = HISTOGRAM_STEPS, s = 0; 1088 high_i >= 0 && s < NET_PIXELS * norm_percentage / 100; high_i--) 1089 { 1090 s += histogram[high_i]; 1091 } 1092 high_i = (high_i * max_i + HISTOGRAM_STEPS / 2) / HISTOGRAM_STEPS; 1093 *high_i_ptr = high_i; 1094 } 1095/* 1096if (verbose) printf ("%s: determine_limits: low_i = %d, high_i = %d\n", __progname, low_i, high_i); 1097*/ 1098} 1099 1100/* 1101 * The original dc20ctrl program used a default gamma of 0.35, but I thought 1102 * 0.45 looks better. In addition, since xscanimage seems to always force 1103 * a resolution of 0.1, I multiply everything by 10 and make the default 1104 * 4.5. 1105 */ 1106 1107static unsigned char * 1108make_gamma_table (int range) 1109{ 1110 int i; 1111 double factor = 1112 pow (256.0, 1.0 / (SANE_UNFIX (dc25_opt_gamma) / 10.0)) / range; 1113 unsigned char *gamma_table; 1114 if ((gamma_table = malloc (range * sizeof (unsigned char))) == NULL) 1115 { 1116 DBG (1, "make_gamma_table: can't allocate memory for gamma table\n"); 1117 return NULL; 1118 } 1119 for (i = 0; i < range; i++) 1120 { 1121 int g = 1122 pow ((double) i * factor, (SANE_UNFIX (dc25_opt_gamma) / 10.0)) + 0.5; 1123/* 1124 if (verbose) fprintf (stderr, "%s: make_gamma_table: gamma[%4d] = %3d\n", __progname, i, g); 1125*/ 1126 if (g > 255) 1127 g = 255; 1128 gamma_table[i] = g; 1129 } 1130 return gamma_table; 1131} 1132 1133static int 1134lookup_gamma_table (int i, int low_i, int high_i, 1135 const unsigned char gamma_table[]) 1136{ 1137 if (i <= low_i) 1138 return 0; 1139 if (i >= high_i) 1140 return 255; 1141 return gamma_table[i - low_i]; 1142} 1143 1144static int 1145output_rgb (const short red[], 1146 const short green[], 1147 const short blue[], int low_i, int high_i, struct pixmap *pp) 1148{ 1149 int r_min = 255, g_min = 255, b_min = 255; 1150 int r_max = 0, g_max = 0, b_max = 0; 1151 int column, line; 1152 unsigned char *gamma_table = make_gamma_table (high_i - low_i); 1153 1154 if (gamma_table == NULL) 1155 { 1156 DBG (10, "output_rgb: error: cannot make gamma table\n"); 1157 return -1; 1158 } 1159 1160 for (line = TOP_MARGIN; line < HEIGHT - BOTTOM_MARGIN; line++) 1161 { 1162 for (column = MY_LEFT_MARGIN; column < columns - right_margin; column++) 1163 { 1164 int r = 1165 lookup_gamma_table (BIDIM_ARRAY (red, column, line, columns), 1166 low_i, high_i, gamma_table); 1167 int g = 1168 lookup_gamma_table (BIDIM_ARRAY (green, column, line, columns), 1169 low_i, high_i, gamma_table); 1170 int b = 1171 lookup_gamma_table (BIDIM_ARRAY (blue, column, line, columns), 1172 low_i, high_i, gamma_table); 1173 if (r > 255) 1174 r = 255; 1175 else if (r < 0) 1176 r = 0; 1177 if (g > 255) 1178 g = 255; 1179 else if (g < 0) 1180 g = 0; 1181 if (b > 255) 1182 b = 255; 1183 else if (b < 0) 1184 b = 0; 1185 set_pixel_rgb (pp, column - MY_LEFT_MARGIN, line - TOP_MARGIN, r, g, 1186 b); 1187 if (r_min > r) 1188 r_min = r; 1189 if (g_min > g) 1190 g_min = g; 1191 if (b_min > b) 1192 b_min = b; 1193 if (r_max < r) 1194 r_max = r; 1195 if (g_max < g) 1196 g_max = g; 1197 if (b_max < b) 1198 b_max = b; 1199 } 1200 } 1201 free (gamma_table); 1202 return 0; 1203} 1204 1205static int 1206comet_to_pixmap (unsigned char *pic, struct pixmap *pp) 1207{ 1208 unsigned char *ccd; 1209 short *horizontal_interpolation, *red, *green, *blue; 1210 int retval = 0; 1211 1212 if (pic == NULL) 1213 { 1214 DBG (1, "cmttoppm: error: no input image\n"); 1215 return -1; 1216 } 1217 1218 if (pic[4] == 0x01) 1219 { 1220 /* Low resolution mode */ 1221 columns = LOW_WIDTH; 1222 right_margin = MY_LOW_RIGHT_MARGIN; 1223 camera_header_size = LOW_CAMERA_HEADER; 1224 } 1225 else 1226 { 1227 /* High resolution mode */ 1228 columns = HIGH_WIDTH; 1229 right_margin = HIGH_RIGHT_MARGIN; 1230 camera_header_size = HIGH_CAMERA_HEADER; 1231 } 1232 ccd = pic + camera_header_size; 1233 1234 if ((horizontal_interpolation = 1235 malloc (sizeof (short) * HEIGHT * columns)) == NULL) 1236 { 1237 DBG (1, 1238 "cmttoppm: error: not enough memory for horizontal_interpolation\n"); 1239 return -1; 1240 } 1241 1242 1243 if ((red = malloc (sizeof (short) * HEIGHT * columns)) == NULL) 1244 { 1245 DBG (1, "error: not enough memory for red\n"); 1246 return -1; 1247 } 1248 1249 if ((green = malloc (sizeof (short) * HEIGHT * columns)) == NULL) 1250 { 1251 DBG (1, "error: not enough memory for green\n"); 1252 return -1; 1253 } 1254 1255 if ((blue = malloc (sizeof (short) * HEIGHT * columns)) == NULL) 1256 { 1257 DBG (1, "error: not enough memory for blue\n"); 1258 return -1; 1259 } 1260 1261 /* Decode raw CCD data to RGB */ 1262 set_initial_interpolation (ccd, horizontal_interpolation); 1263 interpolate_horizontally (ccd, horizontal_interpolation); 1264 interpolate_vertically (ccd, horizontal_interpolation, red, green, blue); 1265 1266 adjust_color_and_saturation (red, green, blue); 1267 1268 /* Determine lower and upper limit using histogram */ 1269 if (low_i == -1 || high_i == -1) 1270 { 1271 determine_limits (red, green, blue, &low_i, &high_i); 1272 } 1273 1274 /* Output pixmap structure */ 1275 retval = output_rgb (red, green, blue, low_i, high_i, pp); 1276 1277 return retval; 1278} 1279 1280static int 1281convert_pic (char *base_name, int format) 1282{ 1283 FILE *ifp; 1284 unsigned char pic[MAX_IMAGE_SIZE]; 1285 int res, image_width, net_width, components; 1286 struct pixmap *pp2; 1287 1288 DBG (127, "convert_pic() called\n"); 1289 1290 /* 1291 * Read the image in memory 1292 */ 1293 1294 if ((ifp = fopen (base_name, "rb")) == NULL) 1295 { 1296 DBG (10, "convert_pic: error: cannot open %s for reading\n", base_name); 1297 return -1; 1298 } 1299 1300 if (fread (pic, COMET_HEADER_SIZE, 1, ifp) != 1) 1301 { 1302 DBG (10, "convert_pic: error: cannot read COMET header\n"); 1303 fclose (ifp); 1304 return -1; 1305 } 1306 1307 if (strncmp ((char *) pic, COMET_MAGIC, sizeof (COMET_MAGIC)) != 0) 1308 { 1309 DBG (10, "convert_pic: error: file %s is not in COMET format\n", 1310 base_name); 1311 fclose (ifp); 1312 return -1; 1313 } 1314 1315 if (fread (pic, LOW_CAMERA_HEADER, 1, ifp) != 1) 1316 { 1317 DBG (10, "convert_pic: error: cannot read camera header\n"); 1318 fclose (ifp); 1319 return -1; 1320 } 1321 1322 res = pic[4]; 1323 if (res == 0) 1324 { 1325 /* 1326 * We just read a LOW_CAMERA_HEADER block, so resync with the 1327 * HIGH_CAMERA_HEADER length by reading once more one of this. 1328 */ 1329 if (fread (pic + LOW_CAMERA_HEADER, LOW_CAMERA_HEADER, 1, ifp) != 1) 1330 { 1331 DBG (10, 1332 "convert_pic: error: cannot resync with high resolution header\n"); 1333 fclose (ifp); 1334 return -1; 1335 } 1336 } 1337 1338 if (fread (pic + CAMERA_HEADER (res), WIDTH (res), HEIGHT, ifp) != HEIGHT) 1339 { 1340 DBG (9, "convert_pic: error: cannot read picture\n"); 1341 fclose (ifp); 1342 return -1; 1343 } 1344 1345 fclose (ifp); 1346 1347 /* 1348 * Setup image size with resolution 1349 */ 1350 1351 image_width = WIDTH (res); 1352 net_width = image_width - LEFT_MARGIN - RIGHT_MARGIN (res); 1353 components = (format & SAVE_24BITS) ? 3 : 1; 1354 1355 /* 1356 * Convert the image to 24 bits 1357 */ 1358 1359 if ((pp = 1360 alloc_pixmap (net_width - 1, HEIGHT - BOTTOM_MARGIN - 1, 1361 components)) == NULL) 1362 { 1363 DBG (1, "convert_pic: error: alloc_pixmap\n"); 1364 return -1; 1365 } 1366 1367 comet_to_pixmap (pic, pp); 1368 1369 if (format & SAVE_ADJASPECT) 1370 { 1371 /* 1372 * Stretch image 1373 */ 1374 1375 if (res) 1376 pp2 = alloc_pixmap (320, HEIGHT - BOTTOM_MARGIN - 1, components); 1377 else 1378 pp2 = alloc_pixmap (net_width - 1, 373, components); 1379 1380 if (pp2 == NULL) 1381 { 1382 DBG (2, "convert_pic: error: alloc_pixmap\n"); 1383 free_pixmap (pp); 1384 return -1; 1385 } 1386 1387 if (res) 1388 zoom_x (pp, pp2); 1389 else 1390 zoom_y (pp, pp2); 1391 1392 free_pixmap (pp); 1393 pp = pp2; 1394 pp2 = NULL; 1395 1396 } 1397 1398 return 0; 1399} 1400 1401#define PGM_EXT "pgm" 1402#define PPM_EXT "ppm" 1403 1404#define RED 0.30 1405#define GREEN 0.59 1406#define BLUE 0.11 1407 1408#define RED_OFFSET 0 1409#define GREEN_OFFSET 1 1410#define BLUE_OFFSET 2 1411 1412#define GET_COMP(pp, x, y, c) (pp->planes[((x) + (y)*pp->width)*pp->components + (c)]) 1413 1414#define GET_R(pp, x, y) (GET_COMP(pp, x, y, RED_OFFSET)) 1415#define GET_G(pp, x, y) (GET_COMP(pp, x, y, GREEN_OFFSET)) 1416#define GET_B(pp, x, y) (GET_COMP(pp, x, y, BLUE_OFFSET)) 1417 1418static struct pixmap * 1419alloc_pixmap (int x, int y, int d) 1420{ 1421 struct pixmap *result = NULL; 1422 1423 if (d == 1 || d == 3) 1424 { 1425 if (x > 0) 1426 { 1427 if (y > 0) 1428 { 1429 if ((result = malloc (sizeof (struct pixmap))) != NULL) 1430 { 1431 result->width = x; 1432 result->height = y; 1433 result->components = d; 1434 if (!(result->planes = malloc (x * y * d))) 1435 { 1436 DBG (10, 1437 "alloc_pixmap: error: not enough memory for bitplanes\n"); 1438 free (result); 1439 result = NULL; 1440 } 1441 } 1442 else 1443 DBG (10, 1444 "alloc_pixmap: error: not enough memory for pixmap\n"); 1445 } 1446 else 1447 DBG (10, "alloc_pixmap: error: y is out of range\n"); 1448 } 1449 else 1450 DBG (10, "alloc_pixmap: error: x is out of range\n"); 1451 } 1452 else 1453 DBG (10, "alloc_pixmap: error: cannot handle %d components\n", d); 1454 1455 return result; 1456} 1457 1458static void 1459free_pixmap (struct pixmap *p) 1460{ 1461 if (p) 1462 { 1463 free (p->planes); 1464 free (p); 1465 } 1466} 1467 1468static int 1469set_pixel_rgb (struct pixmap *p, int x, int y, unsigned char r, 1470 unsigned char g, unsigned char b) 1471{ 1472 int result = 0; 1473 1474 if (p) 1475 { 1476 if (x >= 0 && x < p->width) 1477 { 1478 if (y >= 0 && y < p->height) 1479 { 1480 if (p->components == 1) 1481 { 1482 GET_R (p, x, y) = RED * r + GREEN * g + BLUE * b; 1483 } 1484 else 1485 { 1486 GET_R (p, x, y) = r; 1487 GET_G (p, x, y) = g; 1488 GET_B (p, x, y) = b; 1489 } 1490 } 1491 else 1492 { 1493 DBG (10, "set_pixel_rgb: error: y out of range\n"); 1494 result = -1; 1495 } 1496 } 1497 else 1498 { 1499 DBG (10, "set_pixel_rgb: error: x out of range\n"); 1500 result = -1; 1501 } 1502 } 1503 1504 return result; 1505} 1506 1507static int 1508zoom_x (struct pixmap *source, struct pixmap *dest) 1509{ 1510 int result = 0, dest_col, row, component, src_index; 1511 float ratio, src_ptr, delta; 1512 unsigned char src_component; 1513 1514 if (source && dest) 1515 { 1516 /* 1517 * We could think of resizing a pixmap and changing the number of 1518 * components at the same time. Maybe this will be implemented later. 1519 */ 1520 if (source->height == dest->height 1521 && source->components == dest->components) 1522 { 1523 if (source->width < dest->width) 1524 { 1525 ratio = ((float) source->width / (float) dest->width); 1526 1527 for (src_ptr = 0, dest_col = 0; dest_col < dest->width; 1528 src_ptr += ratio, dest_col++) 1529 { 1530 /* 1531 * dest[dest_col] = source[(int)src_ptr] + 1532 * (source[((int)src_ptr) + 1] - source[(int)src_ptr]) 1533 * * (src_ptr - (int)src_ptr); 1534 */ 1535 src_index = (int) src_ptr; 1536 delta = src_ptr - src_index; 1537 1538 for (row = 0; row < source->height; row++) 1539 { 1540 for (component = 0; component < source->components; 1541 component++) 1542 { 1543 src_component = 1544 GET_COMP (source, src_index, row, component); 1545 1546 GET_COMP (dest, dest_col, row, component) = 1547 src_component + 1548 (GET_COMP (source, src_index + 1, row, 1549 component) - src_component) * delta; 1550 } 1551 } 1552 } 1553 } 1554 else 1555 { 1556 DBG (10, "zoom_x: error: can only zoom out\n"); 1557 result = -1; 1558 } 1559 } 1560 else 1561 { 1562 DBG (10, "zoom_x: error: incompatible pixmaps\n"); 1563 result = -1; 1564 } 1565 } 1566 1567 return result; 1568} 1569 1570static int 1571zoom_y (struct pixmap *source, struct pixmap *dest) 1572{ 1573 int result = 0, dest_row, column, component, src_index; 1574 float ratio, src_ptr, delta; 1575 unsigned char src_component; 1576 1577 if (source && dest) 1578 { 1579 /* 1580 * We could think of resizing a pixmap and changing the number of 1581 * components at the same time. Maybe this will be implemented later. 1582 */ 1583 if (source->width == dest->width 1584 && source->components == dest->components) 1585 { 1586 if (source->height < dest->height) 1587 { 1588 ratio = ((float) source->height / (float) dest->height); 1589 1590 for (src_ptr = 0, dest_row = 0; dest_row < dest->height; 1591 src_ptr += ratio, dest_row++) 1592 { 1593 /* 1594 * dest[dest_row] = source[(int)src_ptr] + 1595 * (source[((int)src_ptr) + 1] - source[(int)src_ptr]) 1596 * * (src_ptr - (int)src_ptr); 1597 */ 1598 src_index = (int) src_ptr; 1599 delta = src_ptr - src_index; 1600 1601 for (column = 0; column < source->width; column++) 1602 { 1603 for (component = 0; component < source->components; 1604 component++) 1605 { 1606 src_component = 1607 GET_COMP (source, column, src_index, component); 1608 1609 GET_COMP (dest, column, dest_row, component) = 1610 src_component + 1611 (GET_COMP (source, column, src_index + 1, 1612 component) - src_component) * delta; 1613 } 1614 } 1615 } 1616 } 1617 else 1618 { 1619 DBG (10, "zoom_y: error: can only zoom out\n"); 1620 result = -1; 1621 } 1622 } 1623 else 1624 { 1625 DBG (10, "zoom_y: error: incompatible pixmaps\n"); 1626 result = -1; 1627 } 1628 } 1629 1630 return result; 1631} 1632 1633static unsigned char shoot_pck[] = SHOOT_PCK; 1634 1635static int 1636shoot (int fd) 1637{ 1638 struct termios tty_temp, tty_old; 1639 int result = 0; 1640 1641 DBG (127, "shoot() called\n"); 1642 1643 if (write (fd, (char *) shoot_pck, 8) != 8) 1644 { 1645 DBG (3, "shoot: error: write error\n"); 1646 return -1; 1647 } 1648 1649 if (CameraInfo.model != 0x25) 1650 { 1651 /* 1652 * WARNING: now we set the serial port to 9600 baud! 1653 */ 1654 1655 if (tcgetattr (fd, &tty_old) == -1) 1656 { 1657 DBG (3, "shoot: error: could not get attributes\n"); 1658 return -1; 1659 } 1660 1661 memcpy ((char *) &tty_temp, (char *) &tty_old, sizeof (struct termios)); 1662 1663 cfsetispeed (&tty_temp, B9600); 1664 cfsetospeed (&tty_temp, B9600); 1665 1666 /* 1667 * Apparently there is a bug in the DC20 where the response to 1668 * the shoot request is always at 9600. The DC25 does not have 1669 * this bug, so we skip this block. 1670 */ 1671 if (tcsetattr (fd, TCSANOW, &tty_temp) == -1) 1672 { 1673 DBG (3, "shoot: error: could not set attributes\n"); 1674 return -1; 1675 } 1676 } 1677 1678 if (read (fd, (char *) &result, 1) != 1) 1679 { 1680 DBG (3, "shoot: error: read returned -1\n"); 1681 result = -1; 1682 } 1683 else 1684 { 1685 result = (result == 0xD1) ? 0 : -1; 1686 } 1687 1688 if (CameraInfo.model != 0x25) 1689 { 1690 /* 1691 * We reset the serial to its original speed. 1692 * We can skip this on the DC25 also. 1693 */ 1694 if (tcsetattr (fd, TCSANOW, &tty_old) == -1) 1695 { 1696 DBG (3, "shoot: error: could not reset attributes\n"); 1697 result = -1; 1698 } 1699 } 1700 1701 if (result == 0) 1702 { 1703 if (CameraInfo.model == 0x25) 1704 { 1705 /* 1706 * If we don't put this in, the next read will time out 1707 * and return failure. Does the DC-20 need it too? 1708 */ 1709 sleep (3); 1710 } 1711 if (end_of_data (fd) == -1) 1712 { 1713 DBG (3, "shoot: error: end_of_data returned -1\n"); 1714 result = -1; 1715 } 1716 } 1717 1718 return result; 1719} 1720 1721 1722static unsigned char erase_pck[] = ERASE_PCK; 1723 1724static int 1725erase (int fd) 1726{ 1727 int count = 0; 1728 1729 DBG (127, "erase() called for image %d\n", dc25_opt_image_number); 1730 erase_pck[3] = dc25_opt_image_number; 1731 if (dc25_opt_erase) 1732 { 1733 erase_pck[3] = 0; 1734 } 1735 1736 if (send_pck (fd, erase_pck) == -1) 1737 { 1738 DBG (3, "erase: error: send_pck returned -1\n"); 1739 return -1; 1740 } 1741 1742 if (CameraInfo.model == 0x25) 1743 { 1744 /* 1745 * This block may really apply to the DC20 also, but since I 1746 * don't have one, it's hard to say for sure. On the DC25, erase 1747 * takes long enough that the read may timeout without returning 1748 * any data before the erase is complete. We let this happen 1749 * up to 4 times, then give up. 1750 */ 1751 while (count < 4) 1752 { 1753 if (end_of_data (fd) == -1) 1754 { 1755 count++; 1756 } 1757 else 1758 { 1759 break; 1760 } 1761 } 1762 if (count == 4) 1763 { 1764 DBG (3, "erase: error: end_of_data returned -1\n"); 1765 return -1; 1766 } 1767 } 1768 else 1769 { /* Assume DC-20 */ 1770 1771 if (end_of_data (fd) == -1) 1772 { 1773 DBG (3, "erase: error: end_of_data returned -1\n"); 1774 return -1; 1775 } 1776 } 1777 1778 return 0; 1779} 1780 1781static unsigned char res_pck[] = RES_PCK; 1782 1783static int 1784change_res (int fd, unsigned char res) 1785{ 1786 DBG (127, "change_res called\n"); 1787 if (res != 0 && res != 1) 1788 { 1789 DBG (3, "change_res: error: unsupported resolution\n"); 1790 return -1; 1791 } 1792 1793 res_pck[2] = res; 1794 1795 if (send_pck (fd, res_pck) == -1) 1796 { 1797 DBG (4, "change_res: error: send_pck returned -1\n"); 1798 } 1799 1800 if (end_of_data (fd) == -1) 1801 { 1802 DBG (4, "change_res: error: end_of_data returned -1\n"); 1803 } 1804 return 0; 1805} 1806 1807SANE_Status 1808sane_init (SANE_Int * version_code, SANE_Auth_Callback __sane_unused__ authorize) 1809{ 1810 char dev_name[PATH_MAX], *p; 1811 size_t len; 1812 FILE *fp; 1813 int baud; 1814 1815 strcpy (tty_name, DEF_TTY_NAME); 1816 1817 DBG_INIT (); 1818 1819 if (version_code) 1820 *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, 0); 1821 1822 fp = sanei_config_open (DC25_CONFIG_FILE); 1823 1824 DBG (127, "sane_init()\n"); 1825 1826 if (!fp) 1827 { 1828 /* default to /dev/ttyS0 instead of insisting on config file */ 1829 DBG (1, "sane_init: missing config file '%s'\n", DC25_CONFIG_FILE); 1830 } 1831 else 1832 { 1833 while (sanei_config_read (dev_name, sizeof (dev_name), fp)) 1834 { 1835 dev_name[sizeof (dev_name) - 1] = '\0'; 1836 DBG (20, "sane_init: config- %s", dev_name); 1837 1838 if (dev_name[0] == '#') 1839 continue; /* ignore line comments */ 1840 len = strlen (dev_name); 1841 if (!len) 1842 continue; /* ignore empty lines */ 1843 if (strncmp (dev_name, "port=", 5) == 0) 1844 { 1845 p = strchr (dev_name, '/'); 1846 if (p) 1847 { 1848 strcpy (tty_name, p); 1849 } 1850 DBG (20, "Config file port=%s\n", tty_name); 1851 } 1852 else if (strncmp (dev_name, "baud=", 5) == 0) 1853 { 1854 baud = atoi (&dev_name[5]); 1855 switch (baud) 1856 { 1857 case 9600: 1858 tty_baud = B9600; 1859 break; 1860 case 19200: 1861 tty_baud = B19200; 1862 break; 1863 case 38400: 1864 tty_baud = B38400; 1865 break; 1866#ifdef B57600 1867 case 57600: 1868 tty_baud = B57600; 1869 break; 1870#endif 1871#ifdef B115200 1872 case 115200: 1873 tty_baud = B115200; 1874 break; 1875#endif 1876 default: 1877 DBG (20, "Unknown baud=%d\n", baud); 1878 tty_baud = DEFAULT_TTY_BAUD; 1879 break; 1880 } 1881 DBG (20, "Config file baud=%lu\n", (u_long) tty_baud); 1882 } 1883 else if (strcmp (dev_name, "dumpinquiry") == 0) 1884 { 1885 dumpinquiry = SANE_TRUE; 1886 } 1887 } 1888 fclose (fp); 1889 } 1890 1891 if ((tfd = init_dc20 (tty_name, tty_baud)) == -1) 1892 { 1893 return SANE_STATUS_INVAL; 1894 } 1895 1896 if ((dc20_info = get_info (tfd)) == NULL) 1897 { 1898 DBG (2, "error: could not get info\n"); 1899 close_dc20 (tfd); 1900 return SANE_STATUS_INVAL; 1901 } 1902 1903 if (dumpinquiry) 1904 { 1905 DBG (0, "\nCamera information:\n~~~~~~~~~~~~~~~~~\n\n"); 1906 DBG (0, "Model...........: DC%x\n", dc20_info->model); 1907 DBG (0, "Firmware version: %d.%d\n", dc20_info->ver_major, 1908 dc20_info->ver_minor); 1909 DBG (0, "Pictures........: %d/%d\n", dc20_info->pic_taken, 1910 dc20_info->pic_taken + dc20_info->pic_left); 1911 DBG (0, "Resolution......: %s\n", 1912 dc20_info->flags.low_res ? "low" : "high"); 1913 DBG (0, "Battery state...: %s\n", 1914 dc20_info->flags.low_batt ? "low" : "good"); 1915 } 1916 1917 if (CameraInfo.pic_taken == 0) 1918 { 1919/* 1920 sod[DC25_OPT_IMAGE_NUMBER].cap |= SANE_CAP_INACTIVE; 1921*/ 1922 image_range.min = 0; 1923 dc25_opt_image_number = 0; 1924 1925 } 1926 else 1927 { 1928/* 1929 sod[DC25_OPT_IMAGE_NUMBER].cap &= ~SANE_CAP_INACTIVE; 1930*/ 1931 image_range.min = 1; 1932 } 1933 1934 return SANE_STATUS_GOOD; 1935} 1936 1937void 1938sane_exit (void) 1939{ 1940} 1941 1942/* Device select/open/close */ 1943 1944static const SANE_Device dev[] = { 1945 { 1946 "0", 1947 "Kodak", 1948 "DC-25", 1949 "still camera"}, 1950}; 1951 1952SANE_Status 1953sane_get_devices (const SANE_Device *** device_list, 1954 SANE_Bool __sane_unused__ local_only) 1955{ 1956 static const SANE_Device *devlist[] = { 1957 dev + 0, 0 1958 }; 1959 1960 DBG (127, "sane_get_devices called\n"); 1961 1962 if (dc20_info == NULL) 1963 { 1964 return SANE_STATUS_INVAL; 1965 } 1966 *device_list = devlist; 1967 return SANE_STATUS_GOOD; 1968} 1969 1970SANE_Status 1971sane_open (SANE_String_Const devicename, SANE_Handle * handle) 1972{ 1973 int i; 1974 1975 DBG (127, "sane_open for device %s\n", devicename); 1976 if (!devicename[0]) 1977 { 1978 i = 0; 1979 } 1980 else 1981 { 1982 for (i = 0; i < NELEMS (dev); ++i) 1983 { 1984 if (strcmp (devicename, dev[i].name) == 0) 1985 { 1986 break; 1987 } 1988 } 1989 } 1990 1991 if (i >= NELEMS (dev)) 1992 { 1993 return SANE_STATUS_INVAL; 1994 } 1995 1996 if (is_open) 1997 { 1998 return SANE_STATUS_DEVICE_BUSY; 1999 } 2000 2001 is_open = 1; 2002 *handle = MAGIC; 2003 2004 if (dc20_info == NULL) 2005 { 2006 DBG (1, "No device info\n"); 2007 } 2008 2009 DBG (3, "sane_open: pictures taken=%d\n", dc20_info->pic_taken); 2010 2011 return SANE_STATUS_GOOD; 2012} 2013 2014void 2015sane_close (SANE_Handle handle) 2016{ 2017 DBG (127, "sane_close called\n"); 2018 if (handle == MAGIC) 2019 is_open = 0; 2020 2021 if (pp) 2022 { 2023 free_pixmap (pp); 2024 pp = NULL; 2025 } 2026 2027 close_dc20 (tfd); 2028 2029 DBG (127, "sane_close returning\n"); 2030} 2031 2032const SANE_Option_Descriptor * 2033sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) 2034{ 2035 if (handle != MAGIC || !is_open) 2036 return NULL; /* wrong device */ 2037 if (option < 0 || option >= NELEMS (sod)) 2038 return NULL; 2039 return &sod[option]; 2040} 2041 2042SANE_Status 2043sane_control_option (SANE_Handle handle, SANE_Int option, 2044 SANE_Action action, void *value, SANE_Int * info) 2045{ 2046 SANE_Int myinfo = info_flags; 2047 SANE_Status status; 2048 2049 info_flags = 0; 2050 2051 DBG (127, "control_option(handle=%p,opt=%s,act=%s,val=%p,info=%p)\n", 2052 handle, sod[option].title, 2053 (action == 2054 SANE_ACTION_SET_VALUE ? "SET" : (action == 2055 SANE_ACTION_GET_VALUE ? "GET" : 2056 "SETAUTO")), value, (void *)info); 2057 2058 if (handle != MAGIC || !is_open) 2059 return SANE_STATUS_INVAL; /* Unknown handle ... */ 2060 2061 if (option < 0 || option >= NELEMS (sod)) 2062 return SANE_STATUS_INVAL; /* Unknown option ... */ 2063 2064 switch (action) 2065 { 2066 case SANE_ACTION_SET_VALUE: 2067 status = sanei_constrain_value (sod + option, value, &myinfo); 2068 if (status != SANE_STATUS_GOOD) 2069 { 2070 DBG (1, "Constraint error in control_option\n"); 2071 return status; 2072 } 2073 2074 switch (option) 2075 { 2076 case DC25_OPT_IMAGE_NUMBER: 2077 dc25_opt_image_number = *(SANE_Word *) value; 2078/* myinfo |= SANE_INFO_RELOAD_OPTIONS; */ 2079 break; 2080 2081 case DC25_OPT_THUMBS: 2082 dc25_opt_thumbnails = !!*(SANE_Word *) value; 2083 myinfo |= SANE_INFO_RELOAD_PARAMS; 2084 2085 if (dc25_opt_thumbnails) 2086 { 2087 /* 2088 * DC20 thumbnail are 80x60 grayscale, DC25 2089 * thumbnails are color. 2090 */ 2091 parms.format = 2092 (CameraInfo.model == 0x25) ? SANE_FRAME_RGB : SANE_FRAME_GRAY; 2093 parms.bytes_per_line = 80 * 3; 2094 parms.pixels_per_line = 80; 2095 parms.lines = 60; 2096 } 2097 else 2098 { 2099 parms.format = SANE_FRAME_RGB; 2100 if (dc20_info->flags.low_res) 2101 { 2102 parms.bytes_per_line = 320 * 3; 2103 parms.pixels_per_line = 320; 2104 parms.lines = 243; 2105 } 2106 else 2107 { 2108 parms.bytes_per_line = 500 * 3; 2109 parms.pixels_per_line = 500; 2110 parms.lines = 373; 2111 } 2112 } 2113 break; 2114 2115 case DC25_OPT_SNAP: 2116 dc25_opt_snap = !!*(SANE_Word *) value; 2117 myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; 2118 if (dc25_opt_snap) 2119 { 2120 sod[DC25_OPT_LOWRES].cap &= ~SANE_CAP_INACTIVE; 2121 } 2122 else 2123 { 2124 sod[DC25_OPT_LOWRES].cap |= SANE_CAP_INACTIVE; 2125 } 2126 break; 2127 2128 case DC25_OPT_LOWRES: 2129 dc25_opt_lowres = !!*(SANE_Word *) value; 2130 myinfo |= SANE_INFO_RELOAD_PARAMS; 2131 2132 if (!dc25_opt_thumbnails) 2133 { 2134 2135 parms.format = SANE_FRAME_RGB; 2136 2137 if (dc20_info->flags.low_res) 2138 { 2139 parms.bytes_per_line = 320 * 3; 2140 parms.pixels_per_line = 320; 2141 parms.lines = 243; 2142 } 2143 else 2144 { 2145 parms.bytes_per_line = 500 * 3; 2146 parms.pixels_per_line = 500; 2147 parms.lines = 373; 2148 } 2149 2150 } 2151 break; 2152 2153 case DC25_OPT_CONTRAST: 2154 dc25_opt_contrast = *(SANE_Word *) value; 2155 break; 2156 2157 case DC25_OPT_GAMMA: 2158 dc25_opt_gamma = *(SANE_Word *) value; 2159 break; 2160 2161 case DC25_OPT_ERASE: 2162 dc25_opt_erase = !!*(SANE_Word *) value; 2163 2164 /* 2165 * erase and erase_one are mutually exclusive. If 2166 * this one is turned on, the other must be off 2167 */ 2168 if (dc25_opt_erase && dc25_opt_erase_one) 2169 { 2170 dc25_opt_erase_one = SANE_FALSE; 2171 myinfo |= SANE_INFO_RELOAD_OPTIONS; 2172 } 2173 break; 2174 2175 case DC25_OPT_ERASE_ONE: 2176 dc25_opt_erase_one = !!*(SANE_Word *) value; 2177 2178 /* 2179 * erase and erase_one are mutually exclusive. If 2180 * this one is turned on, the other must be off 2181 */ 2182 if (dc25_opt_erase_one && dc25_opt_erase) 2183 { 2184 dc25_opt_erase = SANE_FALSE; 2185 myinfo |= SANE_INFO_RELOAD_OPTIONS; 2186 } 2187 break; 2188 2189 case DC25_OPT_DEFAULT: 2190 2191 dc25_opt_contrast = SANE_FIX (DC25_OPT_CONTRAST_DEFAULT); 2192 dc25_opt_gamma = SANE_FIX (DC25_OPT_GAMMA_DEFAULT); 2193 myinfo |= SANE_INFO_RELOAD_OPTIONS; 2194 break; 2195 2196 default: 2197 return SANE_STATUS_INVAL; 2198 } 2199 break; 2200 2201 case SANE_ACTION_GET_VALUE: 2202 switch (option) 2203 { 2204 case 0: 2205 *(SANE_Word *) value = NELEMS (sod); 2206 break; 2207 2208 case DC25_OPT_IMAGE_NUMBER: 2209 *(SANE_Word *) value = dc25_opt_image_number; 2210 break; 2211 2212 case DC25_OPT_THUMBS: 2213 *(SANE_Word *) value = dc25_opt_thumbnails; 2214 break; 2215 2216 case DC25_OPT_SNAP: 2217 *(SANE_Word *) value = dc25_opt_snap; 2218 break; 2219 2220 case DC25_OPT_LOWRES: 2221 *(SANE_Word *) value = dc25_opt_lowres; 2222 break; 2223 2224 case DC25_OPT_CONTRAST: 2225 *(SANE_Word *) value = dc25_opt_contrast; 2226 break; 2227 2228 case DC25_OPT_GAMMA: 2229 *(SANE_Word *) value = dc25_opt_gamma; 2230 break; 2231 2232 case DC25_OPT_ERASE: 2233 *(SANE_Word *) value = dc25_opt_erase; 2234 break; 2235 2236 case DC25_OPT_ERASE_ONE: 2237 *(SANE_Word *) value = dc25_opt_erase_one; 2238 break; 2239 2240 default: 2241 return SANE_STATUS_INVAL; 2242 } 2243 break; 2244 2245 case SANE_ACTION_SET_AUTO: 2246 switch (option) 2247 { 2248#if 0 2249 case DC25_OPT_CONTRAST: 2250 dc25_opt_contrast = SANE_FIX (DC25_OPT_CONTRAST_DEFAULT); 2251 break; 2252 2253 case DC25_OPT_GAMMA: 2254 dc25_opt_gamma = SANE_FIX (DC25_OPT_GAMMA_DEFAULT); 2255 break; 2256#endif 2257 2258 default: 2259 return SANE_STATUS_UNSUPPORTED; /* We are DUMB */ 2260 } 2261 } 2262 2263 if (info) 2264 *info = myinfo; 2265 2266 return SANE_STATUS_GOOD; 2267} 2268 2269SANE_Status 2270sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) 2271{ 2272 int rc = SANE_STATUS_GOOD; 2273 2274 DBG (127, "sane_get_params called\n"); 2275 2276 if (handle != MAGIC || !is_open) 2277 rc = SANE_STATUS_INVAL; /* Unknown handle ... */ 2278 2279 2280 *params = parms; 2281 return rc; 2282} 2283 2284static unsigned char thumb_pck[] = THUMBS_PCK; 2285 2286static unsigned char pic_pck[] = PICS_PCK; 2287 2288static int bytes_in_buffer; 2289static int bytes_read_from_buffer; 2290static SANE_Byte buffer[1024]; 2291static int total_bytes_read; 2292static SANE_Bool started = SANE_FALSE; 2293static int outbytes; 2294 2295SANE_Status 2296sane_start (SANE_Handle handle) 2297{ 2298 int n, i; 2299 FILE *f; 2300 2301 DBG (127, "sane_start called, handle=%lx\n", (u_long) handle); 2302 2303 if (handle != MAGIC || !is_open || 2304 (dc25_opt_image_number == 0 && dc25_opt_snap == SANE_FALSE)) 2305 return SANE_STATUS_INVAL; /* Unknown handle ... */ 2306 2307 if (started) 2308 { 2309 return SANE_STATUS_EOF; 2310 } 2311 2312 if (dc25_opt_snap) 2313 { 2314 2315 /* 2316 * Don't allow picture unless there is room in the 2317 * camera. 2318 */ 2319 if (CameraInfo.pic_left == 0) 2320 { 2321 DBG (3, "No room to store new picture\n"); 2322 return SANE_STATUS_INVAL; 2323 } 2324 2325 /* 2326 * DC-20 can only change resolution when camer is empty. 2327 * DC-25 can do it any time. 2328 */ 2329 if (CameraInfo.model != 0x20 || CameraInfo.pic_taken == 0) 2330 { 2331 if (change_res (tfd, dc25_opt_lowres) == -1) 2332 { 2333 DBG (1, "Failed to set resolution\n"); 2334 return SANE_STATUS_INVAL; 2335 } 2336 } 2337 2338 /* 2339 * Not sure why this delay is needed, but it seems to help: 2340 */ 2341#ifdef HAVE_USLEEP 2342 usleep (10); 2343#else 2344 sleep (1); 2345#endif 2346 if (shoot (tfd) == -1) 2347 { 2348 DBG (1, "Failed to snap new picture\n"); 2349 return SANE_STATUS_INVAL; 2350 } 2351 else 2352 { 2353 info_flags |= SANE_INFO_RELOAD_OPTIONS; 2354 CameraInfo.pic_taken++; 2355 CameraInfo.pic_left--; 2356 dc25_opt_image_number = CameraInfo.pic_taken; 2357 if (image_range.min == 0) 2358 image_range.min = 1; 2359 image_range.max++; 2360 sod[DC25_OPT_IMAGE_NUMBER].cap &= ~SANE_CAP_INACTIVE; 2361 } 2362 } 2363 2364 if (dc25_opt_thumbnails) 2365 { 2366 2367 /* 2368 * For thumbnails, we can do things right where we 2369 * start the download, and grab the first block 2370 * from the camera. The reamining blocks will be 2371 * fetched as necessary by sane_read(). 2372 */ 2373 thumb_pck[3] = (unsigned char) dc25_opt_image_number; 2374 2375 if (send_pck (tfd, thumb_pck) == -1) 2376 { 2377 DBG (4, "sane_start: error: send_pck returned -1\n"); 2378 return SANE_STATUS_INVAL; 2379 } 2380 2381 if (read_data (tfd, buffer, 1024) == -1) 2382 { 2383 DBG (4, "sane_start: read_data failed\n"); 2384 return SANE_STATUS_INVAL; 2385 } 2386 2387 /* 2388 * DC20 thumbnail are 80x60 grayscale, DC25 2389 * thumbnails are color. 2390 */ 2391 parms.format = 2392 (CameraInfo.model == 0x25) ? SANE_FRAME_RGB : SANE_FRAME_GRAY; 2393 parms.bytes_per_line = 80 * 3; /* 80 pixels, 3 colors */ 2394 parms.pixels_per_line = 80; 2395 parms.lines = 60; 2396 2397 bytes_in_buffer = 1024; 2398 bytes_read_from_buffer = 0; 2399 2400 } 2401 else 2402 { 2403 /* 2404 * We do something a little messy, and violates the SANE 2405 * philosophy. However, since it is fairly tricky to 2406 * convert the DC2x "comet" files on the fly, we read in 2407 * the entire data stream in sane_open(), and use convert_pic 2408 * to convert it to an in-memory pixpmap. Then when 2409 * sane_read() is called, we fill the requests from 2410 * memory. A good project for me (or some kind volunteer) 2411 * would be to rewrite this and move the actual download 2412 * to sane_read(). However, one argument for keeping it 2413 * this way is that the data comes down pretty fast, and 2414 * it helps to dedicate the processor to this task. We 2415 * might get serial port overruns if we try to do other 2416 * things at the same time. 2417 * 2418 * Also, as a side note, I was constantly getting serial 2419 * port overruns on a 90MHz pentium until I used hdparm 2420 * to set the "-u1" flag on the system drives. 2421 */ 2422 char tmpnamebuf[] = TMPFILE_PATTERN; 2423 2424 int fd = mkstemp (tmpnamebuf); 2425 if (fd == -1) 2426 { 2427 DBG (0, "Unable to make temp file %s\n", tmpnamebuf); 2428 return SANE_STATUS_INVAL; 2429 } 2430 2431 f = fdopen (fd, "wb"); 2432 if (f == NULL) 2433 { 2434 DBG (0, "Unable to fdopen tmp file\n"); 2435 return SANE_STATUS_INVAL; 2436 } 2437 2438 strcpy ((char *) buffer, COMET_MAGIC); 2439 fwrite (buffer, 1, COMET_HEADER_SIZE, f); 2440 2441 pic_pck[3] = (unsigned char) dc25_opt_image_number; 2442 2443 if (send_pck (tfd, pic_pck) == -1) 2444 { 2445 DBG (4, "sane_start: error: send_pck returned -1\n"); 2446 return SANE_STATUS_INVAL; 2447 } 2448 2449 if (read_data (tfd, buffer, 1024) == -1) 2450 { 2451 DBG (5, "sane_start: read_data failed\n"); 2452 return SANE_STATUS_INVAL; 2453 } 2454 2455 if (buffer[4] == 0) 2456 { /* hi-res image */ 2457 DBG (5, "sane_start: hi-res image\n"); 2458 n = 122; 2459 2460 parms.bytes_per_line = 500 * 3; /* 3 colors */ 2461 parms.pixels_per_line = 500; 2462 parms.lines = 373; 2463 2464 bytes_in_buffer = 1024; 2465 bytes_read_from_buffer = 0; 2466 } 2467 else 2468 { 2469 n = 61; 2470 DBG (5, "sane_start: low-res image\n"); 2471 2472 parms.bytes_per_line = 320 * 3; /* 3 Colors */ 2473 parms.pixels_per_line = 320; 2474 parms.lines = 243; 2475 2476 bytes_in_buffer = 1024; 2477 bytes_read_from_buffer = 0; 2478 } 2479 2480 2481 fwrite (buffer, 1, 1024, f); 2482 2483 for (i = 1; i < n; i++) 2484 { 2485 if (read_data (tfd, buffer, 1024) == -1) 2486 { 2487 DBG (5, "sane_start: read_data failed\n"); 2488 return SANE_STATUS_INVAL; 2489 } 2490 fwrite (buffer, 1, 1024, f); 2491 } 2492 2493 if (end_of_data (tfd) == -1) 2494 { 2495 fclose (f); 2496 DBG (4, "sane_open: end_of_data error\n"); 2497 return SANE_STATUS_INVAL; 2498 } 2499 else 2500 { 2501 fclose (f); 2502 if (convert_pic (tmpnamebuf, SAVE_ADJASPECT | SAVE_24BITS) == -1) 2503 { 2504 DBG (3, "sane_open: unable to convert\n"); 2505 return SANE_STATUS_INVAL; 2506 } 2507 unlink (tmpnamebuf); 2508 outbytes = 0; 2509 } 2510 } 2511 2512 started = SANE_TRUE; 2513 total_bytes_read = 0; 2514 2515 return SANE_STATUS_GOOD; 2516} 2517 2518 2519SANE_Status 2520sane_read (SANE_Handle __sane_unused__ handle, SANE_Byte * data, 2521 SANE_Int max_length, SANE_Int * length) 2522{ 2523 DBG (127, "sane_read called, maxlen=%d\n", max_length); 2524 2525 if ( ! started ) { 2526 return SANE_STATUS_INVAL; 2527 } 2528 2529 if (dc25_opt_thumbnails) 2530 { 2531 if (total_bytes_read == THUMBSIZE) 2532 { 2533 if (dc25_opt_erase || dc25_opt_erase_one) 2534 { 2535 2536 if (erase (tfd) == -1) 2537 { 2538 DBG (1, "Failed to erase memory\n"); 2539 return SANE_STATUS_INVAL; 2540 } 2541 2542 dc25_opt_erase = SANE_FALSE; 2543 dc25_opt_erase_one = SANE_FALSE; 2544 info_flags |= SANE_INFO_RELOAD_OPTIONS; 2545 2546 if (get_info (tfd) == NULL) 2547 { 2548 DBG (2, "error: could not get info\n"); 2549 close_dc20 (tfd); 2550 return SANE_STATUS_INVAL; 2551 } 2552 DBG (10, "Call get_info!, image range=%d,%d\n", image_range.min, 2553 image_range.max); 2554 } 2555 return SANE_STATUS_EOF; 2556 } 2557 2558 *length = 0; 2559 if (!(bytes_in_buffer - bytes_read_from_buffer)) 2560 { 2561 if (read_data (tfd, buffer, 1024) == -1) 2562 { 2563 DBG (5, "sane_read: read_data failed\n"); 2564 return SANE_STATUS_INVAL; 2565 } 2566 bytes_in_buffer = 1024; 2567 bytes_read_from_buffer = 0; 2568 } 2569 2570 while (bytes_read_from_buffer < bytes_in_buffer && 2571 max_length && total_bytes_read < THUMBSIZE) 2572 { 2573 *data++ = buffer[bytes_read_from_buffer++]; 2574 (*length)++; 2575 max_length--; 2576 total_bytes_read++; 2577 } 2578 2579 if (total_bytes_read == THUMBSIZE) 2580 { 2581 if (end_of_data (tfd) == -1) 2582 { 2583 DBG (4, "sane_read: end_of_data error\n"); 2584 return SANE_STATUS_INVAL; 2585 } 2586 else 2587 { 2588 return SANE_STATUS_GOOD; 2589 } 2590 } 2591 else 2592 { 2593 return SANE_STATUS_GOOD; 2594 } 2595 } 2596 else 2597 { 2598 int i; 2599 int filesize = parms.bytes_per_line * parms.lines; 2600 2601 /* 2602 * If outbytes is zero, then this is the first time 2603 * we've been called, so update the contrast table. 2604 * The formula is something I came up with that has the 2605 * following properties: 2606 * 1) It's a smooth curve that provides the effect I wanted 2607 * (bright pixels are made brighter, dim pixels are made 2608 * dimmer) 2609 * 2) The contrast parameter can be adjusted to provide 2610 * different amounts of contrast. 2611 * 3) A parameter of 1.0 can be used to pass the data 2612 * through unchanged (but values around 1.75 look 2613 * a lot better 2614 */ 2615 if (outbytes == 0) 2616 { 2617 double d; 2618 double cont = SANE_UNFIX (dc25_opt_contrast); 2619 2620 for (i = 0; i < 256; i++) 2621 { 2622 d = (i * 2.0) / 255 - 1.0; 2623 d = 2624 ((-pow (1 - d, cont)) + 1) * (d >= 2625 0) + (((pow (d + 1, cont)) - 2626 1)) * (d < 0); 2627 contrast_table[i] = (d * 127.5) + 127.5; 2628/* 2629 fprintf (stderr,"%03d %03d\n",i,contrast_table[i]); 2630*/ 2631 } 2632 } 2633 2634 /* We're done, so return EOF */ 2635 if (outbytes >= filesize) 2636 { 2637 free_pixmap (pp); 2638 pp = NULL; 2639 2640 if (dc25_opt_erase || dc25_opt_erase_one) 2641 { 2642 if (erase (tfd) == -1) 2643 { 2644 DBG (1, "Failed to erase memory\n"); 2645 return SANE_STATUS_INVAL; 2646 } 2647 } 2648 2649 if (get_info (tfd) == NULL) 2650 { 2651 DBG (2, "error: could not get info\n"); 2652 close_dc20 (tfd); 2653 return SANE_STATUS_INVAL; 2654 } 2655 DBG (10, "Call get_info!, image range=%d,%d\n", image_range.min, 2656 image_range.max); 2657 2658 get_info (tfd); 2659 2660 *length=0; 2661 2662 return SANE_STATUS_EOF; 2663 } 2664 2665 if (max_length > filesize - outbytes) 2666 { 2667 *length = filesize - outbytes; 2668 } 2669 else 2670 { 2671 *length = max_length; 2672 } 2673 2674 memcpy (data, pp->planes + outbytes, *length); 2675 outbytes += *length; 2676 2677 2678 for (i = 0; i < *length; i++) 2679 { 2680 data[i] = contrast_table[data[i]]; 2681 } 2682 2683 return SANE_STATUS_GOOD; 2684 2685 } 2686} 2687 2688void 2689sane_cancel (SANE_Handle __sane_unused__ handle) 2690{ 2691 DBG (127, "sane_cancel() called\n"); 2692 started = SANE_FALSE; 2693} 2694 2695SANE_Status 2696sane_set_io_mode (SANE_Handle __sane_unused__ handle, 2697 SANE_Bool __sane_unused__ non_blocking) 2698{ 2699 /* sane_set_io_mode() is only valid during a scan */ 2700 if (started) 2701 { 2702 if (non_blocking == SANE_FALSE) 2703 { 2704 return SANE_STATUS_GOOD; 2705 } 2706 else 2707 { 2708 return SANE_STATUS_UNSUPPORTED; 2709 } 2710 } 2711 else 2712 { 2713 /* We aren't currently scanning */ 2714 return SANE_STATUS_INVAL; 2715 } 2716} 2717 2718SANE_Status 2719sane_get_select_fd (SANE_Handle __sane_unused__ handle, SANE_Int __sane_unused__ * fd) 2720{ 2721 return SANE_STATUS_UNSUPPORTED; 2722} 2723