Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,17 @@ NUL
# vscode
.vscode
.clang-format
.cache/
compile_commands.json

# AI
.roomodes
project_journal/
.roo/
.cursor/
.kiro/
.specstory/
.claude/

# deepin-IDE
.unioncode
Expand All @@ -66,3 +71,7 @@ project_journal/
*.tar.gz
*.log
*.substvars

# OpenMemory - IDE/Assistant specific rules
.qoder/rules/openmemory.md
CLAUDE.md
34 changes: 33 additions & 1 deletion src/device/scannerdevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

using namespace DDLog;

#define ADD_TEST_DEVICE 1
#define ADD_TEST_DEVICE 0

// =================================================================
// ScannerDevice Implementation (UI Thread)
Expand Down Expand Up @@ -200,6 +200,38 @@ QList<int> ScannerDevice::getSupportedResolutions()
return m_supportedResolutions;
}

// Paper size methods
void ScannerDevice::setPaperSize(PaperSize size)
{
m_currentPaperSize = size;
}

ScannerDevice::PaperSize ScannerDevice::getPaperSize() const
{
return m_currentPaperSize;
}

QSizeF ScannerDevice::getPaperSizeDimensions(PaperSize size)
{
switch(size) {
case PAPER_SIZE_A3:
return QSizeF(297, 420); // A3: 297×420mm (standard ISO size)
case PAPER_SIZE_A4:
return QSizeF(210, 297); // A4: 210×297mm (standard ISO size)
case PAPER_SIZE_A5:
return QSizeF(148, 210); // A5: 148×210mm (standard ISO size)
case PAPER_SIZE_A6:
return QSizeF(105, 148); // A6: 105×148mm (standard ISO size)
case PAPER_SIZE_B4:
return QSizeF(250, 353); // B4: 250×353mm (standard ISO size)
case PAPER_SIZE_B5:
return QSizeF(176, 250); // B5: 176×250mm (standard ISO size)
case PAPER_SIZE_AUTO:
default:
return QSizeF(210, 297); // Default to A4
}
}

// --- SLOTS to handle results from worker ---

void ScannerDevice::onWorkerError(const QString &errorMessage)
Expand Down
17 changes: 17 additions & 0 deletions src/device/scannerdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,17 @@ class ScannerDevice : public DeviceBase
SCAN_MODE_ADF_DUPLEX // ADF duplex scan
};
Q_ENUM(ScanMode)

enum PaperSize {
PAPER_SIZE_AUTO = 0, // Auto detect
PAPER_SIZE_A4 = 1, // 210×297mm
PAPER_SIZE_A3 = 2, // 297×420mm
PAPER_SIZE_A5 = 3, // 148×210mm
PAPER_SIZE_A6 = 4, // 105×148mm
PAPER_SIZE_B4 = 5, // 250×353mm
PAPER_SIZE_B5 = 6 // 176×250mm
};
Q_ENUM(PaperSize)

explicit ScannerDevice(QObject *parent = nullptr);
~ScannerDevice() override;
Expand All @@ -52,6 +63,11 @@ class ScannerDevice : public DeviceBase
bool setResolution(int dpi);
int getResolution() const;
QList<int> getSupportedResolutions();

// Paper size methods
void setPaperSize(PaperSize size);
PaperSize getPaperSize() const;
static QSizeF getPaperSizeDimensions(PaperSize size); // Returns size in mm

signals:
// Signals to trigger worker operations
Expand Down Expand Up @@ -85,6 +101,7 @@ private slots:
QList<ScanMode> m_supportedScanModes;
int m_currentResolutionDPI = 300;
ScanMode m_currentScanMode = SCAN_MODE_FLATBED;
PaperSize m_currentPaperSize = PAPER_SIZE_A4;
};

// --- Worker Class for background scanning ---
Expand Down
19 changes: 13 additions & 6 deletions src/libofd/include/ofd/ofd_writer.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,31 @@ class Writer
bool createFromImages(const QString &outputPath,
const QVector<QImage> &images,
float leftMargin = 0.0f,
float topMargin = 0.0f);
float topMargin = 0.0f,
float pageWidth = 210.0f,
float pageHeight = 297.0f);

private:
void createOFDXmlFile(const QString &path);
void createDocFile(const QString &path, float leftM, float topM,
const QVector<QImage> &images);
const QVector<QImage> &images,
float pageWidth = 210.0f, float pageHeight = 297.0f);
void createResourceFiles(const QString &path, const QVector<QImage> &images);

// XML写入辅助函数
void writeDocumentHeader(QTextStream &stream, int maxId);
void writeDocumentHeader(QTextStream &stream, int maxId,
float pageWidth = 210.0f, float pageHeight = 297.0f);
void writeDocumentFooter(QTextStream &stream);
void writePublicResHeader(QTextStream &stream);
void writePublicResFooter(QTextStream &stream, bool hasImages);
void writePage(QTextStream &docStream, QTextStream &publicResStream,
const QString &pagesPath, const QVector<QImage> &images,
int pageIndex, float leftM, float topM, int &currentId);
int pageIndex, float leftM, float topM, int &currentId,
float pageWidth = 210.0f, float pageHeight = 297.0f);
void createPageContent(const QString &path, const QString &minX,
const QString &minY, const QString &maxX,
const QString &maxY, int &id, bool hasImage);
const QString &maxY, int &id, bool hasImage,
float pageWidth = 210.0f, float pageHeight = 297.0f);

// 压缩相关函数
bool compressOFD(const QString &outputPath, const QString &sourcePath);
Expand All @@ -56,7 +62,8 @@ class Writer
bool removeDir(const QString &dirPath);

// 图像处理辅助函数
QSize calculateImageSize(const QImage &image, float leftM, float topM);
QSize calculateImageSize(const QImage &image, float leftM, float topM,
float pageWidth = 210.0f, float pageHeight = 297.0f);
};

} // namespace ofd
Expand Down
47 changes: 27 additions & 20 deletions src/libofd/src/ofd_writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ Writer::~Writer() {}
bool Writer::createFromImages(const QString &outputPath,
const QVector<QImage> &images,
float leftMargin,
float topMargin)
float topMargin,
float pageWidth,
float pageHeight)
{
QFileInfo fileInfo(outputPath);
QString tempPath = QDir::tempPath() + QDir::separator() + fileInfo.baseName();
Expand All @@ -51,7 +53,7 @@ bool Writer::createFromImages(const QString &outputPath,

QString basePath = tempPath + QDir::separator();
createOFDXmlFile(basePath);
createDocFile(basePath, leftMargin, topMargin, images);
createDocFile(basePath, leftMargin, topMargin, images, pageWidth, pageHeight);

bool success = compressOFD(outputPath, tempPath);
removeDir(tempPath);
Expand Down Expand Up @@ -92,14 +94,14 @@ void Writer::createOFDXmlFile(const QString &path)
file.close();
}

void Writer::writeDocumentHeader(QTextStream &stream, int maxId)
void Writer::writeDocumentHeader(QTextStream &stream, int maxId, float pageWidth, float pageHeight)
{
stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
<< "<ofd:Document xmlns:ofd=\"http://www.ofdspec.org\">\n"
<< " <ofd:CommonData>\n"
<< " <ofd:MaxUnitID>" << maxId << "</ofd:MaxUnitID>\n"
<< " <ofd:PageArea>\n"
<< " <ofd:PhysicalBox>0.00 0.00 " << PAGE_WIDTH << " " << PAGE_HEIGHT << "</ofd:PhysicalBox>\n"
<< " <ofd:PhysicalBox>0.00 0.00 " << pageWidth << " " << pageHeight << "</ofd:PhysicalBox>\n"
<< " </ofd:PageArea>\n"
<< " <ofd:PublicRes>PublicRes.xml</ofd:PublicRes>\n"
<< " </ofd:CommonData>\n"
Expand Down Expand Up @@ -129,15 +131,16 @@ void Writer::writePublicResFooter(QTextStream &stream, bool hasImages)
stream << "</ofd:Res>\n";
}

QSize Writer::calculateImageSize(const QImage &image, float leftM, float topM)
QSize Writer::calculateImageSize(const QImage &image, float leftM, float topM,
float pageWidth, float pageHeight)
{
double width = (double)image.width() * 1000 / image.dotsPerMeterX();
double height = (double)image.height() * 1000 / image.dotsPerMeterY();

double scaledWidth = width * DPI_FACTOR;
double scaledHeight = height * DPI_FACTOR;

QRect pageRect(leftM * 25.4, topM * 25.4, PAGE_WIDTH * 25.4, PAGE_HEIGHT * 25.4);
QRect pageRect(leftM * 25.4, topM * 25.4, pageWidth * 25.4, pageHeight * 25.4);
QSize size(scaledWidth, scaledHeight);
size.scale(pageRect.size(), Qt::KeepAspectRatio);

Expand All @@ -147,7 +150,9 @@ QSize Writer::calculateImageSize(const QImage &image, float leftM, float topM)
void Writer::createDocFile(const QString &path,
float leftM,
float topM,
const QVector<QImage> &images)
const QVector<QImage> &images,
float pageWidth,
float pageHeight)
{
QString docPath = path + DOC_DIR;
QDir(docPath).mkpath(".");
Expand Down Expand Up @@ -175,7 +180,7 @@ void Writer::createDocFile(const QString &path,
int maxId = images.isEmpty() ? 5 : 2 + images.count() * 5;
int currentId = 1;

writeDocumentHeader(docStream, maxId);
writeDocumentHeader(docStream, maxId, pageWidth, pageHeight);
writePublicResHeader(publicResStream);

if (!images.isEmpty()) {
Expand All @@ -187,7 +192,7 @@ void Writer::createDocFile(const QString &path,
pagesPath += QDir::separator();

for (int i = 0; i < (images.isEmpty() ? 1 : images.size()); ++i) {
writePage(docStream, publicResStream, pagesPath, images, i, leftM, topM, currentId);
writePage(docStream, publicResStream, pagesPath, images, i, leftM, topM, currentId, pageWidth, pageHeight);
}

writeDocumentFooter(docStream);
Expand All @@ -199,7 +204,8 @@ void Writer::createDocFile(const QString &path,

void Writer::writePage(QTextStream &docStream, QTextStream &publicResStream,
const QString &pagesPath, const QVector<QImage> &images,
int pageIndex, float leftM, float topM, int &currentId)
int pageIndex, float leftM, float topM, int &currentId,
float pageWidth, float pageHeight)
{
docStream << QString("<ofd:Page ID=\"%1\" BaseLoc=\"Pages/Page_%2/Content.xml\"/>")
.arg(currentId).arg(pageIndex);
Expand All @@ -209,17 +215,17 @@ void Writer::writePage(QTextStream &docStream, QTextStream &publicResStream,
QString contentPath = pageDirPath + QDir::separator() + "Content.xml";

if (images.isEmpty()) {
createPageContent(contentPath, "0", "0", "0", "0", currentId, false);
createPageContent(contentPath, "0", "0", "0", "0", currentId, false, pageWidth, pageHeight);
} else {
const QImage &image = images.at(pageIndex);
QSize size = calculateImageSize(image, leftM, topM);
QSize size = calculateImageSize(image, leftM, topM, pageWidth, pageHeight);

QString maxWidth = QString::number(size.width() / 25.4 - leftM, 'f', 2);
QString maxHeight = QString::number(size.height() / 25.4 - topM, 'f', 2);
QString minX = QString::number(leftM, 'f', 2);
QString minY = QString::number(topM, 'f', 2);

createPageContent(contentPath, minX, minY, maxWidth, maxHeight, currentId, true);
createPageContent(contentPath, minX, minY, maxWidth, maxHeight, currentId, true, pageWidth, pageHeight);

publicResStream << QString(" <ofd:MultiMedia ID=\"%1\" Type=\"Image\">\n").arg(currentId)
<< QString(" <ofd:MediaFile>Image_%1.png</ofd:MediaFile>\n").arg(pageIndex + 1)
Expand All @@ -230,7 +236,8 @@ void Writer::writePage(QTextStream &docStream, QTextStream &publicResStream,

void Writer::createPageContent(const QString &path, const QString &minX,
const QString &minY, const QString &maxX,
const QString &maxY, int &id, bool hasImage)
const QString &maxY, int &id, bool hasImage,
float pageWidth, float pageHeight)
{
QFile file(path);
if (!file.open(QIODevice::WriteOnly)) {
Expand All @@ -247,22 +254,22 @@ void Writer::createPageContent(const QString &path, const QString &minX,
stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
<< "<ofd:Page xmlns:ofd=\"http://www.ofdspec.org\">\n"
<< " <ofd:Area>\n"
<< " <ofd:PhysicalBox>0.00 0.00 " << PAGE_WIDTH << " " << PAGE_HEIGHT << "</ofd:PhysicalBox>\n"
<< " <ofd:PhysicalBox>0.00 0.00 " << pageWidth << " " << pageHeight << "</ofd:PhysicalBox>\n"
<< " </ofd:Area>\n"
<< " <ofd:Content>\n"
<< QString(" <ofd:Layer ID=\"%1\">\n").arg(id++);

// 背景路径对象
stream << QString(" <ofd:PathObject ID=\"%1\" Boundary=\"0.00 0.00 %2 %3\" ")
.arg(id++)
.arg(PAGE_WIDTH + 0.01)
.arg(PAGE_HEIGHT)
.arg(pageWidth + 0.01)
.arg(pageHeight)
<< "MiterLimit=\"4.23\" Stroke=\"false\" Fill=\"true\" Rule=\"Even-Odd\">\n"
<< " <ofd:FillColor Value=\"255 255 255\" ColorSpace=\"4\"/>\n"
<< " <ofd:AbbreviatedData>M 0.00 0.00 L "
<< PAGE_WIDTH + 0.01 << " 0.00 L "
<< PAGE_WIDTH + 0.01 << " " << PAGE_HEIGHT << " L "
<< "0.00 " << PAGE_HEIGHT << " L "
<< pageWidth + 0.01 << " 0.00 L "
<< pageWidth + 0.01 << " " << pageHeight << " L "
<< "0.00 " << pageHeight << " L "
<< "0.00 0.00 C </ofd:AbbreviatedData>\n"
<< " </ofd:PathObject>\n";

Expand Down
Loading