#include "image_process.h" #include "../wrapper/hg_log.h" #include #include #if !defined(WIN32) && !defined(_WIN64) #include #pragma pack(push) #pragma pack(1) typedef struct BITMAPFILEHEADER { u_int16_t bfType; u_int32_t bfSize; u_int16_t bfReserved1; u_int16_t bfReserved2; u_int32_t bfOffBits; }BITMAPFILEHEADER; typedef struct BITMAPINFOHEADER { u_int32_t biSize; u_int32_t biWidth; u_int32_t biHeight; u_int16_t biPlanes; u_int16_t biBitCount; u_int32_t biCompression; u_int32_t biSizeImage; u_int32_t biXPelsPerMeter; u_int32_t biYPelsPerMeter; u_int32_t biClrUsed; u_int32_t biClrImportant; }BITMAPINFODEADER; #pragma pack(pop) #define BI_RGB 0 #define MAKEWORD(a, b) (((a) & 0x0ff) | (((b) & 0x0ff) << 8)) #define MAKELONG(a, b) (((a) & 0x0ffff) | (((b) & 0x0ffff) << 16)) #define _countof(a) (sizeof(a) / sizeof((a)[0])) #else #include #include #pragma comment(lib, "Shell32.lib") #pragma comment(lib, "hanwangOCRdetect.lib") #endif #include #include "ImageMatQueue.h" #include "../ImageProcess/ImageApplyHeaders.h" #include "ImageMultiOutput.h" #include "PaperSize.h" #include "imgproc/HGOCR.h" #if defined(WIN32) || defined(_WIN64) #include "scanner_manager.h" #include "ocr/hanwangOCRdetect.h" #else #include extern "C" { #include "ocr/hanwangOCRdetect.h" } #endif #include "hg_ipc.h" #include "../ImageProcess/G4Tiff.h" #include "base/HGImage.h" #include #define CV_MAT_DEPTH_SET(flags, depth) (((flags) & ~(CV_MAT_DEPTH_MASK)) | (depth & CV_MAT_DEPTH_MASK)) using namespace std; #define GET_BYTE(a) ((a) & 0x0ff) #define MAKE_INT(a, b, c, d) (GET_BYTE(a) | (GET_BYTE(b) << 8) | (GET_BYTE(c) << 16) | (GET_BYTE(d) << 24)) #define IMAGE_DATA_BUF_CVMAT (void*)MAKE_INT('M', 'T', 'R', 'X') #define IMAGE_DATA_BUF_CHAR (void*)MAKE_INT('C', 'H', 'A', 'R') //动态打开库的命名 #ifdef OEM_HANWANG #ifdef WIN32 #define IMGPRC_LIBNANE L"HwImgProc.dll" #define HGBASE_LIBNAME L"HwBase.dll" #else #define IMGPRC_LIBNANE "libHwImgProc.so" #define HGBASE_LIBNAME "libHwBase.so" #endif #elif defined(OEM_LISICHENG) #ifdef WIN32 #define IMGPRC_LIBNANE L"LscImgProc.dll" #define HGBASE_LIBNAME L"LscBase.dll" #else #define IMGPRC_LIBNANE "libLscImgProc.so" #define HGBASE_LIBNAME "libLscBase.so" #endif #else #ifdef WIN32 #define IMGPRC_LIBNANE L"HGImgProc.dll" #define HGBASE_LIBNAME L"HGBase.dll" #else #define IMGPRC_LIBNANE "libHGImgProc.so" #define HGBASE_LIBNAME "libHGBase.so" #endif #endif ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // functional ... //////////////////////////////////////////////////////////////////////////////// // static int num=0; namespace hg_imgproc { typedef union { unsigned char ch; struct { unsigned char bit0 : 1; unsigned char bit1 : 1; unsigned char bit2 : 1; unsigned char bit3 : 1; unsigned char bit4 : 1; unsigned char bit5 : 1; unsigned char bit6 : 1; unsigned char bit7 : 1; }bits; }BITS; class bit_stream { unsigned char* byte_stream_; bool lsb_first_; // whether the Lowest_bit is first pop ... int offset_; public: bit_stream(unsigned char* data, bool lsb_first = true) : byte_stream_(data), lsb_first_(lsb_first) , offset_(0) {} ~bit_stream() {} public: void reset(int off = 0) { offset_ = off; } unsigned char get(void) { unsigned char ret = 0; if (lsb_first_) ret = (byte_stream_[offset_ / 8] >> (offset_ % 8)) & 1; else ret = (byte_stream_[offset_ / 8] >> (7 - (offset_ % 8))) & 1; offset_++; return ret; } }; typedef unsigned int (*SDKHGImgProc_InitOCR_)(unsigned int ocrtype, void** pstOcrHandle); typedef unsigned int (*SDKHGImgProc_FreeImage_)(void* pstOcrHandle); typedef unsigned int (*SDKHGImgProc_GetTextDir_)(void* pstOcrHandle, void* image, unsigned int* pDirect); typedef unsigned int (*SDKHGBase_CreateImage_)(void* data, void* imageinfo, void* image); typedef unsigned int (*SDKHGBase_FreeImage_)(void* image); class imgproc { std::string my_path_; IMGPRCPARAM param_; SCANCONF img_conf_; std::shared_ptr raw_data_; std::shared_ptr> buffer_; std::vector mats_; int pid_; Device::PaperSize papersize_; SANE_Image_Statu img_statu_; SDKHGImgProc_InitOCR_ ocrinit_ = NULL; SDKHGImgProc_GetTextDir_ ocrgetdirectimage_ = NULL; SDKHGImgProc_FreeImage_ ocrexit_ = NULL; SDKHGBase_CreateImage_ HGBase_CreatImg = NULL; SDKHGBase_FreeImage_ HGBase_FreeImg = NULL; void* Auto_Txt_pHanld = NULL; #ifndef WIN32 void *Dynamicopen_HGBase_pHandle_; void *Dynamicopen_HGImageprc_pHandle_; #else HINSTANCE Dynamicopen_HGBase_pHandle_; HINSTANCE Dynamicopen_HGImageprc_pHandle_; #endif void swap_rgb(cv::Mat& mat) { unsigned char* first = (unsigned char*)mat.data, * oper = first; int line_bytes = mat.rows ? mat.total() * mat.channels() / mat.rows : mat.cols * mat.channels(); for (int i = 0; i < mat.rows; ++i) { oper = first; for (int j = 0; j < mat.cols; ++j) { unsigned char ch = oper[0]; oper[0] = oper[2]; oper[2] = ch; oper += 3; } first += line_bytes; } } // construction public: imgproc(int pid) : pid_(pid),papersize_(pid_) , img_statu_(SANE_Image_Statu_OK) ,Dynamicopen_HGBase_pHandle_(NULL) ,Dynamicopen_HGImageprc_pHandle_(NULL) { my_path_ = hg_log::pe_path(); } ~imgproc() { free_auto_txt_hanld(); } // load data public: int load_raw_data(std::shared_ptr buff) { int ret = SCANNER_ERR_INSUFFICIENT_MEMORY; buffer_.reset(new std::vector(buff->size())); if (buffer_.get()) { unsigned int total = buff->size(), off = 0, size = total; unsigned char* mem = buff->data(off, &size); while (mem) { memcpy(buffer_->data(), mem, size); off += size; if (off >= total) { ret = SCANNER_ERR_OK; break; } size = total - off; mem = buff->data(off, &size); } } mats_.clear(); img_statu_ = (SANE_Image_Statu)buff->get_image_statu(); return ret; } int load_file(const char* path_file) { mats_.clear(); FILE* src = fopen(path_file, "rb"); if (!src) return SCANNER_ERR_OPEN_FILE_FAILED; long len = 0; fseek(src, 0, SEEK_END); len = ftell(src); fseek(src, 0, SEEK_SET); if (len > 1 * 1024 * 1024 * 1024) { fclose(src); return SCANNER_ERR_INSUFFICIENT_MEMORY; } raw_data_.reset(new std::string()); raw_data_->resize(len); fread(&(*raw_data_)[0], 1, len, src); fclose(src); return SCANNER_ERR_OK; } // image-processing public: int init_auto_txt_hanld() { int ret = 0; #ifndef WIN32 #ifdef OEM_HANWANG string libname = "libhwdriver.so"; #elif defined(OEM_LISICHENG) string libname = "liblscdriver.so"; #else string libname = "libhgdriver.so"; #endif string scanner_path = hg_log::get_module_full_path(libname.c_str()); if (scanner_path.empty()) { return SCANNER_ERR_OUT_OF_RANGE; } scanner_path = scanner_path.substr(0, scanner_path.size() - libname.size()); string HGImagePrclib_path = scanner_path + IMGPRC_LIBNANE; string HGBaselib_path = scanner_path + HGBASE_LIBNAME; printf("get auto txt path is:%s\r\n", scanner_path.c_str()); if (access(HGBaselib_path.c_str(), F_OK) != 0 && access(HGImagePrclib_path.c_str(), F_OK) != 0) { return SCANNER_ERR_OUT_OF_RANGE; } printf("HGBaselib_path:%s HGImagePrclib_path:%s\r\n",HGBaselib_path.c_str(),HGImagePrclib_path.c_str()); Dynamicopen_HGImageprc_pHandle_ = dlopen(HGImagePrclib_path.c_str(), RTLD_LAZY); Dynamicopen_HGBase_pHandle_ = dlopen(HGBaselib_path.c_str(), RTLD_LAZY); if (!Dynamicopen_HGBase_pHandle_ && !Dynamicopen_HGImageprc_pHandle_) { return SCANNER_ERR_OUT_OF_RANGE; } ocrinit_ = (SDKHGImgProc_InitOCR_)dlsym(Dynamicopen_HGImageprc_pHandle_, "HGImgProc_CreateOCRMgr"); ocrgetdirectimage_ = (SDKHGImgProc_GetTextDir_)dlsym(Dynamicopen_HGImageprc_pHandle_, "HGImgProc_ImageTextDirectOCR"); ocrexit_ = (SDKHGImgProc_FreeImage_)dlsym(Dynamicopen_HGImageprc_pHandle_, "HGImgProc_DestroyOCRMgr"); HGBase_CreatImg = (SDKHGBase_CreateImage_)dlsym(Dynamicopen_HGBase_pHandle_,"HGBase_CreateImageWithData"); HGBase_FreeImg = (SDKHGBase_FreeImage_)dlsym(Dynamicopen_HGBase_pHandle_,"HGBase_DestroyImage"); #else Dynamicopen_HGImageprc_pHandle_ = LoadLibrary(IMGPRC_LIBNANE); Dynamicopen_HGBase_pHandle_ = LoadLibrary(HGBASE_LIBNAME); if (Dynamicopen_HGImageprc_pHandle_ && Dynamicopen_HGBase_pHandle_) { ocrinit_ = (SDKHGImgProc_InitOCR_)GetProcAddress(Dynamicopen_HGImageprc_pHandle_, "HGImgProc_CreateOCRMgr"); ocrgetdirectimage_ = (SDKHGImgProc_GetTextDir_)GetProcAddress(Dynamicopen_HGImageprc_pHandle_, "HGImgProc_ImageTextDirectOCR"); ocrexit_ = (SDKHGImgProc_FreeImage_)GetProcAddress(Dynamicopen_HGImageprc_pHandle_, "HGImgProc_DestroyOCRMgr"); HGBase_CreatImg = (SDKHGBase_CreateImage_)GetProcAddress(Dynamicopen_HGBase_pHandle_,"HGBase_CreateImageWithData"); HGBase_FreeImg = (SDKHGBase_FreeImage_)GetProcAddress(Dynamicopen_HGBase_pHandle_,"HGBase_DestroyImage"); } #endif ret = ocrinit_(HGIMGPROC_OCRALGO_HANVON, &Auto_Txt_pHanld); return ret; } int free_auto_txt_hanld() { if (Auto_Txt_pHanld) { int ret = ocrexit_(Auto_Txt_pHanld); Auto_Txt_pHanld = NULL; } int ret = 0; if (Dynamicopen_HGImageprc_pHandle_) { #ifndef WIN32 ret = dlclose(Dynamicopen_HGImageprc_pHandle_); #else ret = FreeLibrary(Dynamicopen_HGImageprc_pHandle_); #endif Dynamicopen_HGImageprc_pHandle_ = NULL; } if (Dynamicopen_HGBase_pHandle_) { #ifndef WIN32 ret = dlclose(Dynamicopen_HGBase_pHandle_); #else ret = FreeLibrary(Dynamicopen_HGBase_pHandle_); #endif Dynamicopen_HGBase_pHandle_ = NULL; } return ret; } int decode(int pid, LPSCANCONF img_param, LPIMGPRCPARAM param) { if (!buffer_) return SCANNER_ERR_NO_DATA; img_conf_ = *img_param; param_ = *param; size_t origin = buffer_->size(); std::vector>> buffs; if(pid == 0x100 || pid == 0x200) buffs = G200Decode(buffer_,img_conf_.is_duplex,img_conf_.is_switchfrontback).getImageBuffs(); else if(pid == 0x139 || pid == 0x239) buffs = GRawDecode(buffer_).getImageBuffs(); else if(pid == 0x300 || pid == 0x400 ||pid == 0x402) buffs = G400Decode(buffer_,img_conf_.is_duplex).getImageBuffs(); if(buffs.empty()) return -1; buffer_.reset(new std::vector()); int i=0; for (auto& buf : buffs) { i++; cv::ImreadModes rmc = param_.channels > 1 ? cv::IMREAD_COLOR : cv::IMREAD_GRAYSCALE; try { if (buf->at(0) == -119 && buf->at(1) == 0x50 && buf->at(2) == 0x4e && buf->at(3) == 0x47) { rmc = cv::IMREAD_GRAYSCALE; param_.black_white = true; } else param_.black_white = false; if((pid == 0x100 || pid == 0x200 || pid == 0x300 || pid == 0x400|| pid == 0x402) && (img_conf_.filter != 3 || img_conf_.multiOutput == 1 || img_conf_.multiOutput == 2 || img_conf_.multiOutput == 0)) { rmc = cv::IMREAD_COLOR; } cv::Mat mat(cv::imdecode(*buf, rmc)); //("/home/huagao/Desktop/1.jpg",mat); if (mat.empty()) { LOG_INFO(LOG_LEVEL_FATAL, "decode image data error\n"); continue; } if(pid == 0x100 || pid == 0x200 || pid == 0x139 || pid == 0x239) { mats_.push_back(mat); //cv::imwrite(std::to_string(i)+"_decode.jpg",mat); } else if(pid == 0x300 || pid == 0x400|| pid == 0x402) { cv::Mat back = mat(cv::Rect(0, 0, mat.cols / 2, mat.rows)); cv::Mat front = mat(cv::Rect(mat.cols / 2, 0, mat.cols / 2, mat.rows)); if(img_conf_.is_duplex) { mats_.push_back(img_conf_.is_switchfrontback ? back :front); mats_.push_back(img_conf_.is_switchfrontback ? front :back); } else { mats_.push_back(front); } back.release(); front.release(); } buffer_.reset(new std::vector()); } catch (const std::exception& e) { LOG_INFO(LOG_LEVEL_FATAL, e.what()); } } buffs.clear(); VLOG_MINI_2(LOG_LEVEL_DEBUG_INFO, "Decode %u bytes to %u picture(s)\n", origin, mats_.size()); if (mats_.empty()) { return SCANNER_ERR_NO_DATA; } return SCANNER_ERR_OK; } public: int correct_text(void) { std::string sample(my_path_ + "/data/img/osd.traineddata"); CImageApplyRotation rot(CImageApplyRotation::RotationType::AutoTextOrientation, false, param_.dpi, sample.c_str()); rot.apply(mats_, img_conf_.is_duplex); if (mats_.empty()) { return SCANNER_ERR_NO_DATA; } return SCANNER_ERR_OK; } int split(int split3399) { std::vector mats(mats_); mats_.clear(); int colormode = 1; //Ĭ��1 if (img_conf_.filter == 3) colormode = img_conf_.pixtype; CImageApplySplit split(img_conf_.multiOutput, img_conf_.splitImage, img_conf_.multi_output_red, colormode); auto matexs = split.SplitMats(mats, img_conf_.is_duplex); std::string filename ; int rotation01_ = 1; int rotation02_ = 1; if((pid_ == 0x139 || pid_ == 0x239 || pid_ == 0x100 || pid_ == 0x200) && (split3399 % 2 ==0) && img_conf_.is_duplex) { rotation01_ = 0; rotation02_ = 1; } int i = 0; for(auto &matex : matexs) { cv::flip(matex.mat, matex.mat, rotation01_); cv::flip(matex.mat,matex.mat,rotation02_); if (i > 1 && ((pid_ == 0x402) || pid_ == 0x100 || pid_ == 0x400)) { cv::flip(matex.mat,matex.mat,-1); } if(!matex.mat.empty()) mats_.push_back(matex.mat); i++; } CImageApplyRotation::RotationType rotatetype = CImageApplyRotation::RotationType::Invalid; if (pid_ == 0x402 || pid_ == 0x400 || pid_ == 0x239) rotatetype = CImageApplyRotation::RotationType::Rotate_90_clockwise; else if(pid_ == 0x100) rotatetype = CImageApplyRotation::RotationType::Rotate_90_anti_clockwise; CImageApplyRotation Rotation(rotatetype,false,img_conf_.resolution_native,"./tessdata"); Rotation.apply(mats_,img_conf_.is_duplex); if (mats_.empty()) { return SCANNER_ERR_NO_DATA; } return SCANNER_ERR_OK; } int fadeback() { std::vector mats(mats_); mats_.clear(); CImageApplyFadeBackGroudColor fade(100,0, img_conf_.fadebackrange); for(size_t i = 0; i < mats.size();i++) { fade.apply(mats[i],img_conf_.is_duplex); mats_.push_back(mats[i]); // std::string filename = "/home/huagao/Desktop/fadeback("+std::to_string(num++)+").jpg"; // cv::imwrite(filename,mats_[i]); // printf("fadeback.size :%d ,filename is =%s\r\n",mats_.size(),filename.c_str()); } if (mats_.empty()) { return SCANNER_ERR_NO_DATA; } return SCANNER_ERR_OK; } int multi_out(void) { std::vector mats(mats_); mats_.clear(); for (size_t i = 0; i < mats.size(); ++i) { if (mats[i].empty()) continue; vector retmats; std::vector> m_multiprc_list; int multiout = 1, colormode = 1; //if (m_param.imageProcess.filter == ColorFilter::FILTER_NONE) //{ // colormode = m_param.pixelType; //} if (param_.channels > 1) m_multiprc_list.push_back(shared_ptr(new ImageMultiOutputRed(2))); m_multiprc_list.push_back(shared_ptr(new IMageMulti(multiout))); for (int j = 0; j < m_multiprc_list.size(); j++) { retmats = m_multiprc_list[j]->apply(mats[i]); } CImageApplySplit isp(multiout, false, 1, colormode); if (!retmats.size()) { std::vector matse; matse.push_back(mats[i]); auto matexs = isp.SplitMats(matse, img_conf_.is_duplex); for (auto& matex : matexs) { mats_.push_back(matex.mat); } break; } else { auto matexs = isp.SplitMats(retmats, img_conf_.is_duplex); for (auto& matex : matexs) { mats_.push_back(matex.mat); } } } if (mats_.empty()) { return SCANNER_ERR_NO_DATA; } return SCANNER_ERR_OK; } int multi_out(int out_type) { std::vector mats(mats_); std::vector mat; mats_.clear(); IMageMulti output(out_type); for(size_t i = 0;i < mats.size();i++) { mat = output.apply(mats[i]); for(size_t j = 0;j < mat.size();j++) { //if (out_type != MULTI_COLOR_AND_GRAY && i == mats.size() - 1) // mats_.push_back(convert_8bit_2_1bit(mat[j], 127, false, false)); //else mats_.push_back(mat[j]); // std::string filename = "multi_out("+std::to_string(num++)+").jpg"; // cv::imwrite(filename,mat[j]); } } if (mats_.empty()) { return SCANNER_ERR_NO_DATA; } return SCANNER_ERR_OK; } int multi_out_red() { std::vector mats(mats_); std::vector mat; mats_.clear(); mat.clear(); ImageMultiOutputRed outred(2); for(size_t i = 0;i < mats.size();i++) { mat = outred.apply(mats[i]); for(size_t j = 0;j < mat.size();j++) { mats_.push_back(mat[j]); } // std::string filename = "/home/huagao/Desktop/multi_out_red("+std::to_string(num++)+").jpg"; // cv::imwrite(filename,mats_[i]); // printf("fadeback.size :%d ,filename is =%s\r\n",mats_.size(),filename.c_str()); } if (mats_.empty()) { return SCANNER_ERR_NO_DATA; } return SCANNER_ERR_OK; } int auto_matic_color(int color_type) { int ret = SCANNER_ERR_OK; std::vector mats(mats_); mats_.clear(); for(size_t i = 0;i < mats.size();i++) { CImageApplyColorRecognition ColorRecognition(color_type==1? CImageApplyColorRecognition::ColorRecognitionMode::Color_Gray : CImageApplyColorRecognition::ColorRecognitionMode::Color_Mono); ColorRecognition.apply(mats[i],img_conf_.is_duplex); mats_.push_back(mats[i]); } if (mats_.empty()) { return SCANNER_ERR_NO_DATA; } return SCANNER_ERR_OK; } /*pixtype 0 colcor; 1 gray; 2 bw*/ int auto_crop() { int ret = SCANNER_ERR_OK; std::vector mats(mats_); mats_.clear(); SIZE temp_Size = papersize_.GetPaperSize(img_conf_.papertype,200,img_conf_.paperAlign); cv::Size cvSize(temp_Size.cx, temp_Size.cy); CImageApplyAutoCrop crop(img_conf_.is_autocrop,img_conf_.autodescrew,img_conf_.fillbackground,cvSize,img_conf_.is_convex,img_conf_.isfillcolor); crop.apply(mats,img_conf_.is_duplex); mats_ = mats; //cv::imwrite("/home/huagao/Desktop/mats_.jpg",mats_[0]); if (mats_.empty()) { return SCANNER_ERR_NO_DATA; } return SCANNER_ERR_OK; } int fillhole(float top,float low,float l,float r) { int ret = SCANNER_ERR_OK; std::vector mats(mats_); mats_.clear(); float scale = img_conf_.fillhole.fillholeratio / 100.0; float val = img_conf_.resolution_dst / 10; cv::Vec4f edgeScale; edgeScale[0] = top; edgeScale[1] = low; edgeScale[2] = l; edgeScale[3] = r; CImageApplyOutHole outh(val, edgeScale,50); outh.apply(mats,img_conf_.is_duplex); mats_ = mats; if (mats_.empty()) { return SCANNER_ERR_NO_DATA; } return SCANNER_ERR_OK; } int resolution_change() { int ret = SCANNER_ERR_OK; CImageApplyFilter::FilterMode sharpenType = CImageApplyFilter::FilterMode::None; std::vector mats(mats_); mats_.clear(); CImageApplyResize::ResizeType resizeType; double ratio = 1.0; SIZE reSize = papersize_.GetPaperSize(img_conf_.papertype, img_conf_.resolution_dst,img_conf_.paperAlign); cv::Size cvSize(reSize.cx, reSize.cy); if (img_conf_.is_autocrop || img_conf_.cropRect.enable) { resizeType = CImageApplyResize::ResizeType::RATIO; ratio = img_conf_.resolution_dst / (float)img_conf_.resolution_native; } else resizeType = CImageApplyResize::ResizeType::DSIZE; CImageApplyResize resize(resizeType,cvSize,ratio,ratio); resize.apply(mats,img_conf_.is_duplex); if (img_conf_.resolution_dst > 200 && img_conf_.sharpen == CImageApplyFilter::FilterMode::None) { if (img_conf_.resolution_dst <= 300) sharpenType = CImageApplyFilter::FilterMode::Sharpen; else if (img_conf_.resolution_dst > 300 && img_conf_.resolution_dst <= 600) sharpenType = CImageApplyFilter::FilterMode::Sharpen_More; CImageApplyFilter Filte(sharpenType); for (size_t i = 0; i < mats.size(); ++i) { Filte.apply(mats[i], img_conf_.is_duplex); mats_.push_back(mats[i]); } } else { if(!mats.empty()) mats_ = mats; } if (mats_.empty()) { return SCANNER_ERR_NO_DATA; } return SCANNER_ERR_OK; } int croprect() { int ret = SCANNER_ERR_OK; std::vector mats(mats_); mats_.clear(); CImageApplyCustomCrop rect(cv::Rect(img_conf_.cropRect.x, img_conf_.cropRect.y, img_conf_.cropRect.width, img_conf_.cropRect.height)); for (size_t i = 0; i < mats.size(); ++i) { rect.apply(mats[i],img_conf_.is_duplex); mats_.push_back(mats[i]); } if (mats_.empty()) { return SCANNER_ERR_NO_DATA; } return SCANNER_ERR_OK; } int channel() { int ret = SCANNER_ERR_OK; std::vector mats(mats_); mats_.clear(); CImageApplyChannel chl((CImageApplyChannel::channel)(img_conf_.filter)); for (size_t i = 0; i < mats.size(); i++) { chl.apply(mats[i],img_conf_.is_duplex); mats_.push_back(mats[i]); } if (mats_.empty()) { return SCANNER_ERR_NO_DATA; } return SCANNER_ERR_OK; } int adjust_color(unsigned char* gamma_table = nullptr, int tableLength = 0) { int ret = SCANNER_ERR_OK; std::vector mats(mats_); mats_.clear(); //VLOG_MINI_4(LOG_LEVEL_DEBUG_INFO, "adjust_color: table len = %d, brightness = %f, contrast = %f, gamma = %f\n", tableLength // , img_conf_.brightness, img_conf_.contrast, img_conf_.gamma); if(gamma_table && tableLength) { CImageApplyCustomGamma gamme(gamma_table, tableLength); gamme.apply(mats, img_conf_.is_duplex); } else { if (img_conf_.brightness != 128 ||img_conf_.contrast != 4 || ((img_conf_.gamma < (1.0f - 1e-2)) || (img_conf_.gamma > (1.0f + 1e-2))) ) { int temp_contrast = (img_conf_.contrast - 4) * 12; CImageApplyAdjustColors justColors(img_conf_.brightness - 128, temp_contrast, img_conf_.gamma); for (size_t i = 0; i < mats.size(); ++i) { justColors.apply(mats[i],img_conf_.is_duplex); } } //cv::imwrite("/home/huagao/Desktop/customgamma2.jpg",mats_[0]); } mats_ = mats; if (mats_.empty()) { return SCANNER_ERR_NO_DATA; } return SCANNER_ERR_OK; } int antiInflow(int permeate_lv) { int ret = SCANNER_ERR_OK; std::vector mats(mats_); mats_.clear(); CImageApplyRefuseInflow Inflow(permeate_lv); for (size_t i = 0; i < mats.size(); ++i) { Inflow.apply(mats[i],img_conf_.is_duplex); mats_.push_back(mats[i]); } if (mats_.empty()) { return SCANNER_ERR_NO_DATA; } return SCANNER_ERR_OK; } int colorCorrection() { int ret = SCANNER_ERR_OK; std::vector mats(mats_); mats_.clear(); CImageApplyAutoContrast con; con.apply(mats,img_conf_.is_duplex); mats_= mats; if (mats_.empty()) { return SCANNER_ERR_NO_DATA; } return SCANNER_ERR_OK; } int orentation() { int ret = SCANNER_ERR_OK; std::vector mats(mats_); mats_.clear(); mats_.resize(mats.size()); CImageApplyRotation::RotationType rotatetype = CImageApplyRotation::RotationType::Invalid; switch ((CImageApplyRotation::RotationType)img_conf_.imageRotateDegree) { case CImageApplyRotation::RotationType::Rotate_90_clockwise: rotatetype = CImageApplyRotation::RotationType::Rotate_90_clockwise; break; case CImageApplyRotation::RotationType::Rotate_180: rotatetype = CImageApplyRotation::RotationType::Rotate_180; break; case CImageApplyRotation::RotationType::Rotate_90_anti_clockwise: rotatetype = CImageApplyRotation::RotationType::Rotate_90_anti_clockwise; break; default: break; } if (img_conf_.is_autotext) rotatetype = CImageApplyRotation::RotationType::AutoTextOrientation; unsigned char back180 = false; if (img_conf_.splitImage) unsigned char back180 = false; else back180 = img_conf_.is_backrotate180; CImageApplyRotation Rotation(rotatetype, back180,img_conf_.resolution_native,"./tessdata"); Rotation.apply(mats,img_conf_.is_duplex); mats_ = mats; if (mats_.empty()) { return SCANNER_ERR_NO_DATA; } return SCANNER_ERR_OK; } int textureRemove() { int ret = SCANNER_ERR_OK; std::vector mats(mats_); mats_.clear(); CImageApplyTextureRemoval Removal; Removal.apply(mats,img_conf_.is_duplex); mats_ = mats; if (mats_.empty()) { return SCANNER_ERR_NO_DATA; } return SCANNER_ERR_OK; } int sharpenType() { int ret = SCANNER_ERR_OK; std::vector mats(mats_); mats_.clear(); CImageApplyFilter::FilterMode sharpenType = (CImageApplyFilter::FilterMode)img_conf_.sharpen; CImageApplyFilter Filte(sharpenType); for (size_t i = 0; i < mats.size(); ++i) { Filte.apply(mats[i],img_conf_.is_duplex); mats_.push_back(mats[i]); } if (mats_.empty()) { return SCANNER_ERR_NO_DATA; } return SCANNER_ERR_OK; } int nosieDetach() { int ret = SCANNER_ERR_OK; std::vector mats(mats_); mats_.clear(); CImageApplyDetachNoise Noise(img_conf_.detachnoise.detachnoise); for (size_t i = 0; i < mats.size(); ++i) { Noise.apply(mats[i],img_conf_.is_duplex); mats_.push_back(mats[i]); } if (mats_.empty()) { return SCANNER_ERR_NO_DATA; } return SCANNER_ERR_OK; } int errorextention() { int ret = SCANNER_ERR_OK; std::vector mats(mats_); mats_.clear(); CImageApplyBWBinaray::ThresholdType thrtype; if(img_conf_.errorExtention) thrtype = CImageApplyBWBinaray::ThresholdType::ERROR_DIFFUSION; else thrtype = CImageApplyBWBinaray::ThresholdType::THRESH_BINARY; CImageApplyBWBinaray BWBinaray(thrtype); for (size_t i = 0; i < mats.size(); ++i) { BWBinaray.apply(mats[i],img_conf_.is_duplex); mats_.push_back(mats[i]); } if (mats_.empty()) { return SCANNER_ERR_NO_DATA; } return SCANNER_ERR_OK; } int discardBlank() { int ret = SCANNER_ERR_OK; std::vector mats(mats_); mats_.clear(); double threshold = 40; int edge = 150; if (img_conf_.is_autodiscradblank_vince) img_conf_.discardblank_percent *= 1.5; CImageApplyDiscardBlank(threshold,edge,img_conf_.discardblank_percent); for (size_t i = 0; i < mats.size(); ++i) { bool b = CImageApplyDiscardBlank::apply(mats[i]); if (b) mats[i].release(); else mats_.push_back(mats[i]); } if (mats_.empty()) { return SCANNER_ERR_NO_DATA; } return SCANNER_ERR_OK; } int answerSheetFilterRed() { int ret = SCANNER_ERR_OK; std::vector mats(mats_); mats_.clear(); CImageApplyHSVCorrect correct((CImageApplyHSVCorrect::Red_Removal)); for (size_t i = 0; i < mats.size(); ++i) { correct.apply(mats[i],img_conf_.is_duplex); mats_.push_back(mats[i]); } if (mats_.empty()) { return SCANNER_ERR_NO_DATA; } return SCANNER_ERR_OK; } int fold() { int ret = SCANNER_ERR_OK; std::vector mats(mats_); mats_.clear(); CImageApplyConcatenation fold((CImageApplyConcatenation::ConcatMode)img_conf_.fold_concatmode); fold.apply(mats,img_conf_.is_duplex); mats_= mats; if (mats_.empty()) { return SCANNER_ERR_NO_DATA; } return SCANNER_ERR_OK; } int quality(int dpi_dst) { int ret = SCANNER_ERR_OK; CImageApplyFilter::FilterMode sharpenType = CImageApplyFilter::FilterMode::None; std::vector mats(mats_); mats_.clear(); //mats_.resize(mats.size()); float xy = (float)dpi_dst/200.0; for (size_t i = 0; i < mats.size(); ++i) { cv::Mat out; cv::resize(mats[i],out, cv::Size(),xy,xy); } if (img_conf_.resolution_dst <= 300) sharpenType = CImageApplyFilter::FilterMode::Sharpen; else if (img_conf_.resolution_dst > 300 && img_conf_.resolution_dst <= 600) sharpenType = CImageApplyFilter::FilterMode::Sharpen_More; CImageApplyFilter Filte(sharpenType); for (size_t i = 0; i < mats.size(); ++i) { Filte.apply(mats[i], img_conf_.is_duplex); mats_.push_back(mats[i]); } if (mats_.empty()) { return SCANNER_ERR_NO_DATA; } return SCANNER_ERR_OK; } #ifdef _WIN32 #endif #define test int ocr_auto_txtdirect() { std::vector mats(mats_); mats_.clear(); int pDirect = -1, ret = SCANNER_ERR_OK; void* pHanld = NULL; typedef int (* SDKInitialize)(void** ppstOcrHandle); typedef void(* SDKExit)(void* pstOcrHandle); typedef int (* SDKGetFileDirectImage)(BYTE* pbImage, int nWidth, int nHeight, TColorType nColorType, void* pstHandle, int* pDirect); SDKInitialize ocrinit = NULL; SDKGetFileDirectImage ocrgetdirectimage = NULL; SDKExit ocrexit = NULL; #ifndef WIN32 #ifdef OEM_HANWANG string libname = "libhwdriver.so"; #elif defined(OEM_LISICHENG) string libname = "liblscdriver.so"; #else string libname = "libhgdriver.so"; #endif string scanner_path = hg_log::get_module_full_path(libname.c_str()); if(scanner_path.empty()) { return SCANNER_ERR_OUT_OF_RANGE; } scanner_path = scanner_path.substr(0,scanner_path.size() - libname.size()); scanner_path+="libhwocrdetect.so"; printf("hwlib path:%s\r\n",scanner_path.c_str()); if(access(scanner_path.c_str(),F_OK) != 0) { return SCANNER_ERR_OUT_OF_RANGE; } #endif #if ((!defined x86_64) && (!defined WIN32)) //linux x86_64 void *hanlde = dlopen(scanner_path.c_str(),RTLD_LAZY); if(!hanlde) { return SCANNER_ERR_OUT_OF_RANGE; } ocrinit = (SDKInitialize)dlsym(hanlde , "HWOCR_SDKInitialize"); ocrgetdirectimage = (SDKGetFileDirectImage)dlsym(hanlde , "HWOCR_GetFileDirectImage"); ocrexit= (SDKExit)dlsym(hanlde , "HWOCR_SDKExit"); #else #ifdef _WIN32 HINSTANCE handle = LoadLibrary(L"hanwangOCRdetect.dll"); if (handle) { ocrinit = (SDKInitialize)GetProcAddress(handle, "HWOCR_SDKInitialize"); ocrgetdirectimage = (SDKGetFileDirectImage)GetProcAddress(handle, "HWOCR_GetFileDirectImage"); ocrexit = (SDKExit)GetProcAddress(handle, "HWOCR_SDKExit"); } #endif // WIN32 #endif int r = ocrinit(&pHanld); for (size_t i = 0; i < mats.size(); i++) { r = ocrgetdirectimage(const_cast(mats[i].data), mats[i].cols, mats[i].rows, mats[i].channels() == 1 ? TColorType::EGray256 : TColorType::EColor16M, pHanld, &pDirect); if (pDirect == 1) pDirect = 3; else if (pDirect == 3) pDirect = 1; CImageApplyRotation(CImageApplyRotation::RotationType(pDirect)).apply(mats[i], false); mats_.push_back(mats[i]); } ocrexit(pHanld); #if ((!defined x86_64) && (!defined WIN32)) dlclose(hanlde); #else #endif if (mats_.empty()) { return SCANNER_ERR_NO_DATA; } return SCANNER_ERR_OK; } int tesseract_auto_txtdirect() { std::vector mats(mats_); mats_.clear(); unsigned int pDirect = 0, ret = SCANNER_ERR_OK; HGImage image; if (ocrinit_ && ocrgetdirectimage_ && ocrexit_) { for (size_t i = 0; i < mats.size(); i++) { HGImage b = opencv_to_hgbase_image(mats[i]); ret = ocrgetdirectimage_(Auto_Txt_pHanld, b, &pDirect); HGBase_FreeImg(b); //HGBase_DestroyImage(b); switch (pDirect) { case HGIMGPROC_OCRTEXTDIRECT_ORI: pDirect = (unsigned int)CImageApplyRotation::RotationType::Invalid; break; case HGIMGPROC_OCRTEXTDIRECT_RIGHT: pDirect = (unsigned int)CImageApplyRotation::RotationType::Rotate_90_anti_clockwise; break; case HGIMGPROC_OCRTEXTDIRECT_LEFT: pDirect = (unsigned int)CImageApplyRotation::RotationType::Rotate_90_clockwise; break; case HGIMGPROC_OCRTEXTDIRECT_180: pDirect = (unsigned int)CImageApplyRotation::RotationType::Rotate_180; break; default: pDirect = (int)CImageApplyRotation::RotationType::Invalid; break; } CImageApplyRotation(CImageApplyRotation::RotationType(pDirect)).apply(mats[i], false); mats_.push_back(mats[i]); } } if (mats_.empty()) { return SCANNER_ERR_NO_DATA; } return SCANNER_ERR_OK; } int size_detection() { int ret = SCANNER_ERR_OK; std::vector mats(mats_); mats_.clear(); CImageApplySizeDetection paper(img_conf_.papertype); for (size_t i = 0; i < mats.size(); ++i) { ret = paper.apply(mats[i]); mats_.push_back(mats[i]); } if(ret == 1) { return SCANNER_ERR_DEVICE_SIZE_CHECK; } return SCANNER_ERR_OK; } HGImage opencv_to_hgbase_image(const cv::Mat& mats) { HGImage image; HGImageInfo info; info.height = mats.rows; info.width = mats.cols; info.origin = HGBASE_IMGORIGIN_TOP; int bits = mats.channels() == 1 ? 8 : 24; info.widthStep = mats.step; //opencv原始值 info.type = mats.channels() == 1 ? HGBASE_IMGTYPE_GRAY : HGBASE_IMGTYPE_BGR; int ret = HGBase_CreatImg(const_cast(mats.data), &info, &image); //int ret = HGBase_CreateImageWithData(const_cast(mats.data), &info, &image); return image; } /// /// 8位图转1位图 /// /// 8bit图 /// 阈值,建议默认127 /// true为反色,即黑0白1;反之亦然 /// true为四字节对齐 /// 1位图 /// static cv::Mat convert_8bit_2_1bit(const cv::Mat& image, uchar threshold, bool reverse, bool align) { if (image.channels() != 1) return cv::Mat(); int cols = align ? (((image.cols + 7) / 8 + 3) / 4 * 4) : ((image.cols + 7) / 8); int rows = image.rows; uchar tableData[256]; memset(tableData, reverse ? 0 : 1, 256); memset(tableData, reverse ? 1 : 0, threshold); int* index_dst = new int[image.cols]; int* index_carry = new int[image.cols]; for (size_t i = 0; i < image.cols; i++) { index_dst[i] = i / 8; index_carry[i] = 7 - (i % 8); } cv::Mat dst = cv::Mat::zeros(rows, cols, CV_8UC1); uchar* ptr_src, * ptr_dst; for (size_t y = 0; y < rows; y++) { ptr_dst = dst.ptr(y); ptr_src = const_cast(image.ptr(y)); for (size_t x = 0; x < image.cols; x++) ptr_dst[index_dst[x]] += tableData[ptr_src[x]] << index_carry[x]; } delete[] index_dst; delete[] index_carry; return dst; } // final public: int final(void) { std::vector mats(mats_); mats_.clear(); for (size_t i = 0; i < mats.size(); ++i) { if (mats[i].empty()) continue; int bpp = param_.black_white ? 8 : param_.bits * param_.channels; MatEx out(mats[i], bpp); if (out.mat.channels() == 3) swap_rgb(out.mat); mats_.push_back(out.mat); //cv::imwrite(std::to_string(i++)+"_final.jpg",out.mat); } return SCANNER_ERR_OK; } int get_final_data(LPIMGHEAD pimh, void** buf, int index) { if ((index < 0 || index >= mats_.size())) return SCANNER_ERR_NO_DATA; pimh->width = mats_[index].cols; pimh->height = mats_[index].rows; pimh->bits = 8; //mats_[index].depth pimh->channels = mats_[index].channels(); pimh->total_bytes = mats_[index].total() * pimh->channels; pimh->line_bytes = pimh->height ? pimh->total_bytes / pimh->height : pimh->width * pimh->channels; *buf = mats_[index].data; pimh->statu = img_statu_; //printf("pimh->channels = %d \r\n",pimh->channels); return SCANNER_ERR_OK; } int get_final_data(LPIMGHEAD pimh, std::vector* buf, int index) { if ((index < 0 || index >= mats_.size())) return SCANNER_ERR_NO_DATA; pimh->width = mats_[index].cols; pimh->height = mats_[index].rows; pimh->bits = 8; //mats_[index].depth pimh->channels = mats_[index].channels(); pimh->statu = img_statu_; if((pimh->width * pimh->channels) % 4) { int len = pimh->width * pimh->channels; pimh->line_bytes = (len + 3) / 4 * 4; pimh->total_bytes = pimh->line_bytes * pimh->height; buf->resize(pimh->total_bytes); //printf("pimh->total_bytes=%d pimh->line_bytes=%d\r\n",pimh->total_bytes,pimh->line_bytes); unsigned char* src = mats_[index].data, *dst = buf->data(); for(int i = 0; i < pimh->height; ++i) { memcpy(dst, src, len); dst += pimh->line_bytes; src += len; } } else { pimh->total_bytes = mats_[index].total() * pimh->channels; pimh->line_bytes = pimh->height ? pimh->total_bytes / pimh->height : pimh->width * pimh->channels; buf->resize(pimh->total_bytes); memcpy(buf->data(), mats_[index].data, pimh->total_bytes); //cv::imwrite(to_string(index)+"_final.jpg",mats_[index]); } //printf("pimh->channels_01 = %d \r\n",pimh->channels); return SCANNER_ERR_OK; } int imgtypechange(std::string img_type_,void *buf,std::vector &bmpdata) { int ret = SCANNER_ERR_OK; if(!buf) { return SCANNER_ERR_NO_DATA; } cv::imencode(img_type_,*((cv::Mat*)buf),bmpdata); return ret; } void dump_2_file(const char* local_file) { if (mats_.size()) { cv::imwrite(local_file, mats_[0]); if (mats_.size() > 1) { std::string path(local_file), name(""), ext(""); size_t pos = path.rfind(PATH_SEPARATOR[0]); char sn[20] = { 0 }; if (pos++ != std::string::npos) { name = path.substr(pos); path.erase(pos); pos = name.rfind('.'); if (pos != std::string::npos) { ext = name.substr(pos); name.erase(pos); } } for (size_t i = 1; i < mats_.size(); ++i) { sprintf(sn, "(%d)", i); cv::imwrite((path + name + sn + ext).c_str(), mats_[i]); } } } else { LOG_INFO(LOG_LEVEL_ALL, "No image output in image_process!\n"); } } }; //////////////////////////////////////////////////////////////////////////////////////////////////////////////// // api ... HIMGPRC init(int pid) { imgproc* obj = new imgproc(pid); return (HIMGPRC)obj; } int load_buffer(HIMGPRC himg, std::shared_ptr buff) { return ((imgproc*)himg)->load_raw_data(buff); } int load_file(HIMGPRC himg, const char* path_file) { return ((imgproc*)himg)->load_file(path_file); } int decode(HIMGPRC himg, int pid, LPSCANCONF img_param, LPIMGPRCPARAM param) { return ((imgproc*)himg)->decode(pid, img_param, param); } int init_auto_txt_hanld(HIMGPRC himg) { return ((imgproc*)himg)->init_auto_txt_hanld(); } int free_auto_txt_hanld(HIMGPRC himg) { return ((imgproc*)himg)->free_auto_txt_hanld(); } int correct_text(HIMGPRC himg) { return ((imgproc*)himg)->correct_text(); } int split(HIMGPRC himg,int split3399) { return ((imgproc*)himg)->split(split3399); } int fadeback(HIMGPRC himg) { return ((imgproc*)himg)->fadeback(); } int multi_out(HIMGPRC himg) { return ((imgproc*)himg)->multi_out(); } int multi_out(HIMGPRC himg,int out_type) { return ((imgproc*)himg)->multi_out(out_type); } int multi_out_red(HIMGPRC himg) { return ((imgproc*)himg)->multi_out_red(); } int auto_matic_color(HIMGPRC himg,int color_type) { return ((imgproc*)himg)->auto_matic_color(color_type); } int auto_crop(HIMGPRC himg) { return ((imgproc*)himg)->auto_crop(); } int fillhole(HIMGPRC himg, float top, float low, float l, float r) { return ((imgproc*)himg)->fillhole(top, low, l,r); } int resolution_change(HIMGPRC himg) { return ((imgproc*)himg)->resolution_change(); } int croprect(HIMGPRC himg) { return ((imgproc*)himg)->croprect(); } int channel(HIMGPRC himg) { return ((imgproc*)himg)->channel(); } int adjust_color(HIMGPRC himg, unsigned char* table, int tableLength) { return ((imgproc*)himg)->adjust_color(table, tableLength); } int antiInflow(HIMGPRC himg,int permeate_lv) { return ((imgproc*)himg)->antiInflow(permeate_lv); } int colorCorrection(HIMGPRC himg) { return ((imgproc*)himg)->colorCorrection(); } int orentation(HIMGPRC himg) { return ((imgproc*)himg)->orentation(); } int textureRemove(HIMGPRC himg) { return ((imgproc*)himg)->textureRemove(); } int sharpenType(HIMGPRC himg) { return ((imgproc*)himg)->sharpenType(); } int nosieDetach(HIMGPRC himg) { return ((imgproc*)himg)->nosieDetach(); } int errorextention(HIMGPRC himg) { return ((imgproc*)himg)->errorextention(); } int discardBlank(HIMGPRC himg) { return ((imgproc*)himg)->discardBlank(); } int answerSheetFilterRed(HIMGPRC himg) { return ((imgproc*)himg)->answerSheetFilterRed(); } //img_type_ = jpg png bmp int imgtypechange(HIMGPRC himg,std::string img_type_,void *buf,std::vector &bmpdata) { return ((imgproc*)himg)->imgtypechange(img_type_,buf,bmpdata); } int fold(HIMGPRC himg) { return ((imgproc*)himg)->fold(); } int quality(HIMGPRC himg,int dpi) { return ((imgproc*)himg)->quality(dpi); } int ocr_auto_txtdirect(HIMGPRC himg) { return ((imgproc*)himg)->ocr_auto_txtdirect(); } int tesseract_auto_txtdirect(HIMGPRC himg) { return ((imgproc*)himg)->tesseract_auto_txtdirect(); } int size_detection(HIMGPRC himg) { return ((imgproc*)himg)->size_detection(); } int final(HIMGPRC himg) { return ((imgproc*)himg)->final(); } int get_final_data(HIMGPRC himg, LPIMGHEAD pimh, void** buf, int index) { return ((imgproc*)himg)->get_final_data(pimh, buf, index); } int get_final_data(HIMGPRC himg, LPIMGHEAD pimh, std::vector* buf, int index) { return ((imgproc*)himg)->get_final_data(pimh, buf, index); } void dump_2_file(HIMGPRC himg, const char* local_file) { ((imgproc*)himg)->dump_2_file(local_file); } void release(HIMGPRC himg) { imgproc* obj = (imgproc*)himg; delete obj; } // seperate utilites ... static cv::Mat from_bmp_file_bits(const BITMAPINFOHEADER& bih, unsigned char* data, bool line_reverse, bool bw_reverse) { cv::Mat m; int bytes = 0, align = 0; unsigned char *dst = NULL; m.create(bih.biHeight, bih.biWidth, bih.biBitCount > 8 ? CV_8UC3 : CV_8UC1); dst = m.ptr(); bytes = (bih.biBitCount * bih.biWidth + 7) / 8; align = (bytes + 3) / 4 * 4; if (line_reverse) { data += align * (bih.biHeight - 1); align *= -1; } if (bih.biBitCount >= 8) { if (bih.biBitCount == 8 && bw_reverse) { for (int i = 0; i < bih.biHeight; ++i) { for (int j = 0; j < bytes; ++j) dst[j] = data[j] ^ 0x0ff; dst += bytes; data += align; } } else { for (int i = 0; i < bih.biHeight; ++i) { memcpy(dst, data, bytes); dst += bytes; data += align; } } } else // if (bih.biBitCount == 1) { unsigned char bw[] = { !bw_reverse - 1, bw_reverse - 1}; bytes = bih.biWidth; for (int i = 0; i < bih.biHeight; ++i) { bit_stream bs(data, false); for (int j = 0; j < bih.biWidth; ++j) dst[j] = bw[bs.get()]; dst += bytes; data += align; } } return m; } int convert_image_file(SANE_ImageFormatConvert* conv) { if (conv->src.fmt.img_format != SANE_IMAGE_TYPE_BMP && conv->src.fmt.compress.compression != SANE_COMPRESSION_NONE) return SCANNER_ERR_DEVICE_NOT_SUPPORT; if(conv->dst.fmt.img_format != SANE_IMAGE_TYPE_JFIF && conv->dst.fmt.img_format != SANE_IMAGE_TYPE_TIFF && conv->dst.fmt.compress.compression != SANE_COMPRESSION_NONE && conv->dst.fmt.compress.compression != SANE_COMPRESSION_GROUP4) return SCANNER_ERR_DEVICE_NOT_SUPPORT; int fh = sizeof(BITMAPFILEHEADER); BITMAPINFOHEADER bih = { 0 }; unsigned char *bits = NULL; std::shared_ptr> data; if (conv->src.is_file) { BITMAPFILEHEADER bfh = { 0 }; FILE* src = fopen(conv->src.data, "rb"); long len = 0; if (!src) return SCANNER_ERR_OPEN_FILE_FAILED; fseek(src, 0, SEEK_END); len = ftell(src) - fh; if (len <= 0) { fclose(src); return SCANNER_ERR_DATA_DAMAGED; } fseek(src, 0, SEEK_SET); fread(&bfh, sizeof(bfh), 1, src); fread(&bih, sizeof(bih), 1, src); if (len < bfh.bfOffBits) { fclose(src); return SCANNER_ERR_DATA_DAMAGED; } // we consider pallete as gray, discard pallete here ... fseek(src, bfh.bfOffBits, SEEK_SET); len -= bfh.bfOffBits; data.reset(new std::vector(len)); fread(&(*data.get())[0], 1, len, src); fclose(src); bits = data.get()->data(); } else { memcpy(&bih, conv->src.data + fh, sizeof(bih)); bits = (unsigned char*)conv->src.data + ((BITMAPFILEHEADER*)conv->src.data)->bfOffBits; } bool tiff = conv->dst.fmt.img_format == SANE_IMAGE_TYPE_TIFF; int resolution = bih.biXPelsPerMeter / 39.37f + .5f, threshold = (int)(long)conv->dst.fmt.compress.detail; cv::Mat imsg = from_bmp_file_bits(bih, data->data(), tiff || conv->dst.fmt.img_format == SANE_IMAGE_TYPE_JFIF, tiff && conv->dst.fmt.compress.compression != SANE_COMPRESSION_GROUP4); data.reset(); if (tiff) { if (bih.biBitCount == 24) { if (conv->dst.fmt.compress.compression == SANE_COMPRESSION_GROUP4) cvtColor(imsg, imsg, cv::COLOR_RGB2GRAY); else { for (int y = 0; y < bih.biHeight; ++y) { uint8_t* row = imsg.ptr(y); for (int x = 0; x < bih.biWidth; ++x) { uint8_t t = row[x * 3 + 0]; row[x * 3 + 0] = row[x * 3 + 2]; row[x * 3 + 2] = t; } } } } int compression = conv->dst.fmt.compress.compression == SANE_COMPRESSION_GROUP4 ? COMPRESSION_CCITT_T6 : COMPRESSION_NONE; if (conv->dst.is_file) { G4Tiff tiff(imsg, G4Tiff::Mode::FileMode, conv->dst.data, threshold, resolution, compression); tiff.SaveG4Tiff(); } else { G4Tiff tiff(imsg, G4Tiff::Mode::MemoryMode, "", threshold, resolution, compression); size_t bytes = 0; conv->dst.data = (SANE_String_Const)tiff.get_compressed_data(&bytes, allocate_memory); conv->dst.data_len = bytes; } } else if (conv->dst.fmt.img_format == SANE_IMAGE_TYPE_JFIF) { // MSB word[7] and word[8] are x and y resolutions std::vector cpr; unsigned short jpeg_r = (resolution << 8) | ((resolution >> 8) & 0x0ff); int resolution_y = bih.biYPelsPerMeter / 39.37f + .5f; cpr.push_back(CV_IMWRITE_JPEG_QUALITY); cpr.push_back((int)(long)conv->dst.fmt.detail); cpr.push_back(CV_IMWRITE_JPEG_RESOLUTION_UNIT); cpr.push_back(1); cpr.push_back(CV_IMWRITE_JPEG_RESOLUTION_X); cpr.push_back(resolution); cpr.push_back(CV_IMWRITE_JPEG_RESOLUTION_Y); cpr.push_back(resolution_y); if (conv->dst.is_file) { cv::imwrite(conv->dst.data, imsg, cpr); //FILE* f = fopen(conv->dst.data, "rb+"); //if (f) //{ // fseek(f, 0x0e, SEEK_SET); // fwrite(&jpeg_r, sizeof(jpeg_r), 1, f); // fwrite(&jpeg_r, sizeof(jpeg_r), 1, f); // fclose(f); //} } else { std::string tmpf(hg_log::temporary_path() + PATH_SEPARATOR + "imgtrans.tmp"); cv::imwrite(tmpf.c_str(), imsg, cpr); size_t bytes = 0; conv->dst.data = (SANE_String_Const)G4Tiff::load_mini_file(tmpf.c_str(), &bytes, allocate_memory); conv->dst.data_len = bytes; remove(tmpf.c_str()); //if (conv->dst.data_len > 0x20) // ((unsigned short*)conv->dst.data)[7] = ((unsigned short*)conv->dst.data)[8] = jpeg_r; } } else if (conv->dst.fmt.compress.compression == SANE_COMPRESSION_GROUP4) { std::vector cmp; if (bih.biBitCount == 24) cvtColor(imsg, imsg, cv::COLOR_RGB2GRAY); if (conv->dst.is_file) { G4Tiff tiff(imsg, G4Tiff::Mode::FileMode, conv->dst.data, threshold, resolution); tiff.SaveG4Tiff(); } else { G4Tiff tiff(imsg, G4Tiff::Mode::MemoryMode, "", threshold, resolution); size_t bytes = 0; conv->dst.data = (SANE_String_Const)tiff.get_compressed_data(&bytes, allocate_memory); conv->dst.data_len = bytes; } } return SCANNER_ERR_OK; } int save_2_bmp_file(const char* bmp_file, LPIMGHEAD head, void* buf, int resolution) { BITMAPINFOHEADER bih = { 0 }; BITMAPFILEHEADER fh = { 0 }; int pal_size = 0, line_len = (head->channels * head->bits * head->width + 31) / 32 * 4; FILE *dst = fopen(bmp_file, "wb"); if (!dst) return errno; bih.biSize = sizeof(bih); bih.biWidth = head->width; bih.biBitCount = head->channels * head->bits; bih.biSizeImage = head->height * line_len; bih.biPlanes = 1; bih.biHeight = head->height; bih.biCompression = BI_RGB; bih.biXPelsPerMeter = bih.biYPelsPerMeter = resolution * 39.37f + .5f; if (bih.biBitCount == 1) pal_size = 2 * sizeof(int); else if (bih.biBitCount == 8) pal_size = 256 * sizeof(int); fh.bfType = MAKEWORD('B', 'M'); fh.bfOffBits = sizeof(fh) + sizeof(bih) + pal_size; fh.bfSize = fh.bfOffBits + bih.biSizeImage; fwrite(&fh, sizeof(fh), 1, dst); fwrite(&bih, sizeof(bih), 1, dst); if (bih.biBitCount == 1) { int pal[] = { 0, 0x0ffffff }; fwrite(pal, sizeof(pal), 1, dst); } else if (bih.biBitCount == 8) { static unsigned int g_bmp8_pallete[256] = { 0 }; if (g_bmp8_pallete[1] == 0) { for (int i = 1; i < _countof(g_bmp8_pallete); ++i) g_bmp8_pallete[i] = MAKELONG(MAKEWORD(i, i), MAKEWORD(i, 0)); } fwrite(g_bmp8_pallete, sizeof(g_bmp8_pallete), 1, dst); } if (line_len == head->line_bytes) fwrite(buf, 1, head->total_bytes, dst); else { unsigned char* ptr = (unsigned char*)buf; unsigned int pad = 0; int pad_l = 4 - (head->line_bytes % 4), step = head->line_bytes; if (1) { ptr += head->total_bytes - head->line_bytes; step *= -1; } for (int i = 0; i < head->height; ++i) { fwrite(ptr, head->line_bytes, 1, dst); fwrite(&pad, 1, pad_l, dst); ptr += step; } } fclose(dst); return 0; } static unsigned char reverse_bit(unsigned char v) { unsigned char r = 0; for (int i = 0; i < 8; ++i) { r <<= 1; r |= v & 1; v >>= 1; } return r; } std::string bmp8_2_1bit(const unsigned char* data, int w, int h, int line_len, int threshold, bool reverse, bool align) { cv::Mat m; unsigned char* dst = NULL; m.create(h, w, CV_8UC1); dst = m.ptr();// +w * (h - 1); for (int i = 0; i < h; ++i) { memcpy(dst, data, w); dst += w; data += line_len; } cv::Mat bw = imgproc::convert_8bit_2_1bit(m, threshold, reverse, align); //std::string ret(""); //dst = bw.ptr(); //for (int i = 0; i < bw.total(); ++i) // dst[i] = reverse_bit(dst[i]); return std::string((char*)bw.ptr(), bw.total()); } }