diff --git a/sane/scanned_img.cpp b/sane/scanned_img.cpp index e5992fb..e1efe43 100644 --- a/sane/scanned_img.cpp +++ b/sane/scanned_img.cpp @@ -381,77 +381,12 @@ unsigned int mapping_buf::mapped_bytes(void) ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // class scanned_img -scanned_img::scanned_img(SANE_Handle dev, SANE_Parameters head, int dpi - , const wchar_t* tmp_file, twain_xfer xfer - , SANE_FinalImgFormat *fmt) : head_(head), dpi_(dpi), header_size_(0), file_(tmp_file ? tmp_file : L"") - , 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 mapping_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 = hg_sane_middleware::instance()->read(dev, dst + rcv, &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 wchar_t* tmp_file , twain_xfer xfer, SANE_FinalImgFormat* fmt) : head_(head), dpi_(dpi), header_size_(0) , file_(tmp_file ? tmp_file : L""), dev_(dev), status_(SANE_Image_Statu_OK) { + const bool prepare_data = true; + if (fmt) fmt_ = *fmt; else @@ -461,7 +396,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; @@ -472,12 +407,15 @@ scanned_img::scanned_img(SANE_Handle dev, SANE_Parameters head, void* data, unsi bytes = h.length(); 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_->bytes() - line_l; + off = bytes; + } + for (; row < (unsigned int)head.lines; ++row) { bytes = head.bytes_per_line; @@ -488,7 +426,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() { @@ -501,11 +447,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; @@ -524,7 +470,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'); @@ -555,73 +500,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 ... + // convert to black-white ... size_t size = data_->bytes(); - mapping_buf* buf = new mapping_buf(); - std::wstring file(file_ + L".tmp"); - unsigned long long off = 0; + mapping_buf* buf = new mapping_buf(); + std::wstring file(file_ + L".tmp"); + unsigned long long off = 0; if (buf->allocate(file.c_str(), size, true) && buf->save(0, data_)) + { + SANE_ImageFormatConvert conv; + std::string sf(local_trans::u2a(file.c_str())), tifff(sf + ".tiff"); + bool conv_2_file = false; + + buf->unmap(); + 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 (hg_sane_middleware::instance()->io_control(dev_, IO_CTRL_CODE_CONVERT_IMAGE_FORMAT, &conv, NULL) == SANE_STATUS_GOOD) { - // if (buf->save(size, data_)) + if(conv_2_file) { - SANE_ImageFormatConvert conv; - std::string sf(local_trans::u2a(file.c_str())); - - buf->unmap(); - 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 = 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 (hg_sane_middleware::instance()->io_control(dev_, IO_CTRL_CODE_CONVERT_IMAGE_FORMAT, &conv, NULL) == SANE_STATUS_GOOD) + FILE* src = fopen(tifff.c_str(), "rb"); + if (src) { delete data_; data_ = new mapping_buf(); - size = conv.dst.data_len; - data_->allocate(file_.c_str(), conv.dst.data_len); - data_->save(conv.dst.data, &size, 0); - hg_sane_middleware::instance()->io_control(dev_, IO_CTRL_CODE_FREE_MEMORY, (void*)conv.dst.data, &conv.dst.data_len); + 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 mapping_buf(); + size = conv.dst.data_len; + data_->allocate(file_.c_str(), conv.dst.data_len); + data_->save(conv.dst.data, &size, 0); + hg_sane_middleware::instance()->io_control(dev_, IO_CTRL_CODE_FREE_MEMORY, (void*)conv.dst.data, &conv.dst.data_len); + + 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(); - } - data_->unmap(); + if (buf) + delete buf; } - 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_->unmap(); + data_done_ = true; } void scanned_img::swap_rgb(void) { @@ -748,6 +713,40 @@ 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/sane/scanned_img.h b/sane/scanned_img.h index c8d8ca0..5481934 100644 --- a/sane/scanned_img.h +++ b/sane/scanned_img.h @@ -65,13 +65,15 @@ class scanned_img : public IScanImg, virtual public refer SANE_Image_Statu status_; - 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 wchar_t* 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 wchar_t* tmp_file , twain_xfer xfer = TWAIN_XFER_Native, SANE_FinalImgFormat *fmt = NULL); @@ -103,6 +105,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/sane/scanner.cpp b/sane/scanner.cpp index 4f07c58..4792d4d 100644 --- a/sane/scanner.cpp +++ b/sane/scanner.cpp @@ -87,11 +87,11 @@ namespace callback int sane_event_callback( // 娉ㄥ唽鍥炶皟鐨勫璞★紝闇€瑕佷繚璇佽鍥炶皟鏄绾跨▼瀹夊叏鐨? SANE_Handle hdev // 浜х敓浜嬩欢鐨勮澶囧彞鏌? - , int code // 鍥炶皟浜嬩欢浠g爜 + , int code // 鍥炶皟浜嬩欢浠g? , void* data // 鍥炶皟浜嬩欢鏁版嵁锛屾牴鎹簨浠朵唬鐮佹湁鎵€涓嶅悓锛屽弬鐓у叿浣撲簨浠跺畾涔? , unsigned int* len // 鏁版嵁闀垮害锛堝瓧鑺傦級锛屾垨鑰卐vent_data鐨勭紦鍐插尯闀垮害锛岃缁嗚鐪嬬浉搴旂殑浜嬩欢浠g爜 , void* param // 鐢ㄦ埛鑷畾涔夋暟鎹紝涓庤皟鐢╯ane_init_ex浼犲叆鏃剁殑淇濇寔涓€鑷? - ) // 杩斿洖鍊间緷涓嶅悓鐨勪簨浠朵唬鐮佽€屽畾锛岄€氬父涓衡€?鈥? + ) // 杩斿洖鍊间緷涓嶅悓鐨勪簨浠朵唬鐮佽€屽畾锛岄€氬父涓衡€?? { std::lock_guard lock(cb_lock_); std::vector::iterator it = std::find(g_scanner_instances.begin(), g_scanner_instances.end(), hdev); @@ -207,9 +207,9 @@ namespace callback , {SANE_STD_OPT_NAME_FOLD_TYPE , OPTION_TITLE_DZMS} , {SANE_STD_OPT_NAME_COLOR_CORRECTION , OPTION_TITLE_SPJZ} }, - g_discard[] = { {SANE_STD_OPT_NAME_REVERSE_01 , "\351\273\221\347\231\275\345\233\276\345\203\217\345\217\215\350\211\262\350\276\223\345\207\272\357\274\210\346\255\243\345\270\270\351\242\234\350\211\262\344\270\272\357\274\2320-\351\273\221\350\211\262\357\274\2331-\347\231\275\350\211\262\357\274\211"} // 榛戠櫧鍥惧儚鍙嶈壊杈撳嚭锛堟甯搁鑹蹭负锛?-榛戣壊锛?-鐧借壊锛? - , {SANE_STD_OPT_NAME_FILTER , "\347\201\260\345\272\246\346\210\226\351\273\221\347\231\275\345\233\276\345\203\217 - \351\231\244\350\211\262"} // 鐏板害鎴栭粦鐧藉浘鍍?- 闄よ壊 - , {SANE_STD_OPT_NAME_IS_AUTO_FEED_STRENGTH , "\350\207\252\345\212\250\346\220\223\347\272\270\345\274\272\345\272\246"} // 鑷姩鎼撶焊寮哄害 + g_discard[] = { {SANE_STD_OPT_NAME_REVERSE_01 , "\351\273\221\347\231\275\345\233\276\345\203\217\345\217\215\350\211\262\350\276\223\345\207\272\357\274\210\346\255\243\345\270\270\351\242\234\350\211\262\344\270\272\357\274\2320-\351\273\221\350\211\262\357\274\2331-\347\231\275\350\211\262\357\274\211"} // 榛戠櫧鍥惧儚鍙嶈壊杈撳嚭锛堟甯搁鑹蹭负锛?-榛戣壊锛?-鐧借壊? + , {SANE_STD_OPT_NAME_FILTER , "\347\201\260\345\272\246\346\210\226\351\273\221\347\231\275\345\233\276\345\203\217 - \351\231\244\350\211\262"} // 鐏板害鎴栭粦鐧藉浘鍍?- 闄よ? + , {SANE_STD_OPT_NAME_IS_AUTO_FEED_STRENGTH , "\350\207\252\345\212\250\346\220\223\347\272\270\345\274\272\345\272\246"} // 鑷姩鎼撶焊寮哄? , {SANE_STD_OPT_NAME_FEED_STRENGTH_VALUE , "\346\220\223\347\272\270\351\230\210\345\200\274"} // " 鎼撶焊闃堝€? }; const char* option_title_2_name(const char* title) @@ -347,12 +347,12 @@ namespace callback // SANE_EVENT_IMAGE_OK - void* unused, be NULL, flag - unused, be 0 static HMODULE hui = NULL; int (*choose_scanner)(const std::vector& devs) = NULL; // blocked. return selected DEVQUE::id or -1 if user cancelled - char* (*apply_current_config)(const char* dev_name, SANE_Handle device, LPSANEAPI api) = NULL; // 搴旂敤璁惧鐨勫綋鍓嶉厤锟? + char* (*apply_current_config)(const char* dev_name, SANE_Handle device, LPSANEAPI api) = NULL; // 搴旂敤璁惧鐨勫綋鍓嶉厤? int (*show_setting_ui)(SANE_Handle device, HWND parent, LPSANEAPI api, const char* devname, bool with_scan, std::function callback) = NULL; int (*show_progress_ui)(HWND parent, std::function callback, std::function* notify) = NULL; int (*show_messagebox_ui)(HWND parent, int event, void* msg, int flag) = NULL; int (*close_ui)(int) = NULL; - int (*apply_given_config)(const char* content, SANE_Handle device, LPSANEAPI api) = NULL; // 搴旂敤鎸囧畾鐨勯厤缃紝content涓洪厤缃暟鎹祦 + int (*apply_given_config)(const char* content, SANE_Handle device, LPSANEAPI api) = NULL; // 搴旂敤鎸囧畾鐨勯厤缃紝content涓洪厤缃暟鎹? char* (*get_config_content)(const char* dev_name, const char* name) = NULL; void (*twain_ui_free)(void* buf) = NULL; @@ -945,7 +945,7 @@ int scanner::open(void) { if (callback::show_messagebox_ui) { - // 绾歌疆鎼撶焊娆℃暟宸茶秴杩囪璁′娇鐢ㄨ寖鍥达紝鎵弿杩囩▼涓悡绾稿け璐ャ€佹鏂溿€佹悡澶氬紶绛夊紓甯搁娆″彲鑳戒細鏄庢樉澧炲锛岃娉ㄦ剰鍙婃椂娓呮磥銆佸苟鑱旂郴璁惧渚涘簲鍟嗚喘涔版浛鎹㈢焊杞紒 + // 绾歌疆鎼撶焊娆℃暟宸茶秴杩囪璁′娇鐢ㄨ寖鍥达紝鎵弿杩囩▼涓悡绾稿け璐ャ€佹鏂溿€佹悡澶氬紶绛夊紓甯搁娆″彲鑳戒細鏄庢樉澧炲锛岃娉ㄦ剰鍙婃椂娓呮磥銆佸苟鑱旂郴璁惧渚涘簲鍟嗚喘涔版浛鎹㈢焊杞? std::wstring roller_msgw(local_trans::lang_trans_between_hz936(L"\u7EB8\u8F6E\u6413\u7EB8\u6B21\u6570\u5DF2\u8D85\u8FC7\u8BBE\u8BA1\u4F7F\u7528\u8303\u56F4\uFF0C\u626B\u63CF\u8FC7\u7A0B\u4E2D\u6413\u7EB8\u5931\u8D25\u3001\u6B6A\u659C\u3001\u6413\u591A\u5F20\u7B49\u5F02\u5E38\u9891\u6B21\u53EF\u80FD\u4F1A\u660E\u663E\u589E\u591A\uFF0C\u8BF7\u6CE8\u610F\u53CA\u65F6\u6E05\u6D01\u3001\u5E76\u8054\u7CFB\u8BBE\u5907\u4F9B\u5E94\u5546\u8D2D\u4E70\u66FF\u6362\u7EB8\u8F6E\uFF01")); std::string roller_msg(local_trans::u2a(roller_msgw.c_str(), CP_UTF8)); app_wnd_ = callback::find_main_wnd(); @@ -2674,7 +2674,7 @@ COM_API_IMPLEMENT(scanner, IScanImg*, take_first_image(twain_xfer xfer)) if (img) { - //img->prepare_data_for_transfer(xfer); + img->prepare_data_for_transfer(xfer); img->add_ref(); wchar_t msg[128] = { 0 }; @@ -3511,7 +3511,7 @@ int scanner::handle_device_event(int ev_code, void* data, unsigned int* len) log_info(msg, 1); } } - //else if (ev_code == SANE_EVENT_ERROR) // 灞忚斀锛屽湪鍋滄鎵弿鏃跺睍绀轰俊鎭?- 2023-05-30 + //else if (ev_code == SANE_EVENT_ERROR) // 灞忚斀锛屽湪鍋滄鎵弿鏃跺睍绀轰俊?- 2023-05-30 //{ // if (callback::show_messagebox_ui && *len) // { diff --git a/twain/twain/huagaods.cpp b/twain/twain/huagaods.cpp index 131c448..2609328 100644 --- a/twain/twain/huagaods.cpp +++ b/twain/twain/huagaods.cpp @@ -1391,8 +1391,11 @@ Result huagao_ds::imageMemXferGet(const Identity& origin, ImageMemXfer& data) if (rows == 0) return badValue(); - else if (rows > img->height()) - rows = img->height(); + else if (want_read > img->bytes() - off) + { + want_read = img->bytes() - off; + rows = (want_read + line_l - 1) / line_l; + } if (pending_xfer_.img) { @@ -1407,7 +1410,7 @@ Result huagao_ds::imageMemXferGet(const Identity& origin, ImageMemXfer& data) data.setColumns(img->width()); data.setRows(rows); data.setXOffset(0); - data.setYOffset(UInt32(off / line_l)); + data.setYOffset(UInt32((off - img->get_bits_offset())/ line_l)); data.setCompression(m_compression); if (m_compression != Compression::None) { @@ -1432,7 +1435,7 @@ Result huagao_ds::imageMemXferGet(const Identity& origin, ImageMemXfer& data) else if (img->read(dst, &want_read, off) == SCANNER_ERR_OK) { want_read /= line_l; - data.setRows(want_read); + // data.setRows(want_read); want_read *= line_l; data.setBytesWritten(want_read); off += want_read;