Sane-0.05/0000755000774200006240000000000011736245771011123 5ustar ra28145a400mcSane-0.05/Changes0000644000774200006240000000134211736245674012420 0ustar ra28145a400mcRevision history for Perl extension Sane. 0.05 Mon, 02 Apr 2012 08:38 +0200 - Export SANE_NAME_PAGE_WIDTH SANE_NAME_PAGE_HEIGHT - fix 'cast from pointer to integer of different size' warnings 0.04 Tue, 14 Feb 2012 10:49:23 +0100 - Check for opt->size=0 - Check for zero-length data 0.03 Mon, 11 May 2009 09:56:37 +0200 - Add Sane->get_version_scalar - Don't export SANE_CAP_ALWAYS_SETTABLE unless libsane 1.0.19 - Add debug message for sane_open 0.02 Wed Nov 26 20:45:00 2008 - Skip most tests if we don't have libsane 1.0.19 - Fix symbol names in write_pnm_header 0.01 Tue Nov 18 20:31:00 2008 - original version; created by h2xs 1.23 with options -A -n Sane Sane-0.05/examples/0000755000774200006240000000000011736245770012740 5ustar ra28145a400mcSane-0.05/examples/scanimage.pl0000755000774200006240000013233511242253716015225 0ustar ra28145a400mc#!/usr/bin/perl use warnings; use strict; use Sane; use Data::Dumper; use Getopt::Long qw(:config no_ignore_case pass_through); use File::Basename; use IO::Handle; #$Sane::DEBUG = 1; my (%options, @window_val_user, @window_option, @window_val, @window, $num_dev_options, $device, $format, $devname, %option_number); my $verbose = 0; my $help = 0; my $test = 0; my $batch = 0; my $batch_start_at = 1; my $batch_count = -1; my $batch_increment = 1; my $buffer_size = (32 * 1024); # default size my $tl_x = 0; my $tl_y = 0; my $br_x = 0; my $br_y = 0; my $w_x = 0; my $h_y = 0; my $resolution_optind = -1; my $resolution_value = 0; my $progress = 0; my $batch_double = 0; my $batch_prompt = 0; my $dont_scan = 0; my $prog_name = basename($0); my @args = (\%options, 'd|device-name=s' => \$devname, 'L|list-devices', 'f|formatted-device-list=s', 'b|batch:s' => \$format, 'batch-start=i' => \$batch_start_at, 'batch-count=i' => \$batch_count, 'batch-increment=i' => \$batch_increment, 'batch-double' => \$batch_double, 'batch-prompt' => \$batch_prompt, 'p|progress' => \$progress, 'n|dont-scan' => \$dont_scan, 'T|test' => \$test, 'h|help' => \$help, 'v|verbose+' => \$verbose, 'B|buffer-size' => \$buffer_size, 'V|version'); sub sighandler { my $signum = shift; my $first_time = SANE_TRUE; if ($device) { print STDERR "$prog_name: received signal $signum\n"; if ($first_time) { $first_time = SANE_FALSE; print STDERR "$prog_name: trying to stop scanner\n"; $device->cancel; } else { print STDERR "$prog_name: aborting\n"; _exit (0); } } } sub print_unit { my ($unit) = @_; if ($unit == SANE_UNIT_PIXEL) { print "pel"; } elsif ($unit == SANE_UNIT_BIT) { print "bit"; } elsif ($unit == SANE_UNIT_MM) { print "mm"; } elsif ($unit == SANE_UNIT_DPI) { print "dpi"; } elsif ($unit == SANE_UNIT_PERCENT) { print "%"; } elsif ($unit == SANE_UNIT_MICROSECOND) { print "us"; } } sub print_option { my ($device, $opt_num, $short_name) = @_; my $not_first = SANE_FALSE; my $maxwindow = 0; my $opt = $device->get_option_descriptor ($opt_num); if ($short_name) { printf " -%s", $short_name; } else { printf " --%s", $opt->{name}; } if ($opt->{type} == SANE_TYPE_BOOL) { print "[=("; print "auto|" if ($opt->{cap} & SANE_CAP_AUTOMATIC); print "yes|no)]"; } elsif ($opt->{type} != SANE_TYPE_BUTTON) { print ' '; if ($opt->{cap} & SANE_CAP_AUTOMATIC) { print "auto|"; $not_first = SANE_TRUE; } if ($opt->{constraint_type} == SANE_CONSTRAINT_NONE) { if ($opt->{type} == SANE_TYPE_INT) { print ""; } elsif ($opt->{type} == SANE_TYPE_FIXED) { print ""; } elsif ($opt->{type} == SANE_TYPE_STRING) { print ""; } print ",..." if ($opt->{max_values} > 1); } elsif ($opt->{constraint_type} == SANE_CONSTRAINT_RANGE) { my $format = "%g..%g"; $format = "%d..%d" if ($opt->{type} == SANE_TYPE_INT); if ($opt->{name} eq SANE_NAME_SCAN_BR_X) { $maxwindow = $opt->{constraint}{max} - $tl_x; printf $format, $opt->{constraint}{min}, $maxwindow; } elsif ($opt->{name} eq SANE_NAME_SCAN_BR_Y) { $maxwindow = $opt->{constraint}{max} - $tl_y; printf $format, $opt->{constraint}{min}, $maxwindow; } else { printf $format, $opt->{constraint}{min}, $opt->{constraint}{max}; } print_unit ($opt->{unit}); print ",..." if ($opt->{max_values} > 1); print " (in steps of $opt->{constraint}{quant})" if ($opt->{constraint}{quant}); } elsif ($opt->{constraint_type} == SANE_CONSTRAINT_STRING_LIST or $opt->{constraint_type} == SANE_CONSTRAINT_WORD_LIST) { for (my $i = 0; $i < @{$opt->{constraint}}; ++$i) { print '|' if ($i > 0); print $opt->{constraint}[$i]; } if ($opt->{constraint_type} == SANE_CONSTRAINT_WORD_LIST) { print_unit ($opt->{unit}); print ",..." if ($opt->{max_values} > 1); } } } if ($opt->{max_values} == 1) { # print current option value if (! ($opt->{cap} & SANE_CAP_INACTIVE)) { my $val = $device->get_option ($opt_num); print " ["; if ($opt->{type} == SANE_TYPE_BOOL) { print ($val ? "yes" : "no"); } elsif ($opt->{type} == SANE_TYPE_INT or $opt->{type} == SANE_TYPE_FIXED) { my $format = "%g"; $format = "%d" if ($opt->{type} == SANE_TYPE_INT); if ($opt->{name} eq SANE_NAME_SCAN_TL_X) { $tl_x = $val; printf $format, $tl_x; } elsif ($opt->{name} eq SANE_NAME_SCAN_TL_Y) { $tl_y = $val; printf $format, $tl_y; } elsif ($opt->{name} eq SANE_NAME_SCAN_BR_X) { $br_x = $val; $w_x = $br_x - $tl_x; printf $format, $w_x; } elsif ($opt->{name} eq SANE_NAME_SCAN_BR_Y) { $br_y = $val; $h_y = $br_y - $tl_y; printf $format, $h_y; } else { printf $format, $val; } } elsif ($opt->{type} == SANE_TYPE_STRING) { print $val; } print ']'; } } print " [inactive]" if ($opt->{cap} & SANE_CAP_INACTIVE); print "\n "; if ($short_name eq 'x') { print "Width of scan-area."; } elsif ($short_name eq 'y') { print "Height of scan-area."; } else { my $column = 8; my $last_break = 0; my $start = 0; for (my $pos = 0; $pos < length($opt->{desc}); ++$pos) { ++$column; $last_break = $pos if (substr($opt->{desc}, $pos, 1) eq ' '); if ($column >= 79 and $last_break) { print substr($opt->{desc}, $start++, 1) while ($start < $last_break); $start = $last_break + 1; # skip blank print "\n "; $column = 8 + $pos - $start; } } print substr($opt->{desc}, $start++, 1) while ($start < length($opt->{desc})); } print "\n"; } # A scalar has the following syntax: # # V [ U ] # # V is the value of the scalar. It is either an integer or a # floating point number, depending on the option type. # # U is an optional unit. If not specified, the default unit is used. # The following table lists which units are supported depending on # what the option's default unit is: # # Option's unit: Allowed units: # # SANE_UNIT_NONE: # SANE_UNIT_PIXEL: pel # SANE_UNIT_BIT: b (bit), B (byte) # SANE_UNIT_MM: mm (millimeter), cm (centimeter), in or " (inches), # SANE_UNIT_DPI: dpi # SANE_UNIT_PERCENT: % # SANE_UNIT_MICROSECOND: us sub parse_scalar { my ($opt, $str) = @_; my ($v, $unit); if ($str =~ /^(\d*\.?\d*)(cm|mm|in|\"|b|B|dpi|%|us)?/) { $v = $1; $unit = $2; $unit = '' if not defined $unit; } else { print STDERR "$prog_name: option --$opt->{name}: bad option value (rest of option: $str)\n"; exit (1); } if ($opt->{unit} == SANE_UNIT_BIT) { $v *= 8 if ($unit eq 'B'); } elsif ($opt->{unit} == SANE_UNIT_MM) { if ($unit eq 'cm') { $v *= 10; } elsif ($unit eq 'in') { $v *= 25.4; } } return $v, substr($str, length($v) + length($unit), length($str)); } # A vector has the following syntax: # # [ '[' I ']' ] S { [','|'-'] [ '[' I ']' S } # # The number in brackets (I), if present, determines the index of the # vector element to be set next. If I is not present, the value of # last index used plus 1 is used. The first index value used is 0 # unless I is present. # # S is a scalar value as defined by parse_scalar(). # # If two consecutive value specs are separated by a comma (,) their # values are set independently. If they are separated by a dash (-), # they define the endpoints of a line and all vector values between # the two endpoints are set according to the value of the # interpolated line. For example, [0]15-[255]15 defines a vector of # 256 elements whose value is 15. Similarly, [0]0-[255]255 defines a # vector of 256 elements whose value starts at 0 and increases to # 255. sub parse_vector { my ($opt, $str) = @_; my $index = -1; my $prev_value = 0; my $prev_index = 0; my $separator = ''; my (@vector, $value); do { if ($str =~ /^\[/) { if ($str =~ /^\[(\d*\.?\d*)\]/) { $index = $1; } else { print STDERR "$prog_name: option --$opt->{name}: closing bracket missing " ."(rest of option: $str)\n"; exit (1); } } else { ++$index; } if ($index < 0 or $index >= length($str)) { printf STDERR "$prog_name: option --$opt->{name}: index $index out of range [0..%d]\n", length($str); exit (1); } # read value ($value, $str) = parse_scalar ($opt, $str); if ($str ne '' and $str !~ /^[-,]/) { print STDERR "$prog_name: option --$opt->{name}: illegal separator (rest of option: $str)\n"; exit (1); } # store value: $vector[$index] = $value; if ($separator eq '-') { # interpolate my $v = $prev_value; my $slope = ($value - $v) / ($index - $prev_index); for (my $i = $prev_index + 1; $i < $index; ++$i) { $v += $slope; $vector[$i] = $v; } } $prev_index = $index; $prev_value = $value; $separator = substr($str, 0, 1); } while ($separator eq ',' || $separator eq '-'); if ($verbose > 2) { print STDERR "$prog_name: value for --$opt->{name} is: "; for (@vector) { print STDERR "$_ "; } print STDERR "\n"; } return @vector; } sub fetch_options { my $device = shift; # We got a device, find out how many options it has: $num_dev_options = $device->get_option(0); if ($Sane::STATUS != SANE_STATUS_GOOD) { print STDERR "$prog_name: unable to determine option count\n"; exit (1); } for (my $i = 0; $i < $num_dev_options; ++$i) { my $opt = $device->get_option_descriptor ($i); next if (! ($opt->{cap} & SANE_CAP_SOFT_SELECT)); $option_number{$opt->{name}} = $i; # Look for scan resolution $resolution_optind = $i if (($opt->{type} == SANE_TYPE_FIXED || $opt->{type} == SANE_TYPE_INT) and ($opt->{unit} == SANE_UNIT_DPI) and ($opt->{name} eq SANE_NAME_SCAN_RESOLUTION)); # Keep track of top-left corner options (if they exist at # all) and replace the bottom-right corner options by a # width/height option (if they exist at all). if (($opt->{type} == SANE_TYPE_FIXED || $opt->{type} == SANE_TYPE_INT) and ($opt->{unit} == SANE_UNIT_MM || $opt->{unit} == SANE_UNIT_PIXEL)) { if ($opt->{name} eq SANE_NAME_SCAN_TL_X) { $window[2] = $i; $opt->{name} = 'l'; } elsif ($opt->{name} eq SANE_NAME_SCAN_TL_Y) { $window[3] = $i; $opt->{name} = 't'; } elsif ($opt->{name} eq SANE_NAME_SCAN_BR_X) { $window[0] = $i; $opt->{name} = 'x'; $window_option[0] = $opt; $window_option[0]->{title} = 'Scan width'; $window_option[0]->{desc} = 'Width of scanning area.'; $window_val[0] = $device->get_option ($i) if (!$window_val_user[0]); } elsif ($opt->{name} eq SANE_NAME_SCAN_BR_Y) { $window[1] = $i; $opt->{name} = 'y'; $window_option[1] = $opt; $window_option[1]->{title} = 'Scan height'; $window_option[1]->{desc} = 'Height of scanning area.'; $window_val[1] = $device->get_option ($i) if (!$window_val_user[1]); } } if ($opt->{type} == SANE_TYPE_BOOL) { push @args, "$opt->{name}:s"; } elsif ($opt->{type} == SANE_TYPE_BUTTON) { push @args, $opt->{name}; } else { push @args, "$opt->{name}=s"; } } # Initialize width & height options based on backend default # values for top-left x/y and bottom-right x/y: for (my $i = 0; $i < 2; ++$i) { if ($window[$i] and $window[$i + 2] and !$window_val_user[$i]) { my $pos = $device->get_option ($window[$i + 2]); $window_val[$i] = $window_val[$i] - $pos if (defined $pos); } } } sub set_option { my ($device, $optnum, $value) = @_; my $opt = $device->get_option_descriptor ($optnum); if ($opt and ($opt->{cap} & SANE_CAP_INACTIVE)) { print STDERR "$prog_name: ignored request to set inactive option $opt->{name}\n" if ($verbose > 0); return; } my $info = $device->set_option($optnum, $value); if ($Sane::STATUS != SANE_STATUS_GOOD) { print STDERR "$prog_name: setting of option --$opt->{name} failed ($Sane::STATUS)\n"; exit (1); } if (($info & SANE_INFO_INEXACT) and $opt->{max_values} == 1) { my $orig = $value; $value = $device->get_option($optnum); if ($opt->{type} == SANE_TYPE_INT) { printf STDERR "$prog_name: rounded value of $opt->{name} from %d to %d\n", $orig, $value; } elsif ($opt->{type} == SANE_TYPE_FIXED) { printf STDERR "$prog_name: rounded value of $opt->{name} from %g to %g\n", $orig, $value; } } fetch_options ($device) if ($info & SANE_INFO_RELOAD_OPTIONS); } sub process_backend_option { my ($device, $optnum, $optarg) = @_; my $opt = $device->get_option_descriptor ($optnum); if ($opt and ($opt->{cap} & SANE_CAP_INACTIVE)) { print STDERR "$prog_name: attempted to set inactive option $opt->{name}\n"; exit (1); } if (($opt->{cap} & SANE_CAP_AUTOMATIC) and $optarg and $optarg =~ /^auto$/i) { $device->set_auto($optnum); if ($Sane::STATUS != SANE_STATUS_GOOD) { printf STDERR "$prog_name: failed to set option --$opt->{name} to automatic ($Sane::STATUS)\n"; exit (1); } return; } my $value; if ($opt->{type} == SANE_TYPE_BOOL) { $value = 1; # no argument means option is set if ($optarg) { if ($optarg =~ /^yes$/i) { $value = 1; } elsif ($optarg =~ /^no$/i) { $value = 0; } else { printf STDERR "$prog_name: option --$opt->{name}: bad option value `$optarg'\n"; exit (1); } } } elsif ($opt->{type} == SANE_TYPE_INT or $opt->{type} == SANE_TYPE_FIXED) { my @vector = parse_vector ($opt, $optarg); $value = \@vector; } elsif ($opt->{type} == SANE_TYPE_STRING) { $value = $optarg; } elsif ($opt->{type} == SANE_TYPE_BUTTON) { $value = 0; # value doesn't matter } else { printf STDERR "$prog_name: duh, got unknown option type $opt->{type}\n"; return; } set_option ($device, $optnum, $value); } sub write_pnm_header { my ($format, $width, $height, $depth) = @_; # The netpbm-package does not define raw image data with maxval > 255. # But writing maxval 65535 for 16bit data gives at least a chance # to read the image. if ($format == SANE_FRAME_RED or $format == SANE_FRAME_GREEN or $format == SANE_FRAME_BLUE or $format == SANE_FRAME_RGB) { printf "P6\n# SANE data follows\n%d %d\n%d\n", $width, $height, ($depth <= 8) ? 255 : 65535; } else { if ($depth == 1) { printf "P4\n# SANE data follows\n%d %d\n", $width, $height; } else { printf "P5\n# SANE data follows\n%d %d\n%d\n", $width, $height, ($depth <= 8) ? 255 : 65535; } } } sub scan_it { my $first_frame = 1; my $offset = 0; my $must_buffer = 0; my $min = 0xff; my $max = 0; my %image; my @format_name = ( "gray", "RGB", "red", "green", "blue" ); my $total_bytes = 0; my $hang_over = -1; my $parm; {do { # extra braces to get last to work. if (!$first_frame) { $device->start; if ($Sane::STATUS != SANE_STATUS_GOOD) { printf STDERR "$prog_name: sane_start: $Sane::STATUS\n"; goto cleanup; } } $parm = $device->get_parameters; if ($Sane::STATUS != SANE_STATUS_GOOD) { printf STDERR "$prog_name: sane_get_parameters: $Sane::STATUS\n"; goto cleanup; } if ($verbose) { if ($first_frame) { if ($parm->{lines} >= 0) { printf STDERR "$prog_name: scanning image of size %dx%d pixels at " ."%d bits/pixel\n", $parm->{pixels_per_line}, $parm->{lines}, 8 * $parm->{bytes_per_line} / $parm->{pixels_per_line}; } else { printf STDERR "$prog_name: scanning image %d pixels wide and " ."variable height at %d bits/pixel\n", $parm->{pixels_per_line}, 8 * $parm->{bytes_per_line} / $parm->{pixels_per_line}; } } printf STDERR "$prog_name: acquiring %s frame\n", $parm->{format} <= SANE_FRAME_BLUE ? $format_name[$parm->{format}]:"Unknown"; } if ($first_frame) { if ($parm->{format} == SANE_FRAME_RED or $parm->{format} == SANE_FRAME_GREEN or $parm->{format} == SANE_FRAME_BLUE) { die unless ($parm->{depth} == 8); $must_buffer = 1; $offset = $parm->{format} - SANE_FRAME_RED; } elsif ($parm->{format} == SANE_FRAME_RGB) { die unless (($parm->{depth} == 8) || ($parm->{depth} == 16)); } if ($parm->{format} == SANE_FRAME_RGB or $parm->{format} == SANE_FRAME_GRAY) { die unless (($parm->{depth} == 1) || ($parm->{depth} == 8) || ($parm->{depth} == 16)); if ($parm->{lines} < 0) { $must_buffer = 1; $offset = 0; } else { # if ($output_format == OUTPUT_TIFF) { # sanei_write_tiff_header ($parm->{format}, # $parm->{pixels_per_line}, $parm->{lines}, # $parm->{depth}, $resolution_value, # icc_profile); # else { write_pnm_header ($parm->{format}, $parm->{pixels_per_line}, $parm->{lines}, $parm->{depth}); # } } } } else { die unless ($parm->{format} >= SANE_FRAME_RED && $parm->{format} <= SANE_FRAME_BLUE); $offset = $parm->{format} - SANE_FRAME_RED; $image{x} = $image{y} = 0; } my $hundred_percent = $parm->{bytes_per_line} * $parm->{lines} * (($parm->{format} == SANE_FRAME_RGB || $parm->{format} == SANE_FRAME_GRAY) ? 1:3); while (1) { my ($buffer, $len) = $device->read ($buffer_size); $total_bytes += $len; my $progr = (($total_bytes * 100.) / $hundred_percent); $progr = 100. if ($progr > 100.); printf STDERR "Progress: %3.1f%%\r", $progr if ($progress); if ($Sane::STATUS != SANE_STATUS_GOOD) { printf STDERR "$prog_name: min/max graylevel value = %d/%d\n", $min, $max if ($verbose && $parm->{depth} == 8); if ($Sane::STATUS != SANE_STATUS_EOF) { print STDERR "$prog_name: sane_read: $Sane::STATUS\n"; return; } last; } if ($must_buffer) { # We're either scanning a multi-frame image or the # scanner doesn't know what the eventual image height # will be (common for hand-held scanners). In either # case, we need to buffer all data before we can write # the image if ($parm->{format} == SANE_FRAME_RED or $parm->{format} == SANE_FRAME_GREEN or $parm->{format} == SANE_FRAME_BLUE) { for (my $i = 0; $i < $len; ++$i) { $image{data}[$offset + 3 * $i] = substr($buffer, $i, 1); } $offset += 3 * $len; } elsif ($parm->{format} == SANE_FRAME_RGB or $parm->{format} == SANE_FRAME_GRAY) { for (my $i = 0; $i < $len; ++$i) { $image{data}[$offset + $i] = substr($buffer, $i, 1); } $offset += $len; } } else { # ! must_buffer # if (($output_format == OUTPUT_TIFF) || ($parm->{depth} != 16)) { # print $buffer; # } # else { ##if !defined(WORDS_BIGENDIAN) # my $start = 0; # # # check if we have saved one byte from the last sane_read # if ($hang_over > -1) { # if ($len > 0) { # print $buffer; # $buffer = $hang_over.$buffer; # $hang_over = -1; # $start = 1; # } # } # # now do the byte-swapping # $buffer = reverse $buffer; # # # check if we have an odd number of bytes # if ((($len - $start) % 2) != 0) { # $hang_over = substr($buffer, $len - 1, 1); # $len--; # } ##endif print $buffer; # } } if ($verbose && $parm->{depth} == 8) { for (split(//, $buffer)) { my $c = ord; if ($c >= $max) { $max = $c; } elsif ($c < $min) { $min = $c; } } } } $first_frame = 0; } while (!$parm->{last_frame});} if ($must_buffer) { if ($parm->{lines} > 0) { $image{height} = $parm->{lines}; } else { $image{height} = @{$image{data}}/$parm->{pixels_per_line}; $image{height} /= 3 if ($parm->{format} == SANE_FRAME_RED or $parm->{format} == SANE_FRAME_GREEN or $parm->{format} == SANE_FRAME_BLUE); } # if ($output_format == OUTPUT_TIFF) { # sanei_write_tiff_header ($parm->{format}, $parm->{pixels_per_line}, # $parm->{lines}, $parm->{depth}, $resolution_value, # icc_profile); # } # else { write_pnm_header ($parm->{format}, $parm->{pixels_per_line}, $image{height}, $parm->{depth}); # } # if (($output_format == OUTPUT_TIFF) || ($image{Bpp} == 1) # || ($image{Bpp} == 3)) { # print $image{data}; # } # else { # $image{Bpp} == 2 or $image{Bpp} == 6 assumed ##if !defined(WORDS_BIGENDIAN) # for (my $i = 0; $i < $image{Bpp} * $image{height} * $image{width}; $i += 2) { # my $LSB = $image{data}[$i]; # $image{data}[$i] = $image{data}[$i + 1]; # $image{data}[$i + 1] = $LSB; # } ##endif for (@{$image{data}}) {print;} # } } # flush the output buffer STDOUT->flush; cleanup: my $expected_bytes = $parm->{bytes_per_line} * $parm->{lines} * (($parm->{format} == SANE_FRAME_RGB || $parm->{format} == SANE_FRAME_GRAY) ? 1 : 3); $expected_bytes = 0 if ($parm->{lines} < 0); if ($total_bytes > $expected_bytes && $expected_bytes != 0) { printf STDERR "%s: WARNING: read more data than announced by backend " ."(%u/%u)\n", $prog_name, $total_bytes, $expected_bytes; } elsif ($verbose) { printf STDERR "%s: read %u bytes in total\n", $prog_name, $total_bytes; } return; } sub pass_fail { my ($max, $len, $buffer) = @_; if ($Sane::STATUS != SANE_STATUS_GOOD) { print STDERR "FAIL Error: $Sane::STATUS\n"; } elsif ($len < length($buffer)) { printf STDERR "FAIL Cheat: %d bytes\n", length($buffer); } elsif ($len > $max) { printf STDERR "FAIL Overflow: %d bytes\n", $len; } elsif ($len == 0) { print STDERR "FAIL No data\n"; } else { print STDERR "PASS\n"; } } sub test_it { my %image; my @format_name = ( "gray", "RGB", "red", "green", "blue" ); $device->start; if ($Sane::STATUS != SANE_STATUS_GOOD) { print STDERR "$prog_name: sane_start: $Sane::STATUS\n"; goto cleanup; } my $parm = $device->get_parameters; if ($Sane::STATUS != SANE_STATUS_GOOD) { print STDERR "$prog_name: sane_get_parameters: $Sane::STATUS\n"; goto cleanup; } if ($parm->{lines} >= 0) { printf STDERR "$prog_name: scanning image of size %dx%d pixels at " ."%d bits/pixel\n", $parm->{pixels_per_line}, $parm->{lines}, 8 * $parm->{bytes_per_line} / $parm->{pixels_per_line}; } else { printf STDERR "$prog_name: scanning image %d pixels wide and " ."variable height at %d bits/pixel\n",$parm->{pixels_per_line}, 8 * $parm->{bytes_per_line} / $parm->{pixels_per_line}; } printf STDERR "$prog_name: acquiring %s frame, %d bits/sample\n", $parm->{format} <= SANE_FRAME_BLUE ? $format_name[$parm->{format}]:"Unknown", $parm->{depth}; printf STDERR "$prog_name: reading one scanline, %d bytes...\t", $parm->{bytes_per_line}; ($image{data}, my $len) = $device->read ($parm->{bytes_per_line}); pass_fail ($parm->{bytes_per_line}, $len, $image{data}); goto cleanup if ($Sane::STATUS != SANE_STATUS_GOOD); print STDERR "$prog_name: reading one byte...\t\t"; ($image{data}, $len) = $device->read (1); pass_fail (1, $len, $image{data}); goto cleanup if ($Sane::STATUS != SANE_STATUS_GOOD); my $i; for ($i = 2; $i < $parm->{bytes_per_line} * 2; $i *= 2) { printf STDERR "$prog_name: stepped read, %d bytes... \t", $i; ($image{data}, $len) = $device->read ($i); pass_fail ($i, $len, $image{data}); goto cleanup if ($Sane::STATUS != SANE_STATUS_GOOD); } for ($i /= 2; $i > 2; $i /= 2) { printf STDERR "$prog_name: stepped read, %d bytes... \t", $i - 1; ($image{data}, $len) = $device->read ($i - 1); pass_fail ($i - 1, $len, $image{data}); goto cleanup if ($Sane::STATUS != SANE_STATUS_GOOD); } cleanup: $device->cancel; return; } # There seems to be a bug in Getopt::Long 2.37 where l is treated as L whilst # l is not in @args. Therefore the workaround is to rename l to m for the first # scan and back to l for the second. for (@ARGV) { $_ = '-m' if ($_ eq '-l'); $_ = '-u' if ($_ eq '-t'); } # make a first pass through the options with error printing and argument # permutation disabled: GetOptions (@args); if (defined($options{L}) or defined($options{f})) { my @device_list = Sane->get_devices; if ($Sane::STATUS != SANE_STATUS_GOOD) { print STDERR "$prog_name: sane_get_devices() failed: $Sane::STATUS\n"; exit (1); } if (defined($options{L})) { foreach (@device_list) { printf "device `%s' is a %s %s %s\n", $_->{name}, $_->{vendor}, $_->{model}, $_->{type}; } printf "\nNo scanners were identified. If you were expecting " ."something different,\ncheck that the scanner is plugged " ."in, turned on and detected by the\nsane-find-scanner tool " ."(if appropriate). Please read the documentation\nwhich came " ."with this software (README, FAQ, manpages).\n" if ($#device_list == -1); } else { for (my $i = 0; $i < @device_list; $i++) { my $format = $options{f}; $format =~ s/%d/$device_list[$i]->{name}/g; $format =~ s/%v/$device_list[$i]->{vendor}/g; $format =~ s/%m/$device_list[$i]->{model}/g; $format =~ s/%t/$device_list[$i]->{type}/g; $format =~ s/%i/$i/g; print $format; } } printf "default device is `%s'\n", $ENV{'SANE_DEFAULT_DEVICE'} if (defined($ENV{'SANE_DEFAULT_DEVICE'})); exit (0); } if (defined($options{V})) { printf "%s %s; backend version %d.%d.%d\n", $prog_name, $Sane::VERSION, Sane->get_version; exit (0); } if ($help) { printf "Usage: %s [OPTION]... Start image acquisition on a scanner device and write PNM image data to standard output. Parameters are separated by a blank from single-character options (e.g. -d epson) and by a \"=\" from multi-character options (e.g. --device-name=epson). -d, --device-name=DEVICE use a given scanner device (e.g. hp:/dev/scanner) --format=pnm|tiff file format of output file -i, --icc-profile=PROFILE include this ICC profile into TIFF file", $prog_name; printf " -L, --list-devices show available scanner devices -f, --formatted-device-list=FORMAT similar to -L, but the FORMAT of the output can be specified: %%d (device name), %%v (vendor), %%m (model), %%t (type), and %%i (index number) -b, --batch[=FORMAT] working in batch mode, FORMAT is `out%%d.pnm' or `out%%d.tif' by default depending on --format"; printf " --batch-start=# page number to start naming files with --batch-count=# how many pages to scan in batch mode --batch-increment=# increase number in filename by an amount of # --batch-double increment page number by two for 2sided originals being scanned in a single sided scanner --batch-prompt ask for pressing a key before scanning a page --accept-md5-only only accept authorization requests using md5"; printf " -p, --progress print progress messages -n, --dont-scan only set options, don't actually scan -T, --test test backend thoroughly -h, --help display this help message and exit -v, --verbose give even more status messages -B, --buffer-size change default input buffersize -V, --version print version information\n"; } if (! $devname) { # If no device name was specified explicitly, we look at the # environment variable SANE_DEFAULT_DEVICE. If this variable # is not set, we open the first device we find (if any): if (defined($ENV{'SANE_DEFAULT_DEVICE'})) { $devname = $ENV{'SANE_DEFAULT_DEVICE'}; } else { my @device_list = Sane->get_devices; if ($Sane::STATUS != SANE_STATUS_GOOD) { print STDERR "$prog_name: sane_get_devices() failed: $Sane::STATUS\n"; exit (1); } if ($#device_list == -1) { print STDERR "$prog_name: no SANE devices found\n"; exit (1); } $devname = $device_list[0]{name}; } } $device = Sane::Device->open($devname); if ($Sane::STATUS != SANE_STATUS_GOOD) { print STDERR "$prog_name: open of device $devname failed: $Sane::STATUS\n"; print STDERR "\nYou seem to have specified a UNIX device name, " ."or filename instead of selecting\nthe SANE scanner or " ."image acquisition device you want to use. As an example,\n" ."you might want \"epson:/dev/sg0\" or " ."\"hp:/dev/usbscanner0\". If any supported\ndevices are " ."installed in your system, you should be able to see a " ."list with\n\"$prog_name --list-devices\".\n" if ($devname =~ /^\//); if ($help) { undef $device; } else { exit (1); } } if (defined($device)) { fetch_options($device); # re-enable error printing and arg permutation Getopt::Long::Configure('no_pass_through'); # There seems to be a bug in Getopt::Long 2.37 where l is treated as L whilst # l is not in @args. Therefore the workaround is to rename l to m for the first # scan and back to l for the second. for (@ARGV) { $_ = '-l' if ($_ eq '-m'); $_ = '-t' if ($_ eq '-u'); } my @ARGV_old = @ARGV; exit 1 if (! GetOptions (@args)); # As it isn't possible to get the argument order from Getopt::Long 2.37, do # this myself for (@ARGV_old) { my $ch; if (/--(.*)/) { $ch = $1; my $i = index($ch, '='); $ch = substr($ch, 0, $i) if ($i > -1); } elsif (/-(.)/) { $ch = $1; } else { next; } if (defined $options{$ch}) { if ($ch eq 'x') { $window_val_user[0] = 1; ($window_val[0]) = parse_vector ($window_option[0], $options{x}); } elsif ($ch eq 'y') { $window_val_user[1] = 1; ($window_val[1]) = parse_vector ($window_option[1], $options{y}); } elsif ($ch eq 'l') { # tl-x process_backend_option ($device, $window[2], $options{l}); } elsif ($ch eq 't') { # tl-y process_backend_option ($device, $window[3], $options{t}); } else { process_backend_option ($device, $option_number{$ch}, $options{$ch}); } } } for (my $index = 0; $index < 2; ++$index) { if ($window[$index] and defined($window_val[$index])) { my $val = $window_val[$index] - 1; if ($window[$index + 2]) { my $pos = $device->get_option ($window[$index + 2]); $val = $pos + $window_val[$index] if (defined $pos); } set_option ($device, $window[$index], $val); } } if ($help) { printf "\nOptions specific to device `%s':\n", $devname; for (my $i = 0; $i < $num_dev_options; ++$i) { my $short_name = ''; my $opt = 0; for (my $j = 0; $j < 4; ++$j) { if ($i == $window[$j]) { $short_name = substr("xylt", $j, 1); $opt = $window_option[$j] if ($j < 2); } } $opt = $device->get_option_descriptor ($i) if (!$opt); printf " %s:\n", $opt->{title} if ($opt->{type} == SANE_TYPE_GROUP); next if (! ($opt->{cap} & SANE_CAP_SOFT_SELECT)); print_option ($device, $i, $short_name); } print "\n" if ($num_dev_options); } } if ($help) { printf "Type ``$prog_name --help -d DEVICE'' to get list of all options for DEVICE.\n\nList of available devices:"; my @device_list = Sane->get_devices; if ($Sane::STATUS == SANE_STATUS_GOOD) { my $column = 80; foreach (@device_list) { if ($column + length ($_->{name}) + 1 >= 80) { printf "\n "; $column = 4; } if ($column > 4) { print ' '; $column += 1; } print $_->{name}; $column += length ($_->{name}); } } print "\n"; exit (0); } exit (0) if ($dont_scan); $SIG{HUP} = \&sighandler; $SIG{INT} = \&sighandler; $SIG{PIPE} = \&sighandler; $SIG{TERM} = \&sighandler; $batch_increment = 2 if ($batch_double); $batch = 1 if ($batch_count); if ($test == 0) { my $n = $batch_start_at; $batch = 1 if (defined $format); if ($batch && (! defined($format) || $format eq '')) { # if ($output_format == OUTPUT_TIFF) { # $format = "out%d.tif"; # } # else { $format = "out%d.pnm"; # } } printf STDERR "Scanning %d pages, incrementing by %d, numbering from %d\n", $batch_count, $batch_increment, $batch_start_at if ($batch); {do { # extra braces to get last to work. my ($path, $fh); $path = sprintf $format, $n if ($batch); # format is NULL unless batch mode if ($batch) { if ($batch_prompt) { printf STDERR "Place document no. %d on the scanner.\n", $n; printf STDERR "Press to continue.\n"; printf STDERR "Press Ctrl + D to terminate.\n"; if (! defined()) { printf STDERR "Batch terminated, %d pages scanned\n", ($n - $batch_increment); last; # get out of this loop } } printf STDERR "Scanning page %d\n", $n; } $device->start; if ($Sane::STATUS != SANE_STATUS_GOOD) { print STDERR "$prog_name: sane_start: $Sane::STATUS\n"; last; } if ($batch && ! (open($fh, '>', $path) && STDOUT->fdopen($fh, '>'))) { print STDERR "cannot open $path\n"; $device->cancel; exit SANE_STATUS_ACCESS_DENIED; } scan_it(); if ($batch) { printf STDERR "Scanned page %d.", $n; printf STDERR " (scanner status = %d)\n", $Sane::STATUS; } if ($Sane::STATUS == SANE_STATUS_GOOD) {} elsif ($Sane::STATUS == SANE_STATUS_EOF) { $Sane::_status = SANE_STATUS_GOOD; } else { if ($batch) { close ($fh); unlink ($path); } last; } $n += $batch_increment; } while (($batch && ($batch_count == -1 || --$batch_count)) && SANE_STATUS_GOOD == $Sane::STATUS);} $device->cancel; } else { $Sane::_status = test_it (); } exit $Sane::STATUS; __END__ =head1 NAME scanimage \- scan an image =head1 SYNOPSIS B B<[ -d | --device-name> I B<[ --format> I B<[ -i | --icc-profile> I B<[ -L | --list-devices ]> B<[ -f | --formatted-device-list > I B<[ --batch > I<[= format ]]> B<[ --batch-start> I B<[ --batch-count> I B<[ --batch-increment> I B<[ --batch-double ]> B<[ --accept-md5-only ]> B<[ -p | --progress ]> B<[ -n | --dont-scan ]> B<[ -T | --test ]> B<[ -h | --help ]> B<[ -v | --verbose ]> B<[ -B | --buffersize ]> B<[ -V | --version ]> I<[ device-specific-options ]> =head1 DESCRIPTION B is a command-line interface to control image acquisition devices such as flatbed scanners or cameras. The device is controlled via command-line options. After command-line processing, B normally proceeds to acquire an image. The image data is written to standard output in one of the PNM (portable aNyMaP) formats (PBM for black-and-white images, PGM for grayscale images, and PPM for color images) or in TIFF (black-and-white, grayscale or color). B accesses image acquisition devices through the B (Scanner Access Now Easy) interface and can thus support any device for which there exists a B backend (try B I to get a list of available backends). =head1 EXAMPLES To get a list of devices: scanimage -L To scan with default settings to the file image.pnm: scanimage >image.pnm To scan 100x100 mm to the file image.tiff (-x and -y may not be available with all devices): scanimage -x 100 -y 100 --format=tiff >image.tiff To print all available options: scanimage -h =head1 OPTIONS Parameters are separated by a blank from single-character options (e.g. -d epson) and by a "=" from multi-character options (e.g. --device-name=epson). The B<-d> or B<--device-name> options must be followed by a B device-name like I<` epson:/dev/sg0 '> or I<` hp:/dev/usbscanner0 '.> A (partial) list of available devices can be obtained with the B<--list-devices> option (see below). If no device-name is specified explicitly, B reads a device-name from the environment variable B If this variable is not set, B will attempt to open the first available device. The B<--format > I option selects how image data is written to standard output. I can be B or B If B<--format> is not used, PNM is written. The B<-i> or B<--icc-profile> option is used to include an ICC profile into a TIFF file. The B<-L> or B<--list-devices> option requests a (partial) list of devices that are available. The list is not complete since some devices may be available, but are not listed in any of the configuration files (which are typically stored in directory I This is particularly the case when accessing scanners through the network. If a device is not listed in a configuration file, the only way to access it is by its full device name. You may need to consult your system administrator to find out the names of such devices. The B<-f> or B<--formatted-device-list> option works similar to B<--list-devices ,> but requires a format string. B replaces the placeholders B<%d %v %m %t %i> with the device name, vendor name, model name, scanner type and an index number respectively. The command =over =item B I<\*(lq scanner number %i device %d is a %t, model %m, produced by %v \*(rq> =back will produce something like: =over =item scanner number 0 device sharp:/dev/sg1 is a flatbed scanner, model JX250 SCSI, produced by SHARP =back The B<--batch*> options provide the features for scanning documents using document feeders. B<--batch> I<[ format ]> is used to specify the format of the filename that each page will be written to. Each page is written out to a single file. If I is not specified, the default of out%d.pnm (or out%d.tif for --format tiff) will be used. I is given as a printf style string with one integer parameter. B<--batch-start> I selects the page number to start naming files with. If this option is not given, the counter will start at 0. B<--batch-count> I specifies the number of pages to attempt to scan. If not given, scanimage will continue scanning until the scanner returns a state other than OK. Not all scanners with document feeders signal when the ADF is empty, use this command to work around them. With B<--batch-increment> I you can change the amount that the number in the filename is incremented by. Generally this is used when you are scanning double-sided documents on a single-sided document feeder. A specific command is provided to aid this: B<--batch-double> will automatically set the increment to 2. B<--batch-prompt> will ask for pressing RETURN before scanning a page. This can be used for scanning multiple pages without an automatic document feeder. The B<--accept-md5-only> option only accepts user authorization requests that support MD5 security. The B network daemon B<( saned )> is capable of doing such requests. See B The B<-p> or B<--progress> option requests that B prints a progress counter. It shows how much image data of the current image has already been received by B (in percent). The B<-n> or B<--dont-scan> option requests that B only sets the options provided by the user but doesn't actually perform a scan. This option can be used to e.g. turn off the scanner's lamp (if supported by the backend). The B<-T> or B<--test> option requests that B performs a few simple sanity tests to make sure the backend works as defined by the B API (in particular the B function is exercised by this test). The B<-h> or B<--help> options request help information. The information is printed on standard output and in this case, no attempt will be made to acquire an image. The B<-v> or B<--verbose> options increase the verbosity of the operation of B The option may be specified repeatedly, each time increasing the verbosity level. The B<-B> or B<--buffersize> option changes the input buffersize that B uses from default 32*1024 to 1024*1024 kbytes. The B<-V> or B<--version> option requests that B prints the program and package name, the version number of the B distribution that it came with and the version of the backend that it loads. Usually that's the dll backend. If more information about the version numbers of the backends are necessary, the B variable for the dll backend can be used. Example: SANE_DEBUG_DLL=3 scanimage -L. As you might imagine, much of the power of B comes from the fact that it can control any B backend. Thus, the exact set of command-line options depends on the capabilities of the selected device. To see the options for a device named I invoke B via a command-line of the form: =over =item B I =back The documentation for the device-specific options printed by B<--help> is best explained with a few examples: -l 0..218mm [0] Top-left x position of scan area. =over =item The description above shows that option B<-l> expects an option value in the range from 0 to 218 mm. The value in square brackets indicates that the current option value is 0 mm. Most backends provide similar geometry options for top-left y position (-t), width (-x) and height of scan-area (-y). =back --brightness -100..100% [0] Controls the brightness of the acquired image. =over =item The description above shows that option B<--brightness> expects an option value in the range from -100 to 100 percent. The value in square brackets indicates that the current option value is 0 percent. =back --default-enhancements Set default values for enhancement controls. =over =item The description above shows that option B<--default-enhancements> has no option value. It should be thought of as having an immediate effect at the point of the command-line at which it appears. For example, since this option resets the B<--brightness> option, the option-pair B<--brightness 50 --default-enhancements> would effectively be a no-op. =back --mode Lineart|Gray|Color [Gray] Selects the scan mode (e.g., lineart or color). =over =item The description above shows that option B<--mode> accepts an argument that must be one of the strings B B or B The value in the square bracket indicates that the option is currently set to B For convenience, it is legal to abbreviate the string values as long as they remain unique. Also, the case of the spelling doesn't matter. For example, option setting B<--mode col> is identical to B<"--mode Color" .> =back --custom-gamma[=(yes|no)] [inactive] Determines whether a builtin or a custom gamma-table should be used. =over =item The description above shows that option B<--custom-gamma> expects either no option value, a "yes" string, or a "no" string. Specifying the option with no value is equivalent to specifying "yes". The value in square-brackets indicates that the option is not currently active. That is, attempting to set the option would result in an error message. The set of available options typically depends on the settings of other options. For example, the B<--custom-gamma> table might be active only when a grayscale or color scan-mode has been requested. =back Note that the B<--help> option is processed only after all other options have been processed. This makes it possible to see the option settings for a particular mode by specifying the appropriate mode-options along with the B<--help> option. For example, the command-line: B< scanimage --help --mode> I would print the option settings that are in effect when the color-mode is selected. =back --gamma-table 0..255,... Gamma-correction table. In color mode this option equally affects the red, green, and blue channels simultaneously (i.e., it is an intensity gamma table). =over =item The description above shows that option B<--gamma-table> expects zero or more values in the range 0 to 255. For example, a legal value for this option would be "3,4,5,6,7,8,9,10,11,12". Since it's cumbersome to specify long vectors in this form, the same can be expressed by the abbreviated form "[0]3-[9]12". What this means is that the first vector element is set to 3, the 9-th element is set to 12 and the values in between are interpolated linearly. Of course, it is possible to specify multiple such linear segments. For example, "[0]3-[2]3-[6]7,[7]10-[9]6" is equivalent to "3,3,3,4,5,6,7,10,8,6". The program B can be used to generate such gamma tables (see B for details). =back --filename [/tmp/input.ppm] The filename of the image to be loaded. =over =item The description above is an example of an option that takes an arbitrary string value (which happens to be a filename). Again, the value in brackets show that the option is current set to the filename B =back =head1 ENVIRONMENT =over =item B The default device-name. =back =head1 FILES =over =item I This directory holds various configuration files. For details, please refer to the manual pages listed below. =item I<~/.sane/pass> This file contains lines of the form =item user:password:resource scanimage uses this information to answer user authorization requests automatically. The file must have 0600 permissions or stricter. You should use this file in conjunction with the --accept-md5-only option to avoid server-side attacks. The resource may contain any character but is limited to 127 characters. =back =head1 "SEE ALSO" B B B B B B B B B =head1 AUTHOR Transliterated from the C original by Jeffrey Ratcliffe. =head1 BUGS All the bugs of scanimage and much, much more. Sane-0.05/examples/scanadf.pl0000755000774200006240000010642711242253717014701 0ustar ra28145a400mc#!/usr/bin/perl use warnings; use strict; use Sane; use Data::Dumper; use Getopt::Long qw(:config no_ignore_case pass_through); use File::Basename; use IO::Handle; #$Sane::DEBUG = 1; my (%options, @window_val_user, @window_option, @window_val, @window, $device, $format, $devname, %option_number); my $num_dev_options = 0; my $verbose = 0; my $help = 0; my $test = 0; my $batch_start_at = 1; my $batch_count = -1; my $batch_increment = 1; my $buffer_size = (32 * 1024); # default size my $tl_x = 0; my $tl_y = 0; my $br_x = 0; my $br_y = 0; my $w_x = 0; my $h_y = 0; my $resolution_optind = -1; my $resolution_value = 0; my $prog_name = basename($0); my $SANE_FRAME_TEXT = 10; my $SANE_FRAME_JPEG = 11; my $SANE_FRAME_G31D = 12; my $SANE_FRAME_G32D = 13; my $SANE_FRAME_G42D = 14; my $no_overwrite = 0; my $outputFile = "image-%04d"; # file name(format) to write output to my $raw = SANE_FALSE; my $scanScript; # script to run at end of scan my $startNum = 1, my $endNum = -1; # start/end numbers of pages to scan my @args = (\%options, 'd|device-name=s' => \$devname, 'L|list-devices', 'h|help' => \$help, 'v|verbose+' => \$verbose, 'N|no-overwrite' => \$no_overwrite, 'o|output-file:s' => \$outputFile, 's|start-count=i' => \$startNum, 'e|end-count=i' => \$endNum, 'r|raw' => \$raw); sub sane_strframe { my $frame = shift; my %frame = ( SANE_FRAME_GRAY => "gray", SANE_FRAME_RGB => "RGB", SANE_FRAME_RED => "red", SANE_FRAME_GREEN => "green", SANE_FRAME_BLUE => "blue", $SANE_FRAME_TEXT => "text", $SANE_FRAME_JPEG => "jpeg", $SANE_FRAME_G31D => "g31d", $SANE_FRAME_G32D => "g32d", $SANE_FRAME_G42D => "g42d", ); if (defined $frame{$frame}) { return $frame{$frame}; } else { return "unknown"; } } sub sane_isbasicframe { my $frame = shift; return $frame == SANE_FRAME_GRAY || $frame == SANE_FRAME_RGB || $frame == SANE_FRAME_RED || $frame == SANE_FRAME_GREEN || $frame == SANE_FRAME_BLUE } sub sighandler { my $signum = shift; if ($device) { print STDERR "$prog_name: stopping scanner...\n"; $device->cancel; } } sub print_unit { my ($unit) = @_; if ($unit == SANE_UNIT_PIXEL) { print "pel"; } elsif ($unit == SANE_UNIT_BIT) { print "bit"; } elsif ($unit == SANE_UNIT_MM) { print "mm"; } elsif ($unit == SANE_UNIT_DPI) { print "dpi"; } elsif ($unit == SANE_UNIT_PERCENT) { print "%"; } elsif ($unit == SANE_UNIT_MICROSECOND) { print "us"; } } sub print_option { my ($device, $opt_num, $short_name) = @_; my $not_first = SANE_FALSE; my $maxwindow = 0; my $opt = $device->get_option_descriptor ($opt_num); if ($short_name) { printf " -%s", $short_name; } else { printf " --%s", $opt->{name}; } if ($opt->{type} == SANE_TYPE_BOOL) { print "[=("; print "auto|" if ($opt->{cap} & SANE_CAP_AUTOMATIC); print "yes|no)]"; } elsif ($opt->{type} != SANE_TYPE_BUTTON) { print ' '; if ($opt->{cap} & SANE_CAP_AUTOMATIC) { print "auto|"; $not_first = SANE_TRUE; } if ($opt->{constraint_type} == SANE_CONSTRAINT_NONE) { if ($opt->{type} == SANE_TYPE_INT) { print ""; } elsif ($opt->{type} == SANE_TYPE_FIXED) { print ""; } elsif ($opt->{type} == SANE_TYPE_STRING) { print ""; } print ",..." if ($opt->{max_values} > 1); } elsif ($opt->{constraint_type} == SANE_CONSTRAINT_RANGE) { my $format = "%g..%g"; $format = "%d..%d" if ($opt->{type} == SANE_TYPE_INT); if ($opt->{name} eq SANE_NAME_SCAN_BR_X) { $maxwindow = $opt->{constraint}{max} - $tl_x; printf $format, $opt->{constraint}{min}, $maxwindow; } elsif ($opt->{name} eq SANE_NAME_SCAN_BR_Y) { $maxwindow = $opt->{constraint}{max} - $tl_y; printf $format, $opt->{constraint}{min}, $maxwindow; } else { printf $format, $opt->{constraint}{min}, $opt->{constraint}{max}; } print_unit ($opt->{unit}); print ",..." if ($opt->{max_values} > 1); print " (in steps of $opt->{constraint}{quant})" if ($opt->{constraint}{quant}); } elsif ($opt->{constraint_type} == SANE_CONSTRAINT_STRING_LIST or $opt->{constraint_type} == SANE_CONSTRAINT_WORD_LIST) { for (my $i = 0; $i < @{$opt->{constraint}}; ++$i) { print '|' if ($i > 0); print $opt->{constraint}[$i]; } if ($opt->{constraint_type} == SANE_CONSTRAINT_WORD_LIST) { print_unit ($opt->{unit}); print ",..." if ($opt->{max_values} > 1); } } } if ($opt->{max_values} == 1) { # print current option value if (! ($opt->{cap} & SANE_CAP_INACTIVE)) { my $val = $device->get_option ($opt_num); print " ["; if ($opt->{type} == SANE_TYPE_BOOL) { print ($val ? "yes" : "no"); } elsif ($opt->{type} == SANE_TYPE_INT or $opt->{type} == SANE_TYPE_FIXED) { my $format = "%g"; $format = "%d" if ($opt->{type} == SANE_TYPE_INT); if ($opt->{name} eq SANE_NAME_SCAN_TL_X) { $tl_x = $val; printf $format, $tl_x; } elsif ($opt->{name} eq SANE_NAME_SCAN_TL_Y) { $tl_y = $val; printf $format, $tl_y; } elsif ($opt->{name} eq SANE_NAME_SCAN_BR_X) { $br_x = $val; $w_x = $br_x - $tl_x; printf $format, $w_x; } elsif ($opt->{name} eq SANE_NAME_SCAN_BR_Y) { $br_y = $val; $h_y = $br_y - $tl_y; printf $format, $h_y; } else { printf $format, $val; } } elsif ($opt->{type} == SANE_TYPE_STRING) { print $val; } print ']'; } } print " [inactive]" if ($opt->{cap} & SANE_CAP_INACTIVE); print "\n "; if ($short_name eq 'x') { print "Width of scan-area."; } elsif ($short_name eq 'y') { print "Height of scan-area."; } else { my $column = 8; my $last_break = 0; my $start = 0; for (my $pos = 0; $pos < length($opt->{desc}); ++$pos) { ++$column; $last_break = $pos if (substr($opt->{desc}, $pos, 1) eq ' '); if ($column >= 79 and $last_break) { print substr($opt->{desc}, $start++, 1) while ($start < $last_break); $start = $last_break + 1; # skip blank print "\n "; $column = 8 + $pos - $start; } } print substr($opt->{desc}, $start++, 1) while ($start < length($opt->{desc})); } print "\n"; } # A scalar has the following syntax: # # V [ U ] # # V is the value of the scalar. It is either an integer or a # floating point number, depending on the option type. # # U is an optional unit. If not specified, the default unit is used. # The following table lists which units are supported depending on # what the option's default unit is: # # Option's unit: Allowed units: # # SANE_UNIT_NONE: # SANE_UNIT_PIXEL: pel # SANE_UNIT_BIT: b (bit), B (byte) # SANE_UNIT_MM: mm (millimeter), cm (centimeter), in or " (inches), # SANE_UNIT_DPI: dpi # SANE_UNIT_PERCENT: % # SANE_UNIT_MICROSECOND: us sub parse_scalar { my ($opt, $str) = @_; my ($v, $unit); if ($str =~ /^(\d*\.?\d*)(cm|mm|in|\"|b|B|dpi|%|us)?/) { $v = $1; $unit = $2; $unit = '' if not defined $unit; } else { print STDERR "$prog_name: option --$opt->{name}: bad option value (rest of option: $str)\n"; exit (1); } if ($opt->{unit} == SANE_UNIT_BIT) { $v *= 8 if ($unit eq 'B'); } elsif ($opt->{unit} == SANE_UNIT_MM) { if ($unit eq 'cm') { $v *= 10; } elsif ($unit eq 'in') { $v *= 25.4; } } return $v, substr($str, length($v) + length($unit), length($str)); } # A vector has the following syntax: # # [ '[' I ']' ] S { [','|'-'] [ '[' I ']' S } # # The number in brackets (I), if present, determines the index of the # vector element to be set next. If I is not present, the value of # last index used plus 1 is used. The first index value used is 0 # unless I is present. # # S is a scalar value as defined by parse_scalar(). # # If two consecutive value specs are separated by a comma (,) their # values are set independently. If they are separated by a dash (-), # they define the endpoints of a line and all vector values between # the two endpoints are set according to the value of the # interpolated line. For example, [0]15-[255]15 defines a vector of # 256 elements whose value is 15. Similarly, [0]0-[255]255 defines a # vector of 256 elements whose value starts at 0 and increases to # 255. sub parse_vector { my ($opt, $str) = @_; my $index = -1; my $prev_value = 0; my $prev_index = 0; my $separator = ''; my (@vector, $value); do { if ($str =~ /^\[/) { if ($str =~ /^\[(\d*\.?\d*)\]/) { $index = $1; } else { print STDERR "$prog_name: option --$opt->{name}: closing bracket missing " ."(rest of option: $str)\n"; exit (1); } } else { ++$index; } if ($index < 0 or $index >= length($str)) { printf STDERR "$prog_name: option --$opt->{name}: index $index out of range [0..%d]\n", length($str); exit (1); } # read value ($value, $str) = parse_scalar ($opt, $str); if ($str ne '' and $str !~ /^[-,]/) { print STDERR "$prog_name: option --$opt->{name}: illegal separator (rest of option: $str)\n"; exit (1); } # store value: $vector[$index] = $value; if ($separator eq '-') { # interpolate my $v = $prev_value; my $slope = ($value - $v) / ($index - $prev_index); for (my $i = $prev_index + 1; $i < $index; ++$i) { $v += $slope; $vector[$i] = $v; } } $prev_index = $index; $prev_value = $value; $separator = substr($str, 0, 1); } while ($separator eq ',' || $separator eq '-'); if ($verbose > 2) { print STDERR "$prog_name: value for --$opt->{name} is: "; for (@vector) { print STDERR "$_ "; } print STDERR "\n"; } return @vector; } sub fetch_options { my $device = shift; # We got a device, find out how many options it has: $num_dev_options = $device->get_option(0); if ($Sane::STATUS != SANE_STATUS_GOOD) { print STDERR "$prog_name: unable to determine option count\n"; exit (1); } for (my $i = 0; $i < $num_dev_options; ++$i) { my $opt = $device->get_option_descriptor ($i); next if (! ($opt->{cap} & SANE_CAP_SOFT_SELECT)); $option_number{$opt->{name}} = $i; # Look for scan resolution $resolution_optind = $i if (($opt->{type} == SANE_TYPE_FIXED || $opt->{type} == SANE_TYPE_INT) and ($opt->{unit} == SANE_UNIT_DPI) and ($opt->{name} eq SANE_NAME_SCAN_RESOLUTION)); # Keep track of top-left corner options (if they exist at # all) and replace the bottom-right corner options by a # width/height option (if they exist at all). if (($opt->{type} == SANE_TYPE_FIXED || $opt->{type} == SANE_TYPE_INT) and ($opt->{unit} == SANE_UNIT_MM || $opt->{unit} == SANE_UNIT_PIXEL)) { if ($opt->{name} eq SANE_NAME_SCAN_TL_X) { $window[2] = $i; $opt->{name} = 'l'; } elsif ($opt->{name} eq SANE_NAME_SCAN_TL_Y) { $window[3] = $i; $opt->{name} = 't'; } elsif ($opt->{name} eq SANE_NAME_SCAN_BR_X) { $window[0] = $i; $opt->{name} = 'x'; $window_option[0] = $opt; $window_option[0]->{title} = 'Scan width'; $window_option[0]->{desc} = 'Width of scanning area.'; $window_val[0] = $device->get_option ($i) if (!$window_val_user[0]); } elsif ($opt->{name} eq SANE_NAME_SCAN_BR_Y) { $window[1] = $i; $opt->{name} = 'y'; $window_option[1] = $opt; $window_option[1]->{title} = 'Scan height'; $window_option[1]->{desc} = 'Height of scanning area.'; $window_val[1] = $device->get_option ($i) if (!$window_val_user[1]); } } if ($opt->{type} == SANE_TYPE_BOOL) { push @args, "$opt->{name}:s"; } elsif ($opt->{type} == SANE_TYPE_BUTTON) { push @args, $opt->{name}; } else { push @args, "$opt->{name}=s"; } } # Initialize width & height options based on backend default # values for top-left x/y and bottom-right x/y: for (my $i = 0; $i < 2; ++$i) { if ($window[$i] and $window[$i + 2] and !$window_val_user[$i]) { my $pos = $device->get_option ($window[$i + 2]); $window_val[$i] = $window_val[$i] - $pos if (defined $pos); } } } sub set_option { my ($device, $optnum, $value) = @_; my $opt = $device->get_option_descriptor ($optnum); if ($opt and ($opt->{cap} & SANE_CAP_INACTIVE)) { print STDERR "$prog_name: ignored request to set inactive option $opt->{name}\n" if ($verbose > 0); return; } my $info = $device->set_option($optnum, $value); if ($Sane::STATUS != SANE_STATUS_GOOD) { print STDERR "$prog_name: setting of option --$opt->{name} failed ($Sane::STATUS)\n"; exit (1); } if (($info & SANE_INFO_INEXACT) and $opt->{max_values} == 1) { my $orig = $value; $value = $device->get_option($optnum); if ($opt->{type} == SANE_TYPE_INT) { printf STDERR "$prog_name: rounded value of $opt->{name} from %d to %d\n", $orig, $value; } elsif ($opt->{type} == SANE_TYPE_FIXED) { printf STDERR "$prog_name: rounded value of $opt->{name} from %g to %g\n", $orig, $value; } } fetch_options ($device) if ($info & SANE_INFO_RELOAD_OPTIONS); } sub process_backend_option { my ($device, $optnum, $optarg) = @_; my $opt = $device->get_option_descriptor ($optnum); if ($opt and ($opt->{cap} & SANE_CAP_INACTIVE)) { print STDERR "$prog_name: attempted to set inactive option $opt->{name}\n"; exit (1); } if (($opt->{cap} & SANE_CAP_AUTOMATIC) and $optarg and $optarg =~ /^auto$/i) { $device->set_auto($optnum); if ($Sane::STATUS != SANE_STATUS_GOOD) { printf STDERR "$prog_name: failed to set option --$opt->{name} to automatic ($Sane::STATUS)\n"; exit (1); } return; } my $value; if ($opt->{type} == SANE_TYPE_BOOL) { $value = 1; # no argument means option is set if ($optarg) { if ($optarg =~ /^yes$/i) { $value = 1; } elsif ($optarg =~ /^no$/i) { $value = 0; } else { printf STDERR "$prog_name: option --$opt->{name}: bad option value `$optarg'\n"; exit (1); } } } elsif ($opt->{type} == SANE_TYPE_INT or $opt->{type} == SANE_TYPE_FIXED) { my @vector = parse_vector ($opt, $optarg); $value = \@vector; } elsif ($opt->{type} == SANE_TYPE_STRING) { $value = $optarg; } elsif ($opt->{type} == SANE_TYPE_BUTTON) { $value = 0; # value doesn't matter } else { printf STDERR "$prog_name: duh, got unknown option type $opt->{type}\n"; return; } set_option ($device, $optnum, $value); } sub write_pnm_header_to_file { my ($fh, $format, $width, $height, $depth) = @_; # The netpbm-package does not define raw image data with maxval > 255. # But writing maxval 65535 for 16bit data gives at least a chance # to read the image. if ($format == SANE_FRAME_RED or $format == SANE_FRAME_GREEN or $format == SANE_FRAME_BLUE or $format == SANE_FRAME_RGB) { printf $fh "P6\n# SANE data follows\n%d %d\n%d\n", $width, $height, ($depth <= 8) ? 255 : 65535; } elsif ($format == SANE_FRAME_GRAY) { if ($depth == 1) { printf $fh "P4\n# SANE data follows\n%d %d\n", $width, $height; } else { printf $fh "P5\n# SANE data follows\n%d %d\n%d\n", $width, $height, ($depth <= 8) ? 255 : 65535; } } } sub scan_it_raw { my ($fname, $raw, $script) = @_; my $first_frame = 1, my $offset = 0, my $must_buffer = 0; my $min = 0xff, my $max = 0; my (%image, $fp); my $parm; {do { # extra braces to get last to work. $device->start; if ($Sane::STATUS != SANE_STATUS_GOOD) { print STDERR "$prog_name: sane_start: $Sane::STATUS\n" if ($Sane::STATUS != SANE_STATUS_NO_DOCS); goto cleanup; } $parm = $device->get_parameters; if ($Sane::STATUS != SANE_STATUS_GOOD) { print STDERR "$prog_name: sane_get_parameters: $Sane::STATUS\n"; goto cleanup; } open $fp, '>', $fname; if (!$fp) { print STDERR "Error opening output `$fname': $@\n"; $Sane::_status = SANE_STATUS_IO_ERROR; goto cleanup; } if ($verbose) { if ($first_frame) { if (sane_isbasicframe($parm->{format})) { if ($parm->{lines} >= 0) { printf STDERR "$prog_name: scanning image of size %dx%d pixels at " ."%d bits/pixel\n", $parm->{pixels_per_line}, $parm->{lines}, 8 * $parm->{bytes_per_line} / $parm->{pixels_per_line}; } else { printf STDERR "$prog_name: scanning image %d pixels wide and " ."variable height at %d bits/pixel\n", $parm->{pixels_per_line}, 8 * $parm->{bytes_per_line} / $parm->{pixels_per_line}; } } else { printf STDERR "$prog_name: receiving %s frame " ."bytes/line=%d, " ."pixels/line=%d, " ."lines=%d, " ."depth=%d\n", , sane_strframe($parm->{format}), $parm->{bytes_per_line}, $parm->{pixels_per_line}, $parm->{lines}, $parm->{depth}; } } printf STDERR "$prog_name: acquiring %s frame\n", sane_strframe($parm->{format}); } if ($first_frame) { if ($parm->{format} == SANE_FRAME_RED or $parm->{format} == SANE_FRAME_GREEN or $parm->{format} == SANE_FRAME_BLUE) { die unless ($parm->{depth} == 8); $must_buffer = 1; $offset = $parm->{format} - SANE_FRAME_RED; } elsif ($parm->{format} == SANE_FRAME_RGB) { die unless ($parm->{depth} == 8); } if ($parm->{format} == SANE_FRAME_RGB or $parm->{format} == SANE_FRAME_GRAY) { die unless (($parm->{depth} == 1) || ($parm->{depth} == 8)); # if we're writing raw, we skip the header and never # have to buffer a single frame format. if ($raw == SANE_FALSE) { if ($parm->{lines} < 0) { $must_buffer = 1; $offset = 0; } else { write_pnm_header_to_file ($fp, $parm->{format}, $parm->{pixels_per_line}, $parm->{lines}, $parm->{depth}); } } } elsif ($parm->{format} == $SANE_FRAME_TEXT or $parm->{format} == $SANE_FRAME_JPEG or $parm->{format} == $SANE_FRAME_G31D or $parm->{format} == $SANE_FRAME_G32D or $parm->{format} == $SANE_FRAME_G42D) { if (!$parm->{last_frame}) { $Sane::_status = SANE_STATUS_INVAL; printf STDERR "$prog_name: bad %s frame: must be last_frame\n", sane_strframe ($parm->{format}); goto cleanup; } } # write them out without a header; don't buffer else { # Default action for unknown frametypes; write them out # without a header; issue a warning in verbose mode. # Since we're not writing a header, there's no need to # buffer. printf STDERR "$prog_name: unknown frame format $parm->{format}\n" if ($verbose); if (!$parm->{last_frame}) { $Sane::_status = SANE_STATUS_INVAL; printf STDERR "$prog_name: bad %s frame: must be last_frame\n", sane_strframe ($parm->{format}); goto cleanup; } } } else { die unless ($parm->{format} >= SANE_FRAME_RED && $parm->{format} <= SANE_FRAME_BLUE); $offset = $parm->{format} - SANE_FRAME_RED; $image{x} = $image{y} = 0; } while (1) { my ($buffer, $len) = $device->read ($buffer_size); if ($Sane::STATUS != SANE_STATUS_GOOD) { printf STDERR "$prog_name: min/max graylevel value = %d/%d\n", $min, $max if ($verbose && $parm->{depth} == 8); if ($Sane::STATUS != SANE_STATUS_EOF) { print STDERR "$prog_name: sane_read: $Sane::STATUS\n"; return; } last; } if ($must_buffer) { # We're either scanning a multi-frame image or the # scanner doesn't know what the eventual image height # will be (common for hand-held scanners). In either # case, we need to buffer all data before we can write # the image if ($parm->{format} == SANE_FRAME_RED or $parm->{format} == SANE_FRAME_GREEN or $parm->{format} == SANE_FRAME_BLUE) { for (my $i = 0; $i < $len; ++$i) { $image{data}[$offset + 3 * $i] = substr($buffer, $i, 1); } $offset += 3 * $len; } elsif ($parm->{format} == SANE_FRAME_RGB or $parm->{format} == SANE_FRAME_GRAY) { for (my $i = 0; $i < $len; ++$i) { $image{data}[$offset + $i] = substr($buffer, $i, 1); } $offset += $len; } else { # optional frametypes are never buffered printf STDERR "$prog_name: ERROR: trying to buffer %s frametype\n", sane_strframe($parm->{format}); } } else { print $fp $buffer; } if ($verbose && $parm->{depth} == 8) { for (split(//, $buffer)) { my $c = ord; if ($c >= $max) { $max = $c; } elsif ($c < $min) { $min = $c; } } } } $first_frame = 0; } while (!$parm->{last_frame});} if ($must_buffer) { if ($parm->{lines} > 0) { $image{height} = $parm->{lines}; } else { $image{height} = @{$image{data}}/$parm->{pixels_per_line}; $image{height} /= 3 if ($parm->{format} == SANE_FRAME_RED or $parm->{format} == SANE_FRAME_GREEN or $parm->{format} == SANE_FRAME_BLUE); } if ($raw == SANE_FALSE) { # if we're writing raw, we skip the header write_pnm_header_to_file ($fp, $parm->{format}, $parm->{pixels_per_line}, $image{height}, $parm->{depth}); } for (@{$image{data}}) {print $fp $_;} } if ($fp) { close $fp; undef $fp; } cleanup: close $fp if ($fp); return; } sub scan_docs { my ($start, $end, $no_overwrite, $raw, $outfmt, $script) = @_; $Sane::_status = SANE_STATUS_GOOD; my $scannedPages = 0; while ($end < 0 || $start <= $end) { #!!! buffer overflow; need protection my $fname = sprintf($outfmt, $start); # does the filename already exist? if ($no_overwrite and -r $fname) { $Sane::_status = SANE_STATUS_INVAL; print STDERR "Filename $fname already exists; will not overwrite\n"; } # Scan the document scan_it_raw($fname, $raw, $script) if ($Sane::STATUS == SANE_STATUS_GOOD); # Any scan errors? if ($Sane::STATUS == SANE_STATUS_NO_DOCS) { # out of paper in the hopper; this is our normal exit $Sane::_status = SANE_STATUS_GOOD; last; } elsif ($Sane::STATUS == SANE_STATUS_EOF) { # done with this doc $Sane::_status = SANE_STATUS_GOOD; print STDERR "Scanned document $fname\n"; $scannedPages++; $start++; } else { # unexpected error print STDERR "$Sane::STATUS\n"; last; } } print STDERR "Scanned $scannedPages pages\n"; return; } # There seems to be a bug in Getopt::Long 2.37 where l is treated as L whilst # l is not in @args. Therefore the workaround is to rename l to m for the first # scan and back to l for the second. for (@ARGV) { $_ = '-m' if ($_ eq '-l'); $_ = '-u' if ($_ eq '-t'); } # make a first pass through the options with error printing and argument # permutation disabled: GetOptions (@args); if (defined $options{L}) { my @device_list = Sane->get_devices; if ($Sane::STATUS != SANE_STATUS_GOOD) { print STDERR "$prog_name: sane_get_devices() failed: $Sane::STATUS\n"; exit (1); } foreach (@device_list) { printf "device `%s' is a %s %s %s\n", $_->{name}, $_->{vendor}, $_->{model}, $_->{type}; } printf "\nNo scanners were identified. If you were expecting " ."something different,\ncheck that the scanner is plugged " ."in, turned on and detected by the\nsane-find-scanner tool " ."(if appropriate). Please read the documentation\nwhich came " ."with this software (README, FAQ, manpages).\n" if ($#device_list == -1); printf "default device is `%s'\n", $ENV{'SANE_DEFAULT_DEVICE'} if (defined($ENV{'SANE_DEFAULT_DEVICE'})); exit (0); } if (defined($options{V})) { printf "$prog_name (sane-backends) %s\n", Sane->get_version; exit (0); } if ($help) { print "Usage: $prog_name [OPTION]...\n Start image acquisition on a scanner device and write image data to output files.\n [ -d | --device-name ] use a given scanner device. [ -h | --help ] display this help message and exit. [ -L | --list-devices ] show available scanner devices. [ -v | --verbose ] give even more status messages. [ -V | --version ] print version information. [ -N | --no-overwrite ] don't overwrite existing files.\n [ -o | --output-file ] name of file to write image data (\%d replacement in output file name). [ -S | --scan-script ] name of script to run after every scan. [ --script-wait ] wait for scripts to finish before exit [ -s | --start-count ] page count of first scanned image. [ -e | --end-count ] last page number to scan. [ -r | --raw ] write raw image data to file.\n"; } if (! $devname) { # If no device name was specified explicitly, # we open the first device we find (if any): my @device_list = Sane->get_devices; if ($Sane::STATUS != SANE_STATUS_GOOD) { print STDERR "$prog_name: sane_get_devices() failed: $Sane::STATUS\n"; exit (1); } if ($#device_list == -1) { print STDERR "$prog_name: no SANE devices found\n"; exit (1); } $devname = $device_list[0]{name}; } $device = Sane::Device->open($devname); if ($Sane::STATUS != SANE_STATUS_GOOD) { print STDERR "$prog_name: open of device $devname failed: $Sane::STATUS\n"; if ($help) { undef $device; } else { exit (1); } } if (defined($device)) { fetch_options($device); # re-enable error printing and arg permutation Getopt::Long::Configure('no_pass_through'); # There seems to be a bug in Getopt::Long 2.37 where l is treated as L whilst # l is not in @args. Therefore the workaround is to rename l to m for the first # scan and back to l for the second. for (@ARGV) { $_ = '-l' if ($_ eq '-m'); $_ = '-t' if ($_ eq '-u'); } my @ARGV_old = @ARGV; exit 1 if (! GetOptions (@args)); # As it isn't possible to get the argument order from Getopt::Long 2.37, do # this myself for (@ARGV_old) { my $ch; if (/--(.*)/) { $ch = $1; my $i = index($ch, '='); $ch = substr($ch, 0, $i) if ($i > -1); } elsif (/-(.)/) { $ch = $1; } else { next; } if (defined $options{$ch}) { if ($ch eq 'x') { $window_val_user[0] = 1; ($window_val[0]) = parse_vector ($window_option[0], $options{x}); } elsif ($ch eq 'y') { $window_val_user[1] = 1; ($window_val[1]) = parse_vector ($window_option[1], $options{y}); } elsif ($ch eq 'l') { # tl-x process_backend_option ($device, $window[2], $options{l}); } elsif ($ch eq 't') { # tl-y process_backend_option ($device, $window[3], $options{t}); } else { process_backend_option ($device, $option_number{$ch}, $options{$ch}); } } } for (my $index = 0; $index < 2; ++$index) { if ($window[$index] and defined($window_val[$index])) { my $val = $window_val[$index] - 1; if ($window[$index + 2]) { my $pos = $device->get_option ($window[$index + 2]); $val = $pos + $window_val[$index] if (defined $pos); } set_option ($device, $window[$index], $val); } } if ($help) { printf "\nOptions specific to device `%s':\n", $devname; for (my $i = 0; $i < $num_dev_options; ++$i) { my $short_name = ''; my $opt = 0; for (my $j = 0; $j < 4; ++$j) { if ($i == $window[$j]) { $short_name = substr("xylt", $j, 1); $opt = $window_option[$j] if ($j < 2); } } $opt = $device->get_option_descriptor ($i) if (!$opt); printf " %s:\n", $opt->{title} if ($opt->{type} == SANE_TYPE_GROUP); next if (! ($opt->{cap} & SANE_CAP_SOFT_SELECT)); print_option ($device, $i, $short_name); } print "\n" if ($num_dev_options); } } if ($help) { printf "Type ``$prog_name --help -d DEVICE'' to get list of all options for DEVICE.\n\nList of available devices:"; my @device_list = Sane->get_devices; if ($Sane::STATUS == SANE_STATUS_GOOD) { my $column = 80; foreach (@device_list) { if ($column + length ($_->{name}) + 1 >= 80) { printf "\n "; $column = 4; } if ($column > 4) { print ' '; $column += 1; } print $_->{name}; $column += length ($_->{name}); } } print "\n"; exit (0); } $SIG{HUP} = \&sighandler; $SIG{INT} = \&sighandler; $SIG{PIPE} = \&sighandler; $SIG{TERM} = \&sighandler; scan_docs ($startNum, $endNum, $no_overwrite, $raw, $outputFile, $scanScript); exit $Sane::STATUS; __END__ =head1 NAME scanadf - acquire multiple images from a scanner equipped with an ADF =head1 SYNOPSIS B B<[ -d | --device-name> I B<[ -h | --help ]> B<[ -L | --list-devices ]> B<[ -v | --verbose ]> B<[ -V | --version ]> B<[ -o | --output-file> I B<[ -N | --no-overwrite ]> B<[ -S | --scan-script> I B<[ --script-wait ] > B<[ -s | --start-count> I B<[ -e | --end-count> I B<[ -r | --raw ]> I<[ device-specific-options ]> =head1 DESCRIPTION B is a command-line interface to control image acquisition devices which are capable of returning a series of images (e.g. a scanner with an automatic document feeder (ADF)). The device is controlled via command-line options. After command-line processing, B normally proceeds to acquire a series of images until the device returns the B status code. The images are written to output files, specified by the B<--output-file> option. These files are typically written in one of the PNM (portable aNyMaP) formats (PBM for black-and-white images, PGM for grayscale images, and PPM for color images). Several optional frame formats (SANE_FRAME_JPEG, SANE_FRAME_G31D, SANE_FRAME_G32D, SANE_FRAME_G42D, and SANE_FRAME_TEXT) are supported. In each case, the data is written out to the output file as-is without a header. Unrecognized frame formats are handled in the same way, although a warning message is printed in verbose mode. Typically, the optional frame formats are used in conjunction with a scan script (specified by the B<--scanscript> option) which is invoked for each acquired image. The script is provided with a series of environment variables which describe the parameters and format of the image file. B accesses image acquisition devices through the SANE (Scanner Access Now Easy) interface and can thus support any device for which there exists a SANE backend (try "apropos sane\-" to get a list of available backends). =head1 OPTIONS The B<-d> or B<--device-name> options must be followed by a SANE device-name. A (partial) list of available devices can be obtained with the B<--list-devices> option (see below). If no device-name is specified explicitly, B will attempt to open the first available device. The B<-h> or B<--help> options request help information. The information is printed on standard output and in this case, no attempt will be made to acquire an image. The B<-L> or B<--list-devices> option requests a (partial) list of devices that are available. The list is not complete since some devices may be available, but are not listed in any of the configuration files (which are typically stored in directory /usr/etc/sane.d). This is particularly the case when accessing scanners through the network. If a device is not listed in a configuration file, the only way to access it is by its full device name. You may need to consult your system administrator to find out the names of such devices. The B<-v> or B<--verbose> options increase the verbosity of the operation of B The option may be specified repeatedly, each time increasing the verbosity level. The B<-V> or B<--version> option requests that B print the program and package name, as well as the version number of the SANE distribution that it came with. The B<-o> or B<--output-file> option specifies a format string used to generate the name of file to write the image data to. You can use %d replacement in the output file name; this will be replaced with the current page number. The default format string is image-%04d. The B<-N> or B<--no-overwrite> option prevents B from overwriting existing image files. The B<-S> or B<--scan-script> option specifies the name of script to run after each scanned image is acquired. The script receives the name of the image output file as its first and only command line argument. Additionally the scan script can reference the following environment variables to get information about the parameters of the image. =over =item B - the image resolution (in DPI) =item B - the image width (in pixels) =item B - the image height (in pixels) =item B - the image bit-depth (in bits) =item B - a string representing the image format (e.g. gray, g42d, text, etc) =item B - the numeric image format identifier =back If the B<--scipt-wait> option is given, scanadf will wait until all scan-scripts have been finished before exiting. That will be useful if scanadf is used in conjunction with tools to modify the scanned images. The B<-s> or B<--start-count> option specifies the page number of first scanned image. The B<-e> or B<--end-count> option specifies the last page number to scan. Using this option, you can request a specific number of pages to be scanned, rather than scanning until there are no more images available. The B<-r> or B<--raw> option specifies that the raw image data be written to the output file as-is without interpretation. This disables the writing of the PNM header for basic frame types. This feature is usually used in conjunction with the B<--scan-script> option where the scan script uses the environment variables to understand the format and parameters of the image and converts the file to a more useful format. NOTE: With support for the optional frame types and the default handling of unrecognized frametypes, this option becomes less and less useful. As you might imagine, much of the power of B comes from the fact that it can control any SANE backend. Thus, the exact set of command-line options depends on the capabilities of the selected device. To see the options for a device named I invoke B via a command-line of the form: =over scanadf --help --device I =back The documentation for the device-specific options printed by B<--help> is explained in the manual page for B =head1 FILES =over =item I This directory holds various configuration files. For details, please refer to the manual pages listed below. =back =head1 "SEE ALSO" scanimage(1), xscanimage(1), sane(7) =head1 AUTHOR Transliterated from the C original by Jeffrey Ratcliffe. =head1 BUGS All the bugs of scanadf and much, much more. This program relies on the backend to return the B status code when the automatic document feeder is out of paper. Use of this program with backends that do not support ADFs (e.g. flatbed scanners) will likely result in repeated scans of the same document. In this case, it is essential to use the start-count and end-count to control the number of images acquired. Only a subset of the SANE backends support feeders and return SANE_STATUS_NO_DOCS appropriately. Backends which are known to work at this time are: =over =item B - Bell+Howell Copiscan II series scanners. =item B - Hewlett Packard scanners. A patch to the sane-hp backend is necessary. The --scantype=ADF option must be specified (earlier versions of the backend used the --scan-from-adf option, instead). =item B - UMAX scanners. Support exists in build 12 and later. The --source="Automatic Document Feeder" option must be specified. =back Sane-0.05/t/0000755000774200006240000000000011736245770011365 5ustar ra28145a400mcSane-0.05/t/err.t0000644000774200006240000000353411242253657012342 0ustar ra28145a400mc# Before `make install' is performed this script should be runnable with # `make test'. After `make install' it should work as `perl err.t' ######################### # change 'tests => 1' to 'tests => last_test_to_print'; use Test::More tests => 38; BEGIN { use_ok('Sane') }; ######################### # Insert your test code below, the Test::More module is use()ed here so read # its man page ( perldoc Test::More ) for help writing this test script. SKIP: { skip "libsane 1.0.19 or better required", 37 unless Sane->get_version_scalar > 1.000018; my $test = Sane::Device->open('test'); cmp_ok($Sane::STATUS, '==', SANE_STATUS_GOOD, 'opening test backend'); my $options = $test->get_option_descriptor(21); is ($options->{name}, 'enable-test-options', 'enable-test-options'); my $info = $test->set_option(21, SANE_TRUE); cmp_ok($Sane::STATUS, '==', SANE_STATUS_GOOD, 'set enable-test-options'); $options = $test->get_option_descriptor(16); is ($options->{name}, 'read-return-value', 'read-return-value'); my %status = ( 'SANE_STATUS_UNSUPPORTED' => SANE_STATUS_UNSUPPORTED, 'SANE_STATUS_CANCELLED' => SANE_STATUS_CANCELLED, 'SANE_STATUS_DEVICE_BUSY' => SANE_STATUS_DEVICE_BUSY, 'SANE_STATUS_INVAL' => SANE_STATUS_INVAL, 'SANE_STATUS_EOF' => SANE_STATUS_EOF, 'SANE_STATUS_JAMMED' => SANE_STATUS_JAMMED, 'SANE_STATUS_NO_DOCS' => SANE_STATUS_NO_DOCS, 'SANE_STATUS_COVER_OPEN' => SANE_STATUS_COVER_OPEN, 'SANE_STATUS_IO_ERROR' => SANE_STATUS_IO_ERROR, 'SANE_STATUS_NO_MEM' => SANE_STATUS_NO_MEM, 'SANE_STATUS_ACCESS_DENIED' => SANE_STATUS_ACCESS_DENIED, ); for (keys %status) { my $info = $test->set_option(16, $_); cmp_ok($Sane::STATUS, '==', SANE_STATUS_GOOD, "set $_"); $test->start; cmp_ok($Sane::STATUS, '==', SANE_STATUS_GOOD, 'start'); my ($data, $len) = $test->read (100); cmp_ok($Sane::STATUS, '==', $status{$_}, $_); $test->cancel; } }; Sane-0.05/t/non-blocking.t0000644000774200006240000000403411242253657014126 0ustar ra28145a400mc# Before `make install' is performed this script should be runnable with # `make test'. After `make install' it should work as `perl non-blocking.t' ######################### # change 'tests => 1' to 'tests => last_test_to_print'; use Test::More tests => 14; BEGIN { use_ok('Sane') }; ######################### # Insert your test code below, the Test::More module is use()ed here so read # its man page ( perldoc Test::More ) for help writing this test script. SKIP: { skip "libsane 1.0.19 or better required", 13 unless Sane->get_version_scalar > 1.000018; my $test = Sane::Device->open('test'); cmp_ok($Sane::STATUS, '==', SANE_STATUS_GOOD, 'opening test backend'); $options = $test->get_option_descriptor(10); is ($options->{name}, 'test-picture', 'test-picture'); my $info = $test->set_option(10, 'Color pattern'); cmp_ok($Sane::STATUS, '==', SANE_STATUS_GOOD, 'Color pattern'); $info = $test->set_option(19, SANE_TRUE); cmp_ok($Sane::STATUS, '==', SANE_STATUS_GOOD, 'non-blocking'); $info = $test->set_option(20, SANE_TRUE); cmp_ok($Sane::STATUS, '==', SANE_STATUS_GOOD, 'fd option'); $test->start; cmp_ok($Sane::STATUS, '==', SANE_STATUS_GOOD, 'start'); $test->set_io_mode (SANE_TRUE); cmp_ok($Sane::STATUS, '==', SANE_STATUS_GOOD, 'non-blocking'); my $fd = $test->get_select_fd; cmp_ok($Sane::STATUS, '==', SANE_STATUS_GOOD, 'fd option'); my $param = $test->get_parameters; cmp_ok($Sane::STATUS, '==', SANE_STATUS_GOOD, 'get_parameters'); if ($param->{lines} >= 0) { my $filename = 'fd.pnm'; open my $fh, '>', $filename; binmode $fh; my ($data, $len); my $rin = ''; my $rout = ''; vec($rin, $fd, 1) = 1; my $i = 1; do { select($rout=$rin,undef,undef,undef); ($data, $len) = $test->read ($param->{bytes_per_line}); print $fh substr($data, 0, $len) if ($data); } while ($Sane::STATUS == SANE_STATUS_GOOD); cmp_ok($Sane::STATUS, '==', SANE_STATUS_EOF, 'EOF'); is ($data, undef, 'EOF data'); is ($len, 0, 'EOF len'); $test->cancel; close $fh; is (-s $filename, $param->{bytes_per_line}*$param->{lines}, 'image size'); } }; Sane-0.05/t/options.t0000644000774200006240000000746011736245673013256 0ustar ra28145a400mc# Before `make install' is performed this script should be runnable with # `make test'. After `make install' it should work as `perl options.t' ######################### # change 'tests => 1' to 'tests => last_test_to_print'; use Test::More; BEGIN { use_ok('Sane') }; ######################### # Insert your test code below, the Test::More module is use()ed here so read # its man page ( perldoc Test::More ) for help writing this test script. plan skip_all => 'libsane 1.0.19 or better required' unless Sane->get_version_scalar > 1.000018; my @array = Sane->get_version; is ($#array, 2, 'get_version'); @array = Sane->get_devices; cmp_ok($Sane::STATUS, '==', SANE_STATUS_GOOD, 'get_devices'); my $test = Sane::Device->open('test'); cmp_ok($Sane::STATUS, '==', SANE_STATUS_GOOD, 'open'); my $n = $test->get_option(0); cmp_ok($Sane::STATUS, '==', SANE_STATUS_GOOD, 'get number of options'); my $options = $test->get_option_descriptor(21); if ($options->{name} eq 'enable-test-options') { $info = $test->set_option(21, SANE_TRUE); cmp_ok($Sane::STATUS, '==', SANE_STATUS_GOOD, 'enable-test-options'); for (my $i = 0; $i < $n; $i++) { my $options = $test->get_option_descriptor($i); isnt ($options, undef, 'get_option_descriptor'); if ($options->{cap} & SANE_CAP_SOFT_SELECT) { my $in; if ($options->{constraint_type} == SANE_CONSTRAINT_RANGE) { if ($options->{max_values} == 1) { $in = $options->{constraint}{min}; } else { for (my $i = 0; $i < $options->{max_values}; $i++) { $in->[$i] = $options->{constraint}{min}; } } } elsif ($options->{constraint_type} == SANE_CONSTRAINT_STRING_LIST or $options->{constraint_type} == SANE_CONSTRAINT_WORD_LIST) { if ($options->{max_values} == 1) { $in = $options->{constraint}[0]; } else { for (my $i = 0; $i < $options->{max_values}; $i++) { $in->[$i] = $options->{constraint}[0]; } } } elsif ($options->{type} == SANE_TYPE_BOOL or $options->{type} == SANE_TYPE_BUTTON) { $in = SANE_TRUE; } elsif ($options->{type} == SANE_TYPE_STRING) { $in = 'this is a string with no constraint'; } elsif ($options->{type} == SANE_TYPE_INT) { if ($options->{max_values} == 1) { $in = 12345678; } else { for (my $i = 0; $i < $options->{max_values}; $i++) { $in->[$i] = 12345678; } } } elsif ($options->{type} == SANE_TYPE_FIXED) { if ($options->{max_values} == 1) { $in = 1234.5678; } else { for (my $i = 0; $i < $options->{max_values}; $i++) { $in->[$i] = 1234.5678; } } } if (defined $in) { SKIP: { skip 'Pressing buttons produces too much output', 1 if $options->{type} == SANE_TYPE_BUTTON; $info = $test->set_option($i, $in); }; if ($options->{cap} & SANE_CAP_INACTIVE) { cmp_ok($Sane::STATUS, '==', SANE_STATUS_INVAL, 'set_option'); } else { cmp_ok($Sane::STATUS, '==', SANE_STATUS_GOOD, 'set_option'); } if ($options->{type} != SANE_TYPE_BUTTON) { $out = $test->get_option($i); if ($options->{cap} & SANE_CAP_INACTIVE) { cmp_ok($Sane::STATUS, '==', SANE_STATUS_INVAL, 'get_option'); } elsif ($info & SANE_INFO_INEXACT) { cmp_ok($Sane::STATUS, '==', SANE_STATUS_GOOD, 'get_option'); } elsif ($options->{type} == SANE_TYPE_FIXED) { if ($in == 0) { is (abs($out) < 1.e-6, 1, 'get_option'); } else { is (abs($out-$in)/$in < 1.e-6, 1, 'get_option'); } } else { is_deeply ($out, $in, 'get_option'); } } } } if ($options->{cap} & SANE_CAP_AUTOMATIC and not $options->{cap} & SANE_CAP_INACTIVE) { $info = $test->set_auto($i); cmp_ok($Sane::STATUS, '==', SANE_STATUS_GOOD, 'set_auto'); } } } done_testing(); Sane-0.05/t/data.t0000644000774200006240000000444511716433253012463 0ustar ra28145a400mc# Before `make install' is performed this script should be runnable with # `make test'. After `make install' it should work as `perl data.t' ######################### # change 'tests => 1' to 'tests => last_test_to_print'; use Test::More; BEGIN { use_ok('Sane') }; ######################### # Insert your test code below, the Test::More module is use()ed here so read # its man page ( perldoc Test::More ) for help writing this test script. plan skip_all => 'libsane 1.0.19 or better required' unless Sane->get_version_scalar > 1.000018; my $test = Sane::Device->open('test'); cmp_ok($Sane::STATUS, '==', SANE_STATUS_GOOD, 'opening test backend'); $options = $test->get_option_descriptor(10); is ($options->{name}, 'test-picture', 'test-picture'); my $info = $test->set_option(10, 'Color pattern'); cmp_ok($Sane::STATUS, '==', SANE_STATUS_GOOD, 'Color pattern'); my $n = $test->get_option(0); my $read_length_zero; if ($n > 52) { $options = $test->get_option_descriptor(52); if ($options->{name} eq 'read-length-zero') { $read_length_zero = 1; $info = $test->set_option(52, SANE_TRUE); cmp_ok($Sane::STATUS, '==', SANE_STATUS_GOOD, 'read-length-zero'); } } $options = $test->get_option_descriptor(2); cmp_ok($Sane::STATUS, '==', SANE_STATUS_GOOD, 'Modes'); for my $mode (@{$options->{constraint}}) { my $info = $test->set_option(2, $mode); cmp_ok($Sane::STATUS, '==', SANE_STATUS_GOOD, $mode); $test->start; cmp_ok($Sane::STATUS, '==', SANE_STATUS_GOOD, 'start'); my $param = $test->get_parameters; cmp_ok($Sane::STATUS, '==', SANE_STATUS_GOOD, 'get_parameters'); if ($param->{lines} >= 0) { my $filename = "$mode.pnm"; open my $fh, '>', $filename; binmode $fh; $test->write_pnm_header($fh, $param->{format}, $param->{pixels_per_line}, $param->{lines}, $param->{depth}); my ($data, $len); do { ($data, $len) = $test->read ($param->{bytes_per_line}); is (length($data), 0, 'length-zero') if ($read_length_zero and $len == 0 and $Sane::STATUS == SANE_STATUS_GOOD); print $fh substr($data, 0, $len) if ($data); } while ($Sane::STATUS == SANE_STATUS_GOOD); cmp_ok($Sane::STATUS, '==', SANE_STATUS_EOF, 'EOF'); is ($data, undef, 'EOF data'); is ($len, 0, 'EOF len'); $test->cancel; close $fh; } } done_testing(); Sane-0.05/t/pod.t0000644000774200006240000000020111242253657012320 0ustar ra28145a400mcuse Test::More; eval "use Test::Pod 1.00"; plan skip_all => "Test::Pod 1.00 required for testing POD" if $@; all_pod_files_ok(); Sane-0.05/t/enums.t0000644000774200006240000001763411736245673012716 0ustar ra28145a400mc# Before `make install' is performed this script should be runnable with # `make test'. After `make install' it should work as `perl enums.t' ######################### # change 'tests => 1' to 'tests => last_test_to_print'; use Test::More tests => 117; BEGIN { use_ok('Sane') }; ######################### # Insert your test code below, the Test::More module is use()ed here so read # its man page ( perldoc Test::More ) for help writing this test script. is (SANE_FALSE, 0, "SANE_FALSE"); is (SANE_TRUE, 1, "SANE_TRUE"); is (SANE_STATUS_GOOD, 0, "SANE_STATUS_GOOD"); is (SANE_STATUS_UNSUPPORTED, 1, "SANE_STATUS_UNSUPPORTED"); is (SANE_STATUS_CANCELLED, 2, "SANE_STATUS_CANCELLED"); is (SANE_STATUS_DEVICE_BUSY, 3, "SANE_STATUS_DEVICE_BUSY"); is (SANE_STATUS_INVAL, 4, "SANE_STATUS_INVAL"); is (SANE_STATUS_EOF, 5, "SANE_STATUS_EOF"); is (SANE_STATUS_JAMMED, 6, "SANE_STATUS_JAMMED"); is (SANE_STATUS_NO_DOCS, 7, "SANE_STATUS_NO_DOCS"); is (SANE_STATUS_COVER_OPEN, 8, "SANE_STATUS_COVER_OPEN"); is (SANE_STATUS_IO_ERROR, 9, "SANE_STATUS_IO_ERROR"); is (SANE_STATUS_NO_MEM, 10, "SANE_STATUS_NO_MEM"); is (SANE_STATUS_ACCESS_DENIED, 11, "SANE_STATUS_ACCESS_DENIED"); is (SANE_TYPE_BOOL, 0, "SANE_TYPE_BOOL"); is (SANE_TYPE_INT, 1, "SANE_TYPE_INT"); is (SANE_TYPE_FIXED, 2, "SANE_TYPE_FIXED"); is (SANE_TYPE_STRING, 3, "SANE_TYPE_STRING"); is (SANE_TYPE_BUTTON, 4, "SANE_TYPE_BUTTON"); is (SANE_TYPE_GROUP, 5, "SANE_TYPE_GROUP"); is (SANE_UNIT_NONE, 0, "SANE_UNIT_NONE"); is (SANE_UNIT_PIXEL, 1, "SANE_UNIT_PIXEL"); is (SANE_UNIT_BIT, 2, "SANE_UNIT_BIT"); is (SANE_UNIT_MM, 3, "SANE_UNIT_MM"); is (SANE_UNIT_DPI, 4, "SANE_UNIT_DPI"); is (SANE_UNIT_PERCENT, 5, "SANE_UNIT_PERCENT"); is (SANE_UNIT_MICROSECOND, 6, "SANE_UNIT_MICROSECOND"); is (SANE_CAP_SOFT_SELECT, 1, "SANE_CAP_SOFT_SELECT"); is (SANE_CAP_HARD_SELECT, 2, "SANE_CAP_HARD_SELECT"); is (SANE_CAP_SOFT_DETECT, 4, "SANE_CAP_SOFT_DETECT"); is (SANE_CAP_EMULATED, 8, "SANE_CAP_EMULATED"); is (SANE_CAP_AUTOMATIC, 16, "SANE_CAP_AUTOMATIC"); is (SANE_CAP_INACTIVE, 32, "SANE_CAP_INACTIVE"); is (SANE_CAP_ADVANCED, 64, "SANE_CAP_ADVANCED"); SKIP: { skip 'SANE_CAP_ALWAYS_SETTABLE only available in libsane 1.0.19', 1 unless Sane->get_version_scalar == 1.000019; is (SANE_CAP_ALWAYS_SETTABLE, 128, "SANE_CAP_ALWAYS_SETTABLE"); }; is (SANE_INFO_INEXACT, 1, "SANE_INFO_INEXACT"); is (SANE_INFO_RELOAD_OPTIONS, 2, "SANE_INFO_RELOAD_OPTIONS"); is (SANE_INFO_RELOAD_PARAMS, 4, "SANE_INFO_RELOAD_PARAMS"); is (SANE_CONSTRAINT_NONE, 0, "SANE_CONSTRAINT_NONE"); is (SANE_CONSTRAINT_RANGE, 1, "SANE_CONSTRAINT_RANGE"); is (SANE_CONSTRAINT_WORD_LIST, 2, "SANE_CONSTRAINT_WORD_LIST"); is (SANE_CONSTRAINT_STRING_LIST, 3, "SANE_CONSTRAINT_STRING_LIST"); is (SANE_FRAME_GRAY, 0, "SANE_FRAME_GRAY"); is (SANE_FRAME_RGB, 1, "SANE_FRAME_RGB"); is (SANE_FRAME_RED, 2, "SANE_FRAME_RED"); is (SANE_FRAME_GREEN, 3, "SANE_FRAME_GREEN"); is (SANE_FRAME_BLUE, 4, "SANE_FRAME_BLUE"); is (SANE_NAME_NUM_OPTIONS, "", "SANE_NAME_NUM_OPTIONS"); is (SANE_NAME_PREVIEW, "preview", "SANE_NAME_PREVIEW"); is (SANE_NAME_GRAY_PREVIEW, "preview-in-gray", "SANE_NAME_GRAY_PREVIEW"); is (SANE_NAME_BIT_DEPTH, "depth", "SANE_NAME_BIT_DEPTH"); is (SANE_NAME_SCAN_MODE, "mode", "SANE_NAME_SCAN_MODE"); is (SANE_NAME_SCAN_SPEED, "speed", "SANE_NAME_SCAN_SPEED"); is (SANE_NAME_SCAN_SOURCE, "source", "SANE_NAME_SCAN_SOURCE"); is (SANE_NAME_BACKTRACK, "backtrack", "SANE_NAME_BACKTRACK"); is (SANE_NAME_SCAN_TL_X, "tl-x", "SANE_NAME_SCAN_TL_X"); is (SANE_NAME_SCAN_TL_Y, "tl-y", "SANE_NAME_SCAN_TL_Y"); is (SANE_NAME_SCAN_BR_X, "br-x", "SANE_NAME_SCAN_BR_X"); is (SANE_NAME_SCAN_BR_Y, "br-y", "SANE_NAME_SCAN_BR_Y"); is (SANE_NAME_SCAN_RESOLUTION, "resolution", "SANE_NAME_SCAN_RESOLUTION"); is (SANE_NAME_SCAN_X_RESOLUTION, Sane->get_version_scalar == 1.000019 ? "resolution" : "x-resolution", "SANE_NAME_SCAN_X_RESOLUTION"); is (SANE_NAME_SCAN_Y_RESOLUTION, "y-resolution", "SANE_NAME_SCAN_Y_RESOLUTION"); is (SANE_NAME_PAGE_WIDTH, "page-width", "SANE_NAME_PAGE_WIDTH"); is (SANE_NAME_PAGE_HEIGHT, "page-height", "SANE_NAME_PAGE_HEIGHT"); is (SANE_NAME_CUSTOM_GAMMA, "custom-gamma", "SANE_NAME_CUSTOM_GAMMA"); is (SANE_NAME_GAMMA_VECTOR, "gamma-table", "SANE_NAME_GAMMA_VECTOR"); is (SANE_NAME_GAMMA_VECTOR_R, "red-gamma-table", "SANE_NAME_GAMMA_VECTOR_R"); is (SANE_NAME_GAMMA_VECTOR_G, "green-gamma-table", "SANE_NAME_GAMMA_VECTOR_G"); is (SANE_NAME_GAMMA_VECTOR_B, "blue-gamma-table", "SANE_NAME_GAMMA_VECTOR_B"); is (SANE_NAME_BRIGHTNESS, "brightness", "SANE_NAME_BRIGHTNESS"); is (SANE_NAME_CONTRAST, "contrast", "SANE_NAME_CONTRAST"); is (SANE_NAME_GRAIN_SIZE, "grain", "SANE_NAME_GRAIN_SIZE"); is (SANE_NAME_HALFTONE, "halftoning", "SANE_NAME_HALFTONE"); is (SANE_NAME_BLACK_LEVEL, "black-level", "SANE_NAME_BLACK_LEVEL"); is (SANE_NAME_WHITE_LEVEL, "white-level", "SANE_NAME_WHITE_LEVEL"); is (SANE_NAME_WHITE_LEVEL_R, "white-level-r", "SANE_NAME_WHITE_LEVEL_R"); is (SANE_NAME_WHITE_LEVEL_G, "white-level-g", "SANE_NAME_WHITE_LEVEL_G"); is (SANE_NAME_WHITE_LEVEL_B, "white-level-b", "SANE_NAME_WHITE_LEVEL_B"); is (SANE_NAME_SHADOW, "shadow", "SANE_NAME_SHADOW"); is (SANE_NAME_SHADOW_R, "shadow-r", "SANE_NAME_SHADOW_R"); is (SANE_NAME_SHADOW_G, "shadow-g", "SANE_NAME_SHADOW_G"); is (SANE_NAME_SHADOW_B, "shadow-b", "SANE_NAME_SHADOW_B"); is (SANE_NAME_HIGHLIGHT, "highlight", "SANE_NAME_HIGHLIGHT"); is (SANE_NAME_HIGHLIGHT_R, "highlight-r", "SANE_NAME_HIGHLIGHT_R"); is (SANE_NAME_HIGHLIGHT_G, "highlight-g", "SANE_NAME_HIGHLIGHT_G"); is (SANE_NAME_HIGHLIGHT_B, "highlight-b", "SANE_NAME_HIGHLIGHT_B"); is (SANE_NAME_HUE, "hue", "SANE_NAME_HUE"); is (SANE_NAME_SATURATION, "saturation", "SANE_NAME_SATURATION"); is (SANE_NAME_FILE, "filename", "SANE_NAME_FILE"); is (SANE_NAME_HALFTONE_DIMENSION, "halftone-size", "SANE_NAME_HALFTONE_DIMENSION"); is (SANE_NAME_HALFTONE_PATTERN, "halftone-pattern", "SANE_NAME_HALFTONE_PATTERN"); is (SANE_NAME_RESOLUTION_BIND, "resolution-bind", "SANE_NAME_RESOLUTION_BIND"); is (SANE_NAME_NEGATIVE, "negative", "SANE_NAME_NEGATIVE"); is (SANE_NAME_QUALITY_CAL, "quality-cal", "SANE_NAME_QUALITY_CAL"); is (SANE_NAME_DOR, "double-res", "SANE_NAME_DOR"); is (SANE_NAME_RGB_BIND, "rgb-bind", "SANE_NAME_RGB_BIND"); is (SANE_NAME_THRESHOLD, "threshold", "SANE_NAME_THRESHOLD"); is (SANE_NAME_ANALOG_GAMMA, "analog-gamma", "SANE_NAME_ANALOG_GAMMA"); is (SANE_NAME_ANALOG_GAMMA_R, "analog-gamma-r", "SANE_NAME_ANALOG_GAMMA_R"); is (SANE_NAME_ANALOG_GAMMA_G, "analog-gamma-g", "SANE_NAME_ANALOG_GAMMA_G"); is (SANE_NAME_ANALOG_GAMMA_B, "analog-gamma-b", "SANE_NAME_ANALOG_GAMMA_B"); is (SANE_NAME_ANALOG_GAMMA_BIND, "analog-gamma-bind", "SANE_NAME_ANALOG_GAMMA_BIND"); is (SANE_NAME_WARMUP, "warmup", "SANE_NAME_WARMUP"); is (SANE_NAME_CAL_EXPOS_TIME, "cal-exposure-time", "SANE_NAME_CAL_EXPOS_TIME"); is (SANE_NAME_CAL_EXPOS_TIME_R, "cal-exposure-time-r", "SANE_NAME_CAL_EXPOS_TIME_R"); is (SANE_NAME_CAL_EXPOS_TIME_G, "cal-exposure-time-g", "SANE_NAME_CAL_EXPOS_TIME_G"); is (SANE_NAME_CAL_EXPOS_TIME_B, "cal-exposure-time-b", "SANE_NAME_CAL_EXPOS_TIME_B"); is (SANE_NAME_SCAN_EXPOS_TIME, "scan-exposure-time", "SANE_NAME_SCAN_EXPOS_TIME"); is (SANE_NAME_SCAN_EXPOS_TIME_R, "scan-exposure-time-r", "SANE_NAME_SCAN_EXPOS_TIME_R"); is (SANE_NAME_SCAN_EXPOS_TIME_G, "scan-exposure-time-g", "SANE_NAME_SCAN_EXPOS_TIME_G"); is (SANE_NAME_SCAN_EXPOS_TIME_B, "scan-exposure-time-b", "SANE_NAME_SCAN_EXPOS_TIME_B"); is (SANE_NAME_SELECT_EXPOSURE_TIME, "select-exposure-time", "SANE_NAME_SELECT_EXPOSURE_TIME"); is (SANE_NAME_CAL_LAMP_DEN, "cal-lamp-density", "SANE_NAME_CAL_LAMP_DEN"); is (SANE_NAME_SCAN_LAMP_DEN, "scan-lamp-density", "SANE_NAME_SCAN_LAMP_DEN"); is (SANE_NAME_SELECT_LAMP_DENSITY, "select-lamp-density", "SANE_NAME_SELECT_LAMP_DENSITY"); is (SANE_NAME_LAMP_OFF_AT_EXIT, "lamp-off-at-exit", "SANE_NAME_LAMP_OFF_AT_EXIT"); Sane-0.05/saneperl.h0000644000774200006240000000100311716426624013073 0ustar ra28145a400mc/* * Copyright (c) 2008--2012 by Jeffrey Ratcliffe * * This library is free software; you can redistribute it and/or modify * it under the same terms as Perl itself, either Perl version 5.8.5 or, * at your option, any later version of Perl 5 you may have available. */ #ifndef _SANEPERL_H_ #define _SANEPERL_H_ /* Include all of sane's headers for internal consistency */ #include /*#include "sane/sanei.h"*/ #include "sane/saneopts.h" #endif /* _SANEPERL_H_ */ Sane-0.05/MANIFEST0000644000774200006240000000040411736245771012252 0ustar ra28145a400mcChanges Makefile.PL MANIFEST README Sane.xs examples/scanimage.pl examples/scanadf.pl lib/Sane.pm saneperl.h typemap t/data.t t/enums.t t/err.t t/non-blocking.t t/options.t t/pod.t META.yml Module meta-data (added by MakeMaker) Sane-0.05/typemap0000644000774200006240000000065111242253716012515 0ustar ra28145a400mcTYPEMAP SANE_Auth_Callback T_PTRREF SANE_Bool T_BOOL SANE_Handle T_SANE_HANDLE SANE_Int T_IV SANE_Status T_IV SANE_String_Const T_PV INPUT T_SANE_HANDLE if (sv_derived_from($arg, \"Sane::Device\")) { $var = INT2PTR (SANE_Handle, SvIV ((SV*)SvRV ($arg))); } else { croak(\"$var is not of type Sane::Device\"); } OUTPUT T_SANE_HANDLE sv_setref_pv($arg, \"SANE_Handle\", (void*)$var); Sane-0.05/Sane.xs0000644000774200006240000005732211736245674012400 0ustar ra28145a400mc#include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include MODULE = Sane PACKAGE = Sane::Device PREFIX = sane_ PROTOTYPES: ENABLE void sane_DESTROY (handle) SANE_Handle handle CODE: SV* sv = get_sv("Sane::DEBUG", FALSE); if (SvTRUE(sv)) printf("Closing SANE_Handle %p\n", (void *) handle); sane_close(handle); void sane_get_option_descriptor (h, n) SANE_Handle h SANE_Int n INIT: const SANE_Option_Descriptor * opt; HV* chv = (HV*) sv_2mortal((SV*) newHV()); AV* cav = (AV*) sv_2mortal((SV*) newAV()); HV* hv = (HV*) sv_2mortal((SV*) newHV()); int i; PPCODE: SV* sv = get_sv("Sane::DEBUG", FALSE); if (SvTRUE(sv)) printf("Getting option description %d from SANE_Handle %p\n", n, (void *) h); opt = sane_get_option_descriptor (h, n); if (!opt) croak("Error getting sane_get_option_descriptor"); if (opt->name != NULL) { hv_store(hv, "name", 4, newSVpv(opt->name, 0), 0); } if (opt->title != NULL) { hv_store(hv, "title", 5, newSVpv(opt->title, 0), 0); } if (opt->desc != NULL) { hv_store(hv, "desc", 4, newSVpv(opt->desc, 0), 0); } hv_store(hv, "type", 4, newSViv(opt->type), 0); hv_store(hv, "unit", 4, newSViv(opt->unit), 0); if (opt->type == SANE_TYPE_STRING) hv_store(hv, "max_values", 10, newSViv(1), 0); else hv_store(hv, "max_values", 10, newSViv(opt->size/(SANE_Int) sizeof (SANE_Word)), 0); hv_store(hv, "cap", 3, newSViv(opt->cap), 0); hv_store(hv, "constraint_type", 15, newSViv(opt->constraint_type), 0); switch (opt->constraint_type) { case SANE_CONSTRAINT_RANGE: if (opt->type == SANE_TYPE_FIXED) { hv_store(chv, "min", 3, newSVnv(SANE_UNFIX (opt->constraint.range->min)), 0); hv_store(chv, "max", 3, newSVnv(SANE_UNFIX (opt->constraint.range->max)), 0); hv_store(chv, "quant", 5, newSVnv(SANE_UNFIX (opt->constraint.range->quant)), 0); hv_store(hv, "constraint", 10, newRV((SV *)chv), 0); } else { hv_store(chv, "min", 3, newSViv(opt->constraint.range->min), 0); hv_store(chv, "max", 3, newSViv(opt->constraint.range->max), 0); hv_store(chv, "quant", 5, newSViv(opt->constraint.range->quant), 0); hv_store(hv, "constraint", 10, newRV((SV *)chv), 0); } break; case SANE_CONSTRAINT_WORD_LIST: for (i = 0; i < opt->constraint.word_list[0]; ++i) { if (opt->type == SANE_TYPE_INT) av_push(cav, newSViv(opt->constraint.word_list[i + 1])); else av_push(cav, newSVnv(SANE_UNFIX (opt->constraint.word_list[i + 1]))); } hv_store(hv, "constraint", 10, newRV((SV *)cav), 0); break; case SANE_CONSTRAINT_STRING_LIST: for (i = 0; opt->constraint.string_list[i]; ++i) { av_push(cav, newSVpv(opt->constraint.string_list[i], 0)); } hv_store(hv, "constraint", 10, newRV((SV *)cav), 0); break; default: break; } XPUSHs(newRV((SV *)hv)); void sane_get_option (h, n) SANE_Handle h SANE_Int n INIT: SANE_Status status; void * value; const SANE_Option_Descriptor * opt; PPCODE: SV* sv = get_sv("Sane::DEBUG", FALSE); if (SvTRUE(sv)) printf("Getting option %d from SANE_Handle %p\n", n, (void *) h); opt = sane_get_option_descriptor (h, n); if (!opt) croak("Error getting sane_get_option_descriptor"); if ( opt->size == 0 ) { XSRETURN_UNDEF; return; } value = malloc (opt->size); if (!value) croak("Error allocating memory"); status = sane_control_option (h, n, SANE_ACTION_GET_VALUE, value, 0); sv = get_sv("Sane::_status", FALSE); sv_setiv(sv, status); if (status) { XPUSHs(sv_2mortal(newSV(0))); } else if (opt->type == SANE_TYPE_STRING) XPUSHs(sv_2mortal(newSVpv((char *) value, 0))); else if (opt->size > (SANE_Int) sizeof (SANE_Word)) { AV* av = (AV*) sv_2mortal((SV*) newAV()); int vector_length = opt->size / sizeof (SANE_Word); int i; for (i = 0; i < vector_length; ++i) if (opt->type == SANE_TYPE_INT) av_push(av, newSViv(*(SANE_Int *) (value+i*sizeof(SANE_Word)))); else av_push(av, newSVnv(SANE_UNFIX (*(SANE_Word *) (value+i*sizeof(SANE_Word))))); XPUSHs(newRV((SV *)av)); } else { switch (opt->type) { case SANE_TYPE_BOOL: XPUSHs(sv_2mortal(newSViv(*(SANE_Bool *) value))); break; case SANE_TYPE_INT: XPUSHs(sv_2mortal(newSViv(*(SANE_Int *) value))); break; case SANE_TYPE_FIXED: XPUSHs(sv_2mortal(newSVnv(SANE_UNFIX (*(SANE_Word *) value)))); break; default: break; } } free (value); void sane_set_auto (h, n) SANE_Handle h SANE_Int n INIT: SANE_Status status; SANE_Int info; PPCODE: SV* sv = get_sv("Sane::DEBUG", FALSE); if (SvTRUE(sv)) printf("Setting option %d to automatic on SANE_Handle %p\n", n, (void *) h); status = sane_control_option (h, n, SANE_ACTION_SET_AUTO, 0, &info); sv = get_sv("Sane::_status", FALSE); sv_setiv(sv, status); XPUSHs(sv_2mortal(newSViv(info))); void sane_set_option (h, n, value) SANE_Handle h SANE_Int n SV* value INIT: SANE_Status status; SANE_Int info; void * valuep; const SANE_Option_Descriptor * opt; SANE_Bool b; SANE_Fixed fixed; int i, vector_length = 0; SV ** svp; SANE_Word * vector; char * string; PPCODE: SV* sv = get_sv("Sane::DEBUG", FALSE); if (SvTRUE(sv)) printf("Setting option %d on SANE_Handle %p\n", n, (void *) h); opt = sane_get_option_descriptor (h, n); if (!opt) croak("Error getting sane_get_option_descriptor"); switch (opt->type) { case SANE_TYPE_BOOL: b = (SANE_Bool)SvIV(value); valuep = &b; break; case SANE_TYPE_INT: case SANE_TYPE_FIXED: if (SvNIOK(value) || SvPOK(value)) { if (opt->type == SANE_TYPE_INT) fixed = (SANE_Int)SvIV(value); else fixed = (SANE_Fixed)SANE_FIX(SvNV(value)); valuep = &fixed; } else if (SvROK(value) && SvTYPE(SvRV(value)) == SVt_PVAV) { AV* array = (AV*) SvRV(value); vector_length = av_len((AV*) array) + 1; if (vector_length > opt->size / sizeof (SANE_Word)) croak("Array has too many elements"); vector = malloc (opt->size); if (!vector) croak("Error allocating memory"); for (i = 0; i < vector_length; i++) { svp = av_fetch(array, i, 0); if (SvNIOK(*svp) || SvPOK(*svp)) { if (opt->type == SANE_TYPE_INT) vector[i] = (SANE_Int)SvIV(*(svp)); else vector[i] = (SANE_Fixed)SANE_FIX(SvNV(*svp)); } } valuep = vector; } else croak("Value is neither a number, nor an array reference"); break; case SANE_TYPE_STRING: string = (char *)SvPV_nolen(value); valuep = malloc (opt->size); if (!valuep) croak("Error allocating memory"); strncpy (valuep, string, opt->size); ((char *) valuep)[opt->size - 1] = 0; break; default: break; } status = sane_control_option (h, n, SANE_ACTION_SET_VALUE, valuep, &info); if (opt->type == SANE_TYPE_STRING || ((opt->type == SANE_TYPE_INT || opt->type == SANE_TYPE_FIXED) && vector_length)) free(valuep); sv = get_sv("Sane::_status", FALSE); sv_setiv(sv, status); XPUSHs(sv_2mortal(newSViv(info))); void sane_start (handle) SANE_Handle handle INIT: SANE_Status status; CODE: SV* sv = get_sv("Sane::DEBUG", FALSE); if (SvTRUE(sv)) printf("Running sane_start for SANE_Handle %p\n", (void *) handle); status = sane_start(handle); sv = get_sv("Sane::_status", FALSE); sv_setiv(sv, status); void sane_get_parameters (handle) SANE_Handle handle INIT: SANE_Status status; SANE_Parameters params; HV* hv = (HV*) sv_2mortal((SV*) newHV()); PPCODE: SV* sv = get_sv("Sane::DEBUG", FALSE); if (SvTRUE(sv)) printf("Getting parameters for SANE_Handle %p\n", (void *) handle); status = sane_get_parameters (handle, ¶ms); sv = get_sv("Sane::_status", FALSE); sv_setiv(sv, status); if (status) { XPUSHs(sv_2mortal(newSV(0))); } else { hv_store(hv, "format", 6, newSViv(params.format), 0); hv_store(hv, "last_frame", 10, newSViv(params.last_frame), 0); hv_store(hv, "bytes_per_line", 14, newSViv(params.bytes_per_line), 0); hv_store(hv, "pixels_per_line", 15, newSViv(params.pixels_per_line), 0); hv_store(hv, "lines", 5, newSViv(params.lines), 0); hv_store(hv, "depth", 5, newSViv(params.depth), 0); XPUSHs(newRV((SV *)hv)); } void sane_read (handle, max_length) SANE_Handle handle SANE_Int max_length INIT: SANE_Status status; SANE_Byte * data; SANE_Int length; PPCODE: data = malloc (max_length); status = sane_read (handle, data, max_length, &length); SV* sv = get_sv("Sane::_status", FALSE); sv_setiv(sv, status); if (status) { XPUSHs(sv_2mortal(newSV(0))); XPUSHs(sv_2mortal(newSViv(0))); } else { XPUSHs(sv_2mortal(newSVpvn(data, length))); XPUSHs(sv_2mortal(newSViv(length))); } free (data); void sane_cancel (handle) SANE_Handle handle void sane_set_io_mode (handle, non_blocking) SANE_Handle handle SANE_Bool non_blocking INIT: SANE_Status status; CODE: SV* sv = get_sv("Sane::DEBUG", FALSE); if (SvTRUE(sv)) printf("Setting IO mode to %d on SANE_Handle %p\n", non_blocking, (void *) handle); status = sane_set_io_mode (handle, non_blocking); sv = get_sv("Sane::_status", FALSE); sv_setiv(sv, status); void sane_get_select_fd (handle) SANE_Handle handle INIT: SANE_Status status; SANE_Int fd; PPCODE: SV* sv = get_sv("Sane::DEBUG", FALSE); if (SvTRUE(sv)) printf("Getting file handle of SANE_Handle %p\n", (void *) handle); status = sane_get_select_fd (handle, &fd); sv = get_sv("Sane::_status", FALSE); sv_setiv(sv, status); if (status) { XPUSHs(sv_2mortal(newSV(0))); } else { XPUSHs(sv_2mortal(newSViv(fd))); } MODULE = Sane PACKAGE = Sane PREFIX = sane_ PROTOTYPES: ENABLE BOOT: HV *stash; stash = gv_stashpv("Sane", TRUE); newCONSTSUB(stash, "SANE_FALSE", newSViv(SANE_FALSE)); newCONSTSUB(stash, "SANE_TRUE", newSViv(SANE_TRUE)); newCONSTSUB(stash, "SANE_STATUS_GOOD", newSViv(SANE_STATUS_GOOD)); newCONSTSUB(stash, "SANE_STATUS_UNSUPPORTED", newSViv(SANE_STATUS_UNSUPPORTED)); newCONSTSUB(stash, "SANE_STATUS_CANCELLED", newSViv(SANE_STATUS_CANCELLED)); newCONSTSUB(stash, "SANE_STATUS_DEVICE_BUSY", newSViv(SANE_STATUS_DEVICE_BUSY)); newCONSTSUB(stash, "SANE_STATUS_INVAL", newSViv(SANE_STATUS_INVAL)); newCONSTSUB(stash, "SANE_STATUS_EOF", newSViv(SANE_STATUS_EOF)); newCONSTSUB(stash, "SANE_STATUS_JAMMED", newSViv(SANE_STATUS_JAMMED)); newCONSTSUB(stash, "SANE_STATUS_NO_DOCS", newSViv(SANE_STATUS_NO_DOCS)); newCONSTSUB(stash, "SANE_STATUS_COVER_OPEN", newSViv(SANE_STATUS_COVER_OPEN)); newCONSTSUB(stash, "SANE_STATUS_IO_ERROR", newSViv(SANE_STATUS_IO_ERROR)); newCONSTSUB(stash, "SANE_STATUS_NO_MEM", newSViv(SANE_STATUS_NO_MEM)); newCONSTSUB(stash, "SANE_STATUS_ACCESS_DENIED", newSViv(SANE_STATUS_ACCESS_DENIED)); newCONSTSUB(stash, "SANE_TYPE_BOOL", newSViv(SANE_TYPE_BOOL)); newCONSTSUB(stash, "SANE_TYPE_INT", newSViv(SANE_TYPE_INT)); newCONSTSUB(stash, "SANE_TYPE_FIXED", newSViv(SANE_TYPE_FIXED)); newCONSTSUB(stash, "SANE_TYPE_STRING", newSViv(SANE_TYPE_STRING)); newCONSTSUB(stash, "SANE_TYPE_BUTTON", newSViv(SANE_TYPE_BUTTON)); newCONSTSUB(stash, "SANE_TYPE_GROUP", newSViv(SANE_TYPE_GROUP)); newCONSTSUB(stash, "SANE_UNIT_NONE", newSViv(SANE_UNIT_NONE)); newCONSTSUB(stash, "SANE_UNIT_PIXEL", newSViv(SANE_UNIT_PIXEL)); newCONSTSUB(stash, "SANE_UNIT_BIT", newSViv(SANE_UNIT_BIT)); newCONSTSUB(stash, "SANE_UNIT_MM", newSViv(SANE_UNIT_MM)); newCONSTSUB(stash, "SANE_UNIT_DPI", newSViv(SANE_UNIT_DPI)); newCONSTSUB(stash, "SANE_UNIT_PERCENT", newSViv(SANE_UNIT_PERCENT)); newCONSTSUB(stash, "SANE_UNIT_MICROSECOND", newSViv(SANE_UNIT_MICROSECOND)); newCONSTSUB(stash, "SANE_CAP_SOFT_SELECT", newSViv(SANE_CAP_SOFT_SELECT)); newCONSTSUB(stash, "SANE_CAP_HARD_SELECT", newSViv(SANE_CAP_HARD_SELECT)); newCONSTSUB(stash, "SANE_CAP_SOFT_DETECT", newSViv(SANE_CAP_SOFT_DETECT)); newCONSTSUB(stash, "SANE_CAP_EMULATED", newSViv(SANE_CAP_EMULATED)); newCONSTSUB(stash, "SANE_CAP_AUTOMATIC", newSViv(SANE_CAP_AUTOMATIC)); newCONSTSUB(stash, "SANE_CAP_INACTIVE", newSViv(SANE_CAP_INACTIVE)); newCONSTSUB(stash, "SANE_CAP_ADVANCED", newSViv(SANE_CAP_ADVANCED)); #ifdef SANE_CAP_ALWAYS_SETTABLE newCONSTSUB(stash, "SANE_CAP_ALWAYS_SETTABLE", newSViv(SANE_CAP_ALWAYS_SETTABLE)); #endif newCONSTSUB(stash, "SANE_INFO_INEXACT", newSViv(SANE_INFO_INEXACT)); newCONSTSUB(stash, "SANE_INFO_RELOAD_OPTIONS", newSViv(SANE_INFO_RELOAD_OPTIONS)); newCONSTSUB(stash, "SANE_INFO_RELOAD_PARAMS", newSViv(SANE_INFO_RELOAD_PARAMS)); newCONSTSUB(stash, "SANE_CONSTRAINT_NONE", newSViv(SANE_CONSTRAINT_NONE)); newCONSTSUB(stash, "SANE_CONSTRAINT_RANGE", newSViv(SANE_CONSTRAINT_RANGE)); newCONSTSUB(stash, "SANE_CONSTRAINT_WORD_LIST", newSViv(SANE_CONSTRAINT_WORD_LIST)); newCONSTSUB(stash, "SANE_CONSTRAINT_STRING_LIST", newSViv(SANE_CONSTRAINT_STRING_LIST)); newCONSTSUB(stash, "SANE_FRAME_GRAY", newSViv(SANE_FRAME_GRAY)); newCONSTSUB(stash, "SANE_FRAME_RGB", newSViv(SANE_FRAME_RGB)); newCONSTSUB(stash, "SANE_FRAME_RED", newSViv(SANE_FRAME_RED)); newCONSTSUB(stash, "SANE_FRAME_GREEN", newSViv(SANE_FRAME_GREEN)); newCONSTSUB(stash, "SANE_FRAME_BLUE", newSViv(SANE_FRAME_BLUE)); newCONSTSUB(stash, "SANE_NAME_NUM_OPTIONS", newSVpv(SANE_NAME_NUM_OPTIONS, 0)); newCONSTSUB(stash, "SANE_NAME_PREVIEW", newSVpv(SANE_NAME_PREVIEW, 0)); newCONSTSUB(stash, "SANE_NAME_GRAY_PREVIEW", newSVpv(SANE_NAME_GRAY_PREVIEW, 0)); newCONSTSUB(stash, "SANE_NAME_BIT_DEPTH", newSVpv(SANE_NAME_BIT_DEPTH, 0)); newCONSTSUB(stash, "SANE_NAME_SCAN_MODE", newSVpv(SANE_NAME_SCAN_MODE, 0)); newCONSTSUB(stash, "SANE_NAME_SCAN_SPEED", newSVpv(SANE_NAME_SCAN_SPEED, 0)); newCONSTSUB(stash, "SANE_NAME_SCAN_SOURCE", newSVpv(SANE_NAME_SCAN_SOURCE, 0)); newCONSTSUB(stash, "SANE_NAME_BACKTRACK", newSVpv(SANE_NAME_BACKTRACK, 0)); newCONSTSUB(stash, "SANE_NAME_SCAN_TL_X", newSVpv(SANE_NAME_SCAN_TL_X, 0)); newCONSTSUB(stash, "SANE_NAME_SCAN_TL_Y", newSVpv(SANE_NAME_SCAN_TL_Y, 0)); newCONSTSUB(stash, "SANE_NAME_SCAN_BR_X", newSVpv(SANE_NAME_SCAN_BR_X, 0)); newCONSTSUB(stash, "SANE_NAME_SCAN_BR_Y", newSVpv(SANE_NAME_SCAN_BR_Y, 0)); newCONSTSUB(stash, "SANE_NAME_SCAN_RESOLUTION", newSVpv(SANE_NAME_SCAN_RESOLUTION, 0)); newCONSTSUB(stash, "SANE_NAME_SCAN_X_RESOLUTION", newSVpv(SANE_NAME_SCAN_X_RESOLUTION, 0)); newCONSTSUB(stash, "SANE_NAME_SCAN_Y_RESOLUTION", newSVpv(SANE_NAME_SCAN_Y_RESOLUTION, 0)); #ifdef SANE_NAME_PAGE_WIDTH newCONSTSUB(stash, "SANE_NAME_PAGE_WIDTH", newSVpv(SANE_NAME_PAGE_WIDTH, 0)); #endif #ifdef SANE_NAME_PAGE_HEIGHT newCONSTSUB(stash, "SANE_NAME_PAGE_HEIGHT", newSVpv(SANE_NAME_PAGE_HEIGHT, 0)); #endif newCONSTSUB(stash, "SANE_NAME_CUSTOM_GAMMA", newSVpv(SANE_NAME_CUSTOM_GAMMA, 0)); newCONSTSUB(stash, "SANE_NAME_GAMMA_VECTOR", newSVpv(SANE_NAME_GAMMA_VECTOR, 0)); newCONSTSUB(stash, "SANE_NAME_GAMMA_VECTOR_R", newSVpv(SANE_NAME_GAMMA_VECTOR_R, 0)); newCONSTSUB(stash, "SANE_NAME_GAMMA_VECTOR_G", newSVpv(SANE_NAME_GAMMA_VECTOR_G, 0)); newCONSTSUB(stash, "SANE_NAME_GAMMA_VECTOR_B", newSVpv(SANE_NAME_GAMMA_VECTOR_B, 0)); newCONSTSUB(stash, "SANE_NAME_BRIGHTNESS", newSVpv(SANE_NAME_BRIGHTNESS, 0)); newCONSTSUB(stash, "SANE_NAME_CONTRAST", newSVpv(SANE_NAME_CONTRAST, 0)); newCONSTSUB(stash, "SANE_NAME_GRAIN_SIZE", newSVpv(SANE_NAME_GRAIN_SIZE, 0)); newCONSTSUB(stash, "SANE_NAME_HALFTONE", newSVpv(SANE_NAME_HALFTONE, 0)); newCONSTSUB(stash, "SANE_NAME_BLACK_LEVEL", newSVpv(SANE_NAME_BLACK_LEVEL, 0)); newCONSTSUB(stash, "SANE_NAME_WHITE_LEVEL", newSVpv(SANE_NAME_WHITE_LEVEL, 0)); newCONSTSUB(stash, "SANE_NAME_WHITE_LEVEL_R", newSVpv(SANE_NAME_WHITE_LEVEL_R, 0)); newCONSTSUB(stash, "SANE_NAME_WHITE_LEVEL_G", newSVpv(SANE_NAME_WHITE_LEVEL_G, 0)); newCONSTSUB(stash, "SANE_NAME_WHITE_LEVEL_B", newSVpv(SANE_NAME_WHITE_LEVEL_B, 0)); newCONSTSUB(stash, "SANE_NAME_SHADOW", newSVpv(SANE_NAME_SHADOW, 0)); newCONSTSUB(stash, "SANE_NAME_SHADOW_R", newSVpv(SANE_NAME_SHADOW_R, 0)); newCONSTSUB(stash, "SANE_NAME_SHADOW_G", newSVpv(SANE_NAME_SHADOW_G, 0)); newCONSTSUB(stash, "SANE_NAME_SHADOW_B", newSVpv(SANE_NAME_SHADOW_B, 0)); newCONSTSUB(stash, "SANE_NAME_HIGHLIGHT", newSVpv(SANE_NAME_HIGHLIGHT, 0)); newCONSTSUB(stash, "SANE_NAME_HIGHLIGHT_R", newSVpv(SANE_NAME_HIGHLIGHT_R, 0)); newCONSTSUB(stash, "SANE_NAME_HIGHLIGHT_G", newSVpv(SANE_NAME_HIGHLIGHT_G, 0)); newCONSTSUB(stash, "SANE_NAME_HIGHLIGHT_B", newSVpv(SANE_NAME_HIGHLIGHT_B, 0)); newCONSTSUB(stash, "SANE_NAME_HUE", newSVpv(SANE_NAME_HUE, 0)); newCONSTSUB(stash, "SANE_NAME_SATURATION", newSVpv(SANE_NAME_SATURATION, 0)); newCONSTSUB(stash, "SANE_NAME_FILE", newSVpv(SANE_NAME_FILE, 0)); newCONSTSUB(stash, "SANE_NAME_HALFTONE_DIMENSION", newSVpv(SANE_NAME_HALFTONE_DIMENSION, 0)); newCONSTSUB(stash, "SANE_NAME_HALFTONE_PATTERN", newSVpv(SANE_NAME_HALFTONE_PATTERN, 0)); newCONSTSUB(stash, "SANE_NAME_RESOLUTION_BIND", newSVpv(SANE_NAME_RESOLUTION_BIND, 0)); newCONSTSUB(stash, "SANE_NAME_NEGATIVE", newSVpv(SANE_NAME_NEGATIVE, 0)); newCONSTSUB(stash, "SANE_NAME_QUALITY_CAL", newSVpv(SANE_NAME_QUALITY_CAL, 0)); newCONSTSUB(stash, "SANE_NAME_DOR", newSVpv(SANE_NAME_DOR, 0)); newCONSTSUB(stash, "SANE_NAME_RGB_BIND", newSVpv(SANE_NAME_RGB_BIND, 0)); newCONSTSUB(stash, "SANE_NAME_THRESHOLD", newSVpv(SANE_NAME_THRESHOLD, 0)); newCONSTSUB(stash, "SANE_NAME_ANALOG_GAMMA", newSVpv(SANE_NAME_ANALOG_GAMMA, 0)); newCONSTSUB(stash, "SANE_NAME_ANALOG_GAMMA_R", newSVpv(SANE_NAME_ANALOG_GAMMA_R, 0)); newCONSTSUB(stash, "SANE_NAME_ANALOG_GAMMA_G", newSVpv(SANE_NAME_ANALOG_GAMMA_G, 0)); newCONSTSUB(stash, "SANE_NAME_ANALOG_GAMMA_B", newSVpv(SANE_NAME_ANALOG_GAMMA_B, 0)); newCONSTSUB(stash, "SANE_NAME_ANALOG_GAMMA_BIND", newSVpv(SANE_NAME_ANALOG_GAMMA_BIND, 0)); newCONSTSUB(stash, "SANE_NAME_WARMUP", newSVpv(SANE_NAME_WARMUP, 0)); newCONSTSUB(stash, "SANE_NAME_CAL_EXPOS_TIME", newSVpv(SANE_NAME_CAL_EXPOS_TIME, 0)); newCONSTSUB(stash, "SANE_NAME_CAL_EXPOS_TIME_R", newSVpv(SANE_NAME_CAL_EXPOS_TIME_R, 0)); newCONSTSUB(stash, "SANE_NAME_CAL_EXPOS_TIME_G", newSVpv(SANE_NAME_CAL_EXPOS_TIME_G, 0)); newCONSTSUB(stash, "SANE_NAME_CAL_EXPOS_TIME_B", newSVpv(SANE_NAME_CAL_EXPOS_TIME_B, 0)); newCONSTSUB(stash, "SANE_NAME_SCAN_EXPOS_TIME", newSVpv(SANE_NAME_SCAN_EXPOS_TIME, 0)); newCONSTSUB(stash, "SANE_NAME_SCAN_EXPOS_TIME_R", newSVpv(SANE_NAME_SCAN_EXPOS_TIME_R, 0)); newCONSTSUB(stash, "SANE_NAME_SCAN_EXPOS_TIME_G", newSVpv(SANE_NAME_SCAN_EXPOS_TIME_G, 0)); newCONSTSUB(stash, "SANE_NAME_SCAN_EXPOS_TIME_B", newSVpv(SANE_NAME_SCAN_EXPOS_TIME_B, 0)); newCONSTSUB(stash, "SANE_NAME_SELECT_EXPOSURE_TIME", newSVpv(SANE_NAME_SELECT_EXPOSURE_TIME, 0)); newCONSTSUB(stash, "SANE_NAME_CAL_LAMP_DEN", newSVpv(SANE_NAME_CAL_LAMP_DEN, 0)); newCONSTSUB(stash, "SANE_NAME_SCAN_LAMP_DEN", newSVpv(SANE_NAME_SCAN_LAMP_DEN, 0)); newCONSTSUB(stash, "SANE_NAME_SELECT_LAMP_DENSITY", newSVpv(SANE_NAME_SELECT_LAMP_DENSITY, 0)); newCONSTSUB(stash, "SANE_NAME_LAMP_OFF_AT_EXIT", newSVpv(SANE_NAME_LAMP_OFF_AT_EXIT, 0)); void sane__init (class) INIT: SANE_Status status; SANE_Int version_code; PPCODE: SV* sv = get_sv("Sane::DEBUG", FALSE); if (SvTRUE(sv)) printf("Running sane_init\n"); status = sane_init(&version_code, NULL); sv = get_sv("Sane::_status", FALSE); sv_setiv(sv, status); if (status) { XPUSHs(sv_2mortal(newSV(0))); } else { XPUSHs(sv_2mortal(newSViv(version_code))); } ## Can't test this. If needed, should be integrated into _init above ## void ## CallSubSV(name) ## SV * name ## SANE_String_Const resource ## SANE_Char * username ## SANE_Char * password ## CODE: ## dSP; ## int count; ## ## ENTER; ## SAVETMPS; ## ## PUSHMARK(SP); ## XPUSHs(sv_2mortal(newSVpv(resource, 0))); ## XPUSHs(sv_2mortal(newSVpv(username, 0))); ## XPUSHs(sv_2mortal(newSVpv(password, 0))); ## PUTBACK; ## ## count = call_sv(name, G_DISCARD, G_ARRAY); ## ## SPAGAIN; ## ## if (count != 2) croak("Big trouble\n"); ## ## printf ("Returned %s and %s\n\n", POPs, POPs); ## ## PUTBACK; ## FREETMPS; ## LEAVE; void sane__get_version (class, version_code) SANE_Int version_code PPCODE: XPUSHs(sv_2mortal(newSViv(SANE_VERSION_MAJOR (version_code)))); XPUSHs(sv_2mortal(newSViv(SANE_VERSION_MINOR (version_code)))); XPUSHs(sv_2mortal(newSViv(SANE_VERSION_BUILD (version_code)))); void sane__get_devices (local=SANE_FALSE) SANE_Bool local INIT: SANE_Status status; AV * array; int i; const SANE_Device ** device_list; array = (AV *)sv_2mortal((SV *)newAV()); PPCODE: SV* sv = get_sv("Sane::DEBUG", FALSE); if (SvTRUE(sv)) printf("Running sane_get_devices\n"); status = sane_get_devices (&device_list, local); sv = get_sv("Sane::_status", FALSE); sv_setiv(sv, status); if (status) { XPUSHs(sv_2mortal(newSV(0))); } else { for (i = 0; device_list[i]; ++i) { HV* hv = (HV*) sv_2mortal((SV*) newHV()); hv_store(hv, "name", 4, newSVpv(device_list[i]->name, 0), 0); hv_store(hv, "vendor", 6, newSVpv(device_list[i]->vendor, 0), 0); hv_store(hv, "model", 5, newSVpv(device_list[i]->model, 0), 0); hv_store(hv, "type", 4, newSVpv(device_list[i]->type, 0), 0); XPUSHs(newRV((SV *)hv)); } } void sane__open(class, name) SANE_String_Const name INIT: SANE_Status status; SANE_Handle h; PPCODE: status = sane_open(name, &h); SV* sv = get_sv("Sane::DEBUG", FALSE); if (SvTRUE(sv)) printf("sane_open returned SANE_Handle %p\n", (void *) h); sv = get_sv("Sane::_status", FALSE); sv_setiv(sv, status); if (status) { XPUSHs(sv_2mortal(newSV(0))); } else { XPUSHs(sv_2mortal(newSViv(PTR2IV(h)))); } SANE_String_Const sane_strstatus (status) SANE_Status status void END () CODE: SV* sv = get_sv("Sane::_vc", FALSE); if (SvTRUE(sv)) { sv = get_sv("Sane::DEBUG", FALSE); if (SvTRUE(sv)) printf("Exiting via sane_exit\n"); sane_exit; } Sane-0.05/lib/0000755000774200006240000000000011736245770011670 5ustar ra28145a400mcSane-0.05/lib/Sane.pm0000644000774200006240000005037511736245673013130 0ustar ra28145a400mcpackage Sane; use 5.008005; use strict; use warnings; require Exporter; our @ISA = qw(Exporter); # Items to export into callers namespace by default. Note: do not export # names by default without a very good reason. Use EXPORT_OK instead. # Do not simply export all your public functions/methods/constants. # This allows declaration use SANE ':all'; # If you do not need this, moving things directly into @EXPORT or @EXPORT_OK # will save memory. our %EXPORT_TAGS = ( 'all' => [ qw( SANE_FALSE SANE_TRUE SANE_STATUS_GOOD SANE_STATUS_UNSUPPORTED SANE_STATUS_CANCELLED SANE_STATUS_DEVICE_BUSY SANE_STATUS_INVAL SANE_STATUS_EOF SANE_STATUS_JAMMED SANE_STATUS_NO_DOCS SANE_STATUS_COVER_OPEN SANE_STATUS_IO_ERROR SANE_STATUS_NO_MEM SANE_STATUS_ACCESS_DENIED SANE_TYPE_BOOL SANE_TYPE_INT SANE_TYPE_FIXED SANE_TYPE_STRING SANE_TYPE_BUTTON SANE_TYPE_GROUP SANE_UNIT_NONE SANE_UNIT_PIXEL SANE_UNIT_BIT SANE_UNIT_MM SANE_UNIT_DPI SANE_UNIT_PERCENT SANE_UNIT_MICROSECOND SANE_CAP_SOFT_SELECT SANE_CAP_HARD_SELECT SANE_CAP_SOFT_DETECT SANE_CAP_EMULATED SANE_CAP_AUTOMATIC SANE_CAP_INACTIVE SANE_CAP_ADVANCED SANE_CAP_ALWAYS_SETTABLE SANE_INFO_INEXACT SANE_INFO_RELOAD_OPTIONS SANE_INFO_RELOAD_PARAMS SANE_CONSTRAINT_NONE SANE_CONSTRAINT_RANGE SANE_CONSTRAINT_WORD_LIST SANE_CONSTRAINT_STRING_LIST SANE_FRAME_GRAY SANE_FRAME_RGB SANE_FRAME_RED SANE_FRAME_GREEN SANE_FRAME_BLUE SANE_NAME_NUM_OPTIONS SANE_NAME_PREVIEW SANE_NAME_GRAY_PREVIEW SANE_NAME_BIT_DEPTH SANE_NAME_SCAN_MODE SANE_NAME_SCAN_SPEED SANE_NAME_SCAN_SOURCE SANE_NAME_BACKTRACK SANE_NAME_SCAN_TL_X SANE_NAME_SCAN_TL_Y SANE_NAME_SCAN_BR_X SANE_NAME_SCAN_BR_Y SANE_NAME_SCAN_RESOLUTION SANE_NAME_SCAN_X_RESOLUTION SANE_NAME_SCAN_Y_RESOLUTION SANE_NAME_PAGE_WIDTH SANE_NAME_PAGE_HEIGHT SANE_NAME_CUSTOM_GAMMA SANE_NAME_GAMMA_VECTOR SANE_NAME_GAMMA_VECTOR_R SANE_NAME_GAMMA_VECTOR_G SANE_NAME_GAMMA_VECTOR_B SANE_NAME_BRIGHTNESS SANE_NAME_CONTRAST SANE_NAME_GRAIN_SIZE SANE_NAME_HALFTONE SANE_NAME_BLACK_LEVEL SANE_NAME_WHITE_LEVEL SANE_NAME_WHITE_LEVEL_R SANE_NAME_WHITE_LEVEL_G SANE_NAME_WHITE_LEVEL_B SANE_NAME_SHADOW SANE_NAME_SHADOW_R SANE_NAME_SHADOW_G SANE_NAME_SHADOW_B SANE_NAME_HIGHLIGHT SANE_NAME_HIGHLIGHT_R SANE_NAME_HIGHLIGHT_G SANE_NAME_HIGHLIGHT_B SANE_NAME_HUE SANE_NAME_SATURATION SANE_NAME_FILE SANE_NAME_HALFTONE_DIMENSION SANE_NAME_HALFTONE_PATTERN SANE_NAME_RESOLUTION_BIND SANE_NAME_NEGATIVE SANE_NAME_QUALITY_CAL SANE_NAME_DOR SANE_NAME_RGB_BIND SANE_NAME_THRESHOLD SANE_NAME_ANALOG_GAMMA SANE_NAME_ANALOG_GAMMA_R SANE_NAME_ANALOG_GAMMA_G SANE_NAME_ANALOG_GAMMA_B SANE_NAME_ANALOG_GAMMA_BIND SANE_NAME_WARMUP SANE_NAME_CAL_EXPOS_TIME SANE_NAME_CAL_EXPOS_TIME_R SANE_NAME_CAL_EXPOS_TIME_G SANE_NAME_CAL_EXPOS_TIME_B SANE_NAME_SCAN_EXPOS_TIME SANE_NAME_SCAN_EXPOS_TIME_R SANE_NAME_SCAN_EXPOS_TIME_G SANE_NAME_SCAN_EXPOS_TIME_B SANE_NAME_SELECT_EXPOSURE_TIME SANE_NAME_CAL_LAMP_DEN SANE_NAME_SCAN_LAMP_DEN SANE_NAME_SELECT_LAMP_DENSITY SANE_NAME_LAMP_OFF_AT_EXIT ) ] ); our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); our @EXPORT = qw( SANE_FALSE SANE_TRUE SANE_STATUS_GOOD SANE_STATUS_UNSUPPORTED SANE_STATUS_CANCELLED SANE_STATUS_DEVICE_BUSY SANE_STATUS_INVAL SANE_STATUS_EOF SANE_STATUS_JAMMED SANE_STATUS_NO_DOCS SANE_STATUS_COVER_OPEN SANE_STATUS_IO_ERROR SANE_STATUS_NO_MEM SANE_STATUS_ACCESS_DENIED SANE_TYPE_BOOL SANE_TYPE_INT SANE_TYPE_FIXED SANE_TYPE_STRING SANE_TYPE_BUTTON SANE_TYPE_GROUP SANE_UNIT_NONE SANE_UNIT_PIXEL SANE_UNIT_BIT SANE_UNIT_MM SANE_UNIT_DPI SANE_UNIT_PERCENT SANE_UNIT_MICROSECOND SANE_CAP_SOFT_SELECT SANE_CAP_HARD_SELECT SANE_CAP_SOFT_DETECT SANE_CAP_EMULATED SANE_CAP_AUTOMATIC SANE_CAP_INACTIVE SANE_CAP_ADVANCED SANE_CAP_ALWAYS_SETTABLE SANE_INFO_INEXACT SANE_INFO_RELOAD_OPTIONS SANE_INFO_RELOAD_PARAMS SANE_CONSTRAINT_NONE SANE_CONSTRAINT_RANGE SANE_CONSTRAINT_WORD_LIST SANE_CONSTRAINT_STRING_LIST SANE_FRAME_GRAY SANE_FRAME_RGB SANE_FRAME_RED SANE_FRAME_GREEN SANE_FRAME_BLUE SANE_NAME_NUM_OPTIONS SANE_NAME_PREVIEW SANE_NAME_GRAY_PREVIEW SANE_NAME_BIT_DEPTH SANE_NAME_SCAN_MODE SANE_NAME_SCAN_SPEED SANE_NAME_SCAN_SOURCE SANE_NAME_BACKTRACK SANE_NAME_SCAN_TL_X SANE_NAME_SCAN_TL_Y SANE_NAME_SCAN_BR_X SANE_NAME_SCAN_BR_Y SANE_NAME_SCAN_RESOLUTION SANE_NAME_SCAN_X_RESOLUTION SANE_NAME_SCAN_Y_RESOLUTION SANE_NAME_PAGE_WIDTH SANE_NAME_PAGE_HEIGHT SANE_NAME_CUSTOM_GAMMA SANE_NAME_GAMMA_VECTOR SANE_NAME_GAMMA_VECTOR_R SANE_NAME_GAMMA_VECTOR_G SANE_NAME_GAMMA_VECTOR_B SANE_NAME_BRIGHTNESS SANE_NAME_CONTRAST SANE_NAME_GRAIN_SIZE SANE_NAME_HALFTONE SANE_NAME_BLACK_LEVEL SANE_NAME_WHITE_LEVEL SANE_NAME_WHITE_LEVEL_R SANE_NAME_WHITE_LEVEL_G SANE_NAME_WHITE_LEVEL_B SANE_NAME_SHADOW SANE_NAME_SHADOW_R SANE_NAME_SHADOW_G SANE_NAME_SHADOW_B SANE_NAME_HIGHLIGHT SANE_NAME_HIGHLIGHT_R SANE_NAME_HIGHLIGHT_G SANE_NAME_HIGHLIGHT_B SANE_NAME_HUE SANE_NAME_SATURATION SANE_NAME_FILE SANE_NAME_HALFTONE_DIMENSION SANE_NAME_HALFTONE_PATTERN SANE_NAME_RESOLUTION_BIND SANE_NAME_NEGATIVE SANE_NAME_QUALITY_CAL SANE_NAME_DOR SANE_NAME_RGB_BIND SANE_NAME_THRESHOLD SANE_NAME_ANALOG_GAMMA SANE_NAME_ANALOG_GAMMA_R SANE_NAME_ANALOG_GAMMA_G SANE_NAME_ANALOG_GAMMA_B SANE_NAME_ANALOG_GAMMA_BIND SANE_NAME_WARMUP SANE_NAME_CAL_EXPOS_TIME SANE_NAME_CAL_EXPOS_TIME_R SANE_NAME_CAL_EXPOS_TIME_G SANE_NAME_CAL_EXPOS_TIME_B SANE_NAME_SCAN_EXPOS_TIME SANE_NAME_SCAN_EXPOS_TIME_R SANE_NAME_SCAN_EXPOS_TIME_G SANE_NAME_SCAN_EXPOS_TIME_B SANE_NAME_SELECT_EXPOSURE_TIME SANE_NAME_CAL_LAMP_DEN SANE_NAME_SCAN_LAMP_DEN SANE_NAME_SELECT_LAMP_DENSITY SANE_NAME_LAMP_OFF_AT_EXIT ); our $VERSION = '0.05'; our $DEBUG = 0; our ($STATUS, $_status, $_vc); require XSLoader; XSLoader::load('Sane', $VERSION); sub get_version { if (not $_vc) { print "Running init\n" if $DEBUG; $_vc = Sane->_init; $STATUS = Sane::Status->new; return undef if ($_status); } return Sane->_get_version($_vc); } sub get_version_scalar { if (not $_vc) { print "Running init\n" if $DEBUG; $_vc = Sane->_init; $STATUS = Sane::Status->new; return undef if ($_status); } my @version = Sane->_get_version($_vc); return $version[0]+$version[1]/1000+$version[2]/1000000; } sub get_devices { if (not $_vc) { print "Running init\n" if $DEBUG; $_vc = Sane->_init; $STATUS = Sane::Status->new; return undef if ($_status); } return Sane::_get_devices(); } # todo # add simple sane methods # remove examples/test.pl # add option in test backend with quant=0 # things to report about scanimage.c: # 1. dangerous while statement at line 1460 # 2. Give them pkg-config patch # python interface is here: # http://svn.effbot.org/public/pil/Sane/sanedoc.txt package Sane::Device; use 5.008005; use strict; use warnings; sub open { my $class = shift; my $device = shift; if (not $_vc) { print "Running init\n" if $DEBUG; $_vc = Sane->_init; $STATUS = Sane::Status->new; return undef if ($_status); } $device = '' if (!$device); my $self = Sane->_open($device); return undef if ($_status); bless (\$self, $class); return \$self; } sub write_pnm_header { my ($device, $fh, $format, $width, $height, $depth) = @_; $fh = \*STDOUT if (! defined($fh)); if (! (defined $format and defined $width and defined $height and defined $depth)) { my $param = $device->get_parameters; ($format, $width, $height, $depth) = ($param->{format}, $param->{pixels_per_line}, $param->{lines}, $param->{depth}); } # The netpbm-package does not define raw image data with maxval > 255. # But writing maxval 65535 for 16bit data gives at least a chance # to read the image. # For some reason, the #defines need parentheses here, but not normally if ($format == Sane::SANE_FRAME_RED() or $format == Sane::SANE_FRAME_GREEN() or $format == Sane::SANE_FRAME_BLUE() or $format == Sane::SANE_FRAME_RGB()) { printf $fh "P6\n# SANE data follows\n%d %d\n%d\n", $width, $height, ($depth <= 8) ? 255 : 65535; } # For some reason, the #defines need parentheses here, but not normally elsif ($format == Sane::SANE_FRAME_GRAY()) { if ($depth == 1) { printf $fh "P4\n# SANE data follows\n%d %d\n", $width, $height; } else { printf $fh "P5\n# SANE data follows\n%d %d\n%d\n", $width, $height, ($depth <= 8) ? 255 : 65535; } } } package Sane::Status; use 5.008005; use strict; use warnings; use overload '0+' => \&num, '""' => \&str, fallback => 1; sub new { my $class = shift; my $self = {}; bless ($self, $class); return $self; } sub num {return($_status)} sub str {return(Sane::strstatus($_status))} 1; __END__ =head1 NAME Sane - Perl extension for the SANE (Scanner Access Now Easy) Project =head1 SYNOPSIS use Sane; my @devices = Sane->get_devices; my $device = Sane::Device->open($devices[0]->{name}); my $param = $device->get_parameters; $device->write_pnm_header($fh); my ($data, $len) = $device->read ($param->{bytes_per_line}); print $fh $data; =head1 ABSTRACT Perl bindings for the SANE (Scanner Access Now Easy) Project. This module allows you to access SANE-compatible scanners in a Perlish and object-oriented way, freeing you from the casting and memory management in C, yet remaining very close in spirit to original API. =head1 DESCRIPTION The Sane module allows a Perl developer to use SANE-compatible scanners. Find out more about SANE at L. Most methods set $Sane::STATUS, which is overloaded to give either an integer as dictated by the SANE standard, or the the corresponding message, as required. =head2 Sane->get_version Returns an array with the SANE_VERSION_(MAJOR|MINOR|BUILD) versions: join('.',Sane->get_version) =head2 Sane->get_version_scalar Returns an scalar with the SANE_VERSION_(MAJOR|MINOR|BUILD) versions combined as per the Perl version numbering, i.e. sane 1.0.19 gives 1.000019. This allows simple version comparisons. =head2 Sane->get_devices This function can be used to query the list of devices that are available. If the function executes successfully, it returns a array of hash references with the devices found. The returned list is guaranteed to remain valid until (a) another call to this function is performed or (b) a call to sane_exit() is performed. This function can be called repeatedly to detect when new devices become available. If argument local_only is true, only local devices are returned (devices directly attached to the machine that SANE is running on). If it is false, the device list includes all remote devices that are accessible to the SANE library. my @devices = Sane->get_devices; if ($Sane::STATUS == SANE_STATUS_GOOD) { print "Name: $devices[0]->{name}\n"; print "Vendor: $devices[0]->{vendor}\n"; print "Model: $devices[0]->{model}\n"; print "Type: $devices[0]->{type}\n"; } =head2 Sane::Device->open This function is used to establish a connection to a particular device. The name of the device to be opened is passed in argument name. If the call completes successfully, a Sane::Device object is returned. As a special case, specifying a zero-length string as the device requests opening the first available device (if there is such a device). my $device = Sane::Device->open($device_name); =head2 Sane::Device->get_option_descriptor This function is used to access option descriptors. The function returns a hash reference with the option descriptor for option number n of the Sane::Device object. Option number 0 is guaranteed to be a valid option. Its value is an integer that specifies the number of options that are available for the Sane::Device object (the count includes option 0). If n is not a valid option index, the function croaks. my $option = $device->get_option_descriptor($n); if ($Sane::STATUS == SANE_STATUS_GOOD) { print "Name: $option->{name}\n"; print "Name: $option->{title}\n"; print "Name: $option->{desc}\n"; print "Name: $option->{type}\n"; print "Name: $option->{unit}\n"; print "Name: $option->{cap}\n"; print "Name: $option->{max_values}\n"; print "Name: $option->{constraint_type}\n"; } The contents of the name, title, desc, type, unit, cap and constraint_type are as the C API description (L). There is a further constraint key that either contains an array with the possible option values, or a hash with max, min, and quant keys. The max_values key replaced the size key in the C API, and contains the maximum number of values that the option may contain. =head2 Sane::Device->get_option Returns the current value of the selected option. my $value = $device->get_option($n); if ($Sane::STATUS == SANE_STATUS_GOOD) { print "value: $value\n"; } For $option->{max_values} > 1, $value is a reference to an array. =head2 Sane::Device->set_auto Commands the selected device to automatically select an appropriate value. This mode remains effective until overridden by an explicit set_option request. $device->set_auto($n); =head2 Sane::Device->set_option Sets the selected option, returning flags in $info, which are described in the C API (L). $orig = $device->get_option($n); $info = $device->set_option($n, $value); if ($info & SANE_INFO_INEXACT) { $value = $device->get_option($n); print "rounded value of $opt->{name} from $orig to $value\n"; } For $option->{max_values} > 1, $value can be a reference to an array. =head2 Sane::Device->get_parameters This function is used to obtain the current scan parameters. The returned parameters are guaranteed to be accurate between the time a scan has been started (Sane::Device->start() has been called) and the completion of that request. Outside of that window, the returned values are best-effort estimates of what the parameters will be when Sane::Device->start() gets invoked. Calling this function before a scan has actually started allows, for example, to get an estimate of how big the scanned image will be. $param = $device->get_parameters; if ($Sane::STATUS == SANE_STATUS_GOOD) { print "format $param->{format}\n"; print "last_frame $param->{last_frame}\n"; print "bytes_per_line $param->{bytes_per_line}\n"; print "pixels_per_line $param->{pixels_per_line}\n"; print "lines $param->{lines}\n"; print "depth $param->{depth}\n"; } Please see the C documentation (L) for details of the above values. =head2 Sane::Device->start This function initiates aquisition of an image from the device specified. $device->start; =head2 Sane::Device->read This function is used to read image data from the device specified. The number of bytes returned in $buf is stored in $len. A backend must set this to zero when a status other than SANE_STATUS_GOOD is returned. When the call succeeds, the number of bytes returned can be anywhere in the range from 0 to maxlen bytes. $param = $device->get_parameters; $maxlen = $param->{bytes_per_line}; ($buf, $len) = $test->read ($maxlen); If this function is called when no data is available, one of two things may happen, depending on the I/O mode that is in effect for the device. =over =item 1. If the device is in blocking I/O mode (the default mode), the call blocks until at least one data byte is available (or until some error occurs). =item 2. If the device is in non-blocking I/O mode, the call returns immediately with status SANE_STATUS_GOOD and with $len set to zero. =back The I/O mode of the device can be set via a call to Sane::Device->set_io_mode(). =head2 Sane::Device->cancel This function is used to immediately or as quickly as possible cancel the currently pending operation of the device. $device->cancel; This function can be called at any time (as long as $device is valid) but usually affects long-running operations only (such as image is acquisition). It is safe to call this function asynchronously (e.g., from within a signal handler). It is important to note that completion of this operaton does not imply that the currently pending operation has been cancelled. It only guarantees that cancellation has been initiated. Cancellation completes only when the cancelled call returns (typically with a status value of SANE_STATUS_CANCELLED). Since the SANE API does not require any other operations to be re-entrant, this implies that a frontend must not call any other operation until the cancelled operation has returned. =head2 Sane::Device->set_io_mode This function is used to set the I/O mode of the device. The I/O mode can be either blocking or non-blocking. If argument $bool is SANE_TRUE, the mode is set to non-blocking mode, otherwise it's set to blocking mode. This function can be called only after a call to Sane::Device->start() has been performed. $device->set_io_mode ($bool); By default, newly opened handles operate in blocking mode. A backend may elect not to support non-blocking I/O mode. In such a case the status value SANE_STATUS_UNSUPPORTED is returned. Blocking I/O must be supported by all backends, so calling this function with SANE_FALSE is guaranteed to complete successfully. =head2 Sane::Device->get_select_fd This function is used to obtain a (platform-specific) file-descriptor for the device that is readable if and only if image data is available (i.e., when a call to Sane::Device->read() will return at least one byte of data). $fd = $device->get_select_fd; This function can be called only after a call to Sane::Device->start() has been performed and the returned file-descriptor is guaranteed to remain valid for the duration of the current image acquisition (i.e., until Sane::Device->cancel() or Sane::Device->start() get called again or until Sane::Device->read() returns with status SANE_STATUS_EOF). Indeed, a backend must guarantee to close the returned select file descriptor at the point when the next Sane::Device->read() call would return SANE_STATUS_EOF. This is necessary to ensure the application can detect when this condition occurs without actually having to call Sane::Device->read(). A backend may elect not to support this operation. In such a case, the function returns with status code SANE_STATUS_UNSUPPORTED. Note that the only operation supported by the returned file-descriptor is a host operating-system dependent test whether the file-descriptor is readable (e.g., this test can be implemented using select() or poll() under UNIX). If any other operation is performed on the file descriptor, the behavior of the backend becomes unpredictable. Once the file-descriptor signals ``readable'' status, it will remain in that state until a call to sane_read() is performed. Since many input devices are very slow, support for this operation is strongly encouraged as it permits an application to do other work while image acquisition is in progress. =head2 Sane::Device->write_pnm_header This function is a pure-Perl helper function to write a PNM header. It will fetch the current image settings using Sane::Device->get_parameters, if they are not already provided, e.g.: $device->write_pnm_header($fh); or $parm = $device->get_parameters; $device->write_pnm_header ($fh, $parm->{format}, $parm->{pixels_per_line}, $parm->{lines}, $parm->{depth}); =head1 SEE ALSO The SANE Standard Reference L is a handy companion. The Perl bindings follow the C API very closely, and the C reference documentation should be considered the canonical source. =head1 AUTHOR Jeffrey Ratcliffe, EJeffrey.Ratcliffe@gmail.comE =head1 COPYRIGHT AND LICENSE Copyright (C) 2008--2012 by Jeffrey Ratcliffe This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.5 or, at your option, any later version of Perl 5 you may have available. =cut Sane-0.05/README0000644000774200006240000000147511242253657012004 0ustar ra28145a400mcSane - Perl extension for the SANE (Scanner Access Now Easy) Project ==================================================================== This module allows you to access SANE-compatible scanners in a Perlish and object-oriented way, freeing you from the casting and memory management in C, yet remaining very close in spirit to original API. INSTALLATION To install this module type the following: perl Makefile.PL make make test make install DEPENDENCIES This module requires these other modules and libraries: libsane (>= 1.0.19) COPYRIGHT AND LICENCE Copyright (C) 2008 by Jeffrey Ratcliffe This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.5 or, at your option, any later version of Perl 5 you may have available. Sane-0.05/Makefile.PL0000644000774200006240000000260411644556624013077 0ustar ra28145a400mcuse 5.008; use ExtUtils::MakeMaker; use ExtUtils::Depends; use ExtUtils::PkgConfig; # minimum required version of dependancies we need to build our %build_reqs = ( 'libsane' => '1.0.19', ); # minimum required version of dependancies we need to run our %runtime_reqs = ( 'libsane' => '1.0.19', ); # Can't assume ExtUtils::PkgConfig will return anything useful until # the pkg-config files ship with sane. my $lib = '-lsane'; my $inc = '-I. '; if (eval { %pkgcfg = ExtUtils::PkgConfig->find ('sane-backends >= '. $build_reqs{libsane}) }) { $lib = $pkgcfg{libs}; $inc .= $pkgcfg{cflags}; $runtime_reqs{libsane} = $pkgcfg{modversion}; } # See lib/ExtUtils/MakeMaker.pm for details of how to influence # the contents of the Makefile that is written. WriteMakefile( NAME => 'Sane', VERSION_FROM => 'lib/Sane.pm', # finds $VERSION PREREQ_PM => {}, # e.g., Module::Name => 1.1 ($] >= 5.005 ? ## Add these new keywords supported since 5.005 (ABSTRACT_FROM => 'lib/Sane.pm', # retrieve abstract from module AUTHOR => 'Jeffrey Ratcliffe') : ()), LIBS => [$lib], # e.g., '-lm' DEFINE => '', # e.g., '-DHAVE_SOMETHING' INC => $inc, # e.g., '-I. -I/usr/include/other' # Un-comment this if you add C files to link with later: # OBJECT => '$(O_FILES)', # link all the C files too ); Sane-0.05/META.yml0000644000774200006240000000103611736245771012374 0ustar ra28145a400mc--- #YAML:1.0 name: Sane version: 0.05 abstract: Perl extension for the SANE (Scanner Access Now Easy) Project author: - Jeffrey Ratcliffe license: unknown distribution_type: module configure_requires: ExtUtils::MakeMaker: 0 build_requires: ExtUtils::MakeMaker: 0 requires: {} no_index: directory: - t - inc generated_by: ExtUtils::MakeMaker version 6.56 meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: 1.4