How to create a 32 bit red texture byte buffer - c++

I want to make a red texture image buffer. Would anyone help me to make it in right way. I have tried following but could not copy the buffer into ID3D11Texture2D. I need help:
std::vector<BYTE> redTexture(w*h*4);
const auto stride = w * 4;
BYTE* buf = redTexture.data();
for (int i = 0; i < h; ++i)
{
const auto redValue = Gdiplus::Color::Red;
memcpy(buf, &redValue, stride);
buf += stride;
}

If the DXGI_FORMAT of your texture is R8G8B8A8_UNORM, you can do it like this;
std::vector<BYTE> redTexture(w*h*4);
for(int i=0; i<redTexture.size(); i++)
{
if(i%4==0)
{
redTexture[i]=255;
}
else if(i%4==3)
{
redTexture[i]=255;
}
else
{
redTexture[i]=0;
}
}
Since each pixel consists of RGBA 4 byte value, you should assign first and last bytes to 255, other bytes to 0 to get the red color.

Thanks #HMD. I have solved the issue by doing the following:
CImage m_cImage;
// create a test image
m_cImage.Create(w, -h, 8 * 4); // 8 bpp * 4 channel
auto hdc = m_cImage.GetDC();
Gdiplus::Graphics graphics(hdc);
// Create a SolidBrush object.
Gdiplus::SolidBrush redBrush(Gdiplus::Color::Red);
// Fill the rectangle.
Gdiplus::Status status = graphics.FillRectangle(&redBrush, 0, 0, w, h);
TRY_CONDITION(status == Gdiplus::Status::Ok);
....
// Then saved the m_cImage.GetBits() to bmp file using Gdiplus::Bitmap
// and my expected texture is found

Related

DirectX Partial Screen Capture

I am trying to create a program that will capture a full screen directx application, look for a specific set of pixels on the screen and if it finds it then draw an image on the screen.
I have been able to set up the application to capture the screen the directx libraries using the code the answer for this question Capture screen using DirectX
In this example the code saves to the harddrive using the IWIC libraries. I would rather manipulate the pixels instead of saving it.
After I have captured the screen and have a LPBYTE of the entire screen pixels I am unsure how to crop it to the region I want and then being able to manipulate the pixel array. Is it just a multi dimensional byte array?
The way I think I should do it is
Capture screen to IWIC bitmap (done).
Convert IWIC bitmap to ID2D1 bitmap using ID2D1RenderTarget::CreateBitmapFromWicBitmap
Create new ID2D1::Bitmap to store partial image.
Copy region of the ID2D1 bitmap to a new bitmap using ID2D1::CopyFromBitmap.
Render back onto screen using ID2D1 .
Any help on any of this would be so much appreciated.
Here is a modified version of the original code that only captures a portion of the screen into a buffer, and also gives back the stride. Then it browses all the pixels, dumps their colors as a sample usage of the returned buffer.
In this sample, the buffer is allocated by the function, so you must free it once you've used it:
// sample usage
int main()
{
LONG left = 10;
LONG top = 10;
LONG width = 100;
LONG height = 100;
LPBYTE buffer;
UINT stride;
RECT rc = { left, top, left + width, top + height };
Direct3D9TakeScreenshot(D3DADAPTER_DEFAULT, &buffer, &stride, &rc);
// In 32bppPBGRA format, each pixel is represented by 4 bytes
// with one byte each for blue, green, red, and the alpha channel, in that order.
// But don't forget this is all modulo endianness ...
// So, on Intel architecture, if we read a pixel from memory
// as a DWORD, it's reversed (ARGB). The macros below handle that.
// browse every pixel by line
for (int h = 0; h < height; h++)
{
LPDWORD pixels = (LPDWORD)(buffer + h * stride);
for (int w = 0; w < width; w++)
{
DWORD pixel = pixels[w];
wprintf(L"#%02X#%02X#%02X#%02X\n", GetBGRAPixelAlpha(pixel), GetBGRAPixelRed(pixel), GetBGRAPixelGreen(pixel), GetBGRAPixelBlue(pixel));
}
}
// get pixel at 50, 50 in the buffer, as #ARGB
DWORD pixel = GetBGRAPixel(buffer, stride, 50, 50);
wprintf(L"#%02X#%02X#%02X#%02X\n", GetBGRAPixelAlpha(pixel), GetBGRAPixelRed(pixel), GetBGRAPixelGreen(pixel), GetBGRAPixelBlue(pixel));
SavePixelsToFile32bppPBGRA(width, height, stride, buffer, L"test.png", GUID_ContainerFormatPng);
LocalFree(buffer);
return 0;;
}
#define GetBGRAPixelBlue(p) (LOBYTE(p))
#define GetBGRAPixelGreen(p) (HIBYTE(p))
#define GetBGRAPixelRed(p) (LOBYTE(HIWORD(p)))
#define GetBGRAPixelAlpha(p) (HIBYTE(HIWORD(p)))
#define GetBGRAPixel(b,s,x,y) (((LPDWORD)(((LPBYTE)b) + y * s))[x])
int main()
HRESULT Direct3D9TakeScreenshot(UINT adapter, LPBYTE *pBuffer, UINT *pStride, const RECT *pInputRc = nullptr)
{
if (!pBuffer || !pStride) return E_INVALIDARG;
HRESULT hr = S_OK;
IDirect3D9 *d3d = nullptr;
IDirect3DDevice9 *device = nullptr;
IDirect3DSurface9 *surface = nullptr;
D3DPRESENT_PARAMETERS parameters = { 0 };
D3DDISPLAYMODE mode;
D3DLOCKED_RECT rc;
*pBuffer = NULL;
*pStride = 0;
// init D3D and get screen size
d3d = Direct3DCreate9(D3D_SDK_VERSION);
HRCHECK(d3d->GetAdapterDisplayMode(adapter, &mode));
LONG width = pInputRc ? (pInputRc->right - pInputRc->left) : mode.Width;
LONG height = pInputRc ? (pInputRc->bottom - pInputRc->top) : mode.Height;
parameters.Windowed = TRUE;
parameters.BackBufferCount = 1;
parameters.BackBufferHeight = height;
parameters.BackBufferWidth = width;
parameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
parameters.hDeviceWindow = NULL;
// create device & capture surface (note it needs desktop size, not our capture size)
HRCHECK(d3d->CreateDevice(adapter, D3DDEVTYPE_HAL, NULL, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &parameters, &device));
HRCHECK(device->CreateOffscreenPlainSurface(mode.Width, mode.Height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &surface, nullptr));
// get pitch/stride to compute the required buffer size
HRCHECK(surface->LockRect(&rc, pInputRc, 0));
*pStride = rc.Pitch;
HRCHECK(surface->UnlockRect());
// allocate buffer
*pBuffer = (LPBYTE)LocalAlloc(0, *pStride * height);
if (!*pBuffer)
{
hr = E_OUTOFMEMORY;
goto cleanup;
}
// get the data
HRCHECK(device->GetFrontBufferData(0, surface));
// copy it into our buffer
HRCHECK(surface->LockRect(&rc, pInputRc, 0));
CopyMemory(*pBuffer, rc.pBits, rc.Pitch * height);
HRCHECK(surface->UnlockRect());
cleanup:
if (FAILED(hr))
{
if (*pBuffer)
{
LocalFree(*pBuffer);
*pBuffer = NULL;
}
*pStride = 0;
}
RELEASE(surface);
RELEASE(device);
RELEASE(d3d);
return hr;
}

How to display jpg image by ImageMagicK in MFC?

I have got a hard time to display jpg file at VIEW class by ImageMagicK in MFC.
The following code are my code. the problem is looking as following
image
void CTestview::DoDisplayImage(void)
{
CDC *pDC = GetDC();
if (fileposition != NULL)
AfxMessageBox(fileposition);
char m_szAppPath[255];
//m_szAppPath = (char) * fileposition;
(void)MagickCore::SetClientPath(fileposition);
InitializeMagick(fileposition);
MagickCore::RegisterStaticModules();
// Parse command line for standard shell commands, DDE, file open
Image m_Image;
m_Image.read(fileposition);
/*
char m_szAppPath[255];
(void) MagickCore::SetClientPath(m_szAppPath);
InitializeMagick(m_szAppPath);
MagickCore::RegisterStaticModules();
// Parse command line for standard shell commands, DDE, file open
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
Image master;
master.read("D:\\work\\mfc_test5\\q1.jpg");
*/
if (pDC != NULL && m_Image.isValid())
{
CRect rectClient;
GetClientRect(rectClient);
// Clear the background
pDC->FillSolidRect(rectClient, pDC->GetBkColor());
// Set up the Windows bitmap header
BITMAPINFOHEADER bmi;
bmi.biSize = sizeof(BITMAPINFOHEADER); // Size of structure
bmi.biWidth = m_Image.columns(); // Bitmaps width in pixels
bmi.biHeight = (-1)*m_Image.rows(); // Bitmaps height n pixels
bmi.biPlanes = 1; // Number of planes in the image
bmi.biBitCount = 32; // The number of bits per pixel
bmi.biCompression = BI_RGB; // The type of compression used
bmi.biSizeImage = 0; // The size of the image in bytes
bmi.biXPelsPerMeter = 0; // Horizontal resolution
bmi.biYPelsPerMeter = 0; // Veritical resolution
bmi.biClrUsed = 0; // Number of colors actually used
bmi.biClrImportant = 0; // Colors most important
// Extract the pixels from Magick++ image object and convert to a DIB section
PixelPacket *pPixels = m_Image.getPixels(0, 0, m_Image.columns(), m_Image.rows());
RGBQUAD *prgbaDIB = 0;
HBITMAP hBitmap = CreateDIBSection
(
pDC->m_hDC, // handle to device context
(BITMAPINFO *)&bmi, // pointer to structure containing bitmap size, format, and color data
DIB_RGB_COLORS, // color data type indicator: RGB values or palette indices
(void**)&prgbaDIB, // pointer to variable to receive a pointer to the bitmap's bit values
NULL, // optional handle to a file mapping object
0 // offset to the bitmap bit values within the file mapping object
);
if (!hBitmap)
return;
unsigned long nPixels = m_Image.columns() * m_Image.rows();
RGBQUAD *pDestPixel = prgbaDIB;
// Transfer pixels, scaling to Quantum
/*
for( unsigned long nPixelCount = nPixels; nPixelCount ; nPixelCount-- )
{
pDestPixel->rgbRed = MagickCore::GetPixelRed(m_Image.constImage(),pPixels)/257;
pDestPixel->rgbGreen = MagickCore::GetPixelGreen(m_Image.constImage(),pPixels)/257;
pDestPixel->rgbBlue = MagickCore::GetPixelBlue(m_Image.constImage(),pPixels)/257;
pDestPixel->rgbReserved = 0;
++pDestPixel;
pPixels+=MagickCore::GetPixelChannels(m_Image.constImage());
}
*/
for (int i = 0; i < 256; i++)
{
pPixels->blue = (BYTE)i;
pPixels->green = (BYTE)i;
pPixels->red = (BYTE)i;
pPixels->opacity = 0;
pPixels++;
}
// Now copy the bitmap to device.
HDC hMemDC = CreateCompatibleDC(pDC->m_hDC);
SelectObject(hMemDC, hBitmap);
BitBlt(pDC->m_hDC, 0, 0, m_Image.columns(), m_Image.rows(), hMemDC, 0, 0, SRCCOPY);
DeleteObject(hMemDC);
}
}
Especially, at the following code does not sure.
What should I do for solving this problem?
for( int i = 0 ; i < 256 ; i++ )
{
pPixels->blue = (BYTE)i;
pPixels->green = (BYTE)i;
pPixels->red = (BYTE)i;
pPixels->opacity = 0;
pPixels++;
}
Would you please help me how do I do for solving this problem?
As you can see, the output image has black.

How to access pixel color within a bitmap?

I searched and I understood I'll have to use GetDIBits(). I don't know what to do with the LPVOID lpvBits out parameter.
Could someone please explain it to me? I need to get the pixel color information in a two dimensional matrix form so that I can retrieve the information for a particular (x,y) coordinate pair.
I am programming in C++ using Win32 API.
first you need a bitmap and open it
HBITMAP hBmp = (HBITMAP) LoadImage(GetModuleHandle(NULL), _T("test.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
if(!hBmp) // failed to load bitmap
return false;
//getting the size of the picture
BITMAP bm;
GetObject(hBmp, sizeof(bm), &bm);
int width(bm.bmWidth),
height(bm.bmHeight);
//creating a bitmapheader for getting the dibits
BITMAPINFOHEADER bminfoheader;
::ZeroMemory(&bminfoheader, sizeof(BITMAPINFOHEADER));
bminfoheader.biSize = sizeof(BITMAPINFOHEADER);
bminfoheader.biWidth = width;
bminfoheader.biHeight = -height;
bminfoheader.biPlanes = 1;
bminfoheader.biBitCount = 32;
bminfoheader.biCompression = BI_RGB;
bminfoheader.biSizeImage = width * 4 * height;
bminfoheader.biClrUsed = 0;
bminfoheader.biClrImportant = 0;
//create a buffer and let the GetDIBits fill in the buffer
unsigned char* pPixels = new unsigned char[(width * 4 * height)];
if( !GetDIBits(CreateCompatibleDC(0), hBmp, 0, height, pPixels, (BITMAPINFO*) &bminfoheader, DIB_RGB_COLORS)) // load pixel info
{
//return if fails but first delete the resources
DeleteObject(hBmp);
delete [] pPixels; // delete the array of objects
return false;
}
int x, y; // fill the x and y coordinate
unsigned char r = pPixels[(width*y+x) * 4 + 2];
unsigned char g = pPixels[(width*y+x) * 4 + 1];
unsigned char b = pPixels[(width*y+x) * 4 + 0];
//clean up the bitmap and buffer unless you still need it
DeleteObject(hBmp);
delete [] pPixels; // delete the array of objects
so in short, the lpvBits out parameter is the pointer to the pixels
but if it is only 1 pixel you need i suggest to use getpixel to
I'm not sure if this is what you're looking for but GetPixel does pretty much what you need ...at least from i can tell from the function's description

How to display OpenCV Mat on MFC View

I thought displaying OpenCV2 Mat on MFC View is simple but is not. This is only relevant material I found on google. Excuse me for my ignorance but I can't find any other materials showing how to use SetDIBitsToDevice with one dimensional array "data" member returns. More specifically, I need to know how to specify BITMAPINFO for the function. Do I go back to Old C-style OpenCV to work with MFC?
UPDATE:
I found an example of SetDIBitsToDevice which is actually for old C-style OpenCV. But it was straightforward to convert it for OpenCV2. There are things I need to mention to make it work:
Bpp method does not work well as Mat's depth returns 0. I just changed like this:
static int Bpp(cv::Mat img) { return 8 * img.channels(); }
Mat does not have origin member. But simply putting 0 is fine for origin argument of FillBitmapInfo method.
Other than that, following code works great. Hope this helps other devs too.
void COpenCVTestView::OnDraw(CDC* pDC)
{
COpenCVTestDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
if(pDoc->m_cvImage.empty()) return;
// TODO: add draw code for native data here
int height=pDoc->m_cvImage.rows;
int width=pDoc->m_cvImage.cols;
uchar buffer[sizeof( BITMAPINFOHEADER ) + 1024];
BITMAPINFO* bmi = (BITMAPINFO* )buffer;
FillBitmapInfo(bmi,width,height,Bpp(pDoc->m_cvImage),0);
SetDIBitsToDevice(pDC->GetSafeHdc(), 0, 0, width,
height, 0, 0, 0, height, pDoc->m_cvImage.data, bmi,
DIB_RGB_COLORS);
}
void COpenCVTestView::FillBitmapInfo(BITMAPINFO* bmi, int width, int height, int bpp, int origin)
{
assert(bmi && width >= 0 && height >= 0 && (bpp == 8 || bpp == 24 || bpp == 32));
BITMAPINFOHEADER* bmih = &(bmi->bmiHeader);
memset(bmih, 0, sizeof(*bmih));
bmih->biSize = sizeof(BITMAPINFOHEADER);
bmih->biWidth = width;
bmih->biHeight = origin ? abs(height) : -abs(height);
bmih->biPlanes = 1;
bmih->biBitCount = (unsigned short)bpp;
bmih->biCompression = BI_RGB;
if (bpp == 8)
{
RGBQUAD* palette = bmi->bmiColors;
for (int i = 0; i < 256; i++)
{
palette[i].rgbBlue = palette[i].rgbGreen = palette[i].rgbRed = (BYTE)i;
palette[i].rgbReserved = 0;
}
}
}
Here is another possible way of displaying OpenCV data in MFC which I use and works great:
IplImage* image// <-- this contains the image you want to display
CvvImage tempdefault;
RECT myrect; // <-- specifiy where on the screen you want it to be displayed
myrect.top = 0;
myrect.bottom = _pictureh;
myrect.left = _picturex;
myrect.right = _picturew+_picturex;
tempdefault.Create(_pictureh,_picturew,32);
tempdefault.CopyOf(image);
tempdefault.DrawToHDC(pDC->GetSafeHdc(),&myrect);
From MSDN:
lpvBits [in]
A pointer to the color data stored as an array of bytes. For more information, see the following Remarks section.
This is the pointer you must init with the data returned from Mat::data.
CvvImage is not available in new versions of OpenCV. Using the following code you can convert Mat to CImage and then display CImage everywhere you want:
int Mat2CImage(Mat *mat, CImage &img){
if(!mat || mat->empty())
return -1;
int nBPP = mat->channels()*8;
img.Create(mat->cols, mat->rows, nBPP);
if(nBPP == 8)
{
static RGBQUAD pRGB[256];
for (int i = 0; i < 256; i++)
pRGB[i].rgbBlue = pRGB[i].rgbGreen = pRGB[i].rgbRed = i;
img.SetColorTable(0, 256, pRGB);
}
uchar* psrc = mat->data;
uchar* pdst = (uchar*) img.GetBits();
int imgPitch = img.GetPitch();
for(int y = 0; y < mat->rows; y++)
{
memcpy(pdst, psrc, mat->cols*mat->channels());//mat->step is incorrect for those images created by roi (sub-images!)
psrc += mat->step;
pdst += imgPitch;
}
return 0;
}

Gdiplus::Bitmap to BYTE array?

Here's my attempt (ugly GDI+ and GDI mix...)
// ...
BYTE pixels[BMP_WIDTH * BMP_HEIGHT * BMP_BPP];
HBITMAP hBitmap;
Gdiplus::Bitmap cBitmap(BMP_WIDTH, BMP_HEIGHT, PixelFormat32bppRGB);
Gdiplus::Graphics cGraphics(&cBitmap);
Gdiplus::Pen cPen(Gdiplus::Color(255, 255, 0, 0));
cGraphics.DrawRectangle(&cPen, 0, 0, cBitmap.GetWidth() - 1, cBitmap.GetHeight() - 1);
// and here it get's real ugly, I'd like to change that...
cBitmap.GetHBITMAP(Gdiplus::Color(255, 255, 255), &hBitmap);
GetBitmapBits(hBitmap, sizeof(pixels), pixels);
// ...
Someone told me to use LockBits but I really didn't understand how. I tried it, but I failed so I'm not going to post that attempt, too.
You could use Bitmap::LockBits to get access to a raw array of data. Here you could read about how to use Bitmap::LockBits.
Here's something I wrote that returns a vector of vectors (with the contained vectors representing columns of pixels in the image) when passed a file path:
#include <vector>
std::vector<std::vector<unsigned>> getPixels(const wchar_t *filename, int &width, int &height) {
Gdiplus::Bitmap bitmap(filename);
//Pass up the width and height, as these are useful for accessing pixels in the vector o' vectors.
width = bitmap.GetWidth();
height = bitmap.GetHeight();
auto *bitmapData = new Gdiplus::BitmapData;
//Lock the whole bitmap so we can read pixel data easily.
Gdiplus::Rect rect(0, 0, width, height);
bitmap.LockBits(&rect, Gdiplus::ImageLockModeRead, PixelFormat32bppARGB, bitmapData);
//Get the individual pixels from the locked area.
auto *pixels = static_cast<unsigned *>(bitmapData->Scan0);
//Vector of vectors; each vector is a column.
std::vector<std::vector<unsigned>> resultPixels(width, std::vector<unsigned>(height));
const int stride = abs(bitmapData->Stride);
for(int x = 0; x < width; x++) {
for(int y = 0; y < height; y++) {
//Get the pixel colour from the pixels array which we got earlier.
const unsigned pxColor = pixels[y * stride / 4 + x];
//Get each individual colour component. Bitmap colours are in reverse order.
const unsigned red = (pxColor & 0xFF0000) >> 16;
const unsigned green = (pxColor & 0xFF00) >> 8;
const unsigned blue = pxColor & 0xFF;
//Combine the values in a more typical RGB format (as opposed to the bitmap way).
const int rgbValue = RGB(red, green, blue);
//Assign this RGB value to the pixel location in the vector o' vectors.
resultPixels[x][y] = rgbValue;
}
}
//Unlock the bits that we locked before.
bitmap.UnlockBits(bitmapData);
return resultPixels;
}
Here is how I would do it using GDIPlus Bitmap.LockBits method defined in the header GdiPlusBitmap.h:
Notice that since bitmaps are usually DWORD aligned you may want to discard this unused data that was needed for the alignment, as malat correctly commented..
Gdiplus::BitmapData bitmapData;
Gdiplus::Rect rect(0, 0, bitmap.GetWidth(), bitmap.GetHeight());
//get the bitmap data
if(Gdiplus::Ok == bitmap.LockBits(
&rect, //A rectangle structure that specifies the portion of the Bitmap to lock.
Gdiplus::ImageLockModeRead | Gdiplus::ImageLockModeWrite, //ImageLockMode values that specifies the access level (read/write) for the Bitmap.
bitmap.GetPixelFormat(),// PixelFormat values that specifies the data format of the Bitmap.
&bitmapData //BitmapData that will contain the information about the lock operation.
))
{
//get the lenght of the bitmap data in bytes
int len = bitmapData.Height * std::abs(bitmapData.Stride);
BYTE* buffer = new BYTE[len];
memcpy(bitmapData.Scan0, buffer, len);//copy it to an array of BYTEs
//...
//cleanup
bitmap.UnlockBits(&bitmapData);
delete []buffer;
}
Have you tried supplying the bytes when you create the bitmap:
int width = BMP_WIDTH;
int height = BMP_HEIGHT;
int stride = 4 * width;
BYTE bytes[stride * height];
Gdiplus::Bitmap cBitmap(width, height, stride, PixelFormat32bppRGB, bytes);