2023-07-10 07:28:45 +00:00
|
|
|
|
#include "scanned_img.h"
|
2023-08-22 08:47:28 +00:00
|
|
|
|
|
2023-07-10 07:28:45 +00:00
|
|
|
|
#include "sane_helper.h"
|
2023-08-22 08:47:28 +00:00
|
|
|
|
#include "../../sdk/hginclude/utils.h"
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
//
|
|
|
|
|
extern sane_helper* sane_helper_;
|
|
|
|
|
|
|
|
|
|
namespace local_trans
|
|
|
|
|
{
|
|
|
|
|
static const char* (*invoke_to_default_language)(const char* str, bool* ok) = nullptr;
|
|
|
|
|
static const char* (*invoke_from_default_language)(const char* str, bool* ok) = nullptr;
|
|
|
|
|
|
|
|
|
|
int load_lang_pak(const char* dll)
|
|
|
|
|
{
|
2023-08-22 08:47:28 +00:00
|
|
|
|
HMODULE h = utils::load_dll(dll, LOAD_WITH_ALTERED_SEARCH_PATH);
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
|
|
|
|
if(!h)
|
|
|
|
|
return GetLastError();
|
|
|
|
|
|
|
|
|
|
FARPROC *pfn = (FARPROC*)&invoke_from_default_language;
|
|
|
|
|
*pfn = GetProcAddress(h, "from_default_language");
|
|
|
|
|
|
|
|
|
|
pfn = (FARPROC*)&invoke_to_default_language;
|
|
|
|
|
*pfn = GetProcAddress(h, "to_default_language");
|
|
|
|
|
|
|
|
|
|
return invoke_to_default_language && invoke_to_default_language ? 0 : ENOENT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string lang_trans_between_hz936(const char* in, bool from_hz)
|
|
|
|
|
{
|
|
|
|
|
std::string a(lang_trans_between_hz936(in, from_hz, nullptr));
|
|
|
|
|
|
|
|
|
|
return std::move(a);
|
|
|
|
|
}
|
|
|
|
|
const char* lang_trans_between_hz936(const char* in, bool from_hz, void* param)
|
|
|
|
|
{
|
|
|
|
|
if(from_hz && invoke_from_default_language)
|
|
|
|
|
return invoke_from_default_language(in, nullptr);
|
|
|
|
|
else if(!from_hz && invoke_to_default_language)
|
|
|
|
|
return invoke_to_default_language(in, nullptr);
|
|
|
|
|
else
|
|
|
|
|
return in;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char* to_default_language(const char* str, bool* ok)
|
|
|
|
|
{
|
|
|
|
|
if(invoke_to_default_language)
|
|
|
|
|
return invoke_to_default_language(str, ok);
|
|
|
|
|
|
|
|
|
|
if(ok)
|
|
|
|
|
*ok = false;
|
|
|
|
|
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
const char* from_default_language(const char* str, bool* ok)
|
|
|
|
|
{
|
|
|
|
|
if(invoke_from_default_language)
|
|
|
|
|
return invoke_from_default_language(str, ok);
|
|
|
|
|
|
|
|
|
|
if(ok)
|
|
|
|
|
*ok = false;
|
|
|
|
|
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// class image_buf
|
|
|
|
|
const unsigned int max_mem_block = 2 * 1024 * 1024;
|
|
|
|
|
extern void log_info(const char* info, int level);
|
|
|
|
|
|
|
|
|
|
image_buf::image_buf() : bytes_(0), offset_(0), mapped_bytes_(0), is_mem_(true), buf_(nullptr)
|
|
|
|
|
{}
|
|
|
|
|
image_buf::~image_buf()
|
|
|
|
|
{
|
|
|
|
|
close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void image_buf::close(void)
|
|
|
|
|
{
|
|
|
|
|
if(buf_)
|
|
|
|
|
{
|
|
|
|
|
free(buf_);
|
|
|
|
|
buf_ = nullptr;
|
|
|
|
|
}
|
|
|
|
|
bytes_ = offset_ = mapped_bytes_ = 0;
|
|
|
|
|
is_mem_ = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsigned char* image_buf::allocate(const char* file, unsigned long long size, bool force_file)
|
|
|
|
|
{
|
|
|
|
|
close();
|
|
|
|
|
|
|
|
|
|
if(force_file)
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
|
|
buf_ = (unsigned char*)malloc(size);
|
|
|
|
|
if(buf_)
|
|
|
|
|
{
|
|
|
|
|
memset(buf_, 0, size);
|
|
|
|
|
bytes_ = mapped_bytes_ = size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return buf_;
|
|
|
|
|
}
|
|
|
|
|
bool image_buf::save(const void* data, size_t* bytes, unsigned long long off)
|
|
|
|
|
{
|
|
|
|
|
if(off + *bytes <= mapped_bytes_)
|
|
|
|
|
{
|
|
|
|
|
memcpy(buf_ + off, data, *bytes);
|
|
|
|
|
//if(bytes_ < off + *bytes)
|
|
|
|
|
// bytes_ = off + *bytes;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if(off < mapped_bytes_)
|
|
|
|
|
{
|
|
|
|
|
memcpy(buf_ + off, data, mapped_bytes_ - off);
|
|
|
|
|
*bytes = mapped_bytes_ - off;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
*bytes = 0;
|
|
|
|
|
//if(bytes_ < off + *bytes)
|
|
|
|
|
// bytes_ = off + *bytes;
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
bool image_buf::save(unsigned long long off, image_buf* src)
|
|
|
|
|
{
|
|
|
|
|
if(off + src->bytes() > mapped_bytes_)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
memcpy(buf_ + off, src->buf_, src->bytes());
|
|
|
|
|
//if(bytes_ < off + src->bytes())
|
|
|
|
|
// bytes_ = off + src->bytes();
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
unsigned long long image_buf::bytes(void)
|
|
|
|
|
{
|
|
|
|
|
return bytes_;
|
|
|
|
|
}
|
|
|
|
|
unsigned long long image_buf::size(void)
|
|
|
|
|
{
|
|
|
|
|
return mapped_bytes_;
|
|
|
|
|
}
|
|
|
|
|
unsigned char* image_buf::buffer(unsigned long long off, unsigned int* bytes)
|
|
|
|
|
{
|
|
|
|
|
if(off < mapped_bytes_)
|
|
|
|
|
{
|
|
|
|
|
if(*bytes > mapped_bytes_ - off)
|
|
|
|
|
*bytes = mapped_bytes_ - off;
|
|
|
|
|
|
|
|
|
|
return buf_ + off;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
int image_buf::read(void* buf, size_t* bytes, unsigned long long off)
|
|
|
|
|
{
|
|
|
|
|
if (!bytes)
|
|
|
|
|
return SCANNER_ERR_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
|
|
if(off >= bytes_)
|
|
|
|
|
return SCANNER_ERR_OUT_OF_RANGE;
|
|
|
|
|
|
|
|
|
|
if(*bytes > bytes_ - off)
|
|
|
|
|
{
|
|
|
|
|
*bytes = bytes_ - off;
|
|
|
|
|
}
|
|
|
|
|
memcpy(buf, buf_ + off, *bytes);
|
|
|
|
|
|
|
|
|
|
return SCANNER_ERR_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// class scanned_img
|
|
|
|
|
scanned_img::scanned_img(SANE_Handle dev, SANE_Parameters head, void* data, unsigned int len, int dpi, const char* tmp_file
|
2023-08-03 01:50:51 +00:00
|
|
|
|
, twain_xfer xfer, SANE_FinalImgFormat* fmt) : head_(head), dpi_(dpi), header_size_(0)
|
2023-10-31 06:51:14 +00:00
|
|
|
|
, file_(tmp_file ? tmp_file : ""), dev_(dev), status_(IMG_STATUS_OK)
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
2023-08-03 01:50:51 +00:00
|
|
|
|
const bool prepare_data = true;
|
|
|
|
|
|
2023-07-10 07:28:45 +00:00
|
|
|
|
if (fmt)
|
|
|
|
|
fmt_ = *fmt;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
fmt_.img_format = SANE_IMAGE_TYPE_BMP;
|
|
|
|
|
fmt_.detail = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t bytes = line_bytes() * head.lines;
|
2023-08-03 01:50:51 +00:00
|
|
|
|
std::string h(file_header(fmt_.img_format, (float)dpi));
|
|
|
|
|
unsigned char* dst = NULL, * src = (unsigned char*)data;
|
2023-07-10 07:28:45 +00:00
|
|
|
|
bool ok = false;
|
|
|
|
|
|
|
|
|
|
header_size_ = h.length();
|
|
|
|
|
data_ = new image_buf();
|
|
|
|
|
bytes += header_size_;
|
|
|
|
|
dst = data_->allocate(tmp_file, bytes);
|
|
|
|
|
bytes = h.length();
|
2023-08-03 01:50:51 +00:00
|
|
|
|
if (dst && data_->save(h.c_str(), &bytes, 0))
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
2023-08-03 01:50:51 +00:00
|
|
|
|
unsigned long long line_l = line_bytes(), off = data_->bytes() - line_l;
|
2023-07-10 07:28:45 +00:00
|
|
|
|
unsigned int buf_len = line_bytes(), row = 0;
|
2023-08-03 01:50:51 +00:00
|
|
|
|
|
|
|
|
|
if (prepare_data && xfer == TWAIN_XFER_Memory)
|
|
|
|
|
{
|
2023-07-10 07:28:45 +00:00
|
|
|
|
line_l *= -1;
|
2023-08-03 01:50:51 +00:00
|
|
|
|
off = bytes;
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-10 07:28:45 +00:00
|
|
|
|
for (; row < (unsigned int)head.lines; ++row)
|
|
|
|
|
{
|
|
|
|
|
bytes = head.bytes_per_line;
|
|
|
|
|
if (!data_->save(src, &bytes, off))
|
|
|
|
|
break;
|
|
|
|
|
off -= line_l;
|
|
|
|
|
src += head.bytes_per_line;
|
|
|
|
|
}
|
|
|
|
|
ok = row == head.lines;
|
|
|
|
|
}
|
2023-08-03 01:50:51 +00:00
|
|
|
|
|
|
|
|
|
if (!ok)
|
|
|
|
|
{
|
|
|
|
|
delete data_;
|
|
|
|
|
data_ = NULL;
|
|
|
|
|
header_size_ = 0;
|
|
|
|
|
}
|
|
|
|
|
else if (prepare_data)
|
|
|
|
|
do_result(xfer);
|
2023-07-10 07:28:45 +00:00
|
|
|
|
}
|
|
|
|
|
scanned_img::~scanned_img()
|
|
|
|
|
{
|
|
|
|
|
if (data_)
|
|
|
|
|
delete data_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void scanned_img::set_image_status(SANE_Image_Statu status)
|
|
|
|
|
{
|
|
|
|
|
status_ = status;
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-03 01:50:51 +00:00
|
|
|
|
std::string scanned_img::file_header(SANE_ImageType type, float resolution)
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
|
|
|
|
std::string h("");
|
|
|
|
|
|
2023-08-03 01:50:51 +00:00
|
|
|
|
if (type == SANE_IMAGE_TYPE_BMP)
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
|
|
|
|
BITMAPINFOHEADER bih = { 0 };
|
|
|
|
|
int pal_size = 0;
|
|
|
|
|
|
|
|
|
|
bih.biSize = sizeof(bih);
|
|
|
|
|
bih.biWidth = width();
|
|
|
|
|
bih.biBitCount = depth();
|
|
|
|
|
bih.biSizeImage = line_bytes() * height();
|
|
|
|
|
bih.biPlanes = 1;
|
|
|
|
|
bih.biHeight = height();
|
|
|
|
|
bih.biCompression = BI_RGB;
|
|
|
|
|
bih.biXPelsPerMeter = bih.biYPelsPerMeter = (LONG)(resolution * 39.37f + .5f);
|
|
|
|
|
|
|
|
|
|
if (bih.biBitCount == 1)
|
|
|
|
|
pal_size = 2 * sizeof(int);
|
|
|
|
|
else if (bih.biBitCount == 8)
|
|
|
|
|
pal_size = 256 * sizeof(int);
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
BITMAPFILEHEADER fh = { 0 };
|
|
|
|
|
fh.bfType = MAKEWORD('B', 'M');
|
|
|
|
|
fh.bfSize = sizeof(fh) + bih.biSizeImage + sizeof(bih) + pal_size;
|
|
|
|
|
fh.bfOffBits = sizeof(fh) + sizeof(bih) + pal_size;
|
|
|
|
|
|
|
|
|
|
h = std::string((char*)&fh, sizeof(fh));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
h += std::string((char*)&bih, sizeof(bih));
|
|
|
|
|
pal_size_ = pal_size;
|
|
|
|
|
if (bih.biBitCount == 1)
|
|
|
|
|
{
|
|
|
|
|
int pal[] = { 0, 0x0ffffff };
|
|
|
|
|
h += std::string((char*)pal, pal_size);
|
|
|
|
|
}
|
|
|
|
|
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));
|
|
|
|
|
}
|
|
|
|
|
h += std::string((char*)g_bmp8_pallete, pal_size);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return h;
|
|
|
|
|
}
|
2023-08-03 01:50:51 +00:00
|
|
|
|
void scanned_img::do_result(twain_xfer xfer)
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
2023-08-03 01:50:51 +00:00
|
|
|
|
if (fmt_.img_format == SANE_IMAGE_TYPE_BMP &&
|
|
|
|
|
fmt_.compress.compression == SANE_COMPRESSION_GROUP4 &&
|
|
|
|
|
xfer == TWAIN_XFER_Memory)
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
2023-08-03 01:50:51 +00:00
|
|
|
|
// 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)
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
2023-08-03 01:50:51 +00:00
|
|
|
|
SANE_ImageFormatConvert conv;
|
|
|
|
|
std::string sf(file), tifff(sf + ".tiff");
|
|
|
|
|
SANE_Int after = 0;
|
|
|
|
|
bool conv_2_file = false;
|
|
|
|
|
|
|
|
|
|
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)
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
2023-08-03 01:50:51 +00:00
|
|
|
|
if (conv_2_file)
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
2023-08-03 01:50:51 +00:00
|
|
|
|
FILE* src = fopen(tifff.c_str(), "rb");
|
|
|
|
|
if (src)
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
|
|
|
|
delete data_;
|
|
|
|
|
data_ = new image_buf();
|
2023-08-03 01:50:51 +00:00
|
|
|
|
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);
|
2023-08-03 02:06:26 +00:00
|
|
|
|
data_->save(mem, (size_t*)&size, 0);
|
2023-08-03 01:50:51 +00:00
|
|
|
|
delete[] mem;
|
|
|
|
|
|
2023-07-10 07:28:45 +00:00
|
|
|
|
head_.format = SANE_FRAME_GRAY;
|
|
|
|
|
head_.depth = 1;
|
|
|
|
|
head_.bytes_per_line = (head_.pixels_per_line + 7) / 8;
|
2023-08-03 01:50:51 +00:00
|
|
|
|
fmt_.img_format = SANE_IMAGE_TYPE_TIFF;
|
2023-07-10 07:28:45 +00:00
|
|
|
|
}
|
2023-08-03 01:50:51 +00:00
|
|
|
|
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);
|
2023-08-03 02:06:26 +00:00
|
|
|
|
data_->save(conv.dst.data, (size_t*)&size, 0);
|
2023-08-03 01:50:51 +00:00
|
|
|
|
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;
|
2023-07-10 07:28:45 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-08-03 01:50:51 +00:00
|
|
|
|
if (dst)
|
|
|
|
|
fclose(dst);
|
|
|
|
|
remove(file.c_str());
|
2023-07-10 07:28:45 +00:00
|
|
|
|
}
|
2023-08-03 01:50:51 +00:00
|
|
|
|
else if (fmt_.img_format == SANE_IMAGE_TYPE_BMP
|
|
|
|
|
&& channel() == 3
|
|
|
|
|
&& xfer != TWAIN_XFER_Memory)
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
2023-08-03 01:50:51 +00:00
|
|
|
|
// swap RGB
|
|
|
|
|
swap_rgb();
|
2023-07-10 07:28:45 +00:00
|
|
|
|
}
|
2023-08-03 01:50:51 +00:00
|
|
|
|
data_done_ = true;
|
2023-07-10 07:28:45 +00:00
|
|
|
|
}
|
|
|
|
|
void scanned_img::swap_rgb(void)
|
|
|
|
|
{
|
|
|
|
|
unsigned long long off = 0;
|
|
|
|
|
unsigned int line = line_bytes(), len = line;
|
|
|
|
|
unsigned char* dst = NULL;
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < height(); ++i)
|
|
|
|
|
{
|
|
|
|
|
int l = head_.bytes_per_line, cur = 0;
|
|
|
|
|
|
|
|
|
|
off = i * line + header_size_;
|
|
|
|
|
while (l > 0)
|
|
|
|
|
{
|
|
|
|
|
len = l;
|
|
|
|
|
dst = data_->buffer(off + cur, &len);
|
|
|
|
|
if (!dst)
|
|
|
|
|
break;
|
|
|
|
|
if (len > (unsigned int)l)
|
|
|
|
|
len = l;
|
|
|
|
|
len /= 3;
|
|
|
|
|
for (int pos = 0; pos < (int)len; ++pos)
|
|
|
|
|
{
|
|
|
|
|
unsigned char uc = dst[pos * 3 + 0];
|
|
|
|
|
dst[pos * 3 + 0] = dst[pos * 3 + 2];
|
|
|
|
|
dst[pos * 3 + 2] = uc;
|
|
|
|
|
}
|
|
|
|
|
l -= len * 3;
|
|
|
|
|
cur += len * 3;
|
|
|
|
|
}
|
|
|
|
|
if (!dst)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// IRef
|
2023-10-20 07:21:17 +00:00
|
|
|
|
COM_API_IMPLEMENT(scanned_img, int32_t, add_ref(void))
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
|
|
|
|
return refer::add_ref();
|
|
|
|
|
}
|
2023-10-20 07:21:17 +00:00
|
|
|
|
COM_API_IMPLEMENT(scanned_img, int32_t, release(void))
|
2023-07-10 07:28:45 +00:00
|
|
|
|
{
|
|
|
|
|
return refer::release();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// IScanImg
|
|
|
|
|
COM_API_IMPLEMENT(scanned_img, int, width(void))
|
|
|
|
|
{
|
|
|
|
|
return head_.pixels_per_line;
|
|
|
|
|
}
|
|
|
|
|
COM_API_IMPLEMENT(scanned_img, int, line_bytes(void))
|
|
|
|
|
{
|
|
|
|
|
if (fmt_.img_format == SANE_IMAGE_TYPE_BMP && head_.depth >= 8)
|
|
|
|
|
return (head_.bytes_per_line + 3) / 4 * 4;
|
|
|
|
|
else
|
|
|
|
|
return head_.bytes_per_line;
|
|
|
|
|
}
|
|
|
|
|
COM_API_IMPLEMENT(scanned_img, int, height(void))
|
|
|
|
|
{
|
|
|
|
|
return head_.lines;
|
|
|
|
|
}
|
|
|
|
|
COM_API_IMPLEMENT(scanned_img, int, depth(void))
|
|
|
|
|
{
|
|
|
|
|
if (head_.format == SANE_FRAME_RGB)
|
|
|
|
|
return head_.depth * 3;
|
|
|
|
|
else
|
|
|
|
|
return head_.depth;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
COM_API_IMPLEMENT(scanned_img, int, channel(void))
|
|
|
|
|
{
|
|
|
|
|
return head_.format == SANE_FRAME_RGB ? 3 : 1;
|
|
|
|
|
}
|
|
|
|
|
COM_API_IMPLEMENT(scanned_img, int, dpi(void))
|
|
|
|
|
{
|
|
|
|
|
return dpi_;
|
|
|
|
|
}
|
|
|
|
|
COM_API_IMPLEMENT(scanned_img, SANE_Frame, type(void))
|
|
|
|
|
{
|
|
|
|
|
return head_.format;
|
|
|
|
|
}
|
|
|
|
|
COM_API_IMPLEMENT(scanned_img, unsigned int, bytes(void))
|
|
|
|
|
{
|
|
|
|
|
return data_ ? (unsigned int)data_->bytes() : 0;
|
|
|
|
|
}
|
|
|
|
|
COM_API_IMPLEMENT(scanned_img, unsigned int, header_size(void))
|
|
|
|
|
{
|
|
|
|
|
return header_size_;
|
|
|
|
|
}
|
|
|
|
|
COM_API_IMPLEMENT(scanned_img, unsigned char*, data(unsigned long long off, unsigned int* bytes))
|
|
|
|
|
{
|
|
|
|
|
return data_ ? data_->buffer(off, bytes) : NULL;
|
|
|
|
|
}
|
|
|
|
|
COM_API_IMPLEMENT(scanned_img, int, read(void* buf, size_t* bytes, unsigned long long off))
|
|
|
|
|
{
|
|
|
|
|
return data_ ? data_->read(buf, bytes, off) : SCANNER_ERR_NO_DATA;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
COM_API_IMPLEMENT(scanned_img, const char*, file(void))
|
|
|
|
|
{
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
COM_API_IMPLEMENT(scanned_img, void, keep_file(bool keep))
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
COM_API_IMPLEMENT(scanned_img, void, copy_header(SANE_Parameters* head))
|
|
|
|
|
{
|
|
|
|
|
*head = head_;
|
|
|
|
|
}
|
|
|
|
|
COM_API_IMPLEMENT(scanned_img, int, image_status(void))
|
|
|
|
|
{
|
|
|
|
|
return status_;
|
|
|
|
|
}
|
|
|
|
|
COM_API_IMPLEMENT(scanned_img, size_t, get_bits_offset(void))
|
|
|
|
|
{
|
|
|
|
|
if (fmt_.img_format == SANE_IMAGE_TYPE_BMP)
|
|
|
|
|
return sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + pal_size_;
|
|
|
|
|
else
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-03 01:50:51 +00:00
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2023-07-10 07:28:45 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// class safe_img_queue
|
|
|
|
|
safe_img_queue::safe_img_queue()
|
|
|
|
|
{}
|
|
|
|
|
safe_img_queue::~safe_img_queue()
|
|
|
|
|
{
|
|
|
|
|
clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void safe_img_queue::access_image(scanned_img* img)
|
|
|
|
|
{
|
|
|
|
|
img->add_ref();
|
|
|
|
|
}
|
|
|
|
|
void safe_img_queue::free_image(scanned_img* img)
|
|
|
|
|
{
|
|
|
|
|
img->release();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool safe_img_queue::get_header(SANE_Parameters* header, size_t* bytes, int* dpi)
|
|
|
|
|
{
|
|
|
|
|
scanned_img *img = take(false, &safe_img_queue::access_image);
|
|
|
|
|
bool ok = false;
|
|
|
|
|
|
|
|
|
|
if (bytes)
|
|
|
|
|
*bytes = 0;
|
|
|
|
|
if (img)
|
|
|
|
|
{
|
|
|
|
|
if(header)
|
|
|
|
|
img->copy_header(header);
|
|
|
|
|
if(bytes)
|
|
|
|
|
*bytes = img->bytes();
|
|
|
|
|
if (dpi)
|
|
|
|
|
*dpi = img->dpi();
|
|
|
|
|
ok = true;
|
|
|
|
|
img->release();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ok;
|
|
|
|
|
}
|
|
|
|
|
void safe_img_queue::clear()
|
|
|
|
|
{
|
|
|
|
|
safe_queue<scanned_img*>::clear(&safe_img_queue::free_image);
|
|
|
|
|
}
|
|
|
|
|
|