Anything DIY

SANE on FreeBSD - connecting two scanners, control VIA HTML

Post Reply
other / anything     Views: 971Prev .. Next
SANE on FreeBSD - connecting two scanners, control VIA HTMLPosted: Friday, July 3, 2020 [12:35:32] - 1
rootPosted by:rootMember Since:
June 16 2010
Posts: 357
FreeBSD on Intel NUC is easy!
Check out OS installation page:
www.codemacs.com/other/an..

Next, we need to control two CanoScan LiDE 300 scanners to do an open book style scans.

SANE on FreeBSD - connecting two scanners, control VIA HTML

After OS installation ports collection is installed with:
View Codeportsnap fetch
portsnap extract # for the first time installation
or
portsnap fetch update


Then install portsmaster to make life easier:
View Code# cd /usr/ports/ports-mgmt/portmaster && make install clean


Next we need to install Perl (yes, it is our weapon of choice);
View Codeportmaster -d lang/perl5.30 && make install clean


Now we need to install Apache Web server (NGINX would work as well):
View Codeportmaster -d www/apache24 && make install clean


For light image manipulation ImageMagick (convert) is installed:
View Codeportmaster -d graphics/ImageMagick7-nox11 && make install clean

since we do not use X11 Windows we don't need anything related to it.

and now SANE backends:
View Codeportmaster -d graphics/sane-backends && make install clean


Next we need to make sure we can use scanners from Apache. For this we need proper user/group/permissions.
This is a good source:
www.freebsd.org/doc/handb..

This example creates a group called usb:

View Code# pw groupadd usb


Then, make the /dev/ugen0.2 symlink and the /dev/usb/0.2.0 device node accessible to the usb group with write permissions of 0660 or 0664 by adding the following lines to /etc/devfs.rules:
View Code
[system=5]
add path ugen0.2 mode 0660 group usb
add path usb/0.2.0 mode 0666 group usb

Note: It happens the device node changes with the addition or removal of devices, so one may want to give access to all USB devices using this ruleset instead:
View Code[system=5]
add path 'ugen*' mode 0660 group usb
add path 'usb/*' mode 0666 group usb

Refer to devfs.rules(5) for more information about this file.

Next, enable the ruleset in /etc/rc.conf:

View Codedevfs_system_ruleset="system"

And, restart the devfs(8) system:

View Code# service devfs restart

Finally, add the users to usb in order to allow access to the scanner:

View Code# pw groupmod usb -m webserver

instead of user "webserver" use the one set in Apache config file.

Next - web interface access to scanners.There's no place like ~
SANE on FreeBSD Web interfacePosted: Friday, July 3, 2020 [12:50:20] - 2
rootPosted by:rootMember Since:
June 16 2010
Posts: 357
When SANE permissions are properly set and scanners working from Terminal a simple Web interface can be set to scan.
This is a web page:
View Code
<!DOCTYPE html>
<html dir="ltr" lang="en-US">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Scannin</title>
<link rel="profile" href="https://gmpg.org/xfn/11">
<meta name="theme-color" content="#ffffff">
<link rel="icon" href="/favicon.ico" type="image/x-icon" />
<link rel="stylesheet" type="text/css" href="/css/all.css" media="screen" />
<script>
function formsubmit(frm) {
var col = document.getElementById(frm).elements["color"].value;
var scan = document.getElementById(frm).elements["scanner"].value;
var img = 'image' + scan;
var scanimgs = 'Scanning..<br /><img src="/scanning.gif">';
document.getElementById(img).style.display="inline-block";
document.getElementById(img).innerHTML = scanimgs;
var url = '/scan.cgi?c=' + col + '&s=' + scan;
request = new XMLHttpRequest();
try {
request.onreadystatechange = function() {
if (request.readyState == 4) {
var val = request.responseText;
document.getElementById(img).innerHTML = val;
document.getElementById(img).style.display="inline-block";
}
}
request.open("GET", url, true);
request.send();
}
catch (e) {
alert("Unable to connect to server - Scanner" + scan);
}
}

function formsubmit2(frm) {
var cols = document.getElementById(frm).elements["color"].value;
var scans = document.getElementById(frm).elements["scanner"].value;
var imgs = 'image' + scans;
var scanimg = 'Scanning..<br /><img src="/scanning.gif">';
document.getElementById(imgs).style.display="inline-block";
document.getElementById(imgs).innerHTML = scanimg
var urls = '/scan.cgi?c=' + cols + '&s=' + scans;
xhr = new XMLHttpRequest();
try {
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
var vals = xhr.responseText;
document.getElementById(imgs).innerHTML = vals;
document.getElementById(imgs).style.display="inline-block";
}
}
xhr.open("GET", urls, true);
xhr.send();
}
catch (e) {
alert("Unable to connect to server - Scanner" + scans);
}
}
</script>
</head>
<body>
<div id="content">
<h1>Scanning images</h1>
<div id="headimages">
<div id="image1" style="display:none;"></div>
<div id="image2" style="display:none;"></div>
</div>
<div id="forms">
<div id="forms1">
<h4>Left Page</h4>
<form id="scan1">
<input type="radio" name="color" id="color11" value="gray" checked> <label for="color11">Gray</label>
<input type="radio" name="color" id="color21" value="color"> <label for="color21">Color</label>
<input type="radio" name="color" id="color31" value="noscan"> <label for="color31">No Scan</label>
<input type="hidden" name="scanner" value="1">
</form>
</div><!-- form 1-->
<div id="forms2">
<h4>Right Page</h4>
<form id="scan2">
<input type="radio" name="color" id="color12" value="gray" checked> <label for="color12">Gray</label>
<input type="radio" name="color" id="color22" value="color"> <label for="color22">Color</label>
<input type="radio" name="color" id="color32" value="noscan"> <label for="color32">No Scan</label>
<input type="hidden" name="scanner" value="2">
</form>
</div><!-- form 2-->
</div><!-- forms-->
<div id="fsubm">
<a href="#" class="myButton" onclick="formsubmit('scan1');formsubmit2('scan2');return false;">Scan</a>
</div>
</div><!-- content-->
</body>
</html>

It uses two Ajax requests to send scan requests. Why two - we're not that proficient in JS and went with simple solution. It works.

Here is the Perl script that actually handles scanning:
View Code#!/usr/local/bin/perl
use strict;
our %in=();
eval {require '/home/scan/cgi-bin/cgi-lib.pl'};
unless($@) {&ReadParse;}

# Define hashes to properly show results and access scanners
my %pgs = (1,'Left Page',2,'Right Page');
my %scanners = ( ## Defines scanners
1,'pixma:04A91913_XXXXX1',
2,'pixma:04A91913_XXXXX2');
my %colorsby = ('gray','Gray',
'color','Color');

unless($colorsby{$in{c}}) {print "Content-type: text/html\n\n$pgs{$in{s}}<br />\nNot Scanned<br /><img src=\"scanner.open.png\">";exit(0);}
my $imn = time;
`scanimage --mode $colorsby{$in{c}} --device-name=$scanners{$in{s}} --resolution 300 --format=tiff > /tmp/scans/$imn.$in{s}.tif`;
if(-f "/tmp/scans/$imn.$in{s}.tif") {`chmod 777 /tmp/scans/$imn.$in{s}.tif`;}

my $printImage='';
if(-f "/tmp/scans/$imn.$in{s}.tif") { # Make small image to show what was scanned on a screen
`convert -density 72 /tmp/scans/$imn.$in{s}.tif -resize x400 /home/scan/http/images/$imn.$in{s}.jpg`;
$printImage = "<img src=\"/images/$imn.$in{s}.jpg\" alt=\"$pgs{$in{s}}\">\n";
} ## END FILE PRESENT

print "Content-type: text/html\n\n$pgs{$in{s}}<br />\n$printImage";exit(0);

as simple as thatThere's no place like ~
SANE on FreeBSD - Web interface CSS filePosted: Friday, July 3, 2020 [13:01:40] - 3
rootPosted by:rootMember Since:
June 16 2010
Posts: 357
This is CSS file for the web interface:
SANE on FreeBSD - Web interface CSS file
View Codehtml, body {
margin: 0;
padding: 0;
background-color: #fff;
color: #090909;
font: 1em Exo, sans-serif, Corbel, Calibri, Helvetica, Arial
}

#content {
margin: 0;
padding: 0 2em;
text-align: center;
}

a {
color: #ef5a00;
text-decoration: none
}

a:hover {
color: #ff6900;
background-color: #d0d0d0
}

a:visited {
color: #d34c00
}

h1 {
font-size: 2em;
color: #6792c5;
}

#headimages img {
float: left;
display: inline-block;
margin-right: 2em;
margin-top: 1em;
}

#forms {
width: 80%;
margin: 2em auto;
clear: both;
display: block;
overflow: auto;
}

#forms input[type=radio]{
opacity: 0;
position: fixed;
width: 0;
text-align: center;
}

#forms label {
display: block;
background-color: #f1f0f2;
padding: 10px 20px;
font-family: sans-serif, Arial;
font-size: 16px;
border: 2px solid #f1f0f2;
border-radius: 4px;
width: 80px;
text-align: center;
margin-bottom: 5px;
}

#forms input[type="radio"]:checked +label {
background: rgba(226,226,226,1);
background: -moz-linear-gradient(top, rgba(226,226,226,1) 0%, rgba(219,219,219,1) 50%, rgba(209,209,209,1) 51%, rgba(254,254,254,1) 100%);
background: -webkit-gradient(left top, left bottom, color-stop(0%, rgba(226,226,226,1)), color-stop(50%, rgba(219,219,219,1)), color-stop(51%, rgba(209,209,209,1)), color-stop(100%, rgba(254,254,254,1)));
background: -webkit-linear-gradient(top, rgba(226,226,226,1) 0%, rgba(219,219,219,1) 50%, rgba(209,209,209,1) 51%, rgba(254,254,254,1) 100%);
background: -o-linear-gradient(top, rgba(226,226,226,1) 0%, rgba(219,219,219,1) 50%, rgba(209,209,209,1) 51%, rgba(254,254,254,1) 100%);
background: -ms-linear-gradient(top, rgba(226,226,226,1) 0%, rgba(219,219,219,1) 50%, rgba(209,209,209,1) 51%, rgba(254,254,254,1) 100%);
background: linear-gradient(to bottom, rgba(226,226,226,1) 0%, rgba(219,219,219,1) 50%, rgba(209,209,209,1) 51%, rgba(254,254,254,1) 100%);
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#e2e2e2', endColorstr='#fefefe', GradientType=0 );
border-color: #828784;
}

input#color11:checked +label, input#color12:checked +label {
background-color: #fbf9ff!important;
border-color: #444!important;
}
input#color21:checked +label, input#color22:checked +label {
background: rgba(239,197,202,1)!important;
background: -moz-linear-gradient(top, rgba(239,197,202,1) 0%, rgba(210,75,90,1) 50%, rgba(186,39,55,1) 51%, rgba(241,142,153,1) 100%)!important;
background: -webkit-gradient(left top, left bottom, color-stop(0%, rgba(239,197,202,1)), color-stop(50%, rgba(210,75,90,1)), color-stop(51%, rgba(186,39,55,1)), color-stop(100%, rgba(241,142,153,1)))!important;
background: -webkit-linear-gradient(top, rgba(239,197,202,1) 0%, rgba(210,75,90,1) 50%, rgba(186,39,55,1) 51%, rgba(241,142,153,1) 100%)!important;
background: -o-linear-gradient(top, rgba(239,197,202,1) 0%, rgba(210,75,90,1) 50%, rgba(186,39,55,1) 51%, rgba(241,142,153,1) 100%)!important;
background: -ms-linear-gradient(top, rgba(239,197,202,1) 0%, rgba(210,75,90,1) 50%, rgba(186,39,55,1) 51%, rgba(241,142,153,1) 100%)!important;
background: linear-gradient(to bottom, rgba(239,197,202,1) 0%, rgba(210,75,90,1) 50%, rgba(186,39,55,1) 51%, rgba(241,142,153,1) 100%)!important;
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#efc5ca', endColorstr='#f18e99', GradientType=0 )!important;
border-color: #444!important;
color: #fff!important;
}

input#color31:checked +label, input#color32:checked +label {
background: rgba(255,255,255,1)!important;
background: -moz-linear-gradient(top, rgba(255,255,255,1) 0%, rgba(246,246,246,1) 47%, rgba(237,237,237,1) 100%)!important;
background: -webkit-gradient(left top, left bottom, color-stop(0%, rgba(255,255,255,1)), color-stop(47%, rgba(246,246,246,1)), color-stop(100%, rgba(237,237,237,1)))!important;
background: -webkit-linear-gradient(top, rgba(255,255,255,1) 0%, rgba(246,246,246,1) 47%, rgba(237,237,237,1) 100%)!important;
background: -o-linear-gradient(top, rgba(255,255,255,1) 0%, rgba(246,246,246,1) 47%, rgba(237,237,237,1) 100%)!important;
background: -ms-linear-gradient(top, rgba(255,255,255,1) 0%, rgba(246,246,246,1) 47%, rgba(237,237,237,1) 100%)!important;
background: linear-gradient(to bottom, rgba(255,255,255,1) 0%, rgba(246,246,246,1) 47%, rgba(237,237,237,1) 100%)!important;
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#ededed', GradientType=0 )!important;
border-color: #444!important;
color: #c1c1c2!important;
}

#forms input[type="radio"]:focus + label {
border: 2px solid #444;
}

#forms h4 {
font-weight: normal;
font-style: normal;
font-size: 1.3em;
margin-top: 0;
margin-bottom: 15px;
}

#forms1 {
float: left;
display: inline-block;
width: 40%;
margin-right: 2em;
border: 1px solid #c2c2c2;
}

#forms2 {
float: left;
display: inline-block;
width: 40%;
border: 1px solid #c2c2c2;
}

#forms1,#forms2 {
padding: 20px;
}

#fsubm {
margin-top: 2em;
text-align: center;
display: block;
margin-bottom: 4em;
}

,cl {
min-height: 1em;
clear: both;
}

.myButton {
box-shadow: 0px 0px 0px 2px #9fb4f2;
background: linear-gradient(to bottom, #7892c2 5%, #476e9e 100%);
background-color: #7892c2;
border-radius: 10px;
border: 1px solid #4e6096;
display: inline-block;
cursor: pointer;
color: #fff;
font-family: Arial;
font-size: 28px;
font-weight: bold;
padding: 12px 37px;
text-decoration: none;
text-shadow: 0px 1px 0px #283966;
}

.myButton:hover {
background: linear-gradient(to bottom, #476e9e 5%, #7892c2 100%);
background-color: #476e9e;
color: #faf9fb;
}

.myButton:active {
position: relative;
top: 1px;
}

just to make it easierThere's no place like ~
RE: SANE on FreeBSD - connecting two scanners, control VIA HTMLPosted: Thursday, May 11, 2023 [23:58:42] - 4
rootPosted by:rootMember Since:
June 16 2010
Posts: 357
This FreeBSD setup works great with Canon imageFORMULA DR-9080C scanner:
www.codemacs.com/other/an..
It was very simple to add new scanner to the settings.There's no place like ~
other / anythingPrev .. Next
 
Post Reply
Home - Other: Anything DIY
Our Telegram Group