diff --git a/docs/sane-opts/image_encoder.txt b/docs/sane-opts/image_encoder.txt new file mode 100644 index 0000000..21d4bff --- /dev/null +++ b/docs/sane-opts/image_encoder.txt @@ -0,0 +1,41 @@ +{ + "img-fmt": { + "cat": "imgp", + "group": "output", + "title": "图片格式", + "desc": "设备输出的图片文件格式", + "type": "string", + "ver": 1, + "pos": 9900, + "ui-pos": 10, + "auth": 0, + "visible": 0, + "size": 16, + "cur": "JPEG", + "default": "JPEG", + "range": ["JPEG", "PNG", "BMP"] + }, + "jpeg-quality": { + "cat": "imgp", + "group": "output", + "title": "JPEG质量", + "desc": "设置JPEG压缩质量,质量越高,压缩率越低", + "type": "int", + "ver": 1, + "pos": 9901, + "ui-pos": 11, + "auth": 0, + "affect": 4, + "unit": "%", + "visible": 0, + "size": 4, + "cur": 100, + "default": 100, + "range": { + "min": 10, + "max": 100, + "step": 1 + }, + "depend": "img-fmt==JPEG" + } +} \ No newline at end of file diff --git a/hardware/hardware.cpp b/hardware/hardware.cpp index f601b8d..fcd0a72 100644 --- a/hardware/hardware.cpp +++ b/hardware/hardware.cpp @@ -383,13 +383,13 @@ void scanner_hw::thread_image_capture(bool paper_ready) devui::send_message(devui::UI_STATUS_SCANNING, (uint8_t*)&scanstream, sizeof(scanstream)); while(scanning_) // auto scan cycle ... { - err = start_and_wait_lifter(to_lifter_, &over_msg_id); - if(err) - break; - // scanning ONE turn ... if(paper_ready) // auto_scan_ ignore no paper { + err = start_and_wait_lifter(to_lifter_, &over_msg_id); + if(err) + break; + motor_->pick_paper(); err = scan_one_turn(&img, &avail_mem, &used_v4l2_mem, &over_msg_id); if(err || !auto_scan_ || !scanning_) diff --git a/imgproc/algs/image_encoder.cpp b/imgproc/algs/image_encoder.cpp new file mode 100644 index 0000000..a918bde --- /dev/null +++ b/imgproc/algs/image_encoder.cpp @@ -0,0 +1,110 @@ +#include "image_encoder.h" + +#include +#include + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// img_encoder +static std::string device_opt_json[] = { + "{\"img-fmt\":{\"cat\":\"imgp\",\"group\":\"output\",\"title\":\"\\u56fe\\u7247\\u683c\\u5f0f\",\"desc\":\"\\u8bbe\\u5907\\u8f93\\u51fa\\u7684\\u56fe\\u7247\\u6587\\u4ef6\\u683c\\u5f0f\",\"type\":\"string\",\"ver\":1,\"pos\":9900,\"ui-pos\":10,\"auth\":0,\"visible\":0,\"size\":16,\"cur\":\"JPEG\",\"default\":\"JPEG\",\"range\":[\"JPEG\",\"PNG\",\"BMP\"]},\"jpeg-quality\":{\"cat\":\"imgp\",\"group\":\"output\",\"title\":\"JPEG\\u8d28\\u91cf\",\"desc\":\"\\u8bbe\\u7f6eJPEG\\u538b\\u7f29\\u8d28\\u91cf\\uff0c\\u8d28\\u91cf\\u8d8a\\u9ad8\\uff0c\\u538b\\u7f29\\u7387\\u8d8a\\u4f4e\",\"type\":\"int\",\"ver\":1,\"pos\":9901,\"ui-pos\":11,\"auth\":0,\"affect\":4,\"unit\":\"%\",\"visible\":0,\"size\":4,\"cur\":100,\"default\":100,\"range\":{\"min\":10,\"max\":100,\"step\":1},\"depend\":\"img-fmt==JPEG\"}}" +}; + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// img_encoder +img_encoder::img_encoder() : image_processor("img_encoder") +{ + ADD_THIS_JSON(); + // if (!bwimg) + // { + // compression_params.push_back(cv::IMWRITE_JPEG_QUALITY); + // compression_params.push_back(100); + // } + // else{ + // compression_params.push_back(CV_IMWRITE_PNG_STRATEGY); + // compression_params.push_back(cv::IMWRITE_PNG_STRATEGY_FIXED); + // } + param_.push_back(cv::IMWRITE_JPEG_QUALITY); + param_.push_back(jpeg_quality_); +} +img_encoder::~img_encoder() +{} + +int img_encoder::set_value(const char* name, void* val) +{ + int ret = SCANNER_ERR_OK; + + if(strcmp(name, SANE_OPT_NAME(OUT_FORMAT)) == 0) + { + fmt_ = (char*)val; + if(fmt_ == "JPEG") + { + fmt_ = ".jpg"; + + param_.clear(); + param_.push_back(cv::IMWRITE_JPEG_QUALITY); + param_.push_back(jpeg_quality_); + } + else if(fmt_ == "PNG") + { + fmt_ = ".png"; + + param_.clear(); + param_.push_back(CV_IMWRITE_PNG_STRATEGY); + param_.push_back(cv::IMWRITE_PNG_STRATEGY_FIXED); + } + else + { + fmt_ = ".bmp"; + param_.clear(); + } + } + else if(strcmp(name, SANE_OPT_NAME(JPEG_QUALITY)) == 0) + { + jpeg_quality_ = *(int*)val; + } + else + { + ret = SCANNER_ERR_DEVICE_NOT_SUPPORT; + } + + return ret; +} +int img_encoder::process(std::vector& in, std::vector& out) +{ + for(auto& v: in) + { + v.info.prc_stage = get_position(); + v.info.prc_time = 0; + + out.push_back(v); + } + + return SCANNER_ERR_OK; +} + +std::shared_ptr> img_encoder::encode(LPPACKIMAGE head, cv::Mat& mat) +{ + std::shared_ptr> ptr; + chronograph watch; + + head->prc_stage = get_position(); + if(fmt_ == ".bmp") + { + size_t size = mat.total() * mat.channels(); + ptr.reset(new std::vector(size)); + memcpy(ptr->data(), mat.data, size); + head->prc_time = watch.elapse_ms(); + head->format = IMG_FMT_BMP; + } + else + { + ptr.reset(new std::vector()); + head->format = fmt_ == ".jpg" ? IMG_FMT_JPEG : IMG_FMT_PNG; + cv::imencode(fmt_.c_str(), mat, *ptr, param_); + head->prc_time = watch.elapse_ms(); + printf("encode to '%s' in %ums: %u\n", fmt_.c_str(), head->prc_time, ptr->size()); + } + + return ptr; +} \ No newline at end of file diff --git a/imgproc/algs/image_encoder.h b/imgproc/algs/image_encoder.h new file mode 100644 index 0000000..ae0f024 --- /dev/null +++ b/imgproc/algs/image_encoder.h @@ -0,0 +1,30 @@ +// encoder bmp to given format +// +// Date: 2024-02-26 +#pragma once + +#include +#include +#include + +class img_encoder : public image_processor +{ + std::string fmt_ = ".jpg"; + int jpeg_quality_ = 100; + std::vector param_; + +public: + img_encoder(); + +protected: + ~img_encoder(); + +public: + virtual int set_value(const char* name/*nullptr for all options*/, void* val/*nullptr for restore*/) override; + +public: + virtual int process(std::vector& in, std::vector& out) override; + +public: + std::shared_ptr> encode(LPPACKIMAGE head, cv::Mat& mat); +}; diff --git a/imgproc/imgprc_mgr.cpp b/imgproc/imgprc_mgr.cpp index 90ff4df..ade1a0e 100644 --- a/imgproc/imgprc_mgr.cpp +++ b/imgproc/imgprc_mgr.cpp @@ -10,6 +10,7 @@ #include "./algs/auto_crop.h" #include "./algs/color_correct.h" #include "./algs/ImageProcess_Public.h" +#include "./algs/image_encoder.h" @@ -54,7 +55,11 @@ imgproc_mgr::imgproc_mgr(std::function sender else opts_ = new device_option(true); load_processor(nullptr); - rebuild_.reset(new rebuild()); + first_.reset(new rebuild()); + last_.reset(new img_encoder()); + + opts_->add(first_.get()); + opts_->add(last_.get()); auto thrd = [&](void) -> void { @@ -96,12 +101,6 @@ data_source_ptr imgproc_mgr::scan_finished_packet(uint32_t scanid, uint32_t err) return reply; } -image_packet_ptr imgproc_mgr::image_sent_packet(LPPACKIMAGE head, dyn_mem_ptr img, uint32_t scanid, void* info, size_t info_l) -{ - image_packet_ptr pimg = new image_packet(head, img, scanid, info, info_l); - - return pimg; -} uint32_t imgproc_mgr::add_busy_worker(int inc) { @@ -148,7 +147,7 @@ void imgproc_mgr::process(RAWIMG* img) if(do_rebuild_) { - rebuild_->do_rebuild(&img->info, img->data->ptr(), in); + first_->do_rebuild(&img->info, img->data->ptr(), in); utils::to_log(LOG_LEVEL_ALL, "Rebuild paper %d spend %llu milliseconds.\n", img->info.pos.paper_ind, watch.elapse_ms()); } else @@ -161,12 +160,15 @@ void imgproc_mgr::process(RAWIMG* img) if(dump_img_) { - send_image(&img->info, img->data->ptr(), img->info.width * img->info.height); + { + cv::Mat mat(img->info.width, img->info.height, CV_8UC1, img->data->ptr()); + send_image(&img->info, mat); + } img->data->release(); for(auto& v: processors_) { - send_image(*src, false); + send_image(*src); if(v->is_enable()) { process(v, src, dst); @@ -196,7 +198,7 @@ void imgproc_mgr::process(RAWIMG* img) v.info.prc_time = t; } - send_image(*src, true); + send_image(*src); } else { @@ -234,7 +236,7 @@ void imgproc_mgr::process(image_processor* prc, std::vector* in, st throw(exception_ex(msg.c_str())); } } -void imgproc_mgr::send_image(LPPACKIMAGE head, uint8_t* data, size_t size, void* info, size_t info_l) +void imgproc_mgr::send_image(LPPACKIMAGE head, cv::Mat& mat, void* info, size_t info_l) { auto ovr = [&](uint64_t total, uint64_t cur_size, uint32_t err, void* user_data) -> int { @@ -244,31 +246,18 @@ void imgproc_mgr::send_image(LPPACKIMAGE head, uint8_t* data, size_t size, void* return 0; }; - dyn_mem_ptr mem(dyn_mem::memory(size)); - image_packet_ptr ptr = nullptr; - - // mem->set_progress_notify(ovr, mem); - mem->put(data, size); - ptr = imgproc_mgr::image_sent_packet(head, mem, scan_id_, info, info_l); - // ptr->set_progress_notify(ovr, ptr); - // printf("+dyn_mem(%p)\n+image_packet(%p)\n", mem, ptr); - - mem->release(); + PACKIMAGE h(*head); + std::shared_ptr> compd(last_->encode(&h, mat)); + image_packet_ptr ptr = new image_packet(&h, compd, scan_id_, info, info_l); + ptr->set_session_id(session_id_); img_sender_(ptr); ptr->release(); } -void imgproc_mgr::send_image(std::vector& imgs, bool clear_after_send) +void imgproc_mgr::send_image(std::vector& imgs) { for(auto& v: imgs) - { - if(clear_after_send) - v.info.prc_stage = -1; - send_image(&v.info, v.img.ptr(), v.img.total() * v.img.channels() - , v.ext_info.empty() ? nullptr : &v.ext_info[0], v.ext_info.length()); - // if(clear_after_send) - // v.img.release(); - } + send_image(&v.info, v.img, v.ext_info.empty() ? nullptr : &v.ext_info[0], v.ext_info.length()); } int imgproc_mgr::set_value(const char* name, void* val) @@ -317,6 +306,7 @@ int imgproc_mgr::load_processor(const char* path) ADD_IMG_PROCESSOR(stretch); ADD_IMG_PROCESSOR(auto_crop); ADD_IMG_PROCESSOR(color_correct); + // ADD_IMG_PROCESSOR(img_encoder); std::sort(processors_.begin(), processors_.end(), &imgproc_mgr::sort_processor_by_pos); diff --git a/imgproc/imgprc_mgr.h b/imgproc/imgprc_mgr.h index e88136d..f7be708 100644 --- a/imgproc/imgprc_mgr.h +++ b/imgproc/imgprc_mgr.h @@ -17,6 +17,7 @@ typedef std::shared_ptr> dcptr; class device_option; class rebuild; +class img_encoder; class imgproc_mgr : public sane_opt_provider { @@ -27,7 +28,8 @@ class imgproc_mgr : public sane_opt_provider bool img; }RAWIMG; - refer_guard rebuild_; + refer_guard first_; + refer_guard last_; image_processor* stretcher_ = nullptr; bool do_rebuild_ = true; volatile bool run_ = true; @@ -48,14 +50,13 @@ class imgproc_mgr : public sane_opt_provider static bool sort_processor_by_pos(image_processor* l, image_processor* r); static bool sort_image_packet(image_packet_ptr l, image_packet_ptr r); static data_source_ptr scan_finished_packet(uint32_t scanid, uint32_t err = 0); - static image_packet_ptr image_sent_packet(LPPACKIMAGE head, dyn_mem_ptr img, uint32_t scanid, void* info = nullptr, size_t info_l = 0); uint32_t add_busy_worker(int inc = 1); void thread_worker(void); void process(RAWIMG* img); void process(image_processor* prc, std::vector* in, std::vector* out); - void send_image(LPPACKIMAGE head, uint8_t* data, size_t size, void* info = nullptr, size_t info_l = 0); - void send_image(std::vector& imgs, bool clear_after_send); + void send_image(LPPACKIMAGE head, cv::Mat& mat, void* info = nullptr, size_t info_l = 0); + void send_image(std::vector& imgs); public: imgproc_mgr(std::function sender, device_option* devopts, CHK_RES_FUNC res = CHK_RES_FUNC()); diff --git a/sdk/base/data.cpp b/sdk/base/data.cpp index 4536153..cc7395e 100644 --- a/sdk/base/data.cpp +++ b/sdk/base/data.cpp @@ -928,7 +928,8 @@ uint8_t* file_map::buffer(void) //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // image_packet -image_packet::image_packet(LPPACKIMAGE head, dyn_mem_ptr img, uint32_t scanid +image_packet::image_packet(LPPACKIMAGE head, std::shared_ptr> img + , uint32_t scanid , const void* info, size_t info_size) : img_(img), offset_(0), info_over_(false) { @@ -936,7 +937,6 @@ image_packet::image_packet(LPPACKIMAGE head, dyn_mem_ptr img, uint32_t scanid LPPACKIMAGE pimg = nullptr; paper_ind_ = head->pos.paper_ind; - img->add_ref(); if(info && info_size) info_ = std::string((const char*)info, info_size); else @@ -949,7 +949,7 @@ image_packet::image_packet(LPPACKIMAGE head, dyn_mem_ptr img, uint32_t scanid pack->payload_len = sizeof(PACKIMAGE); memcpy(pimg, head, sizeof(*pimg)); - pimg->data_size = img->get_rest(); + pimg->data_size = img->size(); pimg->info_size = info_size; head_->set_len(sizeof(PACK_BASE) + sizeof(PACKIMAGE)); @@ -970,7 +970,6 @@ image_packet::image_packet(LPPACKIMAGE head, dyn_mem_ptr img, uint32_t scanid image_packet::~image_packet() { head_->release(); - img_->release(); } bool image_packet::is_memory_block(void) @@ -979,7 +978,7 @@ bool image_packet::is_memory_block(void) } uint32_t image_packet::get_rest(void) { - return head_->get_rest() + info_.length() + img_->get_rest() - offset_; + return head_->get_rest() + info_.length() + img_->size() - offset_; } // following API valid when is_memory_block() return true @@ -1023,15 +1022,15 @@ int image_packet::fetch_data(void* buf, uint32_t* size) } else { - if(*size + offset_ >= img_->get_rest()) + if(*size + offset_ >= img_->size()) { - memcpy(buf, img_->ptr() + offset_, img_->get_rest() - offset_); - *size = img_->get_rest() - offset_; - offset_ = img_->get_rest(); + memcpy(buf, img_->data() + offset_, img_->size() - offset_); + *size = img_->size() - offset_; + offset_ = img_->size(); } else { - memcpy(buf, img_->ptr() + offset_, *size); + memcpy(buf, img_->data() + offset_, *size); offset_ += *size; } } diff --git a/sdk/base/data.h b/sdk/base/data.h index deb1471..f880a5b 100644 --- a/sdk/base/data.h +++ b/sdk/base/data.h @@ -11,6 +11,9 @@ #include #define CLS_PTR(cls) typedef cls* cls##_ptr; +#ifndef uchar +typedef unsigned char uchar; +#endif //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -309,7 +312,8 @@ public: class image_packet : public data_source { - dyn_mem* img_; + // dyn_mem* img_; + std::shared_ptr> img_; dyn_mem* head_; uint32_t offset_; uint32_t paper_ind_ = 0; @@ -318,7 +322,7 @@ class image_packet : public data_source std::string pos_str_; public: - image_packet(LPPACKIMAGE head, dyn_mem* img, uint32_t scanid, const void* info = nullptr, size_t info_size = 0); + image_packet(LPPACKIMAGE head, std::shared_ptr> img, uint32_t scanid, const void* info = nullptr, size_t info_size = 0); protected: virtual ~image_packet(); diff --git a/sdk/base/plat_types.h b/sdk/base/plat_types.h index db12144..dde7936 100644 --- a/sdk/base/plat_types.h +++ b/sdk/base/plat_types.h @@ -185,6 +185,9 @@ extern uint64_t GetCurrentThreadId(void); #define pid_t int #define pthread_t HANDLE +#define _GLIBCXX_TXN_SAFE_DYN +#define _GLIBCXX_USE_NOEXCEPT + #endif diff --git a/sdk/base/utils.h b/sdk/base/utils.h index 163f05f..0565f5e 100644 --- a/sdk/base/utils.h +++ b/sdk/base/utils.h @@ -298,6 +298,10 @@ public: { return obj_; } + T* get(void) + { + return obj_; + } }; // time utility diff --git a/sdk/sane/sane_name.h b/sdk/sane/sane_name.h index 797bd2d..b096cca 100644 --- a/sdk/sane/sane_name.h +++ b/sdk/sane/sane_name.h @@ -187,6 +187,9 @@ #define SANE_STD_OPT_NAME_LUT_FILE "lut-file" #define SANE_STD_OPT_NAME_PHASE_FRONT "phase-f" #define SANE_STD_OPT_NAME_PHASE_BACK "phase-b" +#define SANE_STD_OPT_NAME_OUT_FORMAT "img-fmt" +#define SANE_STD_OPT_NAME_JPEG_QUALITY "jpeg-quality" +