#include "QtPainterModule.h" #include #include //#include "..//360StitchingModule/SetParam.h" //数据4对齐 #define ALIGN_4(x) (((x) + 3) & ~3) //数据2对齐 #define ALIGN_2(x) (((x) + 1) & ~1) QtPainterModule::QtPainterModule() { DrawBoard = NULL; OrginImg = NULL; DrawPainter = NULL; EditScaleOrNot = true; m_BackGroundColor = COLORREF(64); Scale = 1; ImgRect = MfcLabel::fRect(0, 0, 0, 0); ClientRect = MfcLabel::fRect(0, 0, 0, 0); CurImageRect = MfcLabel::fRect(0, 0, 0, 0); ShowClientRect = MfcLabel::fRect(0, 0, 0, 0); ShowImageRect = MfcLabel::fRect(0, 0, 0, 0); OutputOffsetX = &Offset.x; OutputOffsetY = &Offset.y; bYUVShowOrNot = false; pYUVData = NULL; pYUVImage.reset(); pClipImage.reset(); } QtPainterModule::~QtPainterModule() { SAFE_DELETE(DrawPainter); } void QtPainterModule::SetLabelRect(QRect pQRect) { ClientRect = pQRect; } void QtPainterModule::SetPixmap(QPixmap* pDrawBoard) { DrawBoard = pDrawBoard; if (DrawPainter == NULL) DrawPainter = new QPainter(DrawBoard); else { SAFE_DELETE(DrawPainter); DrawPainter = new QPainter(DrawBoard); } } void QtPainterModule::SetOrginImage(QImage* pImage) { OrginImg = pImage; ImgRect = OrginImg->rect(); } void QtPainterModule::SetOrginImage(QByteArray* pYuvData, int nWidth, int nHeight) { //设置初值 this->pYUVData = pYuvData; this->nYUVImageWidth = nWidth; this->nYUVImageHeight = nHeight; } void QtPainterModule::SetPainter(QPainter* pPainter) { DrawPainter = pPainter; } void QtPainterModule::SetYUVShowOrNot(bool bYUVShowOrNot) { this->bYUVShowOrNot = bYUVShowOrNot; } void QtPainterModule::init() { //初始化全部的显示参数 Scale = 1.f; Offset.SetPoint(0, 0); } void QtPainterModule::CalculateMouseDragOffset(QPoint ptOldMouse, QPoint ptNewMouse) { MfcLabel::fPoint ptOffset; ptOffset.x = (ptNewMouse.x() - ptOldMouse.x()); ptOffset.y = (ptNewMouse.y() - ptOldMouse.y()); Offset.offset(ptOffset.x, ptOffset.y); CurImageRect.offset(ptOffset.x, ptOffset.y); } void QtPainterModule::CalculateMouseDragOffset(int Offset_x, int Offset_y) { Offset.offset(Offset_x, Offset_y); CurImageRect.offset(Offset_x, Offset_y); } void QtPainterModule::CalculateWheelZoomOffsetAndScale(QPoint ptMouse, bool bEnlargeOrNarrow, double dbScale) { CurImageRect = ImgRect; CurImageRect.Scale(Scale); CurImageRect.offset(Offset.x, Offset.y); if (!bEnlargeOrNarrow) { Scale /= 2; QPoint topleft; topleft.setX(CurImageRect.Left); topleft.setY(CurImageRect.Top); int dx = ptMouse.x() - topleft.x(); int dy = ptMouse.y() - topleft.y(); Offset.offset(0.5 * (double)dx, 0.5 * (double)dy); } else { Scale *= 2; QPoint topleft; topleft.setX(CurImageRect.Left); topleft.setY(CurImageRect.Top); int dx = ptMouse.x() - topleft.x(); int dy = ptMouse.y() - topleft.y(); Offset.offset(-dx, -dy); } } bool QtPainterModule::CalculateShowRectInDC(QPoint ptOffset, double dbScale) { //计算当前预备显示的图像位置 ShowClientRect = CurImageRect.IntersectRect(ClientRect); ShowImageRect.SetRectEmpty(); //计算最终的图片将要复制到显示区域的Rect if (CurImageRect.Bottom > ClientRect.Bottom) { ShowImageRect.Bottom = ClientRect.Height() - CurImageRect.Top; } else if (CurImageRect.Bottom <= ClientRect.Bottom) { ShowImageRect.Bottom = CurImageRect.Height(); } if (CurImageRect.Right > ClientRect.Right) { ShowImageRect.Right = ClientRect.Width() - CurImageRect.Left; } else if (CurImageRect.Right <= ClientRect.Right) { ShowImageRect.Right = CurImageRect.Width(); } if (CurImageRect.Top < 0) { ShowImageRect.Top = -CurImageRect.Top; } else if (CurImageRect.Top > ClientRect.Bottom) { return false; } if (CurImageRect.Left < 0) { ShowImageRect.Left = -CurImageRect.Left; } else if (CurImageRect.Left > ClientRect.Right) { return false; } ShowImageRect.Left = ShowImageRect.Left / Scale; ShowImageRect.Top = ShowImageRect.Top / Scale; ShowImageRect.Right = ShowImageRect.Right / Scale; ShowImageRect.Bottom = ShowImageRect.Bottom / Scale; return true; } void QtPainterModule::PasteImageInDC() { if (EditScaleOrNot) { DrawPainter->setRenderHints(QPainter::SmoothPixmapTransform | QPainter::Antialiasing | QPainter::TextAntialiasing); //首先将数据转入到画板之中 MfcLabel::fRect test; test = OrginImg->rect(); *DrawBoard = (QPixmap::fromImage(*OrginImg)); *DrawBoard = DrawBoard->copy(ShowImageRect.TrunFloat2Int()); //缩放 *DrawBoard = DrawBoard->scaled(ShowClientRect.TrunFloat2Int().size()); EditScaleOrNot = false; } OutputPaintRect = ShowImageRect.TrunFloat2Int(); } void QtPainterModule::ShowInFitMode(void* pCallBack) { //坐标需要转换位double,用于计算比例 //fit模式的比例计算 double nImage_width, nImage_height; nImage_height = ImgRect.Height(); nImage_width = ImgRect.Width(); double rect_height = 0, rect_width = 0; rect_height = ClientRect.Height(); rect_width = ClientRect.Width(); //fit的情况下的初始坐标为0,0 Offset.x = 0; Offset.y = 0; //计算放缩倍数,保证fit形式的 if ((rect_height / rect_width) != (nImage_height / nImage_width)) { if (nImage_height / nImage_width > rect_height / rect_width) { Scale = rect_height / nImage_height; FitUseWidthOrHeight = false; } else { Scale = rect_width / nImage_width; FitUseWidthOrHeight = true; } } CurImageRect = ImgRect; CurImageRect.offset(Offset.x, Offset.y); CurImageRect.Scale(Scale); CalculateShowRectInDC(Offset.TurnFloatToInt(), Scale); //完成绘制 if(this->bYUVShowOrNot == false) PasteImageInDC(); else PasteYUVImageInDC(); if (pCallBack != NULL) { ((ShowPictureInQPixMapCallBack)(pCallBack))(DrawBoard, Scale, Offset.TurnFloatToInt(), pCallBackParam); } } void QtPainterModule::ShowInOneToOneMode(void* pCallBack) { //坐标需要转换位double,用于计算比例 //fit模式的比例计算 double nImage_width, nImage_height; nImage_height = ImgRect.Height(); nImage_width = ImgRect.Width(); double rect_height = 0, rect_width = 0; rect_height = ClientRect.Height(); rect_width = ClientRect.Width(); //计算放缩倍数,保证fit形式的 Scale = 1; CurImageRect = ImgRect; CurImageRect.offset(Offset.x, Offset.y); CurImageRect.Scale(Scale); CalculateShowRectInDC(Offset.TurnFloatToInt(), Scale); //完成绘制 if (this->bYUVShowOrNot == false) PasteImageInDC(); else PasteYUVImageInDC(); if (pCallBack != NULL) { ((ShowPictureInQPixMapCallBack)(pCallBack))(DrawBoard, Scale, Offset.TurnFloatToInt(), pCallBackParam); } } void QtPainterModule::ShowInFreeMode(void* pCallBack) { CurImageRect = ImgRect; CurImageRect.Scale(Scale); CurImageRect.offset(Offset.x, Offset.y); CalculateShowRectInDC(Offset.TurnFloatToInt(), Scale); //完成绘制,需要配置dbscale 和 offset两个参数 PasteImageInDC(); if (pCallBack != NULL) { ((ShowPictureInQPixMapCallBack)(pCallBack))(DrawBoard, Scale, Offset.TurnFloatToInt(), pCallBackParam); } } void QtPainterModule::PasteYUVImageInDC() { if (EditScaleOrNot) { //需要将yuv根据指定的显示区域进行裁剪 //首先根据显示区域计算出来的大小给pYUVImage分配空间 //清空指针内的内容 if (pYUVImage.get() != NULL) std::shared_ptr().swap(pYUVImage); if (pClipImage.get() != NULL) std::shared_ptr().swap(pClipImage); ShowClientRect.Right = ALIGN_2(int(ShowClientRect.Right)); ShowClientRect.Bottom = ALIGN_2(int(ShowClientRect.Bottom)); //设置dest区域和src区域 QRect DestRc, SrcRc; //确定裁剪的区域 DestRc = ShowImageRect.TrunFloat2Int(); SrcRc = ShowClientRect.TrunFloat2Int(); //分配裁剪的空间 pClipImage.reset(new unsigned char[DestRc.width() * DestRc.height() * 3/2] {0}); //分配显示的空间 pYUVImage.reset(new unsigned char[SrcRc.width() * SrcRc.height() * 3/2 ] {0}); //设置原图大小 SrcRc.setWidth(nYUVImageWidth); SrcRc.setHeight(nYUVImageHeight); //开始裁剪 ClipYUVImageByLibYUV((unsigned char*)pYUVData->data(), SrcRc, pClipImage.get(), DestRc); //重新设置原图大小 SrcRc.setWidth(DestRc.width()); SrcRc.setHeight(DestRc.height()); //重新设置dst区域大小 DestRc.setWidth(ShowClientRect.Width()); DestRc.setHeight(ShowClientRect.Height()); //开始缩放 ScaleYUVImageByLibYUV((unsigned char*)pClipImage.get(), SrcRc, pYUVImage.get(), DestRc); //得到当前显示区域的长宽 nYUVShowImageHeight = DestRc.height(); nYUVShowImageWidth = DestRc.width(); } OutputPaintRect = ShowImageRect.TrunFloat2Int(); } void QtPainterModule::Draw(ShowMode Flags, void* pCallBack,void* pParam) { if ((!bYUVShowOrNot || pYUVData == NULL) && (OrginImg == NULL || DrawBoard == NULL || DrawPainter == NULL) ) return; //类内的接住回调的参数 pCallBackParam = pParam; switch (Flags) { case Fit: ShowInFitMode(pCallBack); break; case OneToOne: ShowInOneToOneMode(pCallBack); break; case Free: ShowInFreeMode(pCallBack); break; default: break; } } bool QtPainterModule::ClipYUVImageByLibYUV(unsigned char* pSrcImage, QRect ClipSrcRc, unsigned char* pDstImage, QRect ClipDstRc) { //检查ClipRect是否在pSrcImage之内的工作在外面完成 //检查ClipRect是否为偶数,yuv坐标必须为偶数,如果不为偶数无法定位uv的具体坐标 if (ClipSrcRc.left() % 2 != 0 || ClipSrcRc.top() % 2 != 0) return false; //检查输入的两个地址是否为合法地址 if (pSrcImage == NULL || pDstImage == NULL) return false; //计算yuv各个数据的起始地址 unsigned char* pSrcY = pSrcImage; unsigned char* pSrcU = pSrcImage + ClipSrcRc.width() * ClipSrcRc.height(); unsigned char* pSrcV = pSrcImage + ClipSrcRc.width() * ClipSrcRc.height() * 5 / 4; unsigned char* pDstY = pDstImage; unsigned char* pDstU = pDstImage + ClipDstRc.width() * ClipDstRc.height(); unsigned char* pDstV = pDstImage + ClipDstRc.width() * ClipDstRc.height() * 5 / 4; if (ClipDstRc.width() == ClipSrcRc.width() && ClipDstRc.height() == ClipSrcRc.height()) { libyuv::I420Copy( pSrcY, ClipSrcRc.width(), pSrcU, ClipSrcRc.width() >> 1, pSrcV, ClipSrcRc.width() >> 1, pDstY, ClipDstRc.width(), pDstU, ClipDstRc.width() >> 1, pDstV, ClipDstRc.width() >> 1, ClipSrcRc.width(), ClipSrcRc.height() ); return 0; } else //调用libyuv的函数进行裁剪 return libyuv::ConvertToI420(pSrcY, ClipSrcRc.width(), pDstY, ClipDstRc.width() , pDstU, ClipSrcRc.width() >> 1, pDstV, ClipDstRc.width() >> 1, ClipDstRc.left(), ClipDstRc.top(), ClipSrcRc.width(), ClipSrcRc.height(), ClipDstRc.width(), ClipDstRc.height(), libyuv::kRotate0, libyuv::FOURCC_I420); } bool QtPainterModule::ScaleYUVImageByLibYUV(unsigned char* pSrcImage, QRect ClipRect, unsigned char* pDstImage, QRect ClipDstRc) { //首先判断一下目标数据的宽度是否为偶数 if (ClipDstRc.width() % 2 != 0 || ClipDstRc.height() % 2 != 0) return false; //检查输入的两个地址是否为合法地址 if (pSrcImage == NULL || pDstImage == NULL) return false; //计算yuv各个数据的起始地址 unsigned char* pSrcY = pSrcImage; unsigned char* pSrcU = pSrcImage + ClipRect.width() * ClipRect.height(); unsigned char* pSrcV = pSrcImage + ClipRect.width() * ClipRect.height() * 5 / 4; unsigned char* pDstY = pDstImage; unsigned char* pDstU = pDstImage + ClipDstRc.width() * ClipDstRc.height(); unsigned char* pDstV = pDstU + ClipDstRc.width() * ClipDstRc.height() / 4; //调用libyuv的函数进行图像的缩放 return libyuv::I420Scale(pSrcY, ClipRect.width() , pSrcU, ClipRect.width() >> 1 , pSrcV, ClipRect.width() >> 1, ClipRect.width(), ClipRect.height() , pDstY, ClipDstRc.width() , pDstU, ClipDstRc.width() >> 1 , pDstV, ClipDstRc.width() >> 1 ,ClipDstRc.width(), ClipDstRc.height() ,libyuv::kFilterBilinear); }