I am using a string table in my project and I want to store RGB values in it. how do I convert rgb value from LoadString char to something that can be used for COLORREF for CreateSolidBrush.
According to MSDN COLORREF is a DWORD typedef. So COLORREF cRef = RGB( 0, 0, 0 );is also valid. What I've understood you're trying to is something like:
const char *szTable[] = { "RGB( 255, 255, 255)", "RGB( 255, 0, 255)" }; //etc
COLORREF dwMyColor = szTable[0];
Getting a COLORREF object from a string table. I'm my opinion this is what you should do instead of string table:
COLORREF dwColor1 = RGB( 255, 0, 255 );
COLORREF dwTable[] = { 0xff00ff00, 0xffffffff, dwColor1 };
Why do you NEED a string table to store RGB values anyway? It wasn't clear enough I guess
I got it figured out using:
LoadString(g_hInstance,IDS_STRING151,rBuffer,256);
LoadString(g_hInstance,IDS_STRING152,gBuffer,256);
LoadString(g_hInstance,IDS_STRING153,bBuffer,256);
int r,g,b;
if(EOF == sscanf_s(rBuffer, "%d", &r))
{
//error
}
if(EOF == sscanf_s(gBuffer, "%d", &g))
{
//error
}
if(EOF == sscanf_s(bBuffer, "%d", &b))
{
//error
}
Related
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
This is my method for loading a transparent PNG file into a buffer:
/* static */ void CRibbonButton::LoadImageFromRelativeFilespec(HGLOBAL& rhDIB, bool bLarge,
const CString& rstrImageRelFilespec, UINT32& ruDIBW, int& ruDIBH)
{
USES_CONVERSION;
using namespace RibbonBar ;
// Clear any existing image away.
if (rhDIB != NULL)
::GlobalFree(rhDIB);
// Build the correct filespec.
CString strThisEXE = _T("");
::GetModuleFileName(AfxGetInstanceHandle(),
strThisEXE.GetBuffer(_MAX_PATH + 1),_MAX_PATH);
strThisEXE.ReleaseBuffer();
LPCTSTR lpszPath = (LPCTSTR)strThisEXE ;
LPTSTR lpszFilename = ::PathFindFileName(lpszPath);
CString strPath = strThisEXE.Left( (int)(lpszFilename - lpszPath) );
CString strFilespec = strPath ;
::PathAppend(strFilespec.GetBuffer(_MAX_PATH + 1), rstrImageRelFilespec);
strFilespec.ReleaseBuffer();
HISSRC hSrc = is6_OpenFileSource(CT2A((LPCTSTR)strFilespec));
if (hSrc)
{
// read it
UINT32 w, h;
rhDIB = is6_ReadImage(hSrc, &w, &h, 2, 0); // the "2" = load directly to DIB, in the lowest bit depth possible.
if (rhDIB)
{
// get the dimensions
is6_DIBWidth((BITMAPINFOHEADER *)rhDIB, &ruDIBW);
is6_DIBHeight((BITMAPINFOHEADER *)rhDIB, &ruDIBH);
UINT32 bc;
is6_DIBBitCount((BITMAPINFOHEADER *)rhDIB, &bc);
is6_ClearJPGInputMarkers();
}
else
{
AfxMessageBox(_T("Can't read that image"));
}
is6_CloseSource(hSrc);
}
}
And this is the rendering code:
/* virtual */ void CRibbonButton::PaintData(CDC& rDC)
{
CDC dcMem ;
dcMem.CreateCompatibleDC(NULL); // Screen.
const CRect& rrctImage = GetImageBounds();
if (m_hDIB)
{
// draw to a memory DC
CDC memDC;
if (memDC.CreateCompatibleDC(&rDC))
{
CBitmap bmp;
if (bmp.CreateCompatibleBitmap(&rDC, rrctImage.Width(), rrctImage.Height()))
{
CBitmap *ob = memDC.SelectObject(&bmp);
if (ob)
{
// dark red background
memDC.FillSolidRect(CRect(rrctImage.left, rrctImage.top, rrctImage.Width(), rrctImage.Height()), RibbonBar::kBackColour);
// stretchDrawDIB is typically the fastest way to draw an image from ImgSource.
BOOL ok = is6_StretchDrawDIB(memDC.m_hDC, (BITMAPINFOHEADER *)m_hDIB, 0, 0, m_uDIBW, m_uDIBH);
if (!ok)
{
memDC.SetBkMode(TRANSPARENT);
memDC.SetTextColor(RGB(255, 255, 255));
memDC.TextOut(rrctImage.left, rrctImage.top, _T("X"));
}
// copy this to the window
rDC.BitBlt(rrctImage.left, rrctImage.top, rrctImage.Width(), rrctImage.Height(), &memDC, 0, 0, SRCCOPY);
memDC.SelectObject(ob);
}
}
}
}
dcMem.DeleteDC();
}
It is not drawing the transparent PNG file correctly. I always end up with a black background.
I am using the ISSource libraries for rendering. But the company is now out of business. I am using version 6 library.
Update
Based on the answer I am now loading and rendering the image like this:
CRect rct;
CImage img;
img.Load(_T("d:\\Publishers.png"));
rct.SetRect(rrctImage.left, rrctImage.top, rrctImage.left + img.GetWidth(), rrctImage.top + img.GetHeight());
img.TransparentBlt(rDC.GetSafeHdc(), rct, RGB(255,255,255));
But why do I still get black for where the transparency was set?
If I don't pass RGB(255,255,255) as the last parameter
and use the default I get an exception.
Update
According to the documentation for TransparentBit:
TransparentBlt is supported for source bitmaps of 4 bits per pixel and 8 bits per pixel. Use CImage::AlphaBlend to specify 32 bits-per-pixel bitmaps with transparency.
So, I have stopped using:
img.TransparentBlt(rDC.GetSafeHdc(), rct);
Now I am using:
img.AlphaBlend(rDC.GetSafeHdc(), rct.left, rct.top, rct.Width(), rct.Height(), rct.left, rct.top, rct.Width(), rct.Height(), 0xff, AC_SRC_OVER);
I don't see anything. I confirm the coordinates are right by doing:
CBrush br;
br.CreateStockObject(BLACK_BRUSH);
rDC.FrameRect(rct, &br);
Why do I not see anything?
This is much to complicate. There are existing methods in CImage.
Check out CImage::AlphaBlend or CImage::TransparentBlt.
AlphaBlend: The Dst fields are the coordinates in your DC. the Src values are inside your picture. Usually they start with 0,0 and have the width and height as values. Is xSrc/ySrc are not 0 you have an offset in the source.
I'm trying to create a method that gives me the width of a string in pixels.
My code so far:
inline void getTextWidth(HWND hwnd char* text) {
SIZE textSize;
GetTextExtentPoint32(GetDC(hwnd), text, strlen(text), &textSize);
return ?;
}
I know that I should use LPtoDP (MSDN), but at wants points as parameters and not the SIZE that GetTextExtentPoint32 returns.
How do I convert this?
The SIZE structure contains both a height and a width. Since you only care about the width, you apparently want LPtoDP(textSize.cx);.
I solved it using another method. For everyone who is interested, this is my solution:
int getStringWidth(char *text, HFONT font) {
HDC dc = GetDC(NULL);
SelectObject(dc, font);
RECT rect = { 0, 0, 0, 0 };
DrawText(dc, text, strlen(text), &rect, DT_CALCRECT | DT_NOPREFIX | DT_SINGLELINE);
int textWidth = abs(rect.right - rect.left);
DeleteDC(dc);
return textWidth;
}
I get
Debug assertion failed.
p!=0
and it points to:
_NoAddRefReleaseOnCComPtr<T>* operator->() const throw()
{
ATLASSERT(p!=NULL);
return (_NoAddRefReleaseOnCComPtr<T>*)p;
}
in 'atlcomcli.h'
From what I understand it means I have forgot to initialize a pointer somewhere, but all of them seem to be initialized.
When I use normal pointers instead of 'CComPtr', it throws 'Access Violation Reading Location' at 'font->DrawTextA' in 'D3DFont::Draw' in D3DFont.cpp
//D3DFont.h:
#include <D3DX10.h>
#include <atlbase.h>
#include <string>
class D3DFont
{
public:
D3DFont(void);
~D3DFont(void);
bool Create(ID3D10Device *device, std::string name, int width,
int height, int weight, int mipLevels, bool italic, BYTE charset,
BYTE quality, BYTE pitchAndFamily);
void Draw(LPD3DX10SPRITE sprite, std::string text, int charCount,
LPRECT rect, UINT format, D3DXCOLOR color);
private:
CComPtr<ID3DX10Font> font;
};
//D3DFont.cpp:
#include "D3DFont.h"
D3DFont::D3DFont(void){}
D3DFont::~D3DFont(void){}
bool D3DFont::Create( ID3D10Device *device, std::string name,
int width, int height, int weight, int mipLevels, bool italic,
BYTE charset, BYTE quality, BYTE pitchAndFamily )
{
D3DX10_FONT_DESC fd;
ZeroMemory(&fd, sizeof(D3DX10_FONT_DESC));
fd.Height = height;
fd.Width = width;
fd.Weight = weight;
fd.MipLevels = mipLevels;
fd.Italic = italic;
fd.CharSet = charset;
fd.Quality = quality;
fd.PitchAndFamily = pitchAndFamily;
strcpy_s(fd.FaceName, name.c_str());
// INITIALIZING FONT HERE
D3DX10CreateFontIndirect(device, &fd, &font);
return true;
}
void D3DFont::Draw( LPD3DX10SPRITE sprite, std::string text,
int charCount, LPRECT rect, UINT format, D3DXCOLOR color )
{
// ERROR HERE
font->DrawTextA(sprite, text.c_str(), charCount, rect, format, color);
}
And my use of above functions:
if( !font.Create(d3d.GetDevice(), "Impact", 0, 175, 0, 1, false,
OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE) )
{
MessageBox(0, "Could not create font.", "Error!", MB_OK | MB_ICONERROR);
}
// later on...
RECT r = {35, 50, 0, 0};
font.Draw(0, "Test", -1, &r, DT_NOCLIP, d3d.GetColorObj(1.0f, 1.0f, 0.0f, 1.0f));
What could I miss?
'D3DX10CreateFontIndirect' throws 0x8876086C
Can't find what does it mean, but some google threads are related to d3dDevice, so I guess it must be related to it. Will update when I will have more info.
Calling the D3DX10CreateFontIndirect doesn't actually guarantee that your pointer will be initialized.
Rule of thumb : ALWAYS check HRESULTs when using DirectX functions that initialize a pointer:
HRESULT hr = D3DX10CreateFontIndirect(device, &fd, &font);
if(FAILED(hr)){
//Get the last error, display a message, etc.
//Eventually propagate the error if the code can't continue
//with the font pointer uninitialized.
}
When your function returns E_FAIL, do not try to use the pointer afterward. There are great chances that the values of the parameters are simply incorrect (here, your device pointer might be null or your font description might be incorrect).
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);