ソースを参照

support for single page TEXT mode scans with MFC-7820N exporting as DEFLATE compressed TIFF

Corey Smith 4 年 前
コミット
67f0b6502d
6 ファイル変更87 行追加56 行削除
  1. 3 1
      go.mod
  2. 2 0
      go.sum
  3. 70 43
      src/backend.go
  4. 5 5
      src/definitions.go
  5. 6 6
      src/main.go
  6. 1 1
      src/utils.go

+ 3 - 1
go.mod

@@ -1,3 +1,5 @@
-module github.com/corsmith/mfc-7820n
+module github.com/v0lp3/mfc_j430w
 
 go 1.17
+
+require golang.org/x/image v0.0.0-20211028202545-6944b10bf410 // indirect

+ 2 - 0
go.sum

@@ -0,0 +1,2 @@
+golang.org/x/image v0.0.0-20211028202545-6944b10bf410 h1:hTftEOvwiOq2+O8k2D5/Q7COC7k5Qcrgc2TFURJYnvQ=
+golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=

+ 70 - 43
src/backend.go

@@ -4,32 +4,42 @@ import (
 	"encoding/binary"
 	"fmt"
 	"image"
-	"image/png"
+	"golang.org/x/image/tiff"
 	"log"
 	"net"
 	"os"
 	"time"
 )
 
-func Scan(brotherIP string, brotherPort int, resolution int, color string, adf bool) ([][]byte, int, int) {
-	log.Println("Valid IP address, opening socket...")
+func Scan(brotherIP string, brotherPort int, resolution int, color string, rawinput string) ([][]byte, int, int) {
+	if rawinput == "" {
+		log.Println("Valid IP address, opening socket...")
 
-	socket, err := net.Dial("tcp", fmt.Sprintf("%s:%d", brotherIP, brotherPort))
+		socket, err := net.Dial("tcp", fmt.Sprintf("%s:%d", brotherIP, brotherPort))
 
-	HandleError(err)
-
-	defer socket.Close()
+		HandleError(err)
 
-	width, heigth := sendRequest(socket, resolution, color, adf)
+		defer socket.Close()
 
-	bytes, err := getScanBytes(socket)
+		width, height := sendRequest(socket, resolution, color)
+		bytes, err := getScanBytes(socket)
 
-	HandleError(err)
+		HandleError(err)
+		err = os.WriteFile(".rawbytes", bytes, 0644)
+		HandleError(err)
+		return removeHeaders(bytes), width, height
+	} else {
+		log.Println("Bypassing socket...")
+		width := 1648
+		height := 2287
 
-	return removeHeaders(bytes), width, heigth
+		bytes, err := os.ReadFile(rawinput)
+		HandleError(err)
+		return removeHeaders(bytes), width, height
+	}
 }
 
-func sendRequest(socket net.Conn, resolution int, _mode string, adf bool) (int, int) {
+func sendRequest(socket net.Conn, resolution int, _mode string) (int, int) {
 
 	mode, compression := getCompressionMode(_mode)
 
@@ -48,15 +58,6 @@ func sendRequest(socket net.Conn, resolution int, _mode string, adf bool) (int,
 
 	offer := readPacket(socket)
 
-	if !adf {
-		log.Println("Disabling automatic document feeder (ADF)")
-
-		request = []byte(formats.disableADF)
-		sendPacket(socket, request)
-
-		readPacket(socket)
-	}
-
 	log.Println("Sending scan request...")
 
 	width, height := 0, 0
@@ -64,14 +65,9 @@ func sendRequest(socket net.Conn, resolution int, _mode string, adf bool) (int,
 	dpiX, dpiY := 0, 0
 	adfStatus := 0
 
-	fmt.Sscanf(offer[3:], "%d,%d,%d,%d,%d,%d,%d", &dpiX, &dpiY, &adfStatus, &planeWidth, &width, &planeHeight, &height)
-
-	if planeHeight == 0 {
-		planeHeight = scanner.A4height
-	}
+	fmt.Sscanf(offer[2:], "%d,%d,%d,%d,%d,%d,%d", &dpiX, &dpiY, &adfStatus, &planeWidth, &width, &planeHeight, &height)
 
-	width = mmToPixels(planeWidth, dpiX)
-	height = mmToPixels(planeHeight, dpiY)
+	log.Println("Sending scan request dpiX, dpiY", dpiX, dpiY)
 
 	request = []byte(fmt.Sprintf(formats.scanRequest, dpiX, dpiY, mode, compression, width, height))
 
@@ -101,6 +97,10 @@ readPackets:
 
 		case nil:
 			scanBytes = append(scanBytes, packet[:bytes]...)
+			if bytes == 1 && packet[0] == scanner.endScan {
+				log.Println("Scan received...")
+				break readPackets
+			}
 
 		default:
 			HandleError(err)
@@ -111,6 +111,8 @@ readPackets:
 		return scanBytes, fmt.Errorf("no data received")
 	}
 
+	log.Println("Captured %d bytes...", len(scanBytes))
+
 	return scanBytes, nil
 }
 
@@ -118,28 +120,43 @@ func SaveImage(data []byte, width int, height int, name string, color string) {
 
 	log.Println("Saving image...")
 
+	/* fix height based on actual scan lines received */
+	actualheight := (len(data) * 8) / width
 	_, compression := getCompressionMode(color)
 
 	if compression != scanner.compression.jpeg {
 
 		img := image.NewGray(image.Rectangle{
 			image.Point{0, 0},
-			image.Point{width, height},
+			image.Point{width, actualheight},
 		})
 
-		for y := 0; y < height; y++ {
-			for x := 0; x < width; x++ {
-				img.SetGray(x, y, colorToGray(data[(y*width+x)%len(data)]))
+		for i := 0; i < len(data); i++ {
+			transx := (i * 8) % width
+			transy := ((i * 8) / width)
+			for o := 0; o < 8; o++ {
+				sample := data[i] & (1 << o)
+				if sample > 0 {
+					sample = 255
+				}
+				img.SetGray(transx + (7 - o), transy, colorToGray(sample))
 			}
 		}
 
 		file, err := os.Create(name)
 		HandleError(err)
 
-		png.Encode(file, img)
+		var options tiff.Options = tiff.Options{
+			Compression: tiff.Deflate,
+			Predictor: true,
+		}
 
-	} else {
+		err = tiff.Encode(file, img, &options)
 
+		rawName := fmt.Sprintf("%s.raw", name)
+		err = os.WriteFile(rawName, data, 0644)
+		HandleError(err)
+	} else {
 		err := os.WriteFile(name, data, 0644)
 		HandleError(err)
 	}
@@ -156,10 +173,15 @@ func removeHeaders(data []byte) [][]byte {
 
 headersLoop:
 	for {
-		if data[i] == scanner.endPage {
+		if data[i] == scanner.endScan {
+			log.Println("End Scan...")
+			pages = append(pages, page)
+			break headersLoop
+		} else if data[i] == scanner.endPage {
+			log.Println("End Page...")
 			pages = append(pages, page)
 
-			if len(data) > i+10 && data[i+10] == scanner.endScan {
+			if len(data) > i+1 && data[i+1] == scanner.endScan {
 				break headersLoop
 			}
 
@@ -169,14 +191,19 @@ headersLoop:
 
 			i += scanner.headerLen - 2
 			continue headersLoop
+		} else if data[i] == scanner.startGray {
+			payloadLen := binary.LittleEndian.Uint16(data[i+1 : i+3])
+			// log.Println("... process record", fmt.Sprintf("%#04x", payloadLen))
+			chunkSize := int(payloadLen)
+
+			page = append(page, data[i+scanner.headerLen:i+scanner.headerLen+chunkSize]...)
+
+			i += chunkSize + scanner.headerLen
+		} else {
+			// This is an error
+			log.Fatalln("Invalid header type.  Giving up...")
+			break headersLoop
 		}
-
-		payloadLen := binary.LittleEndian.Uint16(data[i+scanner.headerLen-2 : i+scanner.headerLen])
-		chunkSize := int(payloadLen) + scanner.headerLen
-
-		page = append(page, data[i+scanner.headerLen:i+chunkSize]...)
-
-		i += chunkSize
 	}
 
 	return pages

+ 5 - 5
src/definitions.go

@@ -2,7 +2,6 @@ package main
 
 type requests struct {
 	leaseRequest string
-	disableADF   string
 	scanRequest  string
 }
 
@@ -25,27 +24,28 @@ type constants struct {
 	mmInch      float32
 	endPage     byte
 	endScan     byte
+	startGray   byte
 }
 
 var scanner constants = constants{
 	ready: "+OK 200",
 	mode: modes{
 		color:     "CGRAY",
-		grayscale: "GRAY64",
+		grayscale: "TEXT",
 	},
 	compression: encode{
 		jpeg: "JPEG",
 		none: "NONE",
 	},
-	headerLen: 0xc,
+	headerLen: 3,
 	A4height:  294,
 	mmInch:    25.4,
 	endPage:   0x82,
 	endScan:   0x80,
+	startGray: 0x40,
 }
 
 var formats requests = requests{
 	leaseRequest: "\x1bI\nR=%d,%d\nM=%s\n\x80",
-	disableADF:   "\x1bD\nADF\n\x80",
-	scanRequest:  "\x1bX\nR=%v,%v\nM=%s\nC=%s\nJ=MID\nB=50\nN=50\nA=0,0,%d,%d\n\x80",
+	scanRequest:  "\x1bX\nR=%d,%d\nM=%s\nC=%s\nD=SIN\nB=50\nN=50\nA=0,0,%d,%d\n\x80",
 }

+ 6 - 6
src/main.go

@@ -11,9 +11,9 @@ func main() {
 
 	brotherIP := flag.String("a", "192.168.0.157", "IP address of the Brother scanner")
 	resolution := flag.Int("r", 300, "Resolution of the scan")
-	color := flag.String("c", "CGRAY", "Color mode of the scan (CGRAY, GRAY64)")
-	adf := flag.Bool("m", false, "Enable scan of all pages from feeder")
-	name := flag.String("n", "scan.jpg", "Name of the output file")
+	color := flag.String("c", "CGRAY", "Color mode of the scan (CGRAY, TEXT)")
+	name := flag.String("n", "scan.tiff", "Name of the output file")
+	rawinput := flag.String("i", "", "raw input file to parse instead of socket")
 
 	flag.Parse()
 
@@ -21,14 +21,14 @@ func main() {
 		HandleError(fmt.Errorf("invalid IP address: %s", *brotherIP))
 	}
 
-	rawImages, width, heigth := Scan(*brotherIP, brotherPort, *resolution, *color, *adf)
+	rawImages, width, height := Scan(*brotherIP, brotherPort, *resolution, *color, *rawinput)
 
 	for i, rawImage := range rawImages {
 		if i == len(rawImages)-1 {
-			SaveImage(rawImage, width, heigth, fmt.Sprintf("%s(%d)", *name, i), *color)
+			SaveImage(rawImage, width, height, fmt.Sprintf("%s-%d.tiff", *name, i), *color)
 
 		} else {
-			go SaveImage(rawImage, width, heigth, fmt.Sprintf("%s(%d)", *name, i), *color)
+			go SaveImage(rawImage, width, height, fmt.Sprintf("%s-%d.tiff", *name, i), *color)
 		}
 	}
 }

+ 1 - 1
src/utils.go

@@ -43,5 +43,5 @@ func mmToPixels(mm int, dpi int) int {
 }
 
 func colorToGray(value byte) color.Gray {
-	return color.Gray{Y: value}
+	return color.Gray{Y: value ^ 255}
 }