修复Memory传输模式+GROUP4情况下,BMP位图文件重复写头信息,导致图像移位的错误;添加APP取图日志
This commit is contained in:
parent
9a79911a42
commit
eae869d8cb
|
@ -211,77 +211,12 @@ int image_buf::read(void* buf, size_t* bytes, unsigned long long off)
|
|||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class scanned_img
|
||||
scanned_img::scanned_img(SANE_Handle dev, SANE_Parameters head, int dpi
|
||||
, const char* tmp_file, twain_xfer xfer
|
||||
, SANE_FinalImgFormat *fmt) : head_(head), dpi_(dpi), header_size_(0), file_(tmp_file ? tmp_file : "")
|
||||
, dev_(dev), status_(SANE_Image_Statu_OK)
|
||||
{
|
||||
if (fmt)
|
||||
fmt_ = *fmt;
|
||||
else
|
||||
{
|
||||
fmt_.img_format = SANE_IMAGE_TYPE_BMP;
|
||||
fmt_.detail = 0;
|
||||
}
|
||||
|
||||
size_t bytes = line_bytes() * height();
|
||||
std::string h(file_header(fmt_.img_format, (float)dpi, xfer));
|
||||
unsigned char* dst = NULL;
|
||||
bool ok = false;
|
||||
|
||||
data_ = new image_buf();
|
||||
header_size_ = h.length();
|
||||
dst = data_->allocate(tmp_file, bytes + h.length());
|
||||
if (dst)
|
||||
{
|
||||
unsigned long long off = 0, total = 0;
|
||||
bytes = h.length();
|
||||
if (data_->save(h.c_str(), &bytes, off))
|
||||
{
|
||||
unsigned int len = line_bytes();
|
||||
unsigned long long line = line_bytes();
|
||||
|
||||
if (xfer == TWAIN_XFER_Memory)
|
||||
line *= -1;
|
||||
else
|
||||
off = data_->bytes() - line;
|
||||
dst = data_->buffer(off, &len);
|
||||
|
||||
int want_to_read = head_.bytes_per_line, rcv = 0, dif = line_bytes() - head_.bytes_per_line;
|
||||
while (dst)
|
||||
{
|
||||
int r = want_to_read > (int)(len) - rcv ? (int)(len)- rcv : want_to_read;
|
||||
int ret = sane_helper_->invoke_sane_read(dev, dst + rcv, r, &r);
|
||||
total += r;
|
||||
if (ret != SANE_STATUS_GOOD)
|
||||
break;
|
||||
|
||||
want_to_read -= r;
|
||||
rcv += r;
|
||||
if (want_to_read == 0)
|
||||
{
|
||||
want_to_read = head_.bytes_per_line;
|
||||
off -= line;
|
||||
len = line_bytes();
|
||||
rcv = 0;
|
||||
dst = data_->buffer(off, &len);
|
||||
total += dif;
|
||||
}
|
||||
else
|
||||
{
|
||||
len = want_to_read;
|
||||
dst = data_->buffer(off + rcv, &len);
|
||||
}
|
||||
}
|
||||
ok = total + h.length() + dif == data_->bytes();
|
||||
}
|
||||
}
|
||||
do_result(ok, xfer);
|
||||
}
|
||||
scanned_img::scanned_img(SANE_Handle dev, SANE_Parameters head, void* data, unsigned int len, int dpi, const char* tmp_file
|
||||
, twain_xfer xfer, SANE_FinalImgFormat* fmt) : head_(head), dpi_(dpi), header_size_(0)
|
||||
, file_(tmp_file ? tmp_file : ""), dev_(dev), status_(SANE_Image_Statu_OK)
|
||||
{
|
||||
const bool prepare_data = true;
|
||||
|
||||
if (fmt)
|
||||
fmt_ = *fmt;
|
||||
else
|
||||
|
@ -291,7 +226,7 @@ scanned_img::scanned_img(SANE_Handle dev, SANE_Parameters head, void* data, unsi
|
|||
}
|
||||
|
||||
size_t bytes = line_bytes() * head.lines;
|
||||
std::string h(file_header(fmt_.img_format, (float)dpi, xfer));
|
||||
std::string h(file_header(fmt_.img_format, (float)dpi));
|
||||
unsigned char* dst = NULL, * src = (unsigned char*)data;
|
||||
bool ok = false;
|
||||
|
||||
|
@ -300,14 +235,17 @@ scanned_img::scanned_img(SANE_Handle dev, SANE_Parameters head, void* data, unsi
|
|||
bytes += header_size_;
|
||||
dst = data_->allocate(tmp_file, bytes);
|
||||
bytes = h.length();
|
||||
if (data_->save(h.c_str(), &bytes, 0))
|
||||
if (dst && data_->save(h.c_str(), &bytes, 0))
|
||||
{
|
||||
unsigned long long off = bytes, line_l = line_bytes();
|
||||
unsigned long long line_l = line_bytes(), off = data_->bytes() - line_l;
|
||||
unsigned int buf_len = line_bytes(), row = 0;
|
||||
if (xfer == TWAIN_XFER_Memory)
|
||||
|
||||
if (prepare_data && xfer == TWAIN_XFER_Memory)
|
||||
{
|
||||
line_l *= -1;
|
||||
else
|
||||
off = data_->size() - line_l;
|
||||
off = bytes;
|
||||
}
|
||||
|
||||
for (; row < (unsigned int)head.lines; ++row)
|
||||
{
|
||||
bytes = head.bytes_per_line;
|
||||
|
@ -318,7 +256,15 @@ scanned_img::scanned_img(SANE_Handle dev, SANE_Parameters head, void* data, unsi
|
|||
}
|
||||
ok = row == head.lines;
|
||||
}
|
||||
do_result(ok, xfer);
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
delete data_;
|
||||
data_ = NULL;
|
||||
header_size_ = 0;
|
||||
}
|
||||
else if (prepare_data)
|
||||
do_result(xfer);
|
||||
}
|
||||
scanned_img::~scanned_img()
|
||||
{
|
||||
|
@ -331,11 +277,11 @@ void scanned_img::set_image_status(SANE_Image_Statu status)
|
|||
status_ = status;
|
||||
}
|
||||
|
||||
std::string scanned_img::file_header(SANE_ImageType type, float resolution, twain_xfer xfer)
|
||||
std::string scanned_img::file_header(SANE_ImageType type, float resolution)
|
||||
{
|
||||
std::string h("");
|
||||
|
||||
if (type == SANE_IMAGE_TYPE_BMP /*&& xfer != TWAIN_XFER_Memory*/)
|
||||
if (type == SANE_IMAGE_TYPE_BMP)
|
||||
{
|
||||
BITMAPINFOHEADER bih = { 0 };
|
||||
int pal_size = 0;
|
||||
|
@ -354,7 +300,6 @@ std::string scanned_img::file_header(SANE_ImageType type, float resolution, twai
|
|||
else if (bih.biBitCount == 8)
|
||||
pal_size = 256 * sizeof(int);
|
||||
|
||||
/*if (xfer == TWAIN_XFER_File)*/
|
||||
{
|
||||
BITMAPFILEHEADER fh = { 0 };
|
||||
fh.bfType = MAKEWORD('B', 'M');
|
||||
|
@ -385,43 +330,66 @@ std::string scanned_img::file_header(SANE_ImageType type, float resolution, twai
|
|||
|
||||
return h;
|
||||
}
|
||||
void scanned_img::do_result(bool ok, twain_xfer xfer)
|
||||
{
|
||||
if (ok)
|
||||
void scanned_img::do_result(twain_xfer xfer)
|
||||
{
|
||||
if (fmt_.img_format == SANE_IMAGE_TYPE_BMP &&
|
||||
fmt_.compress.compression == SANE_COMPRESSION_GROUP4 &&
|
||||
xfer == TWAIN_XFER_Memory)
|
||||
{
|
||||
// convert to black-white ...
|
||||
std::string head(file_header(SANE_IMAGE_TYPE_BMP, (float)dpi_, TWAIN_XFER_File));
|
||||
size_t size = head.length();
|
||||
image_buf* buf = new image_buf();
|
||||
std::string file(file_ + ".tmp");
|
||||
unsigned long long off = 0;
|
||||
FILE* dst = fopen(file.c_str(), "wb");
|
||||
unsigned int size = data_->bytes();
|
||||
|
||||
if (buf->allocate(file.c_str(), size + data_->bytes(), false) &&
|
||||
buf->save(head.c_str(), &size, off))
|
||||
{
|
||||
if (buf->save(size, data_))
|
||||
if (dst && fwrite(data_->buffer(0, &size), 1, size, dst) == size)
|
||||
{
|
||||
SANE_ImageFormatConvert conv;
|
||||
std::string sf(file);
|
||||
std::string sf(file), tifff(sf + ".tiff");
|
||||
SANE_Int after = 0;
|
||||
bool conv_2_file = false;
|
||||
|
||||
conv.src.data_len = buf->bytes();
|
||||
conv.src.data = (SANE_String_Const)buf->buffer(0, &conv.src.data_len);
|
||||
fclose(dst);
|
||||
dst = nullptr;
|
||||
conv.src.data = sf.c_str();
|
||||
conv.src.data_len = sf.length();
|
||||
conv.src.fmt.img_format = SANE_IMAGE_TYPE_BMP;
|
||||
conv.src.fmt.compress.compression = SANE_COMPRESSION_NONE;
|
||||
conv.src.is_file = SANE_FALSE;
|
||||
conv.src.is_file = SANE_TRUE;
|
||||
|
||||
conv.dst.data = NULL;
|
||||
conv.dst.data_len = 0;
|
||||
conv.dst.data = conv_2_file ? tifff.c_str() : nullptr;
|
||||
conv.dst.data_len = conv_2_file ? tifff.length() : 0;
|
||||
conv.dst.fmt.img_format = SANE_IMAGE_TYPE_BMP;
|
||||
conv.dst.fmt.compress.compression = SANE_COMPRESSION_GROUP4;
|
||||
conv.dst.fmt.compress.detail = NULL;
|
||||
conv.dst.is_file = false;
|
||||
conv.dst.is_file = conv_2_file ? SANE_TRUE : SANE_FALSE;
|
||||
if (sane_helper_->invoke_sane_control_option(dev_, SANE_OPT_ID_TRANSFORM_IMAGE_FORMAT, SANE_ACTION_SET_VALUE, &conv, &after) == SANE_STATUS_GOOD)
|
||||
{
|
||||
if (conv_2_file)
|
||||
{
|
||||
FILE* src = fopen(tifff.c_str(), "rb");
|
||||
if (src)
|
||||
{
|
||||
delete data_;
|
||||
data_ = new image_buf();
|
||||
fseek(src, 0, SEEK_END);
|
||||
size = ftell(src);
|
||||
fseek(src, 0, SEEK_SET);
|
||||
data_->allocate(file_.c_str(), size);
|
||||
|
||||
char* mem = new char[size];
|
||||
fread(mem, 1, size, src);
|
||||
fclose(src);
|
||||
data_->save(mem, &size, 0);
|
||||
delete[] mem;
|
||||
|
||||
head_.format = SANE_FRAME_GRAY;
|
||||
head_.depth = 1;
|
||||
head_.bytes_per_line = (head_.pixels_per_line + 7) / 8;
|
||||
fmt_.img_format = SANE_IMAGE_TYPE_TIFF;
|
||||
}
|
||||
remove(tifff.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
delete data_;
|
||||
data_ = new image_buf();
|
||||
|
@ -429,14 +397,17 @@ void scanned_img::do_result(bool ok, twain_xfer xfer)
|
|||
data_->allocate(file_.c_str(), conv.dst.data_len);
|
||||
data_->save(conv.dst.data, &size, 0);
|
||||
sane_helper_->invoke_sane_control_option(dev_, SANE_OPT_ID_FREE_BUFFER, SANE_ACTION_SET_VALUE, (void*)&conv.dst.data, &after);
|
||||
|
||||
head_.format = SANE_FRAME_GRAY;
|
||||
head_.depth = 1;
|
||||
head_.bytes_per_line = (head_.pixels_per_line + 7) / 8;
|
||||
fmt_.img_format = SANE_IMAGE_TYPE_TIFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (buf)
|
||||
delete buf;
|
||||
if (dst)
|
||||
fclose(dst);
|
||||
remove(file.c_str());
|
||||
}
|
||||
else if (fmt_.img_format == SANE_IMAGE_TYPE_BMP
|
||||
&& channel() == 3
|
||||
|
@ -445,13 +416,7 @@ void scanned_img::do_result(bool ok, twain_xfer xfer)
|
|||
// swap RGB
|
||||
swap_rgb();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
delete data_;
|
||||
data_ = NULL;
|
||||
header_size_ = 0;
|
||||
}
|
||||
data_done_ = true;
|
||||
}
|
||||
void scanned_img::swap_rgb(void)
|
||||
{
|
||||
|
@ -573,6 +538,41 @@ COM_API_IMPLEMENT(scanned_img, size_t, get_bits_offset(void))
|
|||
return 0;
|
||||
}
|
||||
|
||||
void scanned_img::prepare_data_for_transfer(twain_xfer xfer)
|
||||
{
|
||||
if (fmt_.img_format != SANE_IMAGE_TYPE_BMP || !data_ || data_done_)
|
||||
return;
|
||||
|
||||
//if ((xfer == TWAIN_XFER_Memory && mem_xfer_data_) ||
|
||||
// (xfer != TWAIN_XFER_Memory && !mem_xfer_data_))
|
||||
// return;
|
||||
//
|
||||
|
||||
if (xfer == TWAIN_XFER_Memory)
|
||||
{
|
||||
// reverse line
|
||||
int line_l = line_bytes(),
|
||||
rows = height();
|
||||
unsigned char* buf = new unsigned char[line_l],
|
||||
* buf1 = new unsigned char[line_l];
|
||||
unsigned long long first = get_bits_offset(),
|
||||
last = first + (rows - 1) * line_l;
|
||||
for (int i = 0; i < rows / 2; ++i)
|
||||
{
|
||||
size_t want = line_l, want1 = line_l;
|
||||
data_->read(buf, &want, first);
|
||||
data_->read(buf1, &want1, last);
|
||||
data_->save(buf1, &want1, first);
|
||||
data_->save(buf, &want, last);
|
||||
first += line_l;
|
||||
last -= line_l;
|
||||
}
|
||||
}
|
||||
|
||||
do_result(xfer);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -55,13 +55,15 @@ class scanned_img : public IScanImg, virtual public refer
|
|||
image_buf* data_;
|
||||
size_t pal_size_ = 0;
|
||||
|
||||
std::string file_header(SANE_ImageType type, float resolution, twain_xfer xfer);
|
||||
void do_result(bool ok, twain_xfer xfer);
|
||||
// 部分APP不会通过XferMech来设置传输模式,原来预先准备数据的方法不适合该场合
|
||||
// 为适应该场景,增加prepare_data_for_transfer接口,在真实读取数据之前调用,以准备恰当的数据
|
||||
bool data_done_ = false;
|
||||
|
||||
std::string file_header(SANE_ImageType type, float resolution);
|
||||
void do_result(twain_xfer xfer);
|
||||
void swap_rgb(void);
|
||||
|
||||
public:
|
||||
scanned_img(SANE_Handle dev, SANE_Parameters head, int dpi, const char* tmp_file
|
||||
, twain_xfer xfer = TWAIN_XFER_Native, SANE_FinalImgFormat *fmt = NULL);
|
||||
scanned_img(SANE_Handle dev, SANE_Parameters head, void* data, unsigned int len, int dpi, const char* tmp_file
|
||||
, twain_xfer xfer = TWAIN_XFER_Native, SANE_FinalImgFormat *fmt = NULL);
|
||||
|
||||
|
@ -93,6 +95,9 @@ public:
|
|||
COM_API_OVERRIDE(void, copy_header(SANE_Parameters* head));
|
||||
COM_API_OVERRIDE(int, image_status(void));
|
||||
COM_API_OVERRIDE(size_t, get_bits_offset(void));
|
||||
|
||||
public:
|
||||
void prepare_data_for_transfer(twain_xfer xfer);
|
||||
};
|
||||
|
||||
template<class T>
|
||||
|
|
|
@ -2311,6 +2311,13 @@ COM_API_IMPLEMENT(scanner, IScanImg*, take_first_image(twain_xfer xfer))
|
|||
{
|
||||
scanned_img* img = images_.take();
|
||||
|
||||
if (img)
|
||||
{
|
||||
img->prepare_data_for_transfer(xfer);
|
||||
|
||||
utils::to_log(LOG_LEVEL_DEBUG, "Begin transferring image %d of %p\r\n", fetch_imgs_ + 1, img);
|
||||
}
|
||||
|
||||
return dynamic_cast<IScanImg*>(img);
|
||||
}
|
||||
COM_API_IMPLEMENT(scanner, bool, get_first_image_header(SANE_Parameters* header, size_t* bytes, int* dpi))
|
||||
|
@ -2343,6 +2350,8 @@ COM_API_IMPLEMENT(scanner, int, image_fetched(IScanImg* tx))
|
|||
if (ui_notify)
|
||||
ui_notify(SANE_EVENT_IMG_UPLOADED, nullptr, fetch_imgs_);
|
||||
|
||||
utils::to_log(LOG_LEVEL_DEBUG, "Transferring image %d of %p finished.\r\n", fetch_imgs_, tx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue