kopia lustrzana https://gitlab.com/sane-project/backends
Fix hpljm1005 #723
1. Fixed scan to jpeg/png 2. Fixed bottom part of the image 3. Removed white pixels from the right part of the image 4. Adjusted physical dimensions of the scanning areamerge-requests/569/merge
rodzic
aefcb71a23
commit
829b11b72e
|
@ -46,16 +46,11 @@
|
|||
#define BUILD 1
|
||||
|
||||
#include "../include/sane/config.h"
|
||||
#include <math.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <netinet/in.h>
|
||||
#define BACKEND_NAME hpljm1005
|
||||
|
@ -110,10 +105,10 @@ static int cur_idx;
|
|||
#define RGB 1
|
||||
#define GRAY 0
|
||||
|
||||
#define MAX_X_H 0x350
|
||||
#define MAX_X_H 0x351
|
||||
#define MAX_Y_H 0x490
|
||||
#define MAX_X_S 220
|
||||
#define MAX_Y_S 330
|
||||
#define MAX_X_S 216
|
||||
#define MAX_Y_S 297
|
||||
|
||||
#define OPTION_MAX 9
|
||||
|
||||
|
@ -144,6 +139,12 @@ static const SANE_String_Const mode_list[] = {
|
|||
#define STATUS_SCANNING 1
|
||||
#define STATUS_CANCELING 2
|
||||
|
||||
struct buffer_s {
|
||||
char *buffer;
|
||||
size_t w_offset;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
struct device_s
|
||||
{
|
||||
struct device_s *next;
|
||||
|
@ -151,15 +152,16 @@ struct device_s
|
|||
int idx; /* Index in the usbid array */
|
||||
int dn; /* Usb "Handle" */
|
||||
SANE_Option_Descriptor optiond[OPTION_MAX];
|
||||
char *buffer;
|
||||
int bufs;
|
||||
struct buffer_s buf_r; /* also for gray mode */
|
||||
struct buffer_s buf_g;
|
||||
struct buffer_s buf_b;
|
||||
int read_offset;
|
||||
int write_offset_r;
|
||||
int write_offset_g;
|
||||
int write_offset_b;
|
||||
int status;
|
||||
int width;
|
||||
int height;
|
||||
int height_h;
|
||||
int data_width; /* width + some padding 0xFF which should be ignored */
|
||||
int scanned_pixels;
|
||||
SANE_Word optionw[OPTION_MAX];
|
||||
uint32_t conf_data[512];
|
||||
uint32_t packet_data[512];
|
||||
|
@ -186,58 +188,6 @@ round2(double x)
|
|||
return (double)(x >= 0.0) ? (int)(x+0.5) : (int)(x-0.5);
|
||||
}
|
||||
|
||||
static void
|
||||
update_img_size (struct device_s *dev)
|
||||
{
|
||||
int dx, dy;
|
||||
|
||||
/* Only update the width when not scanning,
|
||||
* otherwise the scanner give us the correct width */
|
||||
if (dev->status == STATUS_SCANNING)
|
||||
{
|
||||
dev->height = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
dx = dev->optionw[X2_OFFSET] - dev->optionw[X1_OFFSET];
|
||||
dy = dev->optionw[Y2_OFFSET] - dev->optionw[Y1_OFFSET];
|
||||
|
||||
switch (dev->optionw[RES_OFFSET])
|
||||
{
|
||||
case 75:
|
||||
dev->width = round2 ((dx / ((double) MAX_X_S)) * 640);
|
||||
dev->height = round2 ((dy / ((double) MAX_Y_S)) * 880);
|
||||
break;
|
||||
case 100:
|
||||
dev->width = round2 ((dx / ((double) MAX_X_S)) * 848);
|
||||
dev->height = round2 ((dy / ((double) MAX_Y_S)) * 1180);
|
||||
break;
|
||||
case 150:
|
||||
dev->width = round2 ((dx / ((double) MAX_X_S)) * 1264);
|
||||
dev->height = round2 ((dy / ((double) MAX_Y_S)) * 1775);
|
||||
break;
|
||||
case 200:
|
||||
dev->width = round2 ((dx / ((double) MAX_X_S)) * 1696);
|
||||
dev->height = round2 ((dy / ((double) MAX_Y_S)) * 2351);
|
||||
break;
|
||||
case 300:
|
||||
dev->width = round2 ((dx / ((double) MAX_X_S)) * 2528);
|
||||
dev->height = round2 ((dy / ((double) MAX_Y_S)) * 3510);
|
||||
break;
|
||||
case 600:
|
||||
dev->width = round2 ((dx / ((double) MAX_X_S)) * 5088);
|
||||
dev->height = round2 ((dy / ((double) MAX_Y_S)) * 7020);
|
||||
break;
|
||||
case 1200:
|
||||
dev->width = round2 ((dx / ((double) MAX_X_S)) * 10208);
|
||||
dev->height = round2 ((dy / ((double) MAX_Y_S)) * 14025);
|
||||
break;
|
||||
}
|
||||
|
||||
DBG(2,"New image size: %dx%d\n",dev->width, dev->height);
|
||||
|
||||
}
|
||||
|
||||
/* This function is copy/pasted from the Epson backend */
|
||||
static size_t
|
||||
max_string_size (const SANE_String_Const strings[])
|
||||
|
@ -721,7 +671,6 @@ sane_get_parameters (SANE_Handle h, SANE_Parameters * p)
|
|||
p->last_frame = SANE_TRUE;
|
||||
p->depth = 8;
|
||||
|
||||
update_img_size (dev);
|
||||
p->pixels_per_line = dev->width;
|
||||
p->lines = dev->height;
|
||||
p->bytes_per_line = p->pixels_per_line;
|
||||
|
@ -805,7 +754,7 @@ send_conf (struct device_s *dev)
|
|||
dev->conf_data[21] = 0;
|
||||
dev->conf_data[22] = htonl (0x491);
|
||||
dev->conf_data[23] = htonl (0x352);
|
||||
|
||||
dev->height_h = y2 - y1;
|
||||
if (dev->optionw[COLOR_OFFSET] == RGB)
|
||||
{
|
||||
dev->conf_data[15] = htonl (0x2);
|
||||
|
@ -821,116 +770,151 @@ send_conf (struct device_s *dev)
|
|||
sanei_usb_write_bulk (dev->dn, (unsigned char *) dev->conf_data, &size);
|
||||
}
|
||||
|
||||
static SANE_Status
|
||||
get_data (struct device_s *dev)
|
||||
static SANE_Status create_buffer(struct buffer_s *buf, int buffer_size) {
|
||||
if (buf->buffer)
|
||||
{
|
||||
free(buf->buffer);
|
||||
}
|
||||
|
||||
buf->buffer = malloc(buffer_size);
|
||||
if (!buf->buffer)
|
||||
return SANE_STATUS_NO_MEM;
|
||||
buf->size = buffer_size;
|
||||
buf->w_offset = 0;
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
static SANE_Status create_buffers(struct device_s *dev, int buf_size) {
|
||||
if (create_buffer(&dev->buf_r, buf_size) != SANE_STATUS_GOOD)
|
||||
return SANE_STATUS_NO_MEM;
|
||||
if (dev->optionw[COLOR_OFFSET] == RGB)
|
||||
{
|
||||
if (create_buffer(&dev->buf_g, buf_size) != SANE_STATUS_GOOD)
|
||||
return SANE_STATUS_NO_MEM;
|
||||
if (create_buffer(&dev->buf_b, buf_size) != SANE_STATUS_GOOD)
|
||||
return SANE_STATUS_NO_MEM;
|
||||
}
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
static SANE_Status remove_buffers(struct device_s *dev) {
|
||||
if (dev->buf_r.buffer)
|
||||
free(dev->buf_r.buffer);
|
||||
if (dev->buf_g.buffer)
|
||||
free(dev->buf_g.buffer);
|
||||
if (dev->buf_b.buffer)
|
||||
free(dev->buf_b.buffer);
|
||||
dev->buf_r.w_offset = dev->buf_g.w_offset = dev->buf_b.w_offset = 0;
|
||||
dev->buf_r.size = dev->buf_g.size = dev->buf_b.size = 0;
|
||||
dev->buf_r.buffer = dev->buf_g.buffer = dev->buf_b.buffer = NULL;
|
||||
dev->read_offset = 0;
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
static SANE_Status get_data (struct device_s *dev)
|
||||
{
|
||||
int color;
|
||||
size_t size;
|
||||
int packet_size;
|
||||
unsigned char *buffer = (unsigned char *) dev->packet_data;
|
||||
if (dev->status == STATUS_IDLE)
|
||||
{
|
||||
DBG(101, "STATUS == IDLE\n");
|
||||
return SANE_STATUS_IO_ERROR;
|
||||
}
|
||||
/* first wait a standard data pkt */
|
||||
do
|
||||
{
|
||||
size = 32;
|
||||
sanei_usb_read_bulk (dev->dn, buffer, &size);
|
||||
if (size)
|
||||
{
|
||||
size = 32;
|
||||
sanei_usb_read_bulk (dev->dn, buffer, &size);
|
||||
if (size)
|
||||
{
|
||||
if (ntohl (dev->packet_data[0]) == MAGIC_NUMBER)
|
||||
{
|
||||
if (ntohl (dev->packet_data[1]) == PKT_DATA)
|
||||
break;
|
||||
if (ntohl (dev->packet_data[1]) == PKT_END_DATA)
|
||||
{
|
||||
dev->status = STATUS_IDLE;
|
||||
DBG(100,"End of scan encountered on device %s\n",dev->devname);
|
||||
send_pkt (PKT_GO_IDLE, 0, dev);
|
||||
wait_ack (dev, NULL);
|
||||
wait_ack (dev, NULL);
|
||||
send_pkt (PKT_UNKNOW_1, 0, dev);
|
||||
wait_ack (dev, NULL);
|
||||
send_pkt (PKT_RESET, 0, dev);
|
||||
sleep (2); /* Time for the scanning head to go back home */
|
||||
return SANE_STATUS_EOF;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ntohl (dev->packet_data[0]) == MAGIC_NUMBER)
|
||||
{
|
||||
if (ntohl (dev->packet_data[1]) == PKT_DATA)
|
||||
break;
|
||||
if (ntohl (dev->packet_data[1]) == PKT_END_DATA)
|
||||
{
|
||||
dev->status = STATUS_IDLE;
|
||||
DBG(100,"End of scan encountered on device %s\n",dev->devname);
|
||||
send_pkt (PKT_GO_IDLE, 0, dev);
|
||||
wait_ack (dev, NULL);
|
||||
wait_ack (dev, NULL);
|
||||
send_pkt (PKT_UNKNOW_1, 0, dev);
|
||||
wait_ack (dev, NULL);
|
||||
send_pkt (PKT_RESET, 0, dev);
|
||||
sleep (2); /* Time for the scanning head to go back home */
|
||||
return SANE_STATUS_EOF;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (1);
|
||||
} while (1);
|
||||
packet_size = ntohl (dev->packet_data[5]);
|
||||
if (!dev->buffer)
|
||||
{
|
||||
dev->bufs = packet_size - 24 /* size of header */ ;
|
||||
if (dev->optionw[COLOR_OFFSET] == RGB)
|
||||
dev->bufs *= 3;
|
||||
dev->buffer = malloc (dev->bufs);
|
||||
if (!dev->buffer)
|
||||
return SANE_STATUS_NO_MEM;
|
||||
dev->write_offset_r = 0;
|
||||
dev->write_offset_g = 1;
|
||||
dev->write_offset_b = 2;
|
||||
|
||||
}
|
||||
if (! dev->buf_r.buffer)
|
||||
{
|
||||
/*
|
||||
For some reason scanner sends packets in order:
|
||||
<start> R G B ... R G B R G B RRR GGG BBB <end>
|
||||
To hanle the last triple portion create a triple size buffer
|
||||
*/
|
||||
int buf_size = (packet_size - 24) * 3; /* 24 - size of header */ ;
|
||||
if (create_buffers(dev, buf_size) != SANE_STATUS_GOOD)
|
||||
return SANE_STATUS_NO_MEM;
|
||||
}
|
||||
/* Get the "data header" */
|
||||
do
|
||||
{
|
||||
size = 24;
|
||||
sanei_usb_read_bulk (dev->dn, buffer, &size);
|
||||
}
|
||||
while (!size);
|
||||
{
|
||||
size = 24;
|
||||
sanei_usb_read_bulk (dev->dn, buffer, &size);
|
||||
} while (!size);
|
||||
color = ntohl (dev->packet_data[0]);
|
||||
packet_size -= size;
|
||||
dev->width = ntohl (dev->packet_data[5]);
|
||||
DBG(100,"Got data size %d on device %s. Scan width: %d\n",packet_size, dev->devname, dev->width);
|
||||
dev->width = ntohl (dev->packet_data[4]);
|
||||
dev->height = dev->height_h * dev->optionw[RES_OFFSET] / 100;
|
||||
dev->data_width = ntohl (dev->packet_data[5]);
|
||||
DBG(100,"Got data size %d on device %s. Scan width: %d, data width: %d\n",packet_size, dev->devname, dev->width, dev->data_width);
|
||||
/* Now, read the data */
|
||||
do
|
||||
{
|
||||
int ret;
|
||||
do
|
||||
{
|
||||
int j;
|
||||
int i;
|
||||
int ret;
|
||||
do
|
||||
{
|
||||
size = packet_size > 512 ? 512 : packet_size;
|
||||
ret = sanei_usb_read_bulk (dev->dn, buffer, &size);
|
||||
}
|
||||
while (!size || ret != SANE_STATUS_GOOD);
|
||||
packet_size -= size;
|
||||
switch (color)
|
||||
{
|
||||
case RED_LAYER:
|
||||
DBG(101,"Got red layer data on device %s\n",dev->devname);
|
||||
i = dev->write_offset_r + 3 * size;
|
||||
if (i > dev->bufs)
|
||||
i = dev->bufs;
|
||||
for (j = 0; dev->write_offset_r < i; dev->write_offset_r += 3)
|
||||
dev->buffer[dev->write_offset_r] = buffer[j++];
|
||||
break;
|
||||
case GREEN_LAYER:
|
||||
DBG(101,"Got green layer data on device %s\n",dev->devname);
|
||||
i = dev->write_offset_g + 3 * size;
|
||||
if (i > dev->bufs)
|
||||
i = dev->bufs;
|
||||
for (j = 0; dev->write_offset_g < i; dev->write_offset_g += 3)
|
||||
dev->buffer[dev->write_offset_g] = buffer[j++];
|
||||
break;
|
||||
case BLUE_LAYER:
|
||||
DBG(101,"Got blue layer data on device %s\n",dev->devname);
|
||||
i = dev->write_offset_b + 3 * size;
|
||||
if (i > dev->bufs)
|
||||
i = dev->bufs;
|
||||
for (j = 0; dev->write_offset_b < i; dev->write_offset_b += 3)
|
||||
dev->buffer[dev->write_offset_b] = buffer[j++];
|
||||
break;
|
||||
case GRAY_LAYER:
|
||||
DBG(101,"Got gray layer data on device %s\n",dev->devname);
|
||||
if (dev->write_offset_r + (int)size >= dev->bufs)
|
||||
size = dev->bufs - dev->write_offset_r;
|
||||
memcpy (dev->buffer + dev->write_offset_r, buffer, size);
|
||||
dev->write_offset_r += size;
|
||||
break;
|
||||
}
|
||||
size = packet_size > 512 ? 512 : packet_size;
|
||||
ret = sanei_usb_read_bulk (dev->dn, buffer, &size);
|
||||
} while (!size || ret != SANE_STATUS_GOOD);
|
||||
packet_size -= size;
|
||||
struct buffer_s * current_buf;
|
||||
char color_char;
|
||||
switch (color)
|
||||
{
|
||||
case GRAY_LAYER:
|
||||
color_char = 'g';
|
||||
current_buf = &dev->buf_r;
|
||||
break;
|
||||
case RED_LAYER:
|
||||
color_char = 'R';
|
||||
current_buf = &dev->buf_r;
|
||||
break;
|
||||
case GREEN_LAYER:
|
||||
color_char = 'G';
|
||||
current_buf = &dev->buf_g;
|
||||
break;
|
||||
case BLUE_LAYER:
|
||||
color_char = 'B';
|
||||
current_buf = &dev->buf_b;
|
||||
break;
|
||||
default:
|
||||
DBG(101, "Unknown color code: %d \n", color);
|
||||
return SANE_STATUS_IO_ERROR;
|
||||
}
|
||||
DBG(101,"Got %c layer data on device %s\n", color_char, dev->devname);
|
||||
if (current_buf->w_offset + size > current_buf->size) {
|
||||
DBG(100, "buffer overflow\n");
|
||||
return SANE_STATUS_IO_ERROR;
|
||||
}
|
||||
memcpy(current_buf->buffer + current_buf->w_offset, buffer, size);
|
||||
current_buf->w_offset += size;
|
||||
}
|
||||
while (packet_size > 0);
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
@ -943,13 +927,8 @@ sane_start (SANE_Handle h)
|
|||
size_t size;
|
||||
|
||||
dev->read_offset = 0;
|
||||
dev->write_offset_r = 0;
|
||||
dev->write_offset_g = 1;
|
||||
dev->write_offset_b = 2;
|
||||
|
||||
free (dev->buffer);
|
||||
dev->buffer = NULL;
|
||||
|
||||
dev->scanned_pixels = 0;
|
||||
remove_buffers(dev);
|
||||
|
||||
send_pkt (PKT_RESET, 0, dev);
|
||||
send_pkt (PKT_READ_STATUS, 0, dev);
|
||||
|
@ -992,16 +971,12 @@ static void
|
|||
do_cancel(struct device_s *dev)
|
||||
{
|
||||
while (get_data (dev) == SANE_STATUS_GOOD);
|
||||
free (dev->buffer);
|
||||
dev->buffer = NULL;
|
||||
remove_buffers(dev);
|
||||
}
|
||||
|
||||
static int
|
||||
min3 (int r, int g, int b)
|
||||
{
|
||||
/* Optimize me ! */
|
||||
g--;
|
||||
b -= 2;
|
||||
if (r < g && r < b)
|
||||
return r;
|
||||
if (b < r && b < g)
|
||||
|
@ -1009,57 +984,83 @@ min3 (int r, int g, int b)
|
|||
return g;
|
||||
}
|
||||
|
||||
static int
|
||||
min_buf_w_offset (struct device_s * dev)
|
||||
{
|
||||
if (dev->optionw[COLOR_OFFSET] == RGB)
|
||||
return min3 (dev->buf_r.w_offset, dev->buf_g.w_offset, dev->buf_b.w_offset);
|
||||
return dev->buf_r.w_offset;
|
||||
}
|
||||
|
||||
static int is_buf_synchronized(struct device_s * dev) {
|
||||
if (dev->optionw[COLOR_OFFSET] == RGB)
|
||||
return dev->buf_r.w_offset == dev->buf_g.w_offset
|
||||
&& dev->buf_r.w_offset == dev->buf_b.w_offset;
|
||||
return 1;
|
||||
}
|
||||
|
||||
SANE_Status
|
||||
sane_read (SANE_Handle h, SANE_Byte * buf, SANE_Int maxlen, SANE_Int * len)
|
||||
{
|
||||
struct device_s *dev = (struct device_s *) h;
|
||||
int available;
|
||||
int ret;
|
||||
if (dev->optionw[COLOR_OFFSET] == RGB) {
|
||||
maxlen /= 3;
|
||||
}
|
||||
*len = 0;
|
||||
if (dev->status == STATUS_IDLE)
|
||||
{
|
||||
DBG(101, "STATUS == IDLE\n");
|
||||
return SANE_STATUS_IO_ERROR;
|
||||
if (dev->optionw[COLOR_OFFSET] == RGB)
|
||||
}
|
||||
while (min_buf_w_offset(dev) <= dev->read_offset)
|
||||
{
|
||||
ret = get_data (dev);
|
||||
if (ret != SANE_STATUS_GOOD)
|
||||
{
|
||||
while (min3 (dev->write_offset_r, dev->write_offset_g,
|
||||
dev->write_offset_b) <= dev->read_offset)
|
||||
{
|
||||
ret = get_data (dev);
|
||||
if (ret != SANE_STATUS_GOOD)
|
||||
{
|
||||
if (min3 (dev->write_offset_r,
|
||||
dev->write_offset_g,
|
||||
dev->write_offset_b) <= dev->read_offset)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
available = min3 (dev->write_offset_r, dev->write_offset_g,
|
||||
dev->write_offset_b);
|
||||
if (min_buf_w_offset(dev) <= dev->read_offset) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
else
|
||||
}
|
||||
available = min_buf_w_offset(dev);
|
||||
int pixel_len = available - dev->read_offset;
|
||||
if (pixel_len > maxlen)
|
||||
pixel_len = maxlen;
|
||||
int img_size = dev->width * dev->height;
|
||||
for(int i=0; i<pixel_len; ++i)
|
||||
{
|
||||
int pos = dev->read_offset+i;
|
||||
if (pos % dev->data_width >= dev->width)
|
||||
continue;
|
||||
if (dev->scanned_pixels >= img_size)
|
||||
{
|
||||
while (dev->write_offset_r <= dev->read_offset)
|
||||
{
|
||||
ret = get_data (dev);
|
||||
if (ret != SANE_STATUS_GOOD)
|
||||
if (dev->write_offset_r <= dev->read_offset)
|
||||
return ret;
|
||||
}
|
||||
available = dev->write_offset_r;
|
||||
DBG(101, "Extra pixels received.\n");
|
||||
break;
|
||||
}
|
||||
*len = available - dev->read_offset;
|
||||
if (*len > maxlen)
|
||||
*len = maxlen;
|
||||
memcpy (buf, dev->buffer + dev->read_offset, *len);
|
||||
dev->read_offset += *len;
|
||||
if (dev->read_offset == dev->bufs)
|
||||
dev->scanned_pixels++;
|
||||
buf[(*len)++] = dev->buf_r.buffer[pos];
|
||||
if (dev->optionw[COLOR_OFFSET] == RGB)
|
||||
{
|
||||
free (dev->buffer);
|
||||
dev->buffer = NULL;
|
||||
dev->read_offset = 0;
|
||||
dev->write_offset_r = 0;
|
||||
dev->write_offset_g = 1;
|
||||
dev->write_offset_b = 2;
|
||||
buf[(*len)++] = dev->buf_g.buffer[pos];
|
||||
buf[(*len)++] = dev->buf_b.buffer[pos];
|
||||
}
|
||||
}
|
||||
DBG(101, "Moved %d pixels to buffer. Total pixel scanned: %d \n", *len, dev->scanned_pixels);
|
||||
if (dev->scanned_pixels == img_size)
|
||||
DBG(100, "Full image received\n");
|
||||
dev->read_offset += pixel_len;
|
||||
|
||||
/*
|
||||
If w_offset is the same in all buffers and has already been completely transferred
|
||||
to the common buffer - flush buffer. It will be recreated in get_data with a reserve
|
||||
for the last triple portions
|
||||
*/
|
||||
if (is_buf_synchronized(dev) && available == dev->read_offset)
|
||||
{
|
||||
remove_buffers(dev);
|
||||
}
|
||||
|
||||
/* Special case where sane_cancel is called while scanning */
|
||||
if (dev->status == STATUS_CANCELING)
|
||||
|
@ -1082,8 +1083,7 @@ sane_cancel (SANE_Handle h)
|
|||
return;
|
||||
}
|
||||
|
||||
free (dev->buffer);
|
||||
dev->buffer = NULL;
|
||||
remove_buffers(dev);
|
||||
}
|
||||
|
||||
SANE_Status
|
||||
|
|
Ładowanie…
Reference in New Issue