按:至此,软件的雏形基本形成,可以浏览图片,要求不高基本可用了。
多风格显示
多风格显示可以增加工具的娱乐性,人们看图像一方面是看图的内容,一方面也是从不同风格的显示过程中,得到一点轻松的感觉,这可可能很重要。否则,PPT也不用支持动画显示了。目前本软件已经可以支持十几种风格的显示。如图所示
UDRL 分别表示Up,Down,Righ 和Left, perspective 风格就是前文介绍的开关门的风格,如图示:
从上到下:
从左到右:
利用上一章的开关门代码,连续调用有关函数达到动画效果。
void CImgShape::showPerspectiveImage(CImage &src0, bool bOpenDoor, int times, float interval, CString dir, CWnd *ctrWnd, bool bFixdWHRatio=true)
{
int iTopL;
CImage dst;
CRect rect;
ctrWnd->GetClientRect(&rect);
if (bFixdWHRatio) {
getRectWithFixedAspectRatio(src0, rect);
}
CImage src;
GetStrechIMG(src0, src, rect.Width(), rect.Height());
CDC* pDC = ctrWnd->GetDC();
int H, W;
if (dir == "U" || dir == "D") {
W = src.GetWidth();
H = src.GetHeight();
}
else {
H = src.GetWidth();
W = src.GetHeight();
}
float maxRotateAngle;
int tanVal = 6;
maxRotateAngle = atan(tanVal);
float viewDistance = W / 2 * tanVal;//tan(maxRotateAngle)
float step = maxRotateAngle / times;
int ModeOld = SetStretchBltMode(pDC->m_hDC, COLORONCOLOR);//
// 连续调用perspectiveImage,将输出结果显示,得到动画效果。
for (int i = 0; i < times; i++) {
float rotateAngle = step * i;
if (!bOpenDoor) {
rotateAngle = step * (times - i - 1);
}
int th = cos(rotateAngle)*H;
int tw = sin(rotateAngle)*H;
iTopL = (viewDistance - tw) / viewDistance * W;
perspectiveImage(src, th, iTopL, dir, dst);
dst.Draw(pDC->m_hDC,
rect.left,
rect.top,
rect.Width(),
rect.Height());
Sleep(interval);
}
src.Draw(pDC->m_hDC,
rect.left,
rect.top,
rect.Width(),
rect.Height());
SetStretchBltMode(pDC->m_hDC, ModeOld);
ctrWnd->ReleaseDC(pDC);
}
其他效果,将逐步介绍。
显示速度的改善
使用发现,从硬盘load文件需要时间,对图像进行翻转操作也需要时间,这样在连续浏览时,有迟滞的现象,用起来比较卡。为了提高流畅性,采用了多线程技术和缓存技术和图片缩放技术。图片缩放是根据计算机屏幕的大小对原始图片进行缩放,虽然显示的是压缩或者放大的图片,但是这并不影响对图片视觉效果的影响。因为,视窗就那么大,人眼看不到视窗以外的东西。图像操作,针对视窗内的图片操作即可,这样可以大大提高处理速度。(为了编程的简单操作,本软件还是在后台对原始图片进行了操作,抓实际上对于较大图片而言,产生了问题,后面会单独介绍。)
为了简单操作,缓存只做了两个,即上一图片和下一个图片的缓存,经过简单测试,显示速度基本可以接受。
线程有四个
读取buffer主线程,读取前后两个图片的线程和旋转线程。
读缓存线程启动后,等候主线程发送指令是否启动读取图片,并启动旋转线程,判断是否对图片进行旋转。
代码如下:
UINT CseePictureDlg::readBufferThread()
{
while (!g_bStopThread)
{
if(g_beginReadBuffer) {
g_originalImg0Mutex.Lock();
if (g_bCopyNext) {
m_OriginalImg0.copyImg2(m_nextImg0, m_OriginalImg0);
m_OriginalImg0.setRotateDegree(m_nextImg0.getRotateDegree());
}
else {
m_OriginalImg0.copyImg2(m_prevImg0, m_OriginalImg0);
m_OriginalImg0.setRotateDegree(m_prevImg0.getRotateDegree());
}
g_originalImg0Mutex.Unlock();
g_beginRotate = true;
g_readBuffMutex.Lock();
std::thread thr1(&CseePictureDlg::readNextImageThread, this);
std::thread thr2(&CseePictureDlg::readPrevImageThread, this);
thr1.join();
thr2.join();
g_readBuffMutex.Unlock();
g_beginReadBuffer = false;
}
}
return 0;
}
其中copy2 是图片拷贝函数,图片0 和1,,0 是原始图像,可能很大,1 是根据显示区域大小对图像进行了裁剪,图像的处理和操作在没有进行放大和缩小操作时,都是针对图片1进行操作,这样可以提高速度。
读取下一张图片的线程
UINT CseePictureDlg::readNextImageThread()
{
if (m_ImgFilesVct.size() == 0)
return -1;
int pos;
string file;
CString imgFile;
CImage bufImg;
CMyImage myImg;
//1#read the next one
pos = m_Pos +1;
if (pos >= m_ImgFilesVct.size()) {
pos = 0;
}
file = m_ImgPath + "\\" + m_ImgFilesVct[pos].getName();
imgFile = file.c_str();
if (!m_nextImg0.IsNull()) {
m_nextImg0.Destroy();
}
m_nextImg0.Load(imgFile);
if (m_nextImg0.IsNull()) {
throw "Load image failed";
}
//myImg.GetStrechIMG(m_nextImg0, m_nextImg1, m_ImgRect.Width(), m_ImgRect.Height());
getSuitableImage(m_nextImg0, m_nextImg1, m_ImgRect);
if (m_autoUpWard) {
CImage tmpImg;
CExif exif;
exif.setImage(imgFile);
int degree;
degree = exif.getRotateAngle();
if (degree != 0) {
CMsApiRotate rtt;
rtt.filter(m_nextImg1, degree,tmpImg );
myImg.copyImg2(tmpImg, m_nextImg1);
m_nextImg1.setRotateDegree(degree);
m_nextImg0.setRotateDegree(degree);
}
}
return 0;
}
图像旋转的线程
UINT CseePictureDlg::rotatePrevImageThread()
{
if (m_ImgFilesVct.size() == 0)
return -1;
int pos;
string file;
CString imgFile;
CImage bufImg;
CMyImage myImg;
//2# read the previous one
pos = m_Pos - 1;
if (pos < 0) {
pos = m_ImgFilesVct.size() - 1;
}
file = m_ImgPath + "\\" + m_ImgFilesVct[pos].getName();
imgFile = file.c_str();
//myImg.GetStrechIMG(m_prevImg0, m_prevImg1, m_ImgRect.Width(), m_ImgRect.Height());
if (m_autoUpWard)
{
CImage tmpImg;
CExif exif;
exif.setImage(imgFile);
int degree;
degree = exif.getRotateAngle();
if (degree != 0) {
CMsApiRotate rtt;
rtt.filter(m_prevImg0, degree, tmpImg);
CMyImage mImg;
mImg.copyImg(tmpImg, m_prevImg0);
}
}
return 0;
}
考察前面的flag,还有很多功能没有实现
1、按钮扁平化处理:完成
2、鼠标点击处动画水纹效果:没有
3、花样显示效果:完成部分
4、幻灯片效果:没有
5、背景音乐:没有
6、图片说明记录:初步完成
7、相机参数显示:没有
8、简单美图处理:没有
9、对象识别(人,车等):没有
路漫漫其修远兮,还要上下而求索吗?
2020-04-29 于泛五道口地区