diff --git a/twain/ds/scanned_img.cpp b/twain/ds/scanned_img.cpp index a1b7e39..43481f4 100644 --- a/twain/ds/scanned_img.cpp +++ b/twain/ds/scanned_img.cpp @@ -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) + , 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,8 +226,8 @@ 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)); - unsigned char* dst = NULL, *src = (unsigned char*)data; + std::string h(file_header(fmt_.img_format, (float)dpi)); + unsigned char* dst = NULL, * src = (unsigned char*)data; bool ok = false; header_size_ = h.length(); @@ -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,73 +330,93 @@ std::string scanned_img::file_header(SANE_ImageType type, float resolution, twai return h; } -void scanned_img::do_result(bool ok, twain_xfer xfer) +void scanned_img::do_result(twain_xfer xfer) { - if (ok) + if (fmt_.img_format == SANE_IMAGE_TYPE_BMP && + fmt_.compress.compression == SANE_COMPRESSION_GROUP4 && + xfer == TWAIN_XFER_Memory) { - if (fmt_.img_format == SANE_IMAGE_TYPE_BMP && - fmt_.compress.compression == SANE_COMPRESSION_GROUP4 && - xfer == TWAIN_XFER_Memory) + // convert to black-white ... + std::string file(file_ + ".tmp"); + FILE* dst = fopen(file.c_str(), "wb"); + unsigned int size = data_->bytes(); + + if (dst && fwrite(data_->buffer(0, &size), 1, size, dst) == size) { - // 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; + SANE_ImageFormatConvert conv; + std::string sf(file), tifff(sf + ".tiff"); + SANE_Int after = 0; + bool conv_2_file = false; - if (buf->allocate(file.c_str(), size + data_->bytes(), false) && - buf->save(head.c_str(), &size, off)) + 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_TRUE; + + 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 = 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 (buf->save(size, data_)) + if (conv_2_file) { - SANE_ImageFormatConvert conv; - std::string sf(file); - SANE_Int after = 0; - - conv.src.data_len = buf->bytes(); - conv.src.data = (SANE_String_Const)buf->buffer(0, &conv.src.data_len); - conv.src.fmt.img_format = SANE_IMAGE_TYPE_BMP; - conv.src.fmt.compress.compression = SANE_COMPRESSION_NONE; - conv.src.is_file = SANE_FALSE; - - conv.dst.data = NULL; - conv.dst.data_len = 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; - if (sane_helper_->invoke_sane_control_option(dev_, SANE_OPT_ID_TRANSFORM_IMAGE_FORMAT, SANE_ACTION_SET_VALUE, &conv, &after) == SANE_STATUS_GOOD) + FILE* src = fopen(tifff.c_str(), "rb"); + if (src) { delete data_; data_ = new image_buf(); - size = conv.dst.data_len; - 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); + 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(); + size = conv.dst.data_len; + 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; - } - else if (fmt_.img_format == SANE_IMAGE_TYPE_BMP - && channel() == 3 - && xfer != TWAIN_XFER_Memory) - { - // swap RGB - swap_rgb(); } + if (dst) + fclose(dst); + remove(file.c_str()); } - else + else if (fmt_.img_format == SANE_IMAGE_TYPE_BMP + && channel() == 3 + && xfer != TWAIN_XFER_Memory) { - delete data_; - data_ = NULL; - header_size_ = 0; + // swap RGB + swap_rgb(); } + 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); +} + + diff --git a/twain/ds/scanned_img.h b/twain/ds/scanned_img.h index a628e2e..60a804b 100644 --- a/twain/ds/scanned_img.h +++ b/twain/ds/scanned_img.h @@ -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 diff --git a/twain/ds/scanner.cpp b/twain/ds/scanner.cpp index d3da04b..f7f26ef 100644 --- a/twain/ds/scanner.cpp +++ b/twain/ds/scanner.cpp @@ -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(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; }