C++GDI+を使用して画像を切り取る

4227 ワード

概要
現在、C#は画像を切り取るケースが多いが、C++を使うケースは少ない.しかし、現在のプロジェクトは画像をカットする必要があります.私もOpenCVを使うのが簡単だと知っていますが、プロジェクトの中にOpenCVのものをたくさん配置したくありません.プロジェクトはあまり必要ありませんから.
このブログには、ピクチャカット、バイト配列、IStreamの変換、StreamとImageクラスの変換の2つの知識点が含まれています.
画像の切り取り
まず自分でネット上のC++の画像を切り取る方法を探して、それからGDI+の中のDrawImageという関数が画像を切り取ることができることを発見しました.
    Status DrawImage(IN Image* image,                      IN const RectF& destRect,                      IN REAL srcx,                      IN REAL srcy,                      IN REAL srcwidth,                      IN REAL srcheight,                      IN Unit srcUnit,                      IN const ImageAttributes* imageAttributes = NULL,                      IN DrawImageAbort callback = NULL,                      IN VOID* callbackData = NULL)
 
バイト配列とIStreamの変換
1.グローバル領域にメモリハンドルを作成し、ターゲットストリームに使用する.    HGLOBAL hDesMem = GlobalAlloc(GMEM_MOVEABLE, ImageSize);     IStream *pDesStream = NULL;     CreateStreamOnHGlobal(hDesMem, TRUE, &pDesStream);     BYTE *pDesData = (BYTE *)GlobalLock(hDesMem); 2、.メモリを、購買依頼のグローバルスペースにコピーします.    CopyMemory(pDesData, imgSrc, ImageSize);     GlobalUnlock(hDesMem);
3、最後にグローバル空間を解放し、ストリームを解放することを忘れないでください.
    GlobalFree(hDesMem);//グローバルスペースpDesStream->Release();    pOutStream->Release();
IStreamとImageクラスの変換
2時間かけてImageクラスを表示した後、IStreamでインスタンスを作成できるImageのコンストラクション関数が入っていることに気づきました.
 Image(         IN IStream* stream,         IN BOOL useEmbeddedColorManagement = FALSE     );
その後、FromStreamの関数もImageポインタに変換できることが分かった.
inline Image*  Image::FromStream(     IN IStream* stream,     IN BOOL useEmbeddedColorManagement     )
 
include 

#pragma comment(lib, "gdiplus.lib")

using namespace Gdiplus;


//   :    ,     
//   :imgSrc,       ,
//		 ImageSize:      
//		 imgDst:          
//		 xPos:       x  
//		 yPos:       y  
//		 Width:      
//		 Height:      
//    :    0,           
DWORD CutPicture(BYTE *imgSrc, int ImageSize, BYTE* imgDst, int xPos, int yPos, int Width, int Height)
{
	int nRet = -1;

	if (Width<=0 || Height <=0 || imgSrc==nullptr || ImageSize<=0)
	{
		return 0;
	}
	GdiplusStartupInput gdiplusstartupinput;

	ULONG_PTR gdiplustoken;
	DWORD nDstSize = 0;
	GdiplusStartup(&gdiplustoken, &gdiplusstartupinput, NULL);
	{
		CLSID clsid;
		nRet = GetCodecClsid(L"image/jpeg", &clsid);
		if (nRet == -1)
		{
			GdiplusShutdown(gdiplustoken);
			return 0;
		}

		//         ,     
		HGLOBAL hDesMem = GlobalAlloc(GMEM_MOVEABLE, ImageSize);
		IStream *pDesStream = NULL;
		CreateStreamOnHGlobal(hDesMem, TRUE, &pDesStream);
		BYTE *pDesData = (BYTE *)GlobalLock(hDesMem);
		//3.    ,         。
		CopyMemory(pDesData, imgSrc, ImageSize);
		GlobalUnlock(hDesMem);
		// 4.   Image
		Image *bmSrc = Image::FromStream(pDesStream);

//		bmSrc->Save(L"E:\\test3.jpg", &clsid, NULL);


		int w = 0, h = 0;
		w = bmSrc->GetWidth();
		h = bmSrc->GetHeight();

		if (w < h) //         Width Height
		{
			int nTemp = Width;
			Width = Height;
			Height = nTemp;
		}
		Bitmap *bmPhoto = new Bitmap(Width, Height);	// elvsi   

		bmPhoto->SetResolution(bmSrc->GetHorizontalResolution(), bmSrc->GetVerticalResolution());
		//bmPhoto->SetResolution(Width, Height);
		Graphics grPhoto(bmPhoto);
		grPhoto.Clear((ARGB)Color::White);
		grPhoto.SetInterpolationMode(InterpolationModeHighQualityBicubic);

		Rect dest(0, 0, w, h);
		grPhoto.DrawImage((Image*)bmSrc, dest, xPos, yPos, Width, Height, UnitPixel);

//		bmPhoto->Save(L"E:\\test4.jpg", &clsid, NULL);

		//2.   
		IStream *pOutStream = NULL;
		ULARGE_INTEGER   pSeek;
		LARGE_INTEGER    dlibMove = { 0 };

		CreateStreamOnHGlobal(NULL, TRUE, &pOutStream);
		// JPEG           
		bmPhoto->Save(pOutStream, &clsid, NULL);
		pOutStream->Seek(dlibMove, STREAM_SEEK_SET, &pSeek);
		pOutStream->Read(imgDst, ImageSize, &nDstSize);

		GlobalFree(hDesMem);	//       
		delete bmSrc;
		delete bmPhoto;
		pDesStream->Release();
		pOutStream->Release();
		
		
	}
	GdiplusShutdown(gdiplustoken);
	return nDstSize;
}

 
まとめ
初めてブログを出しましたが、間違ったところがあれば、牛さんの包容と指摘をお願いします.