kopia lustrzana https://gitlab.com/sane-project/backends
brother_mfp: Added draft for brother3 driver.
Test machine MFC-290C seems to support JPEG and RAW colour data. However, the raw colour data has what appears to be a strong green component leading to very green images. Maybe some post processing is required to generate a proper image. Dunno. JPEG looks perfectly fine.brother_mfp_backend
rodzic
fbe872ae86
commit
a6f4f816b1
|
@ -1037,7 +1037,11 @@ BrotherDriver::BrotherDriver (BrotherFamily family) :
|
|||
break;
|
||||
|
||||
// case BROTHER_FAMILY_1:
|
||||
// case BROTHER_FAMILY_3:
|
||||
|
||||
case BROTHER_FAMILY_3:
|
||||
encoder = new BrotherEncoderFamily3();
|
||||
break;
|
||||
|
||||
// case BROTHER_FAMILY_5:
|
||||
case BROTHER_FAMILY_NONE:
|
||||
default:
|
||||
|
|
|
@ -586,6 +586,475 @@ SANE_Status BrotherEncoderFamily2::DecodeButtonStateResp (const SANE_Byte *data,
|
|||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* --------------------------------------------
|
||||
* Family 3 Encoding
|
||||
* --------------------------------------------
|
||||
*
|
||||
*/
|
||||
|
||||
SANE_Status BrotherEncoderFamily3::DecodeSessionResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherSessionResponse &response)
|
||||
{
|
||||
/*
|
||||
* Formatting and content checks.
|
||||
*
|
||||
*
|
||||
*/
|
||||
if ((data_len != 5)
|
||||
|| ((memcmp (data, "\x05" "\x10" "\x01" "\x02", 4) != 0)
|
||||
&& (memcmp (data, "\x05" "\x10" "\x02" "\x02", 4) != 0)))
|
||||
|
||||
{
|
||||
DBG (DBG_SERIOUS,
|
||||
"BrotherEncoderFamily3::DecodeSessionResp: invalid session response block: len = %zu\n",
|
||||
data_len);
|
||||
|
||||
return SANE_STATUS_IO_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: Check the valid status values are 0x00 or 0x20
|
||||
*
|
||||
*/
|
||||
if ((data[4] != 0x00) && (data[4] != 0x80))
|
||||
|
||||
{
|
||||
DBG (DBG_SERIOUS,
|
||||
"BrotherEncoderFamily3::DecodeSessionResp: invalid session response: data[4]=%u\n",
|
||||
(unsigned int) data[4]);
|
||||
|
||||
return SANE_STATUS_IO_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: figure out what the rest of the packet is supposed to be.
|
||||
*
|
||||
*/
|
||||
response.ready = data[4] == 0x00? SANE_TRUE: SANE_FALSE;
|
||||
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE:
|
||||
* Supply a buffer that is at least 1 char longer than is necessary
|
||||
* as snprintf() will require space for a terminating NUL.
|
||||
*
|
||||
*/
|
||||
SANE_Status BrotherEncoderFamily3::EncodeBasicParameterBlock (SANE_Byte *data, size_t data_len,
|
||||
size_t *length)
|
||||
{
|
||||
const char *mode_text = ScanModeToText (scan_params.param_scan_mode);
|
||||
if (nullptr == mode_text)
|
||||
{
|
||||
DBG (DBG_SERIOUS,
|
||||
"BrotherEncoderFamily3::EncodeBasicParameterBlock: failed to get scan mode text for mode %d\n",
|
||||
scan_params.param_scan_mode);
|
||||
return SANE_STATUS_INVAL;
|
||||
}
|
||||
|
||||
*length = snprintf ((char*) data,
|
||||
data_len,
|
||||
"\x1b" "I\nR=%u,%u\nM=%s\n" "\x80",
|
||||
(unsigned int) scan_params.param_x_res,
|
||||
(unsigned int) scan_params.param_y_res,
|
||||
mode_text);
|
||||
|
||||
if (*length > data_len)
|
||||
{
|
||||
DBG (DBG_SERIOUS,
|
||||
"BrotherEncoderFamily3::EncodeBasicParameterBlock: parameter block too long for buffer: %zu\n",
|
||||
*length);
|
||||
return SANE_STATUS_INVAL;
|
||||
}
|
||||
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
|
||||
SANE_Status BrotherEncoderFamily3::DecodeBasicParameterBlockResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherBasicParamResponse &response)
|
||||
{
|
||||
/*
|
||||
* TODO: Decode this block.
|
||||
* Might contain some useful stuff, like limits for selected parameters.
|
||||
*
|
||||
*/
|
||||
(void)data;
|
||||
(void)data_len;
|
||||
(void)response;
|
||||
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
|
||||
|
||||
SANE_Status BrotherEncoderFamily3::EncodeParameterBlock (SANE_Byte *data, size_t data_len,
|
||||
size_t *length)
|
||||
{
|
||||
const char *mode_text = ScanModeToText (scan_params.param_scan_mode);
|
||||
if (nullptr == mode_text)
|
||||
{
|
||||
DBG (DBG_SERIOUS,
|
||||
"BrotherEncoderFamily3::EncodeBasicParameterBlock: failed to get scan mode text for mode %d\n",
|
||||
scan_params.param_scan_mode);
|
||||
return SANE_STATUS_INVAL;
|
||||
}
|
||||
|
||||
*length = snprintf ((char*) data,
|
||||
data_len,
|
||||
"\x1b" "X\nR=%u,%u\nM=%s\n"
|
||||
"%s\n"
|
||||
"B=%u\nN=%u\n"
|
||||
"A=%u,%u,%u,%u\n"
|
||||
"D=SIN\n"
|
||||
"\x80",
|
||||
(unsigned int) scan_params.param_x_res,
|
||||
(unsigned int) scan_params.param_y_res,
|
||||
mode_text,
|
||||
// (scan_params.param_scan_mode == BROTHER_SCAN_MODE_COLOR) ?
|
||||
// "C=JPEG\nJ=MID" : "C=RLENGTH",
|
||||
(scan_params.param_scan_mode == BROTHER_SCAN_MODE_COLOR) ?
|
||||
"C=NONE" : "C=RLENGTH",
|
||||
(unsigned int) (scan_params.param_brightness + 50),
|
||||
(unsigned int) (scan_params.param_contrast + 50),
|
||||
(unsigned int) (scan_params.param_pixel_x_offset),
|
||||
(unsigned int) (scan_params.param_pixel_y_offset),
|
||||
(unsigned int) (scan_params.param_pixel_x_offset
|
||||
+ scan_params.param_pixel_x_width),
|
||||
(unsigned int) (scan_params.param_pixel_y_offset
|
||||
+ scan_params.param_pixel_y_height));
|
||||
|
||||
if (*length > data_len)
|
||||
{
|
||||
DBG (DBG_SERIOUS,
|
||||
"BrotherEncoderFamily3::EncodeBasicParameterBlock: parameter block too long for buffer: %zu\n",
|
||||
*length);
|
||||
return SANE_STATUS_INVAL;
|
||||
}
|
||||
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
|
||||
SANE_Status BrotherEncoderFamily3::DecodeScanData (const SANE_Byte *src_data, size_t src_data_len,
|
||||
size_t *src_data_consumed, SANE_Byte *dest_data,
|
||||
size_t dest_data_len, size_t *dest_data_written)
|
||||
{
|
||||
DBG (DBG_EVENT, "BrotherEncoderFamily3::DecodeScanData: \n");
|
||||
SANE_Status ret_status = SANE_STATUS_GOOD;
|
||||
|
||||
*src_data_consumed = 0;
|
||||
*dest_data_written = 0;
|
||||
|
||||
/*
|
||||
* We will use this to compute the bytes consumed at the end.
|
||||
*
|
||||
*/
|
||||
size_t orig_src_data_len = src_data_len;
|
||||
size_t orig_dest_data_len = dest_data_len;
|
||||
|
||||
/*
|
||||
* Now take note here that we do not *necessarily* need src_data to be able to decode.
|
||||
* We might have terminated the previous call not because we ran out of input, but because
|
||||
* we ran out of output space. Some blocks are just repetitions that are unrolled and require
|
||||
* no additional src data. So we enter this loop *even if there is nothing in the src_data buffer*.
|
||||
*
|
||||
* All of the functions that we are about to call must be able to deal with src_data_len == 0
|
||||
* intelligently.
|
||||
*
|
||||
*/
|
||||
for (;;)
|
||||
{
|
||||
/*
|
||||
* If we are not in a block, then decode the next block.
|
||||
*
|
||||
* We might not have enough bytes to fully decode the header.
|
||||
* In which case, we wait for some more data.
|
||||
*
|
||||
*/
|
||||
bool new_block = false;
|
||||
|
||||
if (current_header.block_type == 0)
|
||||
{
|
||||
size_t header_consumed = 0;
|
||||
DecodeStatus res = DecodeScanDataHeader(src_data, src_data_len, &header_consumed, current_header);
|
||||
if (res == DECODE_STATUS_TRUNCATED)
|
||||
{
|
||||
/*
|
||||
* This means we don't have enough data to decode a header yet.
|
||||
* Try again next time if we have read more data.
|
||||
*
|
||||
*/
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Detect special case situations.
|
||||
*
|
||||
* TODO: We need to be able to alert the difference between these
|
||||
* two things to the caller somehow. They are not the same!!
|
||||
*
|
||||
*/
|
||||
if (res == DECODE_STATUS_ENDOFDATA)
|
||||
{
|
||||
DBG (DBG_IMPORTANT, "BrotherEncoderFamily3::DecodeScanData: end of data detected\n");
|
||||
current_header.block_type = 0;
|
||||
|
||||
/*
|
||||
* If we have data in hand, then we will send this up first.
|
||||
* Otherwise, send SANE_STATUS_EOF to trigger stop of scan.
|
||||
*
|
||||
* We don't consume this header so we will see it the next time around.
|
||||
*
|
||||
*/
|
||||
ret_status = orig_dest_data_len > dest_data_len? SANE_STATUS_GOOD: SANE_STATUS_EOF;
|
||||
break;
|
||||
}
|
||||
if (res == DECODE_STATUS_ENDOFFRAME)
|
||||
{
|
||||
DBG (DBG_IMPORTANT, "BrotherEncoderFamily3::DecodeScanData: end of frame detected\n");
|
||||
current_header.block_type = 0;
|
||||
ret_status = orig_dest_data_len > dest_data_len? SANE_STATUS_GOOD: SANE_STATUS_EOF;
|
||||
break;
|
||||
}
|
||||
if (res != DECODE_STATUS_GOOD)
|
||||
{
|
||||
DBG (DBG_IMPORTANT, "BrotherEncoderFamily3::DecodeScanData: failed to decode header\n");
|
||||
current_header.block_type = 0;
|
||||
ret_status = SANE_STATUS_IO_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
DBG (DBG_IMPORTANT,
|
||||
"BrotherEncoderFamily3::DecodeScanData: decoded new block header: 0x%2.2x, length=%zu\n",
|
||||
current_header.block_type,
|
||||
current_header.block_len);
|
||||
|
||||
src_data += header_consumed;
|
||||
src_data_len -= header_consumed;
|
||||
|
||||
new_block = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to decode the data block.
|
||||
* We will exit the function if we can only partially
|
||||
* decode it, hoping to do more next time.
|
||||
*
|
||||
*/
|
||||
DecodeStatus res;
|
||||
size_t bytes_consumed = 0;
|
||||
size_t bytes_written = 0;
|
||||
size_t in_len = MIN(src_data_len, current_header.block_len);
|
||||
|
||||
if ((current_header.block_type == BROTHER_DATA_BLOCK_RED_RAW)
|
||||
|| (current_header.block_type == BROTHER_DATA_BLOCK_GREEN_RAW)
|
||||
|| (current_header.block_type == BROTHER_DATA_BLOCK_BLUE_RAW))
|
||||
{
|
||||
if (new_block)
|
||||
{
|
||||
colour_decoder.NewBlock ();
|
||||
}
|
||||
|
||||
res = colour_decoder.DecodeScanData (src_data,
|
||||
in_len,
|
||||
&bytes_consumed,
|
||||
dest_data,
|
||||
dest_data_len,
|
||||
&bytes_written);
|
||||
}
|
||||
else if (current_header.block_type == BROTHER_DATA_BLOCK_GRAY_RLENGTH)
|
||||
{
|
||||
if (new_block)
|
||||
{
|
||||
gray_decoder.NewBlock ();
|
||||
}
|
||||
|
||||
res = gray_decoder.DecodeScanData (src_data,
|
||||
in_len,
|
||||
&bytes_consumed,
|
||||
dest_data,
|
||||
dest_data_len,
|
||||
&bytes_written);
|
||||
}
|
||||
else if (current_header.block_type == BROTHER_DATA_BLOCK_GRAY_RAW)
|
||||
{
|
||||
if (new_block)
|
||||
{
|
||||
gray_raw_decoder.NewBlock ();
|
||||
}
|
||||
|
||||
res = gray_raw_decoder.DecodeScanData (src_data,
|
||||
in_len,
|
||||
&bytes_consumed,
|
||||
dest_data,
|
||||
dest_data_len,
|
||||
&bytes_written);
|
||||
}
|
||||
else if (current_header.block_type == BROTHER_DATA_BLOCK_JPEG)
|
||||
{
|
||||
if (new_block)
|
||||
{
|
||||
jfif_decoder.NewBlock ();
|
||||
}
|
||||
|
||||
res = jfif_decoder.DecodeScanData (src_data,
|
||||
in_len,
|
||||
&bytes_consumed,
|
||||
dest_data,
|
||||
dest_data_len,
|
||||
&bytes_written);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG (DBG_IMPORTANT,
|
||||
"BrotherEncoderFamily3::DecodeScanData: unknown block encountered: 0x%2.2x\n",
|
||||
(unsigned int) current_header.block_type);
|
||||
ret_status = SANE_STATUS_IO_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
DBG (DBG_DETAIL,
|
||||
"BrotherEncoderFamily3::DecodeScanData: written=%zu\n",
|
||||
bytes_written);
|
||||
if (res != DECODE_STATUS_GOOD)
|
||||
{
|
||||
current_header.block_type = 0;
|
||||
ret_status = SANE_STATUS_IO_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
src_data += bytes_consumed;
|
||||
src_data_len -= bytes_consumed;
|
||||
current_header.block_len -= bytes_consumed;
|
||||
|
||||
DBG (DBG_IMPORTANT,
|
||||
"BrotherEncoderFamily3::DecodeScanData: current block bytes remaining after decode=%zu\n",
|
||||
current_header.block_len);
|
||||
|
||||
dest_data += bytes_written;
|
||||
dest_data_len -= bytes_written;
|
||||
|
||||
/*
|
||||
* Perhaps we have completed the block.
|
||||
*
|
||||
*/
|
||||
if (current_header.block_len == 0)
|
||||
{
|
||||
current_header.block_type = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Deal with special situation whereby we have input
|
||||
* and output buffer space, but we couldn't decode anything.
|
||||
* It might be that there is data in the input buffer
|
||||
* but we need more to proceed.
|
||||
*
|
||||
* If we haven't written anything, we cannot have made any progress.
|
||||
*
|
||||
*/
|
||||
if (bytes_written == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret_status == SANE_STATUS_GOOD)
|
||||
{
|
||||
*src_data_consumed = orig_src_data_len - src_data_len;
|
||||
*dest_data_written = orig_dest_data_len - dest_data_len;
|
||||
}
|
||||
|
||||
return ret_status;
|
||||
}
|
||||
|
||||
/*
|
||||
* EndOfFrame (0x82) is 10 bytes long because it doesn't have the
|
||||
* 2-byte packet length that the others do, so we could assume that
|
||||
* the packet length is not part of the header really.
|
||||
* However, it is convenient in coding terms to assume that it does.
|
||||
*
|
||||
* 0x80 - single byte end of data.
|
||||
* 0x82 - end of frame, with 10 bytes
|
||||
* Others - 12 bytes, including little endian length at the end.
|
||||
*
|
||||
*/
|
||||
DecodeStatus BrotherEncoderFamily3::DecodeScanDataHeader (const SANE_Byte *src_data,
|
||||
size_t src_data_len,
|
||||
size_t *src_data_consumed,
|
||||
ScanDataHeader &header)
|
||||
{
|
||||
if (src_data_len == 0)
|
||||
{
|
||||
return DECODE_STATUS_TRUNCATED;
|
||||
}
|
||||
|
||||
header.block_type = src_data[0];
|
||||
|
||||
header.block_len = 0;
|
||||
|
||||
if (header.block_type == BROTHER_DATA_BLOCK_NO_DATA)
|
||||
{
|
||||
*src_data_consumed = 1;
|
||||
return DECODE_STATUS_ENDOFDATA;
|
||||
}
|
||||
|
||||
if (header.block_type == BROTHER_DATA_BLOCK_END_OF_FRAME)
|
||||
{
|
||||
if (src_data_len < 10)
|
||||
{
|
||||
return DECODE_STATUS_TRUNCATED;
|
||||
}
|
||||
|
||||
*src_data_consumed = 10;
|
||||
return DECODE_STATUS_ENDOFFRAME;
|
||||
}
|
||||
|
||||
/*
|
||||
* Other data-carrying packets.
|
||||
*
|
||||
*/
|
||||
if (src_data_len < 3)
|
||||
{
|
||||
return DECODE_STATUS_TRUNCATED;
|
||||
}
|
||||
|
||||
*src_data_consumed = 3;
|
||||
|
||||
header.block_len = src_data[1] + (src_data[2] << 8);
|
||||
|
||||
return DECODE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
|
||||
SANE_Status BrotherEncoderFamily3::DecodeButtonQueryResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherButtonQueryResponse &response)
|
||||
{
|
||||
if ((data_len != 4) || (data[0] != 0x04) ||(data[1] != 0x10) || (data[2] != 0x03))
|
||||
{
|
||||
return SANE_STATUS_IO_ERROR;
|
||||
}
|
||||
|
||||
response.has_button_press = data[3] == 0x10;
|
||||
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
SANE_Status BrotherEncoderFamily3::DecodeButtonStateResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherButtonStateResponse &response)
|
||||
{
|
||||
if ((data_len != 9) || (memcmp(data, "\x09" "\x10" "\x03" "\x20", 4) != 0))
|
||||
{
|
||||
return SANE_STATUS_IO_ERROR;
|
||||
}
|
||||
response.button_value = data[4];
|
||||
|
||||
return SANE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
/*
|
||||
* --------------------------------------------
|
||||
* Family 4 Encoding
|
||||
|
@ -1203,6 +1672,119 @@ DecodeStatus BrotherGrayRLengthDecoder::DecodeScanData (const SANE_Byte *in_buff
|
|||
return DECODE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
void BrotherInterleavedRGBColourDecoder::NewBlock ()
|
||||
{
|
||||
}
|
||||
|
||||
void BrotherInterleavedRGBColourDecoder::NewPage(const BrotherParameters ¶ms)
|
||||
{
|
||||
decode_params = params;
|
||||
NewBlock();
|
||||
|
||||
/*
|
||||
* Signal that we need to reallocate the scanline_buffer.
|
||||
* We defer the allocation because this function returns void
|
||||
* so we cannot signal an error if there is a problem allocating memory.
|
||||
*
|
||||
*/
|
||||
scanline_length = 0;
|
||||
scanline_buffer_size = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns:
|
||||
*
|
||||
* DECODE_STATUS_GOOD - block all decoded.
|
||||
* DECODE_STATUS_ERROR - error detected in data.
|
||||
*
|
||||
* TODO: This function is assuming 24bit colour. I don't know
|
||||
* if that is always valid.
|
||||
*
|
||||
*/
|
||||
DecodeStatus BrotherInterleavedRGBColourDecoder::DecodeScanData (const SANE_Byte *in_buffer,
|
||||
size_t in_buffer_len,
|
||||
size_t *bytes_consumed,
|
||||
SANE_Byte *out_buffer,
|
||||
size_t out_buffer_len,
|
||||
size_t *bytes_written)
|
||||
{
|
||||
*bytes_consumed = 0;
|
||||
*bytes_written = 0;
|
||||
|
||||
size_t in_buffer_len_start = in_buffer_len;
|
||||
size_t out_buffer_len_start = out_buffer_len;
|
||||
|
||||
if (scanline_length == 0)
|
||||
{
|
||||
/*
|
||||
* Make sure that we have an allocated buffer big enough for
|
||||
* a single output scanline that we will assemble the scanline into.
|
||||
*
|
||||
*/
|
||||
scanline_length = decode_params.param_pixel_x_width * 3;
|
||||
|
||||
if (scanline_length > scanline_buffer_size)
|
||||
{
|
||||
SANE_Byte *new_buffer = (SANE_Byte *)realloc (scanline_buffer, scanline_length);
|
||||
if (new_buffer == nullptr)
|
||||
{
|
||||
scanline_length = 0;
|
||||
return DECODE_STATUS_MEMORY;
|
||||
}
|
||||
scanline_buffer = new_buffer;
|
||||
scanline_buffer_size = scanline_length;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset our decoding.
|
||||
*
|
||||
*/
|
||||
scanline_buffer_data = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Assemble src data into the scanline buffer.
|
||||
*
|
||||
*/
|
||||
while (in_buffer_len && (out_buffer_len > scanline_length))
|
||||
{
|
||||
size_t bytes_avail = MIN(in_buffer_len, scanline_length - scanline_buffer_data);
|
||||
(void)memcpy(scanline_buffer + scanline_buffer_data, in_buffer, bytes_avail);
|
||||
|
||||
scanline_buffer_data += bytes_avail;
|
||||
in_buffer += bytes_avail;
|
||||
in_buffer_len -= bytes_avail;
|
||||
|
||||
/*
|
||||
* See if we have a full scanline now.
|
||||
*
|
||||
*/
|
||||
if (scanline_buffer_data >= scanline_length)
|
||||
{
|
||||
size_t stride = decode_params.param_pixel_x_width;
|
||||
|
||||
SANE_Byte *red = scanline_buffer;
|
||||
SANE_Byte *green = scanline_buffer + stride;
|
||||
SANE_Byte *blue = scanline_buffer + (2 * stride);
|
||||
|
||||
for (size_t col_index = 0; col_index < (size_t) decode_params.param_pixel_x_width;
|
||||
col_index++)
|
||||
{
|
||||
*out_buffer++ = *red++;
|
||||
*out_buffer++ = *green++;
|
||||
*out_buffer++ = *blue++;
|
||||
}
|
||||
scanline_buffer_data = 0;
|
||||
out_buffer_len -= scanline_length;
|
||||
}
|
||||
}
|
||||
|
||||
*bytes_consumed = in_buffer_len_start - in_buffer_len;
|
||||
*bytes_written = out_buffer_len_start - out_buffer_len;
|
||||
|
||||
return DECODE_STATUS_GOOD;
|
||||
}
|
||||
|
||||
|
||||
#include <jpeglib.h>
|
||||
#include <jerror.h>
|
||||
|
|
|
@ -67,7 +67,7 @@ typedef enum
|
|||
BROTHER_FAMILY_NONE,
|
||||
// BROTHER_FAMILY_1,
|
||||
BROTHER_FAMILY_2,
|
||||
// BROTHER_FAMILY_3,
|
||||
BROTHER_FAMILY_3,
|
||||
BROTHER_FAMILY_4,
|
||||
// BROTHER_FAMILY_5
|
||||
} BrotherFamily;
|
||||
|
@ -162,7 +162,8 @@ enum DecodeStatus
|
|||
DECODE_STATUS_TRUNCATED,
|
||||
DECODE_STATUS_ENDOFDATA,
|
||||
DECODE_STATUS_ENDOFFRAME,
|
||||
DECODE_STATUS_ERROR
|
||||
DECODE_STATUS_ERROR,
|
||||
DECODE_STATUS_MEMORY
|
||||
};
|
||||
|
||||
struct ScanDataHeader
|
||||
|
@ -329,6 +330,39 @@ private:
|
|||
};
|
||||
|
||||
|
||||
class BrotherInterleavedRGBColourDecoder
|
||||
{
|
||||
public:
|
||||
BrotherInterleavedRGBColourDecoder():
|
||||
scanline_buffer(nullptr),
|
||||
scanline_buffer_size(0),
|
||||
scanline_length(0),
|
||||
scanline_buffer_data(0)
|
||||
{
|
||||
}
|
||||
|
||||
~BrotherInterleavedRGBColourDecoder()
|
||||
{
|
||||
free(scanline_buffer);
|
||||
}
|
||||
void NewBlock();
|
||||
|
||||
void NewPage(const BrotherParameters ¶ms);
|
||||
|
||||
DecodeStatus DecodeScanData (const SANE_Byte *src_data, size_t src_data_len,
|
||||
size_t *src_data_consumed, SANE_Byte *dst_data, size_t dest_data_len,
|
||||
size_t *dest_data_written);
|
||||
|
||||
private:
|
||||
BrotherParameters decode_params;
|
||||
|
||||
SANE_Byte *scanline_buffer;
|
||||
size_t scanline_buffer_size;
|
||||
size_t scanline_length;
|
||||
size_t scanline_buffer_data;
|
||||
};
|
||||
|
||||
|
||||
class BrotherGrayRawDecoder
|
||||
{
|
||||
public:
|
||||
|
@ -360,6 +394,7 @@ public:
|
|||
|
||||
jfif_decoder.NewPage(scan_params);
|
||||
gray_decoder.NewPage(scan_params);
|
||||
gray_raw_decoder.NewPage(scan_params);
|
||||
}
|
||||
|
||||
SANE_Status DecodeSessionResp (const SANE_Byte *data, size_t data_len,
|
||||
|
@ -411,6 +446,73 @@ private:
|
|||
BrotherGrayRawDecoder gray_raw_decoder;
|
||||
};
|
||||
|
||||
class BrotherEncoderFamily3 : public BrotherEncoder
|
||||
{
|
||||
public:
|
||||
~BrotherEncoderFamily3 ()
|
||||
{
|
||||
}
|
||||
|
||||
void NewPage() override
|
||||
{
|
||||
current_header.block_type = 0;
|
||||
|
||||
gray_raw_decoder.NewPage(scan_params);
|
||||
gray_decoder.NewPage(scan_params);
|
||||
colour_decoder.NewPage(scan_params);
|
||||
jfif_decoder.NewPage(scan_params);
|
||||
}
|
||||
|
||||
SANE_Status DecodeSessionResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherSessionResponse &response) override;
|
||||
|
||||
SANE_Status EncodeBasicParameterBlock (SANE_Byte *data, size_t data_len, size_t *length) override;
|
||||
|
||||
SANE_Status DecodeBasicParameterBlockResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherBasicParamResponse &response) override;
|
||||
|
||||
SANE_Status EncodeADFBlock (SANE_Byte *data, size_t data_len, size_t *length) override
|
||||
{
|
||||
(void)data;
|
||||
(void)data_len;
|
||||
(void)length;
|
||||
return SANE_STATUS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
SANE_Status DecodeADFBlockResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherADFResponse &response) override
|
||||
{
|
||||
(void)data;
|
||||
(void)data_len;
|
||||
(void)response;
|
||||
|
||||
return SANE_STATUS_UNSUPPORTED;
|
||||
}
|
||||
|
||||
SANE_Status EncodeParameterBlock (SANE_Byte *data, size_t data_len, size_t *length) override;
|
||||
|
||||
SANE_Status DecodeScanData (const SANE_Byte *src_data, size_t src_data_len,
|
||||
size_t *src_data_consumed, SANE_Byte *dst_data,
|
||||
size_t dest_data_len, size_t *dest_data_written) override;
|
||||
|
||||
SANE_Status DecodeButtonQueryResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherButtonQueryResponse &response) override;
|
||||
|
||||
SANE_Status DecodeButtonStateResp (const SANE_Byte *data, size_t data_len,
|
||||
BrotherButtonStateResponse &response) override;
|
||||
|
||||
private:
|
||||
DecodeStatus DecodeScanDataHeader (const SANE_Byte *src_data, size_t src_data_len,
|
||||
size_t *src_data_consumed, ScanDataHeader &header);
|
||||
|
||||
ScanDataHeader current_header;
|
||||
|
||||
BrotherGrayRawDecoder gray_raw_decoder;
|
||||
BrotherGrayRLengthDecoder gray_decoder;
|
||||
BrotherInterleavedRGBColourDecoder colour_decoder;
|
||||
BrotherJFIFDecoder jfif_decoder;
|
||||
};
|
||||
|
||||
class BrotherEncoderFamily4 : public BrotherEncoder
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -74,6 +74,9 @@
|
|||
#define CAP_MODE_BUTTON_SCAN_FILE (1u << 6)
|
||||
#define CAP_MODE_BUTTON_SCAN_IMAGE (1u << 7)
|
||||
|
||||
#define CAP_MODE_HAS_ADF (1u << 8)
|
||||
#define CAP_MODE_HAS_ADF_IS_DUPLEX (1u << 9)
|
||||
|
||||
/*
|
||||
* Messages.
|
||||
*
|
||||
|
@ -159,17 +162,51 @@ static Brother_Model models[] =
|
|||
CAP_MODE_BUTTON_SCAN_EMAIL |
|
||||
CAP_MODE_BUTTON_SCAN_FILE |
|
||||
CAP_MODE_BUTTON_SCAN_OCR |
|
||||
CAP_MODE_BUTTON_SCAN_IMAGE },
|
||||
CAP_MODE_BUTTON_SCAN_IMAGE |
|
||||
CAP_MODE_HAS_ADF },
|
||||
|
||||
{ "Brother", "DCP-7030", BROTHER_FAMILY_3, 0x04f9, 0x01ea,
|
||||
{ 0, SANE_FIX(210), 0 },
|
||||
{ 0, SANE_FIX(295), 0 },
|
||||
{ 5, 100, 150, 200, 300, 600 },
|
||||
{ 7, 100, 150, 200, 300, 600, 1200, 2400 },
|
||||
CAP_MODE_COLOUR |
|
||||
CAP_MODE_GRAY |
|
||||
CAP_MODE_GRAY_DITHER |
|
||||
CAP_MODE_BW |
|
||||
CAP_MODE_BUTTON_SCAN_EMAIL |
|
||||
CAP_MODE_BUTTON_SCAN_FILE |
|
||||
CAP_MODE_BUTTON_SCAN_OCR |
|
||||
CAP_MODE_BUTTON_SCAN_IMAGE },
|
||||
|
||||
// TODO: check dimensions
|
||||
{ "Brother", "MFC-290C", BROTHER_FAMILY_3, 0x04f9, 0x01fd,
|
||||
{ 0, SANE_FIX(210), 0 },
|
||||
{ 0, SANE_FIX(295), 0 },
|
||||
{ 5, 100, 150, 200, 300, 600 },
|
||||
{ 7, 100, 150, 200, 300, 600, 1200, 2400 },
|
||||
CAP_MODE_COLOUR |
|
||||
CAP_MODE_GRAY |
|
||||
CAP_MODE_GRAY_DITHER |
|
||||
CAP_MODE_BW |
|
||||
CAP_MODE_BUTTON_SCAN_EMAIL |
|
||||
CAP_MODE_BUTTON_SCAN_FILE |
|
||||
CAP_MODE_BUTTON_SCAN_OCR |
|
||||
CAP_MODE_BUTTON_SCAN_IMAGE },
|
||||
|
||||
{ "Brother", "MFC-J4320DW", BROTHER_FAMILY_4, 0x04f9, 0x033a,
|
||||
{ 0, SANE_FIX(213.9), 0 },
|
||||
{ 0, SANE_FIX(295), 0 },
|
||||
{ 6, 100, 150, 200, 300, 600, 1200 },
|
||||
{ 7, 100, 150, 200, 300, 600, 1200, 2400 },
|
||||
CAP_MODE_COLOUR |
|
||||
CAP_MODE_GRAY |
|
||||
CAP_MODE_GRAY_DITHER |
|
||||
CAP_MODE_BW},
|
||||
CAP_MODE_COLOUR |
|
||||
CAP_MODE_GRAY |
|
||||
CAP_MODE_GRAY_DITHER |
|
||||
CAP_MODE_BW |
|
||||
CAP_MODE_BUTTON_SCAN_EMAIL |
|
||||
CAP_MODE_BUTTON_SCAN_FILE |
|
||||
CAP_MODE_BUTTON_SCAN_OCR |
|
||||
CAP_MODE_BUTTON_SCAN_IMAGE },
|
||||
|
||||
{NULL, NULL, BROTHER_FAMILY_NONE, 0, 0, {0, 0, 0}, {0, 0, 0}, {0}, {0}, 0}
|
||||
};
|
||||
|
|
Ładowanie…
Reference in New Issue