Coder Social home page Coder Social logo

stapelberg / scan2drive Goto Github PK

View Code? Open in Web Editor NEW
161.0 12.0 7.0 12.07 MB

scan paper documents šŸ“„ from a scanner šŸ–Øļø as PDFs to Google Drive for full-text search

License: Apache License 2.0

Go 47.30% JavaScript 2.32% Makefile 0.39% C++ 1.18% Dockerfile 0.04% C 48.55% Shell 0.23%
google-drive scan golang scanner

scan2drive's Introduction

scan2drive

scan2drive screenshot

scan2drive is a Go program (with a web interface) for scanning, converting and uploading physical documents to Google Drive. The author runs scan2drive as a gokrazy appliance on a Raspberry Pi 4.

During the conversion step, scan2drive skips empty pages and converts the rest from multi-megabyte JPEGs into a kilobyte-sized PDF. This allows you to use Google Driveā€™s OCR-based full text search.

Both the originals and the converted PDF are uploaded to Google Drive, so that you can enjoy full text search but still have the full-quality originals just in case.

In comparison to the native Google Drive connectivity which some document scanner vendors provide, scan2drive has these main advantages:

  1. scan2drive integrates with the scan button of your document scanner. You press one button and your documents will end up on Google Drive. Other solutions require you to use a mobile app or software on your PC.
  2. scan2drive is self-hosted and depends only on Google Drive being available, not the scanner vendorā€™s cloud integration service. Many vendors send documents into their own clouds and then to Google Drive. You are welcome to archive the scan directory of scan2drive to other places you see fit, in case there are any issues with Google Drive.
  3. scan2drive converts the scanned documents into a PDF which is small enough to be full text indexed by Google Drive, but it also retains the original JPEGs in case you need them.

Project status and vision

Currently, there are a number of open issues and not all functionality might work well. Use at your own risk!

The project vision is described above. Notably, scan2drive is already feature complete. We donā€™t want to add any more features to it than it currently has.

scan2drive was published in the hope that it could be useful to others, but the main author has no time to create an active community around it or accept contributions in a timely manner. All support, development and bug fixes are strictly best effort.

Supported scanners {#supported}

  • scan2drive can scan from any AirScan-compatible scanner. This means any scanner that is marketed as compatible with Apple iPhones should work. You can find a list of tested devices at https://github.com/stapelberg/airscan#tested-devices
  • Fujitsu ScanSnap iX500 connected via USB

Architecture

Directory structure

The scans directory (-scans_dir flag) contains the following files:

  • <sub>/ is the per-user directory under which scans are placed
  • 2016-05-09-21:05:02+0200/ is a directory for an individual scan
    • page*.jpg are the raw pages obtained by calling scanimage
    • scan.pdf is the converted PDF
    • thumb.png is the first page of the converted PDF for display in the UI
    • COMPLETE.* are empty files recording which individual processing steps are done

Any file in the scans directory can be deleted at will, with the caveat that deleting scans before the COMPLETE.uploadoriginals file is present will result in that scan being irrevocably lost.

The state directory (-state_dir flag) contains the following files:

  • cookies.key is a secret key with which cookies are encrypted
  • sessions/ contains session contents
  • users/ is a directory containing per-user data
  • users/<sub>/ is a directory for an individual user
    • drive_folder.json contains information about the selected destination Google Drive folder. In case this file is deleted, the user will need to re-select the destination folder and scans cannot be uploaded until a new destination folder has been selected.
    • token.json contains the offline OAuth token for accessing Google Drive on behalf of the user. In case this file is deleted, the user will need to re-login. In case this file is leaked, the user should revoke the token

Installation

First, follow the gokrazy quickstart instructions.

Then, add github.com/stapelberg/scan2drive/cmd/scan2drive package to your gokrazy instance:

gok -i scanner add github.com/stapelberg/scan2drive/cmd/scan2drive

Deploy your gokrazy instance to your Raspberry Pi and connect a supported scanner.

You should be able to access the gokrazy web interface at the URL which the gok tool printed. To access the scan2drive web interface, switch to port 7120.

For setting up Google OAuth, youā€™ll need to access scan2drive via a domain name with a valid TLS certificate. scan2drive has builtin support to obtain free certificates from Letā€™s Encrypt, but you do need to make your scan2drive installation reachable over the internet for this to work:

  1. If your provider offers IPv6, set your domain nameā€™s AAAA record to point to your Raspberry Piā€™s internet-reachable IPv6 address.
  2. If you donā€™t have IPv6 available, set up a port forwarding on your router and use Dynamic DNS to make your domain name point to your current IP address.

Building with libjpeg-turbo

libjpeg-turbo is a JPEG image codec that uses SIMD instructions (Arm Neon in case of the Raspberry Pi) to accelerate baseline JPEG compression.

scan2drive can optionally make use of libjpeg-turbo (via the turbojpeg build tag), but doesnā€™t include it by default because of the cumbersome setup.

Using libjpeg-turbo on gokrazy requires a few extra setup steps. Because gokrazy does not include a C runtime environment (neither libc nor a dynamic linker), we need to link scan2drive statically.

  1. Install the gcc cross compiler, for example on Debian:

    apt install crossbuild-essential-arm64
    
  2. Enable cgo for your gokrazy instance. This means setting the following environment variables when calling gok (for example in your ā€œgoklineā€, see gokrazy ā†’ Automation):

    export CC=aarch64-linux-gnu-gcc
    export CGO_ENABLED=1
    
  3. Enable static linking and the turbojpeg build tag for scan2drive in your instance config (use gok edit):

{
    "Hostname": "scanner",
    "Packages": [
        "github.com/gokrazy/fbstatus",
        "github.com/gokrazy/hello",
        "github.com/gokrazy/serial-busybox",
        "github.com/gokrazy/breakglass",
        "github.com/stapelberg/scan2drive/cmd/scan2drive"
    ],
    "PackageConfig": {
        "github.com/stapelberg/scan2drive/cmd/scan2drive": {
            "GoBuildFlags": [
                "-ldflags=-linkmode external -extldflags -static"
            ],
            "GoBuildTags": [
                "turbojpeg"
            ]
        }
    }
}

scan2drive's People

Contributors

dependabot[bot] avatar markdrayton avatar stapelberg avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

scan2drive's Issues

Unify internal/g3 with image/jpeg/writer.go

Turns out writing a JPEG image uses similar primitives as writing a G3 encoded image (e.g. run-length encoding, bitstream writing). We should have a look at which version is faster and then make them more alike.

neonjpeg-created images cannot be loaded by Go

Currently, any JPEG file that is created with neonjpeg can apparently not be loaded with the Go JPEG code: invalid JPEG format: missing 0xff00 sequence. The files can be viewed in web browsers and image viewers, so perhaps this is an issue with the Go JPEG code? Needs investigation.

eSCL (ā€œAirScanā€) support

Instead of custom drivers, it would be cool to support a broad range of devices via Appleā€™s AirScan, which is called eSCL on a technical level.

It looks like a fairly simple combination of HTTP, XML and JPEG, so should be easy enough.

I have ordered a Brother MFC-L2750DW to test.

Here are some resources:

create thumbnails asynchronously for button-triggered scans

With the scan processing speed-ups from issue #7, creating thumbnails is now the bottleneck.

While thumbnails are useful when scanning via the web UI, they are typically not looked at when using the scannerā€™s scan button. Hence, we should create them asynchronously. As thumbnail creation is part of the ā€œconvertā€ step currently, weā€™ll need to create a new step.

gokr-packer exiting with status 2 after `*grpc.ClientConn has no field or method State`

Trying to write scan2drive on to SD card. After below error old gokrazy image and apps remain.

# gokr-packer -overwrite=/dev/mmcblk0 github.com/stapelberg/scan2drive

2017/05/03 13:15:47 packer.go:225: installing [github.com/stapelberg/scan2drive]
2017/05/03 13:15:47 gotool.go:60: getting incomplete packages [github.com/stapelberg/scan2drive]
# github.com/stapelberg/scan2drive
go/src/github.com/stapelberg/scan2drive/main.go:410: scanConn.State undefined (type *grpc.ClientConn has no field or method State)
2017/05/03 13:19:02 packer.go:228: exit status 2

Unable to read client secret file: open /perm/client_secret_...

gokrazy loops on starting scan2drive, which remains restarting.
from stderr:

  2017/05/04 09:02:43 gokrazy: attempt 357, starting [/user/scan2dri]
  2017/05/04 09:02:43 Unable to read client secret file: open /perm/client_secret_197950901230-jee3asvone1tnh7k2qsshm369723vkun.apps.googleusercontent.com.json: no such file or directory
  2017/05/04 09:02:44 gokrazy: exit status 1

Please tell me if I can gather more info about this issue (file system permissions, install breakglass etc).

Edit: /perm is empty.

Update Google Drive Libraries

Hello, thanks for open sourcing this project!

I'm attempting to get it running on a rpi4

When attempting to bring up the google drive connection I'm getting this error:

can2driveā€™s purpose is to store scans on Google Drive, so please

Error idpiframe_initialization_failed: You have created a new client application that uses libraries for user authentication or authorization that will soon be deprecated. New clients must use the new libraries instead; existing clients must also migrate before these libraries are deprecated. See the [Migration Guide](https://developers.google.com/identity/gsi/web/guides/gis-migration) for more information.

Investigate using ARM NEON instructions to speed up image processing

http://hilbert-space.de/?p=22 contains examples for how one could approach converting from color to grayscale.

We currently perform the following operations:

  • (3s) binarization (color ā†’ black/white)
  • (5s) rotating by 180 degrees
  • (4s) g3 compression
  • (15s) JPEG encoding
  • (TODO) PNG encoding of the first page (thumbnail)

Binarization and rotation should be easy to implement, but also provide the smallest wins. Making JPEG encoding faster seems like the biggest win, but Iā€™m not sure if thatā€™s possible.

race condition: setup mode redirect might run into transient HTTP 404

This is because the default listeners are set up way later than the redirect happens.

Iā€™m not entirely sure yet how to fix this properly: possibly we need another state in the setupMux to delay responses until the handlers are set up. Or maybe there is a more elegant solution :).

As a workaround, reloading the page helps.

main.go:846: undefined: s

Could reproduce this, also after deleting go/src/github.com/stapelberg/scan2drive

$ gokr-packer -overwrite=/dev/mmcblk0 github.com/stapelberg/scan2drive
2017/05/18 19:31:37 packer.go:225: installing [github.com/stapelberg/scan2drive]
2017/05/18 19:31:37 gotool.go:60: getting incomplete packages [github.com/stapelberg/scan2drive]
# github.com/stapelberg/scan2drive
src/github.com/stapelberg/scan2drive/main.go:846: undefined: s
src/github.com/stapelberg/scan2drive/main.go:847: undefined: s in s.Serve
2017/05/18 19:34:48 packer.go:228: exit status 2

Consider supporting other authentication providers and sinks

Currently, Google Drive is used both as a scan sink, and as an authentication provider.

This is convenient for users: you only need to log in once to grant permission to write scans, and to authenticate to scan2drive.

Theoretically, one could want to authenticate via tailscale and sink scans to amazon S3. This is currently not possible, and Iā€™m not entirely sure yet how to re-architect the program to make it possible without losing the convenience of using one provider for both, authentication and storing scans.

scan2drive-get-default-user takes 0.5s on ARM

This might be because CGO is disabled by default when cross-compiling? On amd64, itā€™s much quicker, and strace on arm doesnā€™t show anything but futex calls during the time when the program just seems to sit there.

scan2drive doesn't append DNSSD Domain to scanner service for Avahi-style name resolution

Currently scan2drive just tries to access the scanner directly from the hostname found in its DNSSD service description:

sourceFinder.sources[srv.Host] = &AirscanSource{
name: unescapedName,
host: srv.Host,
iconURL: srv.Text["representation"],
}

Whereas the original airscan also takes the Domain from the DNSSD response and attempts to connect to it by that:
https://github.com/stapelberg/airscan/blob/9b9f6be23a95c8c8f33e69a3aabeb45e62f7425d/airscan.go#L334-L340

settings panel does not show

Not sure why/when this broke. When clicking the icon, the translucent overlay appears, but no dialog.

Issue #3 might be related.

Listen address/oauth redirect trouble

I'm having some trouble with listen addresses and oauth redirect URLs. I'm sure I am missing something obvious.

From https://github.com/stapelberg/scan2drive/blob/main/README.md:

You should be able to access the gokrazy web interface at the URL which the gok tool printed. To access the scan2drive web interface, switch to port 7120.

By default scan2drive listens on localhost which is (obviously) not reachable over the network. I noticed there were some recent changes around this code (e.g. a33d0c6) but from a quick glance it doesn't seem anything has changed much, so I don't understand how it'd have ever been possible to hit port 7120 from another host. Is there something fundamental that I'm misunderstanding about how this part works?

I then tried -http_listen_address=gokrazy.lan:7120 (my gokrazy's instance hostname), which allowed me to reach the UI, but Google then gave me this error when I tried to sign in:

device_id and device_name are required for private IP: http://192.168.x.y:7120/oauth

It feels like I'll need to somehow provide an internet-reachable address to which Google can redirect me once authenticated, unless I'm completely lost.

Any clues?

Support airscan-only operation on MacOS?

Currently scan2drive only runs on Linux due to the usb support for fss500. However, a simple change to scan2drive.go to only add the fss500 finder on Linux and a stub could fix that to permit operation on MacOS:

diff --git a/cmd/scan2drive/scan2drive.go b/cmd/scan2drive/scan2drive.go
index d553434..c51e86e 100644
--- a/cmd/scan2drive/scan2drive.go
+++ b/cmd/scan2drive/scan2drive.go
@@ -25,6 +25,7 @@ import (
 	"net/http"
 	"os"
 	"path/filepath"
+	"runtime"
 	"strings"
 	"time"
 
@@ -276,7 +277,7 @@ func logic() error {
 
 	var finders []scan2drive.ScanSourceFinder
 	finders = append(finders, airscan.SourceFinder())
-	{
+	if runtime.GOOS == "linux" {
 		finders = append(finders, fss500.SourceFinder(ingesterForDefault))
 	}
 
diff --git a/internal/fss500/usb/usb_darwin.go b/internal/fss500/usb/usb_darwin.go
new file mode 100644
index 0000000..04b8bd9
--- /dev/null
+++ b/internal/fss500/usb/usb_darwin.go
@@ -0,0 +1,21 @@
+package usb
+
+import "errors"
+
+type Device struct{}
+
+func (u *Device) Read(p []byte) (n int, err error) {
+	return -1, errors.New("usb access to fss500 is not supported on MacOS")
+}
+
+func (u *Device) Write(p []byte) (n int, err error) {
+	return -1, errors.New("usb access to fss500 is not supported on MacOS")
+}
+
+func (u *Device) Close() error {
+	return nil
+}
+
+func FindDevice() (*Device, error) {
+	return nil, errors.New("usb access to fss500 is not supported on MacOS")
+}

Would this be reasonable?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    šŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. šŸ“ŠšŸ“ˆšŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ā¤ļø Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.