void CMyPS2Dlg::OnPaint()
{
CPaintDC dc(this);
CRect clientRect;
GetClientRect(&clientRect);
if (m_memDC.GetSafeHdc() == NULL ||
m_memBitmap.GetSafeHandle() == NULL ||
GetBitmapDimension(m_memBitmap) != clientRect.Size())
{
if (m_memDC.GetSafeHdc()) {
m_memDC.SelectObject((HBITMAP)NULL); // 必须先取消选择位图
m_memDC.DeleteDC();
}
if (m_memBitmap.GetSafeHandle()) {
m_memBitmap.DeleteObject();
}
CDC dcScreen;
dcScreen.CreateDC(_T(“DISPLAY”), NULL, NULL, NULL);
m_memDC.CreateCompatibleDC(&dcScreen);
m_memBitmap.CreateCompatibleBitmap(&dcScreen, clientRect.Width(), clientRect.Height());
CBitmap* pOldBitmap = m_memDC.SelectObject(&m_memBitmap); if (pOldBitmap) { pOldBitmap->DeleteObject(); // 删除默认的位图对象 } dcScreen.DeleteDC(); } m_memDC.FillSolidRect(clientRect, GetSysColor(COLOR_BTNFACE)); Gdiplus::Graphics graphics(m_memDC); // 2. 绘制底层(未选中的图层) ImageLayer* bottomLayer = m_layer1.isSelected ? &m_layer2 : &m_layer1; if (bottomLayer->isVisible && !bottomLayer->displayImage.IsNull()) { DrawLayer(graphics, bottomLayer->displayImage, bottomLayer->alpha); } // 3. 绘制上层(选中的图层) ImageLayer* topLayer = m_layer1.isSelected ? &m_layer1 : &m_layer2; if (topLayer->isVisible && !topLayer->displayImage.IsNull()) { DrawLayer(graphics, topLayer->displayImage, topLayer->alpha); // 4. 在选中的图层上绘制选区 if (!m_rcSelection.IsRectNull() || !m_freeFormPoints.empty()) { DrawSelection(m_memDC, topLayer); } } if (m_bDoodleMode && !m_doodleTempImage.IsNull()) { CRect imgRect = GetImageClientRect(topLayer->image); std::unique_ptr<Gdiplus::Bitmap> gdiBitmap(CImageToGdiPlusBitmap(m_doodleTempImage)); if (gdiBitmap) { graphics.DrawImage( gdiBitmap.get(), Gdiplus::Rect(imgRect.left, imgRect.top, imgRect.Width(), imgRect.Height()), 0, 0, m_doodleTempImage.GetWidth(), m_doodleTempImage.GetHeight(), Gdiplus::UnitPixel ); } } // 绘制克隆区域 ImageLayer& activeLayer = m_layer1.isSelected ? m_layer1 : m_layer2; if (activeLayer.clonedRegion.active && activeLayer.clonedRegion.visible) { CRect srcRect(0, 0, activeLayer.clonedRegion.image.GetWidth(), activeLayer.clonedRegion.image.GetHeight()); CRect screenRect = ConvertToScreenRect(activeLayer.clonedRegion.destRect); std::unique_ptr<Gdiplus::Bitmap> gdiBitmap( CImageToGdiPlusBitmap(activeLayer.clonedRegion.image)); if (gdiBitmap) { graphics.DrawImage(gdiBitmap.get(), Gdiplus::Rect(screenRect.left, screenRect.top, screenRect.Width(), screenRect.Height()), 0, 0, srcRect.Width(), srcRect.Height(), Gdiplus::UnitPixel); } } // 5. 输出到屏幕 dc.BitBlt(0, 0, clientRect.Width(), clientRect.Height(), &m_memDC, 0, 0, SRCCOPY);
}
void CMyPS2Dlg::DrawLayer(Gdiplus::Graphics& graphics, CImage& image, float alpha) {
CRect imgRect = GetImageClientRect(image);
std::unique_ptrGdiplus::Bitmap gdiBitmap(CImageToGdiPlusBitmap(image));
if (gdiBitmap) { Gdiplus::ColorMatrix matrix = { 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, alpha, 0, 0, 0, 0, 0, 1 }; Gdiplus::ImageAttributes attr; attr.SetColorMatrix(&matrix); graphics.DrawImage( gdiBitmap.get(), Gdiplus::Rect(imgRect.left, imgRect.top, imgRect.Width(), imgRect.Height()), 0, 0, image.GetWidth(), image.GetHeight(), Gdiplus::UnitPixel, &attr ); }
}
void CMyPS2Dlg::DrawSelection(CDC& dc, ImageLayer* layer) {
if (m_selectionMode == SELECT_RECTANGLE && !m_rcSelection.IsRectNull()) {
//将图像坐标的选区转换为屏幕坐标
CRect selRect = ConvertToScreenRect(m_rcSelection);
// 区分选中状态和保持状态 if (m_bSelecting) { // 动态选区:使用XOR模式(无闪烁拖动) CPen pen(PS_DOT, 1, RGB(255, 0, 0)); CPen* pOldPen = m_memDC.SelectObject(&pen); m_memDC.SelectStockObject(NULL_BRUSH); int oldROP = m_memDC.SetROP2(R2_XORPEN); m_memDC.Rectangle(selRect); m_memDC.SetROP2(oldROP); m_memDC.SelectObject(pOldPen); pen.DeleteObject(); } else { // 静态选区:使用常规绘制(保持可见) CPen pen(PS_SOLID, 1, RGB(0, 255, 0)); // 绿色实线 CPen* pOldPen = m_memDC.SelectObject(&pen); m_memDC.SelectStockObject(NULL_BRUSH); m_memDC.Rectangle(selRect); m_memDC.SelectObject(pOldPen); pen.DeleteObject(); } } else if (m_selectionMode == SELECT_FREE_FORM && !m_freeFormPoints.empty()) { //转换为屏幕坐标数组 CPoint* screenPoints = new CPoint[m_freeFormPoints.size()]; for (size_t i = 0; i < m_freeFormPoints.size(); ++i) { screenPoints[i] = ConvertToScreenPoint(m_freeFormPoints[i]); } // 绘制路径 CPen pen(PS_SOLID, 1, m_bFreeFormSelecting ? RGB(255, 0, 0) : RGB(0, 255, 0)); CPen* pOldPen = m_memDC.SelectObject(&pen); m_memDC.SelectStockObject(NULL_BRUSH); // 使用Polyline绘制连续线条 m_memDC.Polyline(screenPoints, (int)m_freeFormPoints.size()); // 如果是闭合路径,绘制填充区域 if (!m_bFreeFormSelecting && m_freeFormPoints.size() > 2) { // 绘制闭合提示标记 CRect markRect(screenPoints[0].x - 3, screenPoints[0].y - 3, screenPoints[0].x + 3, screenPoints[0].y + 3); CBrush markBrush(RGB(255, 255, 0)); m_memDC.FillRect(&markRect, &markBrush); } m_memDC.SelectObject(pOldPen); pen.DeleteObject(); delete[] screenPoints; }
}
//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CMyPS2Dlg::OnQueryDragIcon()
{
return static_cast(m_hIcon);
}
//打开
void CMyPS2Dlg::OnBnClickedButton2()
{
if (!m_layer1.image.IsNull()) {
UINT i;
i = MessageBox(_T(“确认重新打开图片吗?”), _T(“提示”), MB_YESNO | MB_ICONQUESTION);
if (i != IDYES)
{
return;
}
}
CFileDialog dlg(TRUE, _T(“.bmp;.jpg;.png"), NULL, OFN_FILEMUSTEXIST,
_T("Image Files|.bmp;.jpg;.png||”), this);
if (dlg.DoModal() == IDOK) { // 释放旧资源 m_layer1.history.clear(); m_layer1.currentHistoryIndex = -1; m_layer1.isSelected = true; if (!m_layer1.image.IsNull()) { m_layer1.image.Destroy(); } if (!m_layer1.displayImage.IsNull()) { m_layer1.displayImage.Destroy(); } if (m_layer1.image.Load(dlg.GetPathName()) != S_OK) { AfxMessageBox(L"图像加载失败!\n请检查格式支持(BMP/JPG/PNG)"); return; } else { // 加载新图像 ImageState initialState; initialState.brightness = 0; initialState.saturation = 1.0f; initialState.mosaic = 1; initialState.alpha = 1.0f; if (!m_layer1.image.IsNull()) { if (!initialState.image.IsNull()) { initialState.image.Destroy(); } initialState.image.Create(m_layer1.image.GetWidth(), m_layer1.image.GetHeight(), m_layer1.image.GetBPP()); CDC* pSrcDC = CDC::FromHandle(m_layer1.image.GetDC()); CDC* pDstDC = CDC::FromHandle(initialState.image.GetDC()); pDstDC->BitBlt(0, 0, m_layer1.image.GetWidth(), m_layer1.image.GetHeight(), pSrcDC, 0, 0, SRCCOPY); m_layer1.image.ReleaseDC(); initialState.image.ReleaseDC(); } m_layer1.history.push_back(initialState); m_layer1.history.push_back(initialState); m_layer1.currentHistoryIndex = 1; // 重置所有参数 m_nlightValue = 0; m_nsatureValue = 1.0f; m_nmskValue = 1; m_layer1.alpha = 1.0f; // 重置底层透明度为不透明 m_layer2.alpha = 0.5f; // 重置顶层透明度为半透明 // 初始化UI控件 litslider.SetPos(100); // 假设滑块范围0-200,100对应亮度0 saturslider.SetPos(100); // 假设滑块范围0-200,100对应饱和度1.0 mskslider.SetPos(1); // 马赛克块大小(1~20) m_sliderLay1.SetPos(100); // 新增:底层透明度滑块(0-100) m_sliderLay2.SetPos(50); // 新增:顶层透明度滑块(0-100) // 生成显示图像 UpdateDisplayImage(m_layer1); } }
}
//保存
void CMyPS2Dlg::OnBnClickedButton3()
{
CFileDialog dlg(FALSE, _T(“.jpg"), _T(“output.jpg”), OFN_OVERWRITEPROMPT,
_T("JPEG Files|.jpg||”), this);
if (dlg.DoModal() == IDOK) { if (m_layer1.isSelected) { if (m_layer1.displayImage.IsNull()) { // 改为检查 m_displayImage AfxMessageBox(_T("请先打开图片!")); return; } if (m_layer1.currentHistoryIndex < 0) { AfxMessageBox(_T("图片失效")); return; } else { m_layer1.displayImage.Save(dlg.GetPathName()); } } // 保存处理后的图像 else { if (m_layer2.displayImage.IsNull()) { // 改为检查 m_displayImage AfxMessageBox(_T("请先打开图片!")); return; } if (m_layer2.currentHistoryIndex < 0) { AfxMessageBox(_T("图片失效")); return; } else { m_layer2.displayImage.Save(dlg.GetPathName()); } } } // TODO: 在此添加控件通知处理程序代码
}
//退出
void CMyPS2Dlg::OnBnClickedButton4()
{
UINT i;
i = MessageBox(_T(“请确认图片保存再退出。”), _T(“提示”), MB_YESNO | MB_ICONQUESTION);
if (i == IDYES)
{
exit(0);
}
// TODO: 在此添加控件通知处理程序代码
}
//亮度滑块
void CMyPS2Dlg::OnNMCustomdrawSliderlit(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMCUSTOMDRAW pNMCD = reinterpret_cast(pNMHDR);
*pResult = 0;
}
//亮度编辑框
void CMyPS2Dlg::OnEnChangeEditlit()
{
if (m_bStateDirty) return;
CString strValue;
litedit.GetWindowText(strValue);
int brightness = _ttoi(strValue)+100;
// 检查输入值是否在有效范围内 (-100 到 100) brightness = max(0, min(200, brightness)); litslider.SetPos(brightness); // 应用亮度调整 OnParameterChanged(); // TODO: 如果该控件是 RICHEDIT 控件,它将不 // 发送此通知,除非重写 CDialogEx::OnInitDialog() // 函数并调用 CRichEditCtrl().SetEventMask(), // 同时将 ENM_CHANGE 标志“或”运算到掩码中。 // TODO: 在此添加控件通知处理程序代码
}
void CMyPS2Dlg::ApplyBrightnessToPixels(BYTE* pBits, int width, int height, int pitch, int channels, int brightness)
{
for (int y = 0; y < height; y++)
{
BYTE* pRow = pBits + y * pitch;
for (int x = 0; x < width; x++)
{
for (int c = 0; c < 3; c++) // 处理BGR通道
{
int newVal = pRow[x * channels + c] + brightness;
pRow[x * channels + c] = (BYTE)min(255, max(0, newVal));
}
}
}
}
void CMyPS2Dlg::ApplySaturationToPixels(BYTE* pBits, int width, int height, int pitch, int channels, float saturation) {
// 确保饱和度范围合理(0.0~3.0)
saturation = min(max(saturation, 0.0f), 2.0f);
for (int y = 0; y < height; y++) { BYTE* pRow = pBits + y * pitch; for (int x = 0; x < width; x++) { BYTE& b = pRow[x * channels]; BYTE& g = pRow[x * channels + 1]; BYTE& r = pRow[x * channels + 2]; // 计算灰度值(更精确的权重) float gray = 0.299f * r + 0.587f * g + 0.114f * b; // 调整饱和度(非线性插值,避免过度失真) float blendFactor = saturation ; r = (BYTE)min(255.0f, max(0.0f, gray + blendFactor * (r - gray))); g = (BYTE)min(255.0f, max(0.0f, gray + blendFactor * (g - gray))); b = (BYTE)min(255.0f, max(0.0f, gray + blendFactor * (b - gray))); } }
}
void CMyPS2Dlg::ApplyMosaicToPixels(BYTE* pBits, int width, int height, int pitch, int channels, int blockSize) {
for (int y = 0; y < height; y += blockSize) {
for (int x = 0; x < width; x += blockSize) {
// 计算当前块的边界
int blockEndX = min(x + blockSize, width);
int blockEndY = min(y + blockSize, height);
// 计算块内像素的平均颜色 long sumR = 0, sumG = 0, sumB = 0; int count = 0; for (int by = y; by < blockEndY; by++) { BYTE* pRow = pBits + by * pitch; for (int bx = x; bx < blockEndX; bx++) { sumB += pRow[bx * channels]; sumG += pRow[bx * channels + 1]; sumR += pRow[bx * channels + 2]; count++; } } BYTE avgR = (BYTE)(sumR / count); BYTE avgG = (BYTE)(sumG / count); BYTE avgB = (BYTE)(sumB / count); // 将整个块设为平均颜色 for (int by = y; by < blockEndY; by++) { BYTE* pRow = pBits + by * pitch; for (int bx = x; bx < blockEndX; bx++) { pRow[bx * channels] = avgB; pRow[bx * channels + 1] = avgG; pRow[bx * channels + 2] = avgR; } } } }
}
void CMyPS2Dlg::OnNMCustomdrawSlidersatur(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMCUSTOMDRAW pNMCD = reinterpret_cast(pNMHDR);
// TODO: 在此添加控件通知处理程序代码 *pResult = 0;
}
//饱和度编辑框
void CMyPS2Dlg::OnEnChangeEditsatur()
{
if (m_bStateDirty) return;
CString strValue; saturedit.GetWindowText(strValue); float sat = _ttof(strValue)*100.0f+100.0f; // 限制范围并同步滑块 sat = max(0.0f, min(200.0f, sat)); saturslider.SetPos((int)sat); // 统一计算为浮点数(0.0~2.0) m_nsatureValue = sat / 100.0f; // 新增此行 OnParameterChanged(); // TODO: 如果该控件是 RICHEDIT 控件,它将不 // 发送此通知,除非重写 CDialogEx::OnInitDialog() // 函数并调用 CRichEditCtrl().SetEventMask(), // 同时将 ENM_CHANGE 标志“或”运算到掩码中。 // TODO: 在此添加控件通知处理程序代码
}
void CMyPS2Dlg::OnNMCustomdrawSlidermsk(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMCUSTOMDRAW pNMCD = reinterpret_cast(pNMHDR);
// TODO: 在此添加控件通知处理程序代码 *pResult = 0;
}
//马赛克编辑框
void CMyPS2Dlg::OnEnChangeEditmsk()
{
if (m_bStateDirty) return;
CString strValue; mskedit.GetWindowText(strValue); int size = _ttoi(strValue); // 限制范围并同步滑块 size = max(1, min(50, size)); mskslider.SetPos(size); // 应用马赛克效果 OnParameterChanged(); // TODO: 如果该控件是 RICHEDIT 控件,它将不 // 发送此通知,除非重写 CDialogEx::OnInitDialog() // 函数并调用 CRichEditCtrl().SetEventMask(), // 同时将 ENM_CHANGE 标志“或”运算到掩码中。 // TODO: 在此添加控件通知处理程序代码
}
//滑块
void CMyPS2Dlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
if (m_bStateDirty)return;
int id = pScrollBar->GetDlgCtrlID();
if (id == IDC_SLIDERLIT) { // 亮度滑块 m_nlightValue = litslider.GetPos() - 100; // 范围:-100 ~ +100 CString strValue; strValue.Format(_T("%d"), m_nlightValue); litedit.SetWindowText(strValue); } else if (id == IDC_SLIDERSATUR) { // 饱和度滑块 m_nsatureValue = (saturslider.GetPos()) / 100.0f; // 范围:0.0 ~ 2.0 float sat = m_nsatureValue - 1.0f; CString strValue; strValue.Format(_T("%.1f"), sat); saturedit.SetWindowText(strValue); //UpdateDisplayImage(); } else if (id == IDC_SLIDERMSK) { // 马赛克滑块 m_nmskValue = mskslider.GetPos(); // 范围:1 ~ 50 CString strValue; strValue.Format(_T("%d"), m_nmskValue); mskedit.SetWindowText(strValue); //UpdateDisplayImage(); } else if (id == IDC_SLIDERL1) { m_layer1.alpha = (float)m_sliderLay1.GetPos() / 100.0f; // 范围:0.0 ~ 1.0 InvalidateRect(GetImageClientRect(m_layer1.image)); // 重绘图片区域 } // 顶层图片透明度滑块 else if (id == IDC_SLIDERL2) { m_layer2.alpha = (float)m_sliderLay2.GetPos() / 100.0f; // 范围:0.0 ~ 1.0 InvalidateRect(m_overlayRect); // 只重绘叠加层区域 } OnParameterChanged(); CDialogEx::OnHScroll(nSBCode, nPos, pScrollBar);
}
void CMyPS2Dlg::OnBnClickedButtonReset() {
//if (!m_originalImage.IsNull()) {
// m_nlightValue = 0;
// m_nsatureValue = 0.0f;
// m_nmskValue = 1;
// litslider.SetPos(50); // saturslider.SetPos(50); // litslider.SetPos(1); // litedit.SetWindowText(_T("0")); // saturedit.SetWindowText(_T("0.0")); // mskedit.SetWindowText(_T("1")); // UpdateDisplayImage(); //}
}
//更新1
void CMyPS2Dlg::UpdateDisplayImage(ImageLayer& layer)
{
if (layer.currentHistoryIndex < 0) return;
if(layer.image.IsNull()) return;
if (layer.displayImage.IsNull() ||
layer.displayImage.GetWidth() != layer.image.GetWidth() ||
layer.displayImage.GetHeight() != layer.image.GetHeight())
{
layer.displayImage.Destroy();
layer.displayImage.Create(layer.image.GetWidth(),
layer.image.GetHeight(),
layer.image.GetBPP());
}
// 复制原图到显示图像 CDC* pSrcDC = CDC::FromHandle(layer.image.GetDC()); CDC* pDstDC = CDC::FromHandle(layer.displayImage.GetDC()); pDstDC->BitBlt(0, 0, layer.image.GetWidth(), layer.image.GetHeight(), pSrcDC, 0, 0, SRCCOPY); layer.image.ReleaseDC(); layer.displayImage.ReleaseDC(); // 应用当前参数效果 BYTE* pBits = (BYTE*)layer.displayImage.GetBits(); if (!pBits) return; int pitch = layer.displayImage.GetPitch(); int width = layer.displayImage.GetWidth(); int height = layer.displayImage.GetHeight(); int bpp = layer.displayImage.GetBPP(); int channels = (bpp == 32) ? 4 : 3; if (select) { if (layer.history[layer.currentHistoryIndex].mosaic > 1) { ApplyMosaicToPixels(pBits, width, height, pitch, channels, layer.history[layer.currentHistoryIndex].mosaic); } if (layer.history[layer.currentHistoryIndex].brightness != 0) { ApplyBrightnessToPixels(pBits, width, height, pitch, channels, layer.history[layer.currentHistoryIndex].brightness); } if (layer.history[layer.currentHistoryIndex].saturation != 1.0f) { ApplySaturationToPixels(pBits, width, height, pitch, channels, layer.history[layer.currentHistoryIndex].saturation); } ApplyAdvancedEffectsToSelection(m_nlightValue, m_nsatureValue, m_isBlackWhite, m_isSepia, m_nmskValue, layer); } else { // 全局应用效果 if (m_nmskValue > 1) { ApplyMosaicToPixels(pBits, width, height, pitch, channels, m_nmskValue); } if (m_nlightValue != 0) { ApplyBrightnessToPixels(pBits, width, height, pitch, channels, m_nlightValue); } if (m_nsatureValue != 1.0f) { ApplySaturationToPixels(pBits, width, height, pitch, channels, m_nsatureValue); } if (m_isBlackWhite) ApplyBlackWhiteToPixels(pBits, width, height, pitch, channels); else if (m_isSepia) ApplySepiaToPixels(pBits, width, height, pitch, channels); } InvalidateRect(NULL, FALSE); UpdateWindow();
}
//黑白
void CMyPS2Dlg::ApplyBlackWhiteToPixels(BYTE* pBits, int width, int height, int pitch, int channels)
{
for (int y = 0; y < height; y++)
{
BYTE* pRow = pBits + y * pitch;
for (int x = 0; x < width; x++)
{
BYTE& b = pRow[x * channels];
BYTE& g = pRow[x * channels + 1];
BYTE& r = pRow[x * channels + 2];
// 计算灰度值(加权平均) BYTE gray = (BYTE)(0.299f * r + 0.587f * g + 0.114f * b); // 所有通道设为灰度值 b = g = r = gray; } }
}
//怀旧
void CMyPS2Dlg::ApplySepiaToPixels(BYTE* pBits, int width, int height, int pitch, int channels)
{
for (int y = 0; y < height; y++)
{
BYTE* pRow = pBits + y * pitch;
for (int x = 0; x < width; x++)
{
BYTE& b = pRow[x * channels];
BYTE& g = pRow[x * channels + 1];
BYTE& r = pRow[x * channels + 2];
// 怀旧色计算公式 int newR = min(255, (int)(0.393f * r + 0.769f * g + 0.189f * b)); int newG = min(255, (int)(0.349f * r + 0.686f * g + 0.168f * b)); int newB = min(255, (int)(0.272f * r + 0.534f * g + 0.131f * b)); r = (BYTE)newR; g = (BYTE)newG; b = (BYTE)newB; } }
}
//定时器
void CMyPS2Dlg::OnTimer(UINT_PTR nIDEvent)
{
if (nIDEvent == SAVE_DELAY_TIMER) {
KillTimer(m_nSaveTimer);
m_nSaveTimer = 0;
if (m_bStateDirty) { if (m_layer1.isSelected) { SaveCurrentState(m_layer1); } else { SaveCurrentState(m_layer2); } m_bStateDirty = false; } } CDialogEx::OnTimer(nIDEvent);
}
//参数变化
void CMyPS2Dlg::OnParameterChanged()
{
ImageLayer& activeLayer = m_layer1.isSelected ? m_layer1 : m_layer2;
// 更新当前参数值
m_nlightValue = litslider.GetPos() - 100;
m_nsatureValue = (saturslider.GetPos()) / 100.0f;
m_nmskValue = mskslider.GetPos();
// 标记状态已改变 m_bStateDirty = true; // 重置保存定时器 if (m_nSaveTimer) { KillTimer(m_nSaveTimer); } m_nSaveTimer = SetTimer(SAVE_DELAY_TIMER, SAVE_DELAY, NULL); // 立即更新显示 if (m_layer1.isSelected) { UpdateDisplayImage(m_layer1); } else { UpdateDisplayImage(m_layer2); }
}
//新增状态
void CMyPS2Dlg::SaveCurrentState(ImageLayer& layer)
{
if (!m_bStateDirty) return;
if (layer.currentHistoryIndex < 0) return;
if (select) {
return;
}
ImageState currentState;
if (layer.modified) {
currentState.brightness = layer.history[layer.currentHistoryIndex].brightness;
currentState.saturation = layer.history[layer.currentHistoryIndex].saturation;
currentState.mosaic = layer.history[layer.currentHistoryIndex].mosaic;
currentState.alpha = layer.history[layer.currentHistoryIndex].alpha;
} else { currentState.brightness = m_nlightValue; currentState.saturation = m_nsatureValue; currentState.mosaic = m_nmskValue; currentState.alpha = layer.alpha; } if (!layer.image.IsNull()) { if (!currentState.image.IsNull()) { currentState.image.Destroy(); } currentState.image.Create(layer.image.GetWidth(), layer.image.GetHeight(), layer.image.GetBPP()); CDC* pSrcDC = CDC::FromHandle(layer.image.GetDC()); CDC* pDstDC = CDC::FromHandle(currentState.image.GetDC()); pDstDC->BitBlt(0, 0, layer.image.GetWidth(), layer.image.GetHeight(), pSrcDC, 0, 0, SRCCOPY); layer.image.ReleaseDC(); currentState.image.ReleaseDC(); } if (layer.currentHistoryIndex >= 0 && layer.history[layer.currentHistoryIndex] == currentState&&(!layer.modified)&&(!doodend)) { return; } for (int i = layer.currentHistoryIndex +1; i <= layer.history.size() - 1; i++) { layer.history.erase(layer.history.begin() + i); } layer.history.push_back(currentState); layer.currentHistoryIndex +=1; layer.modified = false; doodend = false; // 限制历史记录数量 const int MAX_HISTORY = 40; if (layer.history.size() > MAX_HISTORY) { layer.history.erase(layer.history.begin()); layer.currentHistoryIndex--; } m_bStateDirty = false;
}
//销毁
void CMyPS2Dlg::OnDestroy()
{
CDialogEx::OnDestroy(); // 调用基类实现
// 清理定时器资源 if (m_nSaveTimer != 0) { KillTimer(m_nSaveTimer); m_nSaveTimer = 0; } // 清理图像资源 if (!m_layer1.image.IsNull()) m_layer1.image.Destroy(); if (!m_layer2.image.IsNull()) m_layer2.image.Destroy(); if (!m_layer1.displayImage.IsNull()) m_layer1.displayImage.Destroy(); if (!m_layer2.displayImage.IsNull()) m_layer2.displayImage.Destroy(); if (!m_doodleTempImage.IsNull()) m_doodleTempImage.Destroy(); //GdiplusShutdown(m_gdiplusToken); CDialogEx::OnDestroy();
}
//撤回
void CMyPS2Dlg::OnUndo()
{
if (m_layer1.isSelected) {
if (m_layer1.currentHistoryIndex > 0) {
m_layer1.currentHistoryIndex–;
ApplyHistoryState(m_layer1.currentHistoryIndex,m_layer1);
}
else {
AfxMessageBox(_T(“不可撤回。”));
}
}
else {
if (m_layer2.currentHistoryIndex > 0) {
m_layer2.currentHistoryIndex–;
ApplyHistoryState(m_layer2.currentHistoryIndex, m_layer2);
}
else {
AfxMessageBox(_T(“不可撤回。”));
}
}
}
//重做
void CMyPS2Dlg::OnRedo()
{
if (m_layer1.isSelected) {
if (m_layer1.currentHistoryIndex < static_cast(m_layer1.history.size()) - 1) {
m_layer1.currentHistoryIndex++;
ApplyHistoryState(m_layer1.currentHistoryIndex,m_layer1);
}
else {
AfxMessageBox(_T(“不可重做。”));
}
}
else {
if (m_layer2.currentHistoryIndex < static_cast(m_layer2.history.size()) - 1) {
m_layer2.currentHistoryIndex++;
ApplyHistoryState(m_layer2.currentHistoryIndex, m_layer2);
}
else {
AfxMessageBox(_T(“不可重做。”));
}
}
}
void CMyPS2Dlg::ApplyHistoryState(int index, ImageLayer& layer)
{
if (index < 0 || index >= static_cast(layer.history.size())) return;
const ImageState& state = layer.history[index]; if (!state.image.IsNull()) { if (!layer.image.IsNull()) { layer.image.Destroy(); } layer.image.Create(state.image.GetWidth(), state.image.GetHeight(), state.image.GetBPP()); CDC* pSrcDC = CDC::FromHandle(state.image.GetDC()); CDC* pDstDC = CDC::FromHandle(layer.image.GetDC()); pDstDC->BitBlt(0, 0, state.image.GetWidth(), state.image.GetHeight(), pSrcDC, 0, 0, SRCCOPY); state.image.ReleaseDC(); layer.image.ReleaseDC(); } // 更新UI控件 litslider.SetPos(state.brightness + 100); saturslider.SetPos((int)(state.saturation * 100.0f)); mskslider.SetPos(state.mosaic); if (m_layer1.isSelected) { m_sliderLay1.SetPos((int)(state.alpha * 100.0f)); } else { m_sliderLay2.SetPos((int)(state.alpha * 100.0f)); } CString str; str.Format(_T("%d"), state.brightness); litedit.SetWindowText(str); str.Format(_T("%.1f"), state.saturation); saturedit.SetWindowText(str); str.Format(_T("%d"), state.mosaic); mskedit.SetWindowText(str); // 更新当前参数 m_nlightValue = state.brightness; m_nsatureValue = state.saturation; m_nmskValue = state.mosaic; layer.alpha = state.alpha; // 更新显示 UpdateDisplayImage(layer);
}
//撤回
void CMyPS2Dlg::OnBnClickedButton1()
{
OnUndo();
// TODO: 在此添加控件通知处理程序代码
}
void CMyPS2Dlg::OnBnClickedButton5()
{
OnRedo();
// TODO: 在此添加控件通知处理程序代码
}
//黑白滤镜
void CMyPS2Dlg::OnBnClickedButton6()
{
m_isBlackWhite = !m_isBlackWhite;
m_isSepia = false; // 确保二者互斥
if (m_layer1.isSelected) {
UpdateDisplayImage(m_layer1);
}
else {
UpdateDisplayImage(m_layer2);
}
// TODO: 在此添加控件通知处理程序代码
}
//怀旧滤镜
void CMyPS2Dlg::OnBnClickedButton7()
{
m_isSepia = !m_isSepia;
m_isBlackWhite = false; // 确保二者互斥
if (m_layer1.isSelected) {
UpdateDisplayImage(m_layer1);
}
else {
UpdateDisplayImage(m_layer2);
}
// TODO: 在此添加控件通知处理程序代码
}
//退出选区
void CMyPS2Dlg::OnBnClickedButton8()
{
ImageLayer& activeLayer = m_layer1.isSelected ? m_layer1 : m_layer2;
if (activeLayer.clonedRegion.active && activeLayer.clonedRegion.visible) { // 将克隆区域绘制到目标位置 CDC* pDstDC = CDC::FromHandle(activeLayer.image.GetDC()); CDC* pSrcDC = CDC::FromHandle(activeLayer.clonedRegion.image.GetDC()); pDstDC->BitBlt( activeLayer.clonedRegion.destRect.left, activeLayer.clonedRegion.destRect.top, activeLayer.clonedRegion.destRect.Width(), activeLayer.clonedRegion.destRect.Height(), pSrcDC, 0, 0, SRCCOPY); activeLayer.image.ReleaseDC(); activeLayer.clonedRegion.image.ReleaseDC(); } // 重置克隆区域 activeLayer.clonedRegion.active = false; activeLayer.clonedRegion.visible = false; select = false; if (m_layer1.isSelected) { if (HasSelection() && !m_layer1.displayImage.IsNull() && !m_layer1.image.IsNull()) { CRect validRect; if (m_selectionMode == SELECT_RECTANGLE) { validRect = m_rcSelection; validRect.IntersectRect(validRect, CRect(0, 0, m_layer1.image.GetWidth(), m_layer1.image.GetHeight())); } else if (m_selectionMode == SELECT_FREE_FORM && m_rgnFreeForm.GetSafeHandle()) { m_rgnFreeForm.GetRgnBox(&validRect); validRect.IntersectRect(validRect, CRect(0, 0, m_layer1.image.GetWidth(), m_layer1.image.GetHeight())); } if (!validRect.IsRectEmpty()) { // 只复制选区内的修改回原图 CDC* pDispDC = CDC::FromHandle(m_layer1.displayImage.GetDC()); CDC* pOrigDC = CDC::FromHandle(m_layer1.image.GetDC()); // 设置裁剪区域(只复制选区内的像素) if (m_selectionMode == SELECT_FREE_FORM) { pOrigDC->SelectClipRgn(&m_rgnFreeForm); } pOrigDC->BitBlt( validRect.left, validRect.top, validRect.Width(), validRect.Height(), pDispDC, validRect.left, validRect.top, SRCCOPY); // 重置裁剪区域 pOrigDC->SelectClipRgn(NULL); m_layer1.image.ReleaseDC(); m_layer1.displayImage.ReleaseDC(); // 保存当前状态到历史记录 m_layer1.modified = true; m_bStateDirty = true; m_nlightValue = m_layer1.history[m_layer1.currentHistoryIndex].brightness; m_nsatureValue = m_layer1.history[m_layer1.currentHistoryIndex].saturation; m_nmskValue = m_layer1.history[m_layer1.currentHistoryIndex].mosaic; SaveCurrentState(m_layer1); } } } else { if (HasSelection() && !m_layer2.displayImage.IsNull() && !m_layer2.image.IsNull()) { CRect validRect; if (m_selectionMode == SELECT_RECTANGLE) { validRect = m_rcSelection; validRect.IntersectRect(validRect, CRect(0, 0, m_layer2.image.GetWidth(), m_layer2.image.GetHeight())); } else if (m_selectionMode == SELECT_FREE_FORM && m_rgnFreeForm.GetSafeHandle()) { m_rgnFreeForm.GetRgnBox(&validRect); validRect.IntersectRect(validRect, CRect(0, 0, m_layer2.image.GetWidth(), m_layer2.image.GetHeight())); } if (!validRect.IsRectEmpty()) { // 只复制选区内的修改回原图 CDC* pDispDC = CDC::FromHandle(m_layer2.displayImage.GetDC()); CDC* pOrigDC = CDC::FromHandle(m_layer2.image.GetDC()); // 设置裁剪区域(只复制选区内的像素) if (m_selectionMode == SELECT_FREE_FORM) { pOrigDC->SelectClipRgn(&m_rgnFreeForm); } pOrigDC->BitBlt( validRect.left, validRect.top, validRect.Width(), validRect.Height(), pDispDC, validRect.left, validRect.top, SRCCOPY); // 重置裁剪区域 pOrigDC->SelectClipRgn(NULL); m_layer2.image.ReleaseDC(); m_layer2.displayImage.ReleaseDC(); // 保存当前状态到历史记录 m_layer2.modified = true; m_bStateDirty = true; m_nlightValue = m_layer2.history[m_layer2.currentHistoryIndex].brightness; m_nsatureValue = m_layer2.history[m_layer2.currentHistoryIndex].saturation; m_nmskValue = m_layer2.history[m_layer2.currentHistoryIndex].mosaic; SaveCurrentState(m_layer2); } } } /*m_bStateDirty = true;*/ litslider.SetPos(m_nlightValue); saturslider.SetPos((int)(m_nsatureValue * 100.0f)); mskslider.SetPos(m_nmskValue); CString strValue; strValue.Format(_T("%d"), m_nlightValue); litedit.SetWindowText(strValue); strValue.Format(_T("%.1f"), m_nsatureValue); saturedit.SetWindowText(strValue); strValue.Format(_T("%d"), m_nmskValue); mskedit.SetWindowText(strValue); m_rcSelection.SetRectEmpty(); m_ptStart = m_ptEnd = CPoint(0, 0); if (m_rgnFreeForm.GetSafeHandle()) { // 2. 清除不规则选区数据 m_rgnFreeForm.DeleteObject(); // 删除区域对象 } m_freeFormPoints.clear(); // 清空点集 m_bSelecting = false;//// 3. 重置状态标志 m_bFreeFormSelecting = false; InvalidateRect(NULL, FALSE); UpdateWindow(); // TODO: 在此添加控件通知处理程序代码
}
CRect CMyPS2Dlg::GetImageClientRect(const CImage& image)
{
CRect ctrlRect;
m_staticImage.GetWindowRect(&ctrlRect);
ScreenToClient(&ctrlRect);
int imgW = image.GetWidth(); int imgH = image.GetHeight(); double ratio = min( (double)ctrlRect.Width() / imgW, (double)ctrlRect.Height() / imgH ); int drawW = (int)(imgW * ratio); int drawH = (int)(imgH * ratio); int x = ctrlRect.left + (ctrlRect.Width() - drawW) / 2; int y = ctrlRect.top + (ctrlRect.Height() - drawH) / 2; return CRect(x, y, x + drawW, y + drawH);
}
std::unique_ptrGdiplus::Bitmap CMyPS2Dlg::CImageToGdiPlusBitmap(CImage& image)
{
if (image.IsNull())
return nullptr;
// 直接通过HBITMAP转换 return std::unique_ptr<Gdiplus::Bitmap>( Gdiplus::Bitmap::FromHBITMAP( (HBITMAP)image, // CImage可隐式转换为HBITMAP NULL // 不使用调色板 ) );
}
void CMyPS2Dlg::OnLButtonDown(UINT nFlags, CPoint point)
{
ImageLayer& activeLayer = m_layer1.isSelected ? m_layer1 : m_layer2;
// 检查是否点击在克隆区域上 if (activeLayer.clonedRegion.active && activeLayer.clonedRegion.visible) { CRect screenRect = ConvertToScreenRect(activeLayer.clonedRegion.destRect); if (screenRect.PtInRect(point)) { // 记录拖动起始点 m_ptDragStart = point; m_ptCloneStart = activeLayer.clonedRegion.destRect.TopLeft(); m_bDragging = true; SetCapture(); // 捕获鼠标 TRACE(_T("开始拖动克隆区域\n")); TRACE(_T("原始位置: (%d, %d)\n"), m_ptCloneStart.x, m_ptCloneStart.y); TRACE(_T("屏幕位置: (%d, %d)\n"), point.x, point.y); return; // 不处理其他逻辑 } } if (m_bDoodleMode) { CRect imgRect = GetImageClientRect(m_layer1.isSelected?m_layer1.image:m_layer2.image); if (imgRect.PtInRect(point)) { // 转换为图像坐标 CPoint imgPoint; imgPoint.x = (point.x - imgRect.left) * m_doodleTempImage.GetWidth() / imgRect.Width(); imgPoint.y = (point.y - imgRect.top) * m_doodleTempImage.GetHeight() / imgRect.Height(); m_ptDoodleStart = imgPoint; m_bDoodling = true; } return; // 涂鸦模式下不进行其他选择操作 } if (m_layer1.isSelected) { CRect imgRect = GetImageClientRect(m_layer1.image); if (imgRect.PtInRect(point)) { if (m_selectionMode == SELECT_RECTANGLE) { // 原有矩形选区代码 m_ptStart.x = (point.x - imgRect.left) * m_layer1.displayImage.GetWidth() / imgRect.Width(); m_ptStart.y = (point.y - imgRect.top) * m_layer1.displayImage.GetHeight() / imgRect.Height(); m_ptEnd = m_ptStart; m_bSelecting = true; SetCapture(); } else if (m_selectionMode == SELECT_FREE_FORM) { m_bFreeFormSelecting = true; m_freeFormPoints.clear(); // 转换为图像坐标存储 CPoint imgPoint; imgPoint.x = (point.x - imgRect.left) * m_layer1.displayImage.GetWidth() / imgRect.Width(); imgPoint.y = (point.y - imgRect.top) * m_layer1.displayImage.GetHeight() / imgRect.Height(); m_freeFormPoints.push_back(imgPoint); SetCapture(); Invalidate(); } } } else { CRect imgRect = GetImageClientRect(m_layer2.image); if (imgRect.PtInRect(point)) { if (m_selectionMode == SELECT_RECTANGLE) { // 原有矩形选区代码 m_ptStart.x = (point.x - imgRect.left) * m_layer2.displayImage.GetWidth() / imgRect.Width(); m_ptStart.y = (point.y - imgRect.top) * m_layer2.displayImage.GetHeight() / imgRect.Height(); m_ptEnd = m_ptStart; m_bSelecting = true; SetCapture(); } else if (m_selectionMode == SELECT_FREE_FORM) { m_bFreeFormSelecting = true; m_freeFormPoints.clear(); // 转换为图像坐标存储 CPoint imgPoint; imgPoint.x = (point.x - imgRect.left) * m_layer2.displayImage.GetWidth() / imgRect.Width(); imgPoint.y = (point.y - imgRect.top) * m_layer2.displayImage.GetHeight() / imgRect.Height(); m_freeFormPoints.push_back(imgPoint); SetCapture(); Invalidate(); } } } select = false; CDialogEx::OnLButtonDown(nFlags, point);
}
void CMyPS2Dlg::OnMouseMove(UINT nFlags, CPoint point)
{
#ifdef _DEBUG
if (m_nDebugCounter++ % 10 == 0) // 每10次移动输出一次
{
TRACE(_T(“鼠标位置: (%d, %d)\n”), point.x, point.y);
if (m_bDragging) {
TRACE(_T(“正在拖动克隆区域\n”));
}
else if (m_bSelecting) {
TRACE(_T(“正在选区操作\n”));
}
}
#endif
if (m_bDragging) {
ImageLayer& activeLayer = m_layer1.isSelected ? m_layer1 : m_layer2;
// 计算移动距离(转换为图像坐标) CRect imgRect = GetImageClientRect(activeLayer.image); double scaleX = (double)activeLayer.image.GetWidth() / imgRect.Width(); double scaleY = (double)activeLayer.image.GetHeight() / imgRect.Height(); int dx = static_cast<int>((point.x - m_ptDragStart.x) * scaleX); int dy = static_cast<int>((point.y - m_ptDragStart.y) * scaleY); // 更新克隆区域位置(限制在图像范围内) int newX = max(0, min(activeLayer.image.GetWidth() - activeLayer.clonedRegion.destRect.Width(), (int)m_ptCloneStart.x + dx)); int newY = max(0, min(activeLayer.image.GetHeight() - activeLayer.clonedRegion.destRect.Height(), (int)m_ptCloneStart.y + dy)); activeLayer.clonedRegion.destRect.MoveToXY(newX, newY); Invalidate(); // 刷新显示 return; } if (m_bDoodleMode && m_bDoodling) { CRect imgRect = GetImageClientRect(m_layer1.isSelected?m_layer1.image:m_layer2.image); if (imgRect.PtInRect(point)) { // 转换为图像坐标 CPoint imgPoint; imgPoint.x = (point.x - imgRect.left) * m_doodleTempImage.GetWidth() / imgRect.Width(); imgPoint.y = (point.y - imgRect.top) * m_doodleTempImage.GetHeight() / imgRect.Height(); // 绘制线段 DrawDoodleLine(m_ptDoodleStart, imgPoint); m_ptDoodleStart = imgPoint; // 刷新显示 Invalidate(FALSE); } return; } if (m_layer1.isSelected) { if (m_bSelecting && !m_layer1.displayImage.IsNull() && m_selectionMode == SELECT_RECTANGLE) { // 1. 获取图像显示区域 CRect imgRect = GetImageClientRect(m_layer1.image); // 2. 约束鼠标在图像范围内 point.x = max(imgRect.left, min(imgRect.right, point.x)); point.y = max(imgRect.top, min(imgRect.bottom, point.y)); // 3. 保存旧选区用于刷新 CRect oldSelRect = ConvertToScreenRect(m_rcSelection); // 4. 转换为图像坐标并更新选区 m_ptEnd.x = (point.x - imgRect.left) * m_layer1.displayImage.GetWidth() / imgRect.Width(); m_ptEnd.y = (point.y - imgRect.top) * m_layer1.displayImage.GetHeight() / imgRect.Height(); m_rcSelection = CRect( min(m_ptStart.x, m_ptEnd.x), min(m_ptStart.y, m_ptEnd.y), max(m_ptStart.x, m_ptEnd.x), max(m_ptStart.y, m_ptEnd.y) ); // 5. 计算需要刷新的区域(新旧选区合并) CRect newSelRect = ConvertToScreenRect(m_rcSelection); CRect invalidRect = oldSelRect | newSelRect; invalidRect.InflateRect(2, 2); // 扩大2像素避免残影 // 6. 使用临时DC绘制动态选区 CClientDC dc(this); CPen pen(PS_DOT, 1, RGB(255, 0, 0)); CPen* pOldPen = dc.SelectObject(&pen); dc.SelectStockObject(NULL_BRUSH); int oldROP = dc.SetROP2(R2_XORPEN); dc.Rectangle(newSelRect); // 使用已定义的 newSelRect dc.SetROP2(oldROP); dc.SelectObject(pOldPen); pen.DeleteObject(); // 6. 精准刷新 RedrawWindow(invalidRect, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_NOERASE); } else if (m_bFreeFormSelecting && !m_layer1.displayImage.IsNull()) { CRect imgRect = GetImageClientRect(m_layer1.image); if (imgRect.PtInRect(point)) { // 转换为图像坐标 CPoint imgPoint; imgPoint.x = (point.x - imgRect.left) * m_layer1.displayImage.GetWidth() / imgRect.Width(); imgPoint.y = (point.y - imgRect.top) * m_layer1.displayImage.GetHeight() / imgRect.Height(); // 检查是否闭合(当前点接近起始点) if (m_freeFormPoints.size() > 10) // 至少10个点才开始检测闭合 { const CPoint& firstPoint = m_freeFormPoints[0]; double distance = sqrt(pow(imgPoint.x - firstPoint.x, 2) + pow(imgPoint.y - firstPoint.y, 2)); // 如果距离小于10像素认为闭合 if (distance < 10.0) { // 自动闭合路径 m_freeFormPoints.push_back(firstPoint); // 创建多边形区域 if (m_rgnFreeForm.GetSafeHandle()) m_rgnFreeForm.DeleteObject(); m_rgnFreeForm.CreatePolygonRgn( m_freeFormPoints.data(), (int)m_freeFormPoints.size(), ALTERNATE); m_bFreeFormSelecting = false; ReleaseCapture(); Invalidate(); return; } } // 避免重复添加相近点 if (m_freeFormPoints.empty() || abs(imgPoint.x - m_freeFormPoints.back().x) > 2 || abs(imgPoint.y - m_freeFormPoints.back().y) > 2) { m_freeFormPoints.push_back(imgPoint); // 计算需要刷新的区域 CRect invalidRect; if (m_freeFormPoints.size() > 1) { CPoint prevScreen = ConvertToScreenPoint(m_freeFormPoints[m_freeFormPoints.size() - 2]); CPoint currScreen = ConvertToScreenPoint(imgPoint); invalidRect.SetRect( min(prevScreen.x, currScreen.x) - 2, min(prevScreen.y, currScreen.y) - 2, max(prevScreen.x, currScreen.x) + 2, max(prevScreen.y, currScreen.y) + 2 ); } // 智能刷新 if (m_freeFormPoints.size() <= 2) { InvalidateRect(imgRect); } else if (!invalidRect.IsRectEmpty()) { RedrawWindow(invalidRect, NULL, RDW_INVALIDATE | RDW_UPDATENOW); } } } } } else { if (m_bSelecting && !m_layer2.displayImage.IsNull() && m_selectionMode == SELECT_RECTANGLE) { // 1. 获取图像显示区域 CRect imgRect = GetImageClientRect(m_layer2.image); // 2. 约束鼠标在图像范围内 point.x = max(imgRect.left, min(imgRect.right, point.x)); point.y = max(imgRect.top, min(imgRect.bottom, point.y)); // 3. 保存旧选区用于刷新 CRect oldSelRect = ConvertToScreenRect(m_rcSelection); // 4. 转换为图像坐标并更新选区 m_ptEnd.x = (point.x - imgRect.left) * m_layer2.displayImage.GetWidth() / imgRect.Width(); m_ptEnd.y = (point.y - imgRect.top) * m_layer2.displayImage.GetHeight() / imgRect.Height(); m_rcSelection = CRect( min(m_ptStart.x, m_ptEnd.x), min(m_ptStart.y, m_ptEnd.y), max(m_ptStart.x, m_ptEnd.x), max(m_ptStart.y, m_ptEnd.y) ); // 5. 计算需要刷新的区域(新旧选区合并) CRect newSelRect = ConvertToScreenRect(m_rcSelection); CRect invalidRect = oldSelRect | newSelRect; invalidRect.InflateRect(2, 2); // 扩大2像素避免残影 // 6. 使用临时DC绘制动态选区 CClientDC dc(this); CPen pen(PS_DOT, 1, RGB(255, 0, 0)); CPen* pOldPen = dc.SelectObject(&pen); dc.SelectStockObject(NULL_BRUSH); int oldROP = dc.SetROP2(R2_XORPEN); dc.Rectangle(newSelRect); // 使用已定义的 newSelRect dc.SetROP2(oldROP); dc.SelectObject(pOldPen); pen.DeleteObject(); // 6. 精准刷新 RedrawWindow(invalidRect, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_NOERASE); } else if (m_bFreeFormSelecting && !m_layer2.displayImage.IsNull()) { CRect imgRect = GetImageClientRect(m_layer2.image); if (imgRect.PtInRect(point)) { // 转换为图像坐标 CPoint imgPoint; imgPoint.x = (point.x - imgRect.left) * m_layer2.displayImage.GetWidth() / imgRect.Width(); imgPoint.y = (point.y - imgRect.top) * m_layer2.displayImage.GetHeight() / imgRect.Height(); // 检查是否闭合(当前点接近起始点) if (m_freeFormPoints.size() > 10) // 至少10个点才开始检测闭合 { const CPoint& firstPoint = m_freeFormPoints[0]; double distance = sqrt(pow(imgPoint.x - firstPoint.x, 2) + pow(imgPoint.y - firstPoint.y, 2)); // 如果距离小于10像素认为闭合 if (distance < 10.0) { // 自动闭合路径 m_freeFormPoints.push_back(firstPoint); // 创建多边形区域 if (m_rgnFreeForm.GetSafeHandle()) m_rgnFreeForm.DeleteObject(); m_rgnFreeForm.CreatePolygonRgn( m_freeFormPoints.data(), (int)m_freeFormPoints.size(), ALTERNATE); m_bFreeFormSelecting = false; ReleaseCapture(); Invalidate(); return; } } // 避免重复添加相近点 if (m_freeFormPoints.empty() || abs(imgPoint.x - m_freeFormPoints.back().x) > 2 || abs(imgPoint.y - m_freeFormPoints.back().y) > 2) { m_freeFormPoints.push_back(imgPoint); // 计算需要刷新的区域 CRect invalidRect; if (m_freeFormPoints.size() > 1) { CPoint prevScreen = ConvertToScreenPoint(m_freeFormPoints[m_freeFormPoints.size() - 2]); CPoint currScreen = ConvertToScreenPoint(imgPoint); invalidRect.SetRect( min(prevScreen.x, currScreen.x) - 2, min(prevScreen.y, currScreen.y) - 2, max(prevScreen.x, currScreen.x) + 2, max(prevScreen.y, currScreen.y) + 2 ); } // 智能刷新 if (m_freeFormPoints.size() <= 2) { InvalidateRect(imgRect); } else if (!invalidRect.IsRectEmpty()) { RedrawWindow(invalidRect, NULL, RDW_INVALIDATE | RDW_UPDATENOW); } } } } } __super::OnMouseMove(nFlags, point);
}
void CMyPS2Dlg::OnLButtonUp(UINT nFlags, CPoint point)
{
if (m_bDragging) {
m_bDragging = false;
ReleaseCapture();
return; // 不处理其他逻辑
}
if (m_bDoodleMode && m_bDoodling)
{
m_bDoodling = false;
return;
}
if (m_layer1.isSelected) {
if (m_bSelecting || m_bFreeFormSelecting)
{
if (m_selectionMode == SELECT_RECTANGLE) {
// 原有矩形选区结束代码
m_bSelecting = false;
}
else if (m_bFreeFormSelecting && m_selectionMode == SELECT_FREE_FORM)
{
CRect imgRect = GetImageClientRect(m_layer1.image);
if (imgRect.PtInRect(point))
{
// 转换为图像坐标
CPoint imgPoint;
imgPoint.x = (point.x - imgRect.left) * m_layer1.displayImage.GetWidth() / imgRect.Width();
imgPoint.y = (point.y - imgRect.top) * m_layer1.displayImage.GetHeight() / imgRect.Height();
// 确保至少3个点才闭合 if (m_freeFormPoints.size() > 2) { // 闭合路径:添加第一个点作为终点 m_freeFormPoints.push_back(m_freeFormPoints[0]); // 删除旧区域(如果存在) if (m_rgnFreeForm.GetSafeHandle()) m_rgnFreeForm.DeleteObject(); // 创建多边形区域 m_rgnFreeForm.CreatePolygonRgn( m_freeFormPoints.data(), (int)m_freeFormPoints.size(), ALTERNATE); TRACE(_T("创建多边形选区,点数: %d\n"), m_freeFormPoints.size()); } else { // 点数不足,清除选区 m_freeFormPoints.clear(); } } m_bFreeFormSelecting = false; } select = true; ReleaseCapture(); Invalidate(); } } else { if (m_bSelecting || m_bFreeFormSelecting) { if (m_selectionMode == SELECT_RECTANGLE) { // 原有矩形选区结束代码 m_bSelecting = false; select = true; } else if (m_bFreeFormSelecting && m_selectionMode == SELECT_FREE_FORM) { CRect imgRect = GetImageClientRect(m_layer2.image); if (imgRect.PtInRect(point)) { // 转换为图像坐标 CPoint imgPoint; imgPoint.x = (point.x - imgRect.left) * m_layer2.displayImage.GetWidth() / imgRect.Width(); imgPoint.y = (point.y - imgRect.top) * m_layer2.displayImage.GetHeight() / imgRect.Height(); // 确保至少3个点才闭合 if (m_freeFormPoints.size() > 2) { // 闭合路径:添加第一个点作为终点 m_freeFormPoints.push_back(m_freeFormPoints[0]); // 删除旧区域(如果存在) if (m_rgnFreeForm.GetSafeHandle()) m_rgnFreeForm.DeleteObject(); // 创建多边形区域 m_rgnFreeForm.CreatePolygonRgn( m_freeFormPoints.data(), (int)m_freeFormPoints.size(), ALTERNATE); TRACE(_T("创建多边形选区,点数: %d\n"), m_freeFormPoints.size()); } else { // 点数不足,清除选区 m_freeFormPoints.clear(); } } m_bFreeFormSelecting = false; select = true; } ReleaseCapture(); Invalidate(); } } CDialogEx::OnLButtonUp(nFlags, point);
}
void CMyPS2Dlg::ApplyAdvancedEffectsToSelection(int brightness, float saturation,
bool bBlackWhite, bool bSepia, int mosaicSize, ImageLayer& layer)
{
if (layer.image.IsNull())
return;
// 1. 准备选区数据 CRect validRect; bool hasSelection = false; if (m_selectionMode == SELECT_RECTANGLE && !m_rcSelection.IsRectNull()) { // 矩形选区 validRect.SetRect( max(0, (int)m_rcSelection.left), max(0, (int)m_rcSelection.top), min(layer.image.GetWidth(), (int)m_rcSelection.right), min(layer.image.GetHeight(), (int)m_rcSelection.bottom) ); hasSelection = true; } else if (m_selectionMode == SELECT_FREE_FORM && m_rgnFreeForm.GetSafeHandle()) { // 不规则选区 m_rgnFreeForm.GetRgnBox(&validRect); hasSelection = true; } if (!hasSelection) return; // 2. 准备目标图像 if (layer.displayImage.GetBits() == nullptr || layer.displayImage.GetWidth() != layer.image.GetWidth() || layer.displayImage.GetHeight() != layer.image.GetHeight()) { layer.displayImage.Destroy(); layer.displayImage.Create(layer.image.GetWidth(), layer.image.GetHeight(), layer.image.GetBPP()); } // 3. 获取像素数据 BYTE* pDest = (BYTE*)layer.displayImage.GetBits(); BYTE* pSrc = (BYTE*)layer.image.GetBits(); int destPitch = layer.displayImage.GetPitch(); int srcPitch = layer.image.GetPitch(); int channels = (layer.displayImage.GetBPP() == 32) ? 4 : 3; // 4. 处理选区像素(包含马赛克效果)
#pragma omp parallel for
for (int y = validRect.top; y < validRect.bottom; y++)
{
BYTE* pDestRow = pDest + y * destPitch;
BYTE* pSrcRow = pSrc + y * srcPitch;
for (int x = validRect.left; x < validRect.right; x++) { // 检查是否在选区内(不规则选区需要额外检查) bool inSelection = true; if (m_selectionMode == SELECT_FREE_FORM) { inSelection = m_rgnFreeForm.PtInRegion(x, y); } if (inSelection) { BYTE* pDestPixel = &pDest[y * destPitch + x * channels]; // 计算马赛克块的平均颜色(直接从原图获取) if (mosaicSize > 1) { int blockStartX = (x / mosaicSize) * mosaicSize; int blockStartY = (y / mosaicSize) * mosaicSize; int blockEndX = min(blockStartX + mosaicSize, (int)validRect.right); int blockEndY = min(blockStartY + mosaicSize, (int)validRect.bottom); long sumR = 0, sumG = 0, sumB = 0; int count = 0; for (int by = blockStartY; by < blockEndY; by++) { for (int bx = blockStartX; bx < blockEndX; bx++) { // 不规则选区需要检查马赛克块内每个点 if (m_selectionMode != SELECT_FREE_FORM || m_rgnFreeForm.PtInRegion(bx, by)) { BYTE* pSrcPixel = &pSrc[by * srcPitch + bx * channels]; sumB += pSrcPixel[0]; sumG += pSrcPixel[1]; sumR += pSrcPixel[2]; count++; } } } if (count > 0) { BYTE avgR = sumR / count; BYTE avgG = sumG / count; BYTE avgB = sumB / count; // 使用ProcessSinglePixel处理(基于马赛克平均颜色) BYTE mosaicPixel[3] = { avgB, avgG, avgR }; ProcessSinglePixel(pDestPixel, brightness, saturation, bBlackWhite, bSepia, mosaicPixel); } } else { // 无马赛克效果,直接使用原图像素 BYTE* pSrcPixel = &pSrc[y * srcPitch + x * channels]; ProcessSinglePixel(pDestPixel, brightness, saturation, bBlackWhite, bSepia, pSrcPixel); } } } } // 5. 刷新显示 RedrawSelectionArea(validRect); //if (!layer.displayImage.IsNull()) { // // 方法1:使用BitBlt复制(推荐) // layer.image.Destroy(); // 先销毁旧图像 // layer.image.Create(layer.displayImage.GetWidth(), // layer.displayImage.GetHeight(), // layer.displayImage.GetBPP()); // HDC hdcSrc = layer.displayImage.GetDC(); // HDC hdcDst = layer.image.GetDC(); // BitBlt(hdcDst, 0, 0, layer.displayImage.GetWidth(), layer.displayImage.GetHeight(), // hdcSrc, 0, 0, SRCCOPY); // layer.displayImage.ReleaseDC(); // layer.image.ReleaseDC(); //}
}
void CMyPS2Dlg::ProcessSinglePixel(BYTE* pPixel, int brightness, float saturation, bool bBlackWhite, bool bSepia, const BYTE* pOriginalPixel = nullptr) // 新增原始像素参数
{
// 默认使用当前像素作为原始值(兼容旧代码)
BYTE origB = pOriginalPixel ? pOriginalPixel[0] : pPixel[0];
BYTE origG = pOriginalPixel ? pOriginalPixel[1] : pPixel[1];
BYTE origR = pOriginalPixel ? pOriginalPixel[2] : pPixel[2];
// 亮度调整(基于原始值的非线性变换) // brightness=100 → 2.0倍 float r = min(255.0f, max(0.0f, (float)(origR + brightness))); float g = min(255.0f, max(0.0f, (float)(origG + brightness))); float b = min(255.0f, max(0.0f, (float)(origB + brightness))); // 饱和度调整(保持基于原始值) if (saturation != 1.0f) { float gray = 0.299f * origR + 0.587f * origG + 0.114f * origB; r = min(255.0f,max(0.0f,(float)(gray + saturation * (r - gray)))); g = min(255.0f, max(0.0f, (float)(gray + saturation * (g - gray)))); b = min(255.0f, max(0.0f, (float)(gray + saturation * (b - gray)))); } // 写入目标像素(限幅) pPixel[0] = static_cast<BYTE>(min(255, max(0, static_cast<int>(b)))); pPixel[1] = static_cast<BYTE>(min(255, max(0, static_cast<int>(g)))); pPixel[2] = static_cast<BYTE>(min(255, max(0, static_cast<int>(r)))); // 滤镜处理(互斥) if (bBlackWhite || bSepia) { BYTE gray = static_cast<BYTE>(0.299f * pPixel[2] + 0.587f * pPixel[1] + 0.114f * pPixel[0]); if (bBlackWhite) { pPixel[0] = pPixel[1] = pPixel[2] = gray; } else if (bSepia) { pPixel[2] = min(255, static_cast<int>(0.393 * pPixel[2] + 0.769 * pPixel[1] + 0.189 * pPixel[0])); pPixel[1] = min(255, static_cast<int>(0.349 * pPixel[2] + 0.686 * pPixel[1] + 0.168 * pPixel[0])); pPixel[0] = min(255, static_cast<int>(0.272 * pPixel[2] + 0.534 * pPixel[1] + 0.131 * pPixel[0])); } }
}
void CMyPS2Dlg::RedrawSelectionArea(const CRect& imageRect)
{
// 1. 检查输入有效性
if (imageRect.IsRectEmpty() ||( m_layer1.displayImage.IsNull()&&m_layer2.displayImage.IsNull()))
return;
// 2. 精确坐标转换 CRect screenRect = ConvertToScreenRect(imageRect); // 3. 验证屏幕区域有效性 CRect clientRect; GetClientRect(&clientRect); if (!screenRect.IntersectRect(screenRect, clientRect)) return; // 4. 动态调整扩大范围 int inflate = max(2, min(10, screenRect.Width() / 20)); screenRect.InflateRect(inflate, inflate); // 5. 安全刷新 if (!screenRect.IsRectEmpty()) { RedrawWindow(screenRect, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_NOERASE | RDW_NOCHILDREN); }
}
// 将图像坐标系中的矩形转换为屏幕客户区坐标
CRect CMyPS2Dlg::ConvertToScreenRect(const CRect& imageRect)
{
if (m_layer1.isSelected) {
if (m_layer1.displayImage.IsNull())
return CRect(0, 0, 0, 0);
CRect imgClientRect = GetImageClientRect(m_layer1.image); return CRect( imgClientRect.left + imageRect.left * imgClientRect.Width() / m_layer1.displayImage.GetWidth(), imgClientRect.top + imageRect.top * imgClientRect.Height() / m_layer1.displayImage.GetHeight(), imgClientRect.left + imageRect.right * imgClientRect.Width() / m_layer1.displayImage.GetWidth(), imgClientRect.top + imageRect.bottom * imgClientRect.Height() / m_layer1.displayImage.GetHeight() ); } else { if (m_layer2.displayImage.IsNull()) return CRect(0, 0, 0, 0); CRect imgClientRect = GetImageClientRect(m_layer2.image); return CRect( imgClientRect.left + imageRect.left * imgClientRect.Width() / m_layer2.displayImage.GetWidth(), imgClientRect.top + imageRect.top * imgClientRect.Height() / m_layer2.displayImage.GetHeight(), imgClientRect.left + imageRect.right * imgClientRect.Width() / m_layer2.displayImage.GetWidth(), imgClientRect.top + imageRect.bottom * imgClientRect.Height() / m_layer2.displayImage.GetHeight() ); }
}
BOOL CMyPS2Dlg::OnEraseBkgnd(CDC* pDC)
{
return TRUE; // 完全禁用背景擦除
}
// 获取位图实际尺寸的辅助函数
CSize CMyPS2Dlg::GetBitmapDimension(CBitmap& bitmap)
{
BITMAP bm;
if (bitmap.GetSafeHandle() && bitmap.GetBitmap(&bm))
return CSize(bm.bmWidth, bm.bmHeight);
return CSize(0, 0);
}
//规则选区
void CMyPS2Dlg::OnBnClickedButton9()
{
m_selectionMode = SELECT_RECTANGLE;
ResetSelection(); // 重置选区状态
// TODO: 在此添加控件通知处理程序代码
}
//不规则选区
void CMyPS2Dlg::OnBnClickedButton10()
{
m_selectionMode = SELECT_FREE_FORM;
ResetSelection();
// 添加调试输出 TRACE(_T("不规则选区模式已激活\n")); // 强制重绘以确保状态更新 Invalidate(); // TODO: 在此添加控件通知处理程序代码
}
//添加图层
void CMyPS2Dlg::OnBnClickedButton11()
{
if (!m_layer2.image.IsNull()) {
UINT i;
i = MessageBox(_T(“确认重新打开图片吗?”), _T(“提示”), MB_YESNO | MB_ICONQUESTION);
if (i != IDYES)
{
return;
}
}
CFileDialog dlg(TRUE, _T(“.bmp;.jpg;.png"), NULL, OFN_FILEMUSTEXIST,
_T("Image Files|.bmp;.jpg;.png||”), this);
if (dlg.DoModal() == IDOK) { // 释放旧资源 m_layer2.history.clear(); m_layer2.currentHistoryIndex = -1; m_layer1.isSelected = false; m_layer2.isSelected = true; if (!m_layer2.image.IsNull()) { m_layer2.image.Destroy(); } if (!m_layer2.displayImage.IsNull()) { m_layer2.displayImage.Destroy(); } if (m_layer2.image.Load(dlg.GetPathName()) != S_OK) { AfxMessageBox(L"图像加载失败!\n请检查格式支持(BMP/JPG/PNG)"); return; } else { // 加载新图像 ImageState initialState; initialState.brightness = 0; initialState.saturation = 1.0f; initialState.mosaic = 1; initialState.alpha = 0.5f; if (!m_layer2.image.IsNull()) { if (!initialState.image.IsNull()) { initialState.image.Destroy(); } initialState.image.Create(m_layer2.image.GetWidth(), m_layer2.image.GetHeight(), m_layer2.image.GetBPP()); CDC* pSrcDC = CDC::FromHandle(m_layer2.image.GetDC()); CDC* pDstDC = CDC::FromHandle(initialState.image.GetDC()); pDstDC->BitBlt(0, 0, m_layer2.image.GetWidth(), m_layer2.image.GetHeight(), pSrcDC, 0, 0, SRCCOPY); m_layer2.image.ReleaseDC(); initialState.image.ReleaseDC(); } m_layer2.history.push_back(initialState); m_layer2.history.push_back(initialState); m_layer2.currentHistoryIndex = 1; // 重置所有参数 m_nlightValue = 0; m_nsatureValue = 1.0f; m_nmskValue = 1; m_layer1.alpha = 1.0f; // 重置底层透明度为不透明 m_layer2.alpha = 0.5f; // 重置顶层透明度为半透明 // 初始化UI控件 litslider.SetPos(100); // 假设滑块范围0-200,100对应亮度0 saturslider.SetPos(100); // 假设滑块范围0-200,100对应饱和度1.0 mskslider.SetPos(1); // 马赛克块大小(1~20) m_sliderLay1.SetPos(100); // 新增:底层透明度滑块(0-100) m_sliderLay2.SetPos(50); // 新增:顶层透明度滑块(0-100) // 生成显示图像 UpdateDisplayImage(m_layer2); } } // TODO: 在此添加控件通知处理程序代码
}
void CMyPS2Dlg::OnNMCustomdrawSliderl1(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMCUSTOMDRAW pNMCD = reinterpret_cast(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
*pResult = 0;
}
void CMyPS2Dlg::ResetSelection()
{
m_bSelecting = false;
m_bFreeFormSelecting = false;
m_rcSelection.SetRectEmpty();
// 清理不规则选区资源 if (m_rgnFreeForm.GetSafeHandle()) { m_rgnFreeForm.DeleteObject(); } m_freeFormPoints.clear(); Invalidate();
}
BOOL CMyPS2Dlg::HasSelection() const
{
if (m_selectionMode == SELECT_RECTANGLE) {
return !m_rcSelection.IsRectNull();
}
else {
return m_rgnFreeForm.GetSafeHandle() != NULL;
}
}
void CMyPS2Dlg::CleanUpResources()
{
// 清理双缓冲资源
if (m_memDC.GetSafeHdc()) {
m_memDC.SelectObject((HBITMAP)NULL);
m_memDC.DeleteDC();
}
if (m_memBitmap.GetSafeHandle()) {
m_memBitmap.DeleteObject();
}
// 清理其他GDI资源 if (m_rgnFreeForm.GetSafeHandle()) { m_rgnFreeForm.DeleteObject(); }
}
CPoint CMyPS2Dlg::ConvertToScreenPoint(CPoint imagePoint)
{
if (m_layer1.isSelected) {
CRect imgRect = GetImageClientRect(m_layer1.image);
return CPoint(
imgRect.left + imagePoint.x * imgRect.Width() / m_layer1.displayImage.GetWidth(),
imgRect.top + imagePoint.y * imgRect.Height() / m_layer1.displayImage.GetHeight()
);
}
else {
CRect imgRect = GetImageClientRect(m_layer2.image);
return CPoint(
imgRect.left + imagePoint.x * imgRect.Width() / m_layer2.displayImage.GetWidth(),
imgRect.top + imagePoint.y * imgRect.Height() / m_layer2.displayImage.GetHeight()
);
}
}
void CMyPS2Dlg::SelectLayer(bool selectLayer1) {
m_layer1.isSelected = selectLayer1;
m_layer2.isSelected = !selectLayer1;
// 更新滑块显示当前图层的透明度 if (selectLayer1) { m_sliderLay1.SetPos(static_cast<int>(m_layer1.alpha * 100.0f)); } else { m_sliderLay2.SetPos(static_cast<int>(m_layer2.alpha * 100.0f)); } Invalidate(); // 刷新显示
}
//选择图层
void CMyPS2Dlg::OnBnClickedButton12()
{
SelectLayer(!m_layer1.isSelected);
if (m_layer1.isSelected) {
if (m_layer1.displayImage.IsNull()) {
AfxMessageBox(_T(“请先打开图片”));
}
else {
AfxMessageBox(_T(“已选 图层1”));
}
}
else {
if (m_layer2.displayImage.IsNull()) {
AfxMessageBox(_T(“请先打开图片”));
}
else {
AfxMessageBox(_T(“已选 图层2”));
}
}
// TODO: 在此添加控件通知处理程序代码
}
//开始涂鸦
void CMyPS2Dlg::OnBnClickedButton13()
{
StartDoodleMode();
// TODO: 在此添加控件通知处理程序代码
}
//应用涂鸦
void CMyPS2Dlg::OnBnClickedButton14()
{
EndDoodleMode(true);
// TODO: 在此添加控件通知处理程序代码
}
//取消涂鸦
void CMyPS2Dlg::OnBnClickedButton15()
{
EndDoodleMode(false);
// TODO: 在此添加控件通知处理程序代码
}
//颜色滑块
void CMyPS2Dlg::OnNMCustomdrawSlidercol(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMCUSTOMDRAW pNMCD = reinterpret_cast(pNMHDR);
CSliderCtrl* pSlider = (CSliderCtrl*)GetDlgItem(IDC_SLIDERCOL);
if (pSlider)
{
int pos = pSlider->GetPos();
// 将滑块位置转换为颜色 (0-360度色相)
m_doodleColor = HSLtoRGB(pos, 1.0, 0.5);
}
*pResult = 0;
}
// HSL转RGB辅助函数
COLORREF CMyPS2Dlg::HSLtoRGB(float H, float S, float L)
{
float C = (1 - fabs(2 * L - 1)) * S;
float X = C * (1 - fabs(fmod(H / 60.0, 2) - 1));
float m = L - C / 2;
float R, G, B; if (H >= 0 && H < 60) { R = C; G = X; B = 0; } else if (H >= 60 && H < 120) { R = X; G = C; B = 0; } else if (H >= 120 && H < 180) { R = 0; G = C; B = X; } else if (H >= 180 && H < 240) { R = 0; G = X; B = C; } else if (H >= 240 && H < 300) { R = X; G = 0; B = C; } else { R = C; G = 0; B = X; } BYTE r = (BYTE)((R + m) * 255); BYTE g = (BYTE)((G + m) * 255); BYTE b = (BYTE)((B + m) * 255); return RGB(r, g, b);
}
//粗细滑块
void CMyPS2Dlg::OnNMCustomdrawSliderthi(NMHDR* pNMHDR, LRESULT* pResult)
{
LPNMCUSTOMDRAW pNMCD = reinterpret_cast(pNMHDR);
CSliderCtrl* pSlider = (CSliderCtrl*)GetDlgItem(IDC_SLIDERTHI);
if (pSlider)
{
m_doodleThickness = pSlider->GetPos();
}
*pResult = 0;
}
void CMyPS2Dlg::StartDoodleMode()
{
ImageLayer& activeLayer = m_layer1.isSelected ? m_layer1 : m_layer2;
if (activeLayer.displayImage.IsNull())
{
AfxMessageBox(_T(“请先打开图片”));
return;
}
// 创建临时位图 if (!m_doodleTempImage.IsNull()) m_doodleTempImage.Destroy(); int width = activeLayer.displayImage.GetWidth(); int height = activeLayer.displayImage.GetHeight(); m_doodleTempImage.Create(width, height, activeLayer.displayImage.GetBPP()); // 复制当前显示图像到临时位图 CDC* pSrcDC = CDC::FromHandle(activeLayer.displayImage.GetDC()); CDC* pDstDC = CDC::FromHandle(m_doodleTempImage.GetDC()); pDstDC->BitBlt(0, 0, width, height, pSrcDC, 0, 0, SRCCOPY); activeLayer.displayImage.ReleaseDC(); m_doodleTempImage.ReleaseDC(); // 重置涂鸦数据 m_doodleLines.clear(); m_bDoodleMode = true; m_bDoodling = false; // 设置鼠标光标 SetCursor(LoadCursor(NULL, IDC_CROSS));
}
// 结束涂鸦模式
void CMyPS2Dlg::EndDoodleMode(bool apply)
{
if (!m_bDoodleMode) return;
if (apply) { ApplyDoodleToImage(); } // 清理资源 m_doodleTempImage.Destroy(); m_doodleLines.clear(); m_bDoodleMode = false; m_bDoodling = false; // 恢复鼠标光标 SetCursor(LoadCursor(NULL, IDC_ARROW)); // 刷新显示 Invalidate(FALSE);
}
// 将涂鸦应用到当前图层(有改)
void CMyPS2Dlg::ApplyDoodleToImage()
{
ImageLayer* activeLayer = m_layer1.isSelected ? &m_layer1 : &m_layer2;
if (activeLayer->image.IsNull()) return;
// 获取设备上下文 CDC* pDC = CDC::FromHandle(activeLayer->image.GetDC()); CPen pen(PS_SOLID, m_doodleThickness, m_doodleColor); CPen* pOldPen = pDC->SelectObject(&pen); // 绘制所有涂鸦线段 for (const auto& line : m_doodleLines) { pDC->MoveTo(line.first); pDC->LineTo(line.second); } pDC->SelectObject(pOldPen); activeLayer->image.ReleaseDC(); doodend = true; m_bStateDirty = true; // 更新显示图像并保存状态 UpdateDisplayImage(*activeLayer); SaveCurrentState(*activeLayer);
}
// 绘制一条涂鸦线段
void CMyPS2Dlg::DrawDoodleLine(CPoint start, CPoint end)
{
if (m_doodleTempImage.IsNull()) return;
CDC* pDC = CDC::FromHandle(m_doodleTempImage.GetDC()); CPen pen(PS_SOLID, m_doodleThickness, m_doodleColor); CPen* pOldPen = pDC->SelectObject(&pen); pDC->MoveTo(start); pDC->LineTo(end); pDC->SelectObject(pOldPen); m_doodleTempImage.ReleaseDC(); // 将线段添加到列表 m_doodleLines.push_back(std::make_pair(start, end));
}
//复制选区
void CMyPS2Dlg::OnBnClickedButton16()
{
ImageLayer& activelayer = m_layer1.isSelected ? m_layer1 : m_layer2;
if (!HasSelection()) {
AfxMessageBox(_T(“请先创建选区”));
return;
}
if (!activelayer.clonedRegion.active) {
// 首次复制:创建克隆区域
CRect selRect = GetSelectionRect();
activelayer.clonedRegion.sourceRect = selRect;
activelayer.clonedRegion.destRect = selRect;
activelayer.clonedRegion.active = true;
activelayer.clonedRegion.visible = true;
// 复制图像数据 - 从displayImage复制而不是image activelayer.clonedRegion.image.Destroy(); activelayer.clonedRegion.image.Create(selRect.Width(), selRect.Height(), activelayer.displayImage.GetBPP()); // 使用displayImage作为源 CDC* pSrcDC = CDC::FromHandle(activelayer.displayImage.GetDC()); CDC* pDstDC = CDC::FromHandle(activelayer.clonedRegion.image.GetDC()); pDstDC->BitBlt(0, 0, selRect.Width(), selRect.Height(), pSrcDC, selRect.left, selRect.top, SRCCOPY); activelayer.displayImage.ReleaseDC(); activelayer.clonedRegion.image.ReleaseDC(); TRACE(_T("创建克隆区域(带效果)\n")); TRACE(_T("选区位置: (%d, %d) - (%d, %d)\n"), selRect.left, selRect.top, selRect.right, selRect.bottom); } else { // 切换显示状态 activelayer.clonedRegion.visible = !activelayer.clonedRegion.visible; // 添加调试输出 TRACE(_T("切换克隆区域可见性: %s\n"), activelayer.clonedRegion.visible ? _T("可见") : _T("隐藏")); } Invalidate(); // 刷新显示 // 添加状态栏提示 /*CString msg; msg.Format(_T("克隆区域已%s"), activelayer.clonedRegion.visible ? _T("显示") : _T("隐藏")); GetDlgItem(IDC_STATIC)->SetWindowText(msg);*/ // 切换显示状态 //activeLayer.clonedRegion.visible = !activeLayer.clonedRegion.visible; //Invalidate(); // TODO: 在此添加控件通知处理程序代码
}
CRect CMyPS2Dlg::GetSelectionRect() {
if (m_selectionMode == SELECT_RECTANGLE && !m_rcSelection.IsRectNull()) {
return m_rcSelection;
}
else if (m_selectionMode == SELECT_FREE_FORM && m_rgnFreeForm.GetSafeHandle()) {
CRect rect;
m_rgnFreeForm.GetRgnBox(&rect);
return rect;
}
return CRect(0, 0, 0, 0); // 无选区
}为什么这段函数能实现在同一图层,出现多个统一类型的选区,且相互独立
最新发布