From df45966c52bac2eb465cf05c1d6328bf0d00c5ac Mon Sep 17 00:00:00 2001
From: mrDarker <mr.darker@163.com>
Date: 星期六, 16 八月 2025 15:27:10 +0800
Subject: [PATCH] 1. 补提交添加保存图像的类
---
EdgeInspector_App/Thread/Thread_SaveFullImg.h | 45 +++++++++++
EdgeInspector_App/Thread/Thread_SaveFullImg.cpp | 194 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 239 insertions(+), 0 deletions(-)
diff --git a/EdgeInspector_App/Thread/Thread_SaveFullImg.cpp b/EdgeInspector_App/Thread/Thread_SaveFullImg.cpp
new file mode 100644
index 0000000..f38de1d
--- /dev/null
+++ b/EdgeInspector_App/Thread/Thread_SaveFullImg.cpp
@@ -0,0 +1,194 @@
+#include "stdafx.h"
+#include "Thread_SaveFullImg.h"
+
+static void TightCopy(std::vector<BYTE>& vDst, const BYTE* pSrc, int nWidth, int nHeight, int nStride, int nBpp)
+{
+ const int nTight = nWidth * nBpp;
+ vDst.resize(size_t(nTight) * nHeight);
+
+ if (vDst.empty() || nHeight < 1 || nWidth < 1 || nBpp < 1) {
+ g_pLog->DisplayMessage(_T("TightCopy: Invalid parameters, nWidth=%d, nHeight=%d, nBpp=%d"), nWidth, nHeight, nBpp);
+ return;
+ }
+
+ // 如果 nStride 等于 nTight,说明源数据是紧密行存储
+ if (nStride == nTight) {
+ memcpy(vDst.data(), pSrc, vDst.size());
+ return;
+ }
+
+ // 如果 nStride 小于 nTight,说明源数据不是紧密行存储
+ if (nStride < nTight) {
+ g_pLog->DisplayMessage(_T("TightCopy: Invalid nStride %d < nTight %d"), nStride, nTight);
+ return;
+ }
+
+ // 如果 nStride 大于 nTight,逐行复制
+ for (int y = 0; y < nHeight; ++y) {
+ memcpy(vDst.data() + size_t(y) * nTight, pSrc + size_t(y) * nStride, nTight);
+ }
+}
+
+CThread_SaveFullImg::CThread_SaveFullImg()
+{
+ m_bStop = false;
+}
+
+CThread_SaveFullImg::~CThread_SaveFullImg()
+{
+ StopThread();
+}
+
+void CThread_SaveFullImg::CreateThread()
+{
+ if (m_Thread.joinable()) {
+ return;
+ }
+
+ m_bStop = false;
+ m_Thread = std::thread([this] { ThreadProc(); });
+}
+
+void CThread_SaveFullImg::StopThread()
+{
+ {
+ std::lock_guard<std::mutex> oLock(m_Mtx);
+ m_bStop = true;
+ }
+
+ m_Cv.notify_all();
+ if (m_Thread.joinable()) {
+ m_Thread.join();
+ }
+}
+
+void CThread_SaveFullImg::Enqueue(SaveImgJob&& oJob)
+{
+ {
+ std::lock_guard<std::mutex> oLock(m_Mtx);
+ m_Q.push(std::move(oJob));
+ }
+ m_Cv.notify_one();
+}
+
+size_t CThread_SaveFullImg::GetPendingCount() const
+{
+ std::lock_guard<std::mutex> oLock(m_Mtx);
+ return m_Q.size();
+}
+
+void CThread_SaveFullImg::ThreadProc()
+{
+ while (true) {
+ SaveImgJob oJob; {
+ std::unique_lock<std::mutex> oLock(m_Mtx);
+ m_Cv.wait(oLock, [this] {
+ return m_bStop || !m_Q.empty();
+ });
+
+ if (m_bStop && m_Q.empty()) {
+ break;
+ }
+
+ oJob = std::move(m_Q.front());
+ m_Q.pop();
+ }
+
+ try {
+ SaveFullImageModern(oJob);
+ }
+ catch (...) {
+ g_pLog->DisplayMessage(_T("Async save failed: %s"), oJob.strPath.c_str());
+ }
+ }
+}
+
+BOOL CThread_SaveFullImg::SaveFullImageModern(const SaveImgJob& job)
+{
+ int iSide = job.nDimension;
+ if (iSide < 0 || iSide > MAX_DIMENSION_COUNT - 1) {
+ g_pLog->DisplayMessage(_T("Save Full Image Fail(%S, %d), invalid side index"), job.strPath.c_str(), job.nDimension);
+ return FALSE;
+ }
+
+ if (job.vData.empty() || job.nHeight < 100 || job.nWidth < 100 || job.nBpp < 0) {
+ g_pLog->DisplayMessage(_T("Save Full Image Fail(%S, %s, %d, %d)"), job.strPath.c_str(), PANEL_SIDE[iSide], job.nWidth, job.nHeight);
+ return FALSE;
+ }
+
+ if (job.nStride < job.nWidth * job.nBpp) {
+ g_pLog->DisplayMessage(_T("Save Full Image Fail(%S), stride(%d) < width*bpp(%d)"), job.strPath.c_str(), job.nStride, job.nWidth * job.nBpp);
+ return FALSE;
+ }
+
+ int nQuality = job.nQuality;
+ if (nQuality < 0) {
+ nQuality = 0;
+ }
+ if (nQuality > 100) {
+ nQuality = 100;
+ }
+
+ double dTmp = 70 / 100.0;
+ double dRatio = 1.0 - dTmp;
+ dRatio = dRatio - 0.01 < 0.0 ? 1.0 : dRatio;
+
+ g_pLog->DisplayMessage(_T("Save Full Image Start(%S, %s, %d, %d, %d)"), job.strPath.c_str(), PANEL_SIDE[job.nDimension], job.nStartY, job.nHeight, nQuality);
+
+ int nStartY = job.nStartY;
+ if (nStartY < 0) {
+ nStartY = 0;
+ }
+
+ if (nStartY > job.nHeight - 1) {
+ nStartY = job.nHeight - 1;
+ }
+
+ int cvType;
+ switch (job.nBpp)
+ {
+ case 1: cvType = CV_8UC1; break;
+ case 3: cvType = CV_8UC3; break;
+ default:
+ g_pLog->DisplayMessage(_T("Save Full Image Fail(%S), unsupported nBpp=%d"), job.strPath.c_str(), job.nBpp);
+ return FALSE;
+ }
+
+ const BYTE* pBase = job.vData.data() + size_t(nStartY) * size_t(job.nStride);
+ const int nHAvail = job.nHeight - nStartY;
+ if (nHAvail < 100) {
+ g_pLog->DisplayMessage(_T("Save Full Image Skip(%S, %s), nHAvail=%d too small"), job.strPath.c_str(), PANEL_SIDE[iSide], nHAvail);
+ return FALSE;
+ }
+
+ // 原始图像数据转 cv::Mat
+ cv::Mat origin(nHAvail, job.nWidth, cvType, (void*)pBase, size_t(job.nStride));
+
+ // 缩放图像
+ const int nOutW = std::max(1, static_cast<int>(origin.cols * dRatio));
+ const int nOutH = std::max(1, static_cast<int>(origin.rows * dRatio));
+ cv::Mat img;
+ if (nOutW == origin.cols && nOutH == origin.rows) {
+ img = origin;
+ }
+ else {
+ cv::resize(origin, img, cv::Size(nOutW, nOutH), 0, 0, cv::INTER_LINEAR);
+ }
+
+ // 设置 JPEG 压缩参数
+ std::vector<int> params = { cv::IMWRITE_JPEG_QUALITY, nQuality };
+ try {
+ if (!cv::imwrite(job.strPath, img, params)) {
+ g_pLog->DisplayMessage(_T("Save Full Image Fail(%S, %s, %d), imwrite failed"), job.strPath.c_str(), PANEL_SIDE[iSide], nStartY);
+ return FALSE;
+ }
+ }
+ catch (...) {
+ g_pLog->DisplayMessage(_T("Save Full Image Fail(%S, %s, %d), exception during imwrite"), job.strPath.c_str(), PANEL_SIDE[iSide], nStartY);
+ return FALSE;
+ }
+
+ g_pLog->DisplayMessage(_T("Save Full Image Success(%S, %s, %d, %d, %d)"), job.strPath.c_str(), PANEL_SIDE[iSide], nStartY, job.nHeight, nQuality);
+
+ return TRUE;
+}
\ No newline at end of file
diff --git a/EdgeInspector_App/Thread/Thread_SaveFullImg.h b/EdgeInspector_App/Thread/Thread_SaveFullImg.h
new file mode 100644
index 0000000..172302f
--- /dev/null
+++ b/EdgeInspector_App/Thread/Thread_SaveFullImg.h
@@ -0,0 +1,45 @@
+#pragma once
+#include <queue>
+#include <mutex>
+#include <condition_variable>
+#include <thread>
+#include <atomic>
+#include <vector>
+#include <string>
+#include <Windows.h>
+
+struct SaveImgJob
+{
+ std::string strPath;
+ std::vector<BYTE> vData;
+ int nWidth = 0;
+ int nHeight = 0;
+ int nStride = 0;
+ int nBpp = 1;
+ int nStartY = 0;
+ int nDimension = 0;
+ int nQuality = 80;
+};
+
+class CThread_SaveFullImg
+{
+public:
+ CThread_SaveFullImg();
+ ~CThread_SaveFullImg();
+
+ void CreateThread();
+ void StopThread();
+ void Enqueue(SaveImgJob&& oJob);
+ size_t GetPendingCount() const;
+
+private:
+ void ThreadProc();
+ BOOL SaveFullImageModern(const SaveImgJob& job);
+
+private:
+ mutable std::mutex m_Mtx;
+ std::condition_variable m_Cv;
+ std::queue<SaveImgJob> m_Q;
+ std::thread m_Thread;
+ std::atomic<bool> m_bStop;
+};
\ No newline at end of file
--
Gitblit v1.9.3