版权声明:www.gudianxiaoshuo.com (古典小说网) 今日头条号: 古典古韵古典小说、讨厌编程 https://blog.csdn.net/shuilan0066/article/details/87881329
使用GDI+来处理图像,
初始工作
1)头文件
#include <GdiPlus.h>
#pragma comment(lib, "GdiPlus.lib")
using namespace Gdiplus;
2)定义变量
GdiplusStartupInput m_Gdistart;
ULONG_PTR m_GdiplusToken;
3)
//起止位置
GdiplusStartup(&m_GdiplusToken, &m_Gdistart, NULL);
//销毁位置
Gdiplus::GdiplusShutdown(m_pGdiToken)
不过我在云信duilib中,只找到#include <GdiPlus.h> ,估计其它的工作都封装起来了。
一 :分解说明
1、加载图像
将本地图像,加载成GID+ Bitmap, 将此Bitmap数据转换成YUV数据
1)GDI+ 加载图像
Bitmap::Bitmap(
IN const WCHAR *filename,
IN BOOL useEmbeddedColorManagement
)
{
GpBitmap *bitmap = NULL;
if(useEmbeddedColorManagement)
{
lastResult = DllExports::GdipCreateBitmapFromFileICM(filename, &bitmap);
}
else
{
lastResult = DllExports::GdipCreateBitmapFromFile(filename, &bitmap);
}
SetNativeImage(bitmap);
}
2) 加载图像 保存在共享指针变量中
std::shared_ptr<Gdiplus::Bitmap> src_image_;
//加载图像
src_image_.reset(new Gdiplus::Bitmap(path.c_str()));
//判断加载是否成功
status = src_image_->GetLastStatus();
ASSERT(status == Gdiplus::Ok);
if (status != Gdiplus::Ok) {
return false;
}
2、图像字节数据保存
将数据保存在std::string data_中
struct ImageFrame {
std::string data_;
int height_;
int width_;
int time_;
bool alpha_;
int index_;
ImageFrame()
{
height_ = 0;
width_ = 0;
time_ = 100;
alpha_ = false;
index_ = 0;
}
};
有的图像格式 比如gif tif等有好几帧, 这些图像帧也保存起来
std::vector<ImageFrame> image_list_;
这样就涉及到获取图像多少帧,帧间隔,获得某帧视频数据问题,不过这些gdi+都可以处理
3、图像帧处理
1) 获得多少帧
UINT nCount = src_image_->GetFrameDimensionsCount();
std::unique_ptr<GUID[]> pDimensionIDs(new GUID[nCount]);
src_image_->GetFrameDimensionsList(pDimensionIDs.get(), nCount);
int iFrameCount = src_image_->GetFrameCount(&pDimensionIDs.get()[0]);
Gdiplus::PropertyItem* propertyItem = nullptr;
if (iFrameCount > 1) {
int iSize = src_image_->GetPropertyItemSize(PropertyTagFrameDelay);
/*Gdiplus::PropertyItem* */
propertyItem = (Gdiplus::PropertyItem*) malloc(iSize);
status = src_image_->GetPropertyItem(PropertyTagFrameDelay, iSize, propertyItem);
ASSERT(status == Gdiplus::Ok);
if (status != Gdiplus::Ok) {
return false;
}
}
2)获得帧间隔
time_all_ = 0;
for (int i = 0; i < iFrameCount; i++) {
ImageFrame image_frame;
int interval = 100;
if (propertyItem)
{
int interval = ((long*)(propertyItem->value))[i] * 10;
if (interval < 30) {
interval = 100;
}
else if (interval < 50)
{
interval = 50;
}
}
time_all_ += interval;
image_frame.time_ = time_all_;
if (CheckImageFrame(i, &image_frame, 0,0))
{
image_list_.push_back(image_frame);
}
}
3) 将每帧的数据保存在ImageFrame中
- 选择图像中某一帧
if (src_image_ == nullptr)
{
return false;
}
Gdiplus::Status status;
status = src_image_->SelectActiveFrame(&Gdiplus::FrameDimensionTime, index);
ASSERT(status == Gdiplus::Ok);
if (status != Gdiplus::Ok) {
return false;
}
- 获得此帧对应的Bitmap
Gdiplus::Bitmap* bitmap = nullptr;
bool creat_bitmap = false;
if (src_height == height && src_width == width)
{
bitmap = src_image_.get();
}
如果,所要的图像大小和原图大小不一样,则创建一个新Bitmap, 然后在此新 Bitmap上绘图
Gdiplus::Bitmap* bitmap = nullptr;
bool creat_bitmap = false;
if (src_height == height && src_width == width)
{
bitmap = src_image_.get();
}
else
{
bitmap = new Gdiplus::Bitmap(width, height, PixelFormat32bppARGB);
Gdiplus::Graphics g(bitmap);
//Gdiplus::SolidBrush brush(Gdiplus::Color(250, 0, 0, 0));
//g.FillRectangle(&brush, 0, 0, width, height);
g.DrawImage(src_image_.get(), width/4, height/4,width/2,height/2);
//g.DrawImage(src_image_.get(), 0,0, width, height );
creat_bitmap = true;
//Gdiplus::Pen pen(Gdiplus::Color(255, 255, 111, 0), 300);
//Gdiplus::Rect rc(0, 0, width, height);
//g.DrawRectangle(&pen, rc);
//g.DrawImage(src_image_.get(), Gdiplus::Rect(0, 0, width, height), 0, 0, src_width, src_height, Gdiplus::UnitPixel);
}
。。。。
。。。。
。。。。
在处理完毕后,如果是创建的Bitmap,则将其释放掉
if (creat_bitmap)
{
delete bitmap;
bitmap = nullptr;
}
- 获得Bitmap中的数据
class BitmapData
{
public:
UINT Width;
UINT Height;
INT Stride;
PixelFormat PixelFormat;
VOID* Scan0;
UINT_PTR Reserved;
};
//图像数据保存在data.Scan0中
Gdiplus::BitmapData data;
Gdiplus::Rect rect(0, 0, width, height);
int type = bitmap->GetPixelFormat();
// ASSERT(type == PixelFormat32bppARGB);
bitmap->LockBits(&rect, Gdiplus::ImageLockModeRead | Gdiplus::ImageLockModeWrite, PixelFormat32bppARGB, &data);
int byte_width = data.Stride;
image_frame->width_ = width;
image_frame->height_ = height;
image_frame->index_ = index;
image_frame->alpha_ = CopyImageData((const char*)data.Scan0, data.Stride, image_frame->data_, width, height);
bitmap->UnlockBits(&data);
- ARGB数据 转YUV420数据
bool YuvImage::CopyImageData(const char* src, int byte_width, std::string& dest, int width, int height)
{
bool alpha = false;
int wxh = width * height;
dest.clear();
dest.append(wxh * 3, (char)0);
uint8_t* des_y = (uint8_t*)dest.c_str();
uint8_t* des_u = des_y + wxh * 2;
uint8_t* des_v = des_u + wxh / 2;
const uint8_t* src_argb = (const uint8_t*)src;
libyuv::ARGBToI420(src_argb, byte_width,
des_y, width * 2,
des_u, width,
des_v, width,
width, height);
uint8_t* a1 = (uint8_t*)src + 3;
uint8_t* des_ya = des_y + width;
uint8_t* des_ua = des_u + width / 2;
uint8_t* des_va = des_v + width / 2;
for (int i = 0; i < height / 2; ++i)
{
uint8_t* a2 = a1 + byte_width;
uint8_t* des_ya2 = des_ya + width * 2;
for (int j = 0; j < width / 2; ++j)
{
int y1 = *a1;
a1 += 4;
*(des_ya++) = y1;
int y2 = *a1;
a1 += 4;
*(des_ya++) = y2;
int y3 = *a2;
a2 += 4;
*(des_ya2++) = y3;
int y4 = *a2;
a2 += 4;
*(des_ya2++) = y4;
uint8_t a_uv = (y1 + y2 + y3 + y4) / 4;
*(des_ua++) = a_uv;
*(des_va++) = a_uv;
if (a_uv != 255)
{
alpha = true;
}
}
a1 += byte_width;
des_ya += width * 3;
des_ua += width / 2;
des_va += width / 2;
}
return alpha;
}
4 图像加载 并转化成YUV数据 封装成单独的YuvImage类处理
class YuvImage
{
public:
YuvImage();
~YuvImage();
bool LoadImage(std::wstring path);
bool AddText(const std::wstring& text, int width, int height, DWORD color, int iFont, UINT uStyle, BYTE uFade, bool bLineLimit);
ImageFrame* GetImageFrame(int index, int width = -1, int height = -1);
ImageFrame* GetImageFrameEx(int64_t time, int width = -1, int height = -1);
ImageFrame* GetOriImageFrame(int index);
private:
bool CheckImageFrame(int index, ImageFrame* image_frame, int width, int height);
bool CopyImageData(const char* src, int byte_width, std::string& dest, int width, int height);
bool DrawText(int index, int width, int height, DWORD color, int iFont, UINT uStyle, BYTE uFade, bool bLineLimit);
private:
std::vector<ImageFrame> image_list_;
std::shared_ptr<Gdiplus::Bitmap> src_image_;
int time_all_;
std::wstring image_path_;
std::wstring text_;
int64_t time_start_;
};
二 具体使用
std::vector<YuvImage> yuv_image_list_;
void ScreenCaptureTool::SetTextLogo(std::wstring text)
{
nbase::NAutoLock auto_lock(&lock_);
yuv_image_list_.clear();
std::wstring dir = QPath::GetAppPath();
std::wstring logoPath, logo2Path;
logoPath = dir;
logo2Path = dir;
logoPath.append(L"logo.png");
logo2Path.append(L"logo2.png");
if (::PathFileExists(logoPath.c_str()))
{
YuvImage image0;
image0.LoadImage(logoPath.c_str());
yuv_image_list_.push_back(image0);
}
if (::PathFileExists(logo2Path.c_str()))
{
YuvImage image0;
image0.LoadImage(logo2Path.c_str());
yuv_image_list_.push_back(image0);
}
}
//贴图
{
POINT pt = { 0, 0 };
int nCouont = 0;
for (auto& it : yuv_image_list_)
{
ImageFrame* image_frame = it.GetOriImageFrame(0);
if (image_frame)
{
if (nCouont==0)
{
CopyI420Data(Logo_NE/*SIZENW*/, data_ret, image_frame->data_, image_frame->width_, image_frame->height_, image_frame->alpha_ ? kYuvDataTypeImageAlpha : kYuvDataTypeImage, pt);
}
else{
CopyI420Data(Logo2_NE/*SIZENW*/, data_ret, image_frame->data_, image_frame->width_, image_frame->height_, image_frame->alpha_ ? kYuvDataTypeImageAlpha : kYuvDataTypeImage, pt);
}
}
nCouont++;
}
}