You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

波形图透明选择叠加正常,频谱图实现遇阻求可行API方案

我太懂这种糟心的情况了——波形图上的选择叠加层好好的,一到频谱图就直接拉胯,毕竟频谱图哪有什么统一背景色啊,原来的cmSrcAnd模式完全吃不住这种复杂背景。不用折腾逐像素操作的话,咱们可以试试这几个VCL/WINAPI的方案,既能兼容现有视图,还能完美搞定频谱图的问题:

解决方案1:用异或模式(pmXor)绘制选择区域

异或模式的优势在于完全不挑背景——不管下方是纯色波形还是色彩复杂的频谱图,绘制的选区都会和背景自动形成鲜明对比,而且绘制两次就能还原原图,动态调整选区时特别顺手。修改代码很简单:

void TWaveDisplayContainer::DrawSelectedRegion(){
 if(selRange.selStart.x == selRange.selEnd.x){
 DrawCursorPosition( selRange.selStart.x);
 return;
 }

 // 把绘制逻辑封装成lambda,避免重复代码
 auto DrawSelection = [&](TCanvas* pCanvas, Graphics::TBitmap* pBmp, const TRect& selRect){
 pCanvas->Draw(0,0, pBmp);
 // 保存原有画布状态,用完要恢复
 auto oldPenMode = pCanvas->Pen->Mode;
 auto oldBrushStyle = pCanvas->Brush->Style;
 auto oldBrushColor = pCanvas->Brush->Color;

 // 设置异或模式
 pCanvas->Pen->Mode = pmXor;
 pCanvas->Brush->Color = clActiveBorder;
 // 想要边框就用bsClear,想要填充选区就用bsSolid
 pCanvas->Brush->Style = bsSolid;
 pCanvas->Rectangle(selRect);

 // 恢复原有状态
 pCanvas->Pen->Mode = oldPenMode;
 pCanvas->Brush->Style = oldBrushStyle;
 pCanvas->Brush->Color = oldBrushColor;
 };

 TRect selRect(selRange.selStart.x, 0, selRange.selEnd.x, pWaveLeft->Height);
 Graphics::TBitmap *pWaveBmp = eContainerView == WAVEFORM ? pWaveBmpLeft : pSfftBmpLeft;
 DrawSelection(pWaveLeft->Canvas, pWaveBmp, selRect);

 if(numChannels == 2){
 Graphics::TBitmap *pWaveBmpRight = eContainerView == WAVEFORM ? pWaveBmpRight : pSfftBmpRight;
 DrawSelection(pWaveRight->Canvas, pWaveBmpRight, selRect);
 }
}
解决方案2:用AlphaBlend实现半透明叠加

如果想要更专业的视觉效果(比如像音频软件里常见的淡蓝色半透明选区),可以用WINAPI的AlphaBlend函数直接绘制带透明度的叠加层,这种方式对任何背景都友好,还能保留下方视图的细节:

#include <Windows.h> // 需要包含WINAPI头文件

void TWaveDisplayContainer::DrawSelectedRegion(){
 if(selRange.selStart.x == selRange.selEnd.x){
 DrawCursorPosition( selRange.selStart.x);
 return;
 }

 auto DrawTransparentSelection = [&](TCanvas* pCanvas, Graphics::TBitmap* pBmp, const TRect& selRect){
 pCanvas->Draw(0,0, pBmp);

 // 创建临时Bitmap用来绘制半透明区域(必须是32位格式支持Alpha通道)
 Graphics::TBitmap* tempBmp = new Graphics::TBitmap();
 tempBmp->Width = selRect.Width();
 tempBmp->Height = selRect.Height();
 tempBmp->PixelFormat = pf32bit;

 // 填充选区颜色,再设置Alpha通道实现半透明
 tempBmp->Canvas->Brush->Color = clActiveBorder;
 tempBmp->Canvas->FillRect(Rect(0,0,tempBmp->Width,tempBmp->Height));
 for(int y=0; y<tempBmp->Height; y++){
 DWORD* pRow = (DWORD*)tempBmp->ScanLine[y];
 for(int x=0; x<tempBmp->Width; x++){
 // 把Alpha位设为128(半透明,范围0-255,数值越小越透明)
 pRow[x] = pRow[x] | 0x80000000;
 }
 }

 // 配置Alpha混合参数
 BLENDFUNCTION blend = {0};
 blend.BlendOp = AC_SRC_OVER;
 blend.SourceConstantAlpha = 128; // 全局透明度,和像素Alpha叠加
 blend.AlphaFormat = AC_SRC_ALPHA;

 // 绘制半透明选区到目标画布
 AlphaBlend(pCanvas->Handle, selRect.Left, selRect.Top, selRect.Width(), selRect.Height(),
 tempBmp->Canvas->Handle, 0, 0, tempBmp->Width(), tempBmp->Height(), blend);

 delete tempBmp;
 };

 TRect selRect(selRange.selStart.x, 0, selRange.selEnd.x, pWaveLeft->Height);
 Graphics::TBitmap *pWaveBmp = eContainerView == WAVEFORM ? pWaveBmpLeft : pSfftBmpLeft;
 DrawTransparentSelection(pWaveLeft->Canvas, pWaveBmp, selRect);

 if(numChannels == 2){
 Graphics::TBitmap *pWaveBmpRight = eContainerView == WAVEFORM ? pWaveBmpRight : pSfftBmpRight;
 DrawTransparentSelection(pWaveRight->Canvas, pWaveBmpRight, selRect);
 }
}
方案3:视图适配策略(兼容原有逻辑)

如果不想改动波形图的原有绘制效果,可以针对不同视图做分支处理——波形图用老方法,频谱图用新方案,以后扩展其他视图也能直接加对应的绘制逻辑:

void TWaveDisplayContainer::DrawSelectedRegion(){
 if(selRange.selStart.x == selRange.selEnd.x){
 DrawCursorPosition( selRange.selStart.x);
 return;
 }

 // 波形图原有绘制逻辑
 auto DrawWaveformSelection = [&](TCanvas* pCanvas, Graphics::TBitmap* pBmp, const TRect& selRect){
 int copyMode = pCanvas->CopyMode;
 pCanvas->Draw(0,0, pBmp);
 pCanvas->Brush->Color = clActiveBorder;
 pCanvas->CopyMode = cmSrcAnd;
 pCanvas->Rectangle(selRect);
 pCanvas->CopyRect(selRect, pBmp->Canvas, selRect);
 pCanvas->CopyMode = copyMode;
 };

 // 频谱图专用绘制逻辑(这里用异或模式,也可以换成AlphaBlend)
 auto DrawSpectrogramSelection = [&](TCanvas* pCanvas, Graphics::TBitmap* pBmp, const TRect& selRect){
 pCanvas->Draw(0,0, pBmp);
 auto oldPenMode = pCanvas->Pen->Mode;
 auto oldBrushStyle = pCanvas->Brush->Style;
 pCanvas->Pen->Mode = pmXor;
 pCanvas->Brush->Color = clActiveBorder;
 pCanvas->Brush->Style = bsSolid;
 pCanvas->Rectangle(selRect);
 pCanvas->Pen->Mode = oldPenMode;
 pCanvas->Brush->Style = oldBrushStyle;
 };

 TRect selRect(selRange.selStart.x, 0, selRange.selEnd.x, pWaveLeft->Height);
 Graphics::TBitmap *pWaveBmp = eContainerView == WAVEFORM ? pWaveBmpLeft : pSfftBmpLeft;

 // 根据视图类型选择绘制逻辑
 if(eContainerView == WAVEFORM){
 DrawWaveformSelection(pWaveLeft->Canvas, pWaveBmp, selRect);
 } else {
 DrawSpectrogramSelection(pWaveLeft->Canvas, pWaveBmp, selRect);
 }

 if(numChannels == 2){
 Graphics::TBitmap *pWaveBmpRight = eContainerView == WAVEFORM ? pWaveBmpRight : pSfftBmpRight;
 if(eContainerView == WAVEFORM){
 DrawWaveformSelection(pWaveRight->Canvas, pWaveBmpRight, selRect);
 } else {
 DrawSpectrogramSelection(pWaveRight->Canvas, pWaveBmpRight, selRect);
 }
 }
}

内容的提问来源于stack exchange,提问作者dsp_user

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:49:10