I m writing code for scaling down the image in VC++. When i save destination bitmap it gives monochrome image.
Code:
int iNewWidth = 400;
int iNewHeight = 500;
CImage image;
HRESULT rs=image.Load(_T("E:\\input.jpg"));
int a=10;
CDC destDC;
int res=destDC.CreateCompatibleDC(NULL);
HDC hdcDest=HDC(destDC);
HBITMAP hDestBitmap=CreateCompatibleBitmap(hdcDest, iNewWidth, iNewHeight);
HBITMAP hOldBitmap=(HBITMAP)SelectObject(hdcDest,hDestBitmap);
SetStretchBltMode(hdcDest,BLACKONWHITE);
BOOL bl=image.StretchBlt(hdcDest,0, 0, iNewWidth, iNewHeight, 0, 0, image.GetWidth(), image.GetHeight(), SRCERASE);
HRESULT res2;
CImage new_image;
new_image.Attach(hDestBitmap);
res2=new_image.Save(_T("E:\\NewImage.jpg"));
HBITMAP hb=new_image.Detach();
ReleaseDC(NULL,hdcDest);
I will be very thankful if someone help me here.
Thanks in advance
When you create a DC it initially has a monochrome bitmap selected into it. When you use CreateCompatibleBitmap with that DC, it uses the characteristics of that selected bitmap - i.e. it creates another monochrome bitmap.
Use the DC returned by GetDC(NULL) in your CreateCompatibleBitmap call.
Related
I am trying to do some basic drawing with skia. Since I'm working on grayscale images I want to use the corresponding color type. The minimal Example I want to use is:
int main(int argc, char * const argv[])
{
int width = 1000;
int heigth = 1000;
float linewidth = 10.0f;
SkImageInfo info = SkImageInfo::Make(
width,
heigth,
SkColorType::kAlpha_8_SkColorType,
SkAlphaType::kPremul_SkAlphaType
);
SkBitmap img;
img.allocPixels(info);
SkCanvas canvas(img);
canvas.drawColor(SK_ColorBLACK);
SkPaint paint;
paint.setColor(SK_ColorWHITE);
paint.setAlpha(255);
paint.setAntiAlias(false);
paint.setStrokeWidth(linewidth);
paint.setStyle(SkPaint::kStroke_Style);
canvas.drawCircle(500.0f, 500.0f, 100.0f, paint);
bool success = SkImageEncoder::EncodeFile("B:\\img.png", img,
SkImageEncoder::kPNG_Type, 100);
return 0;
}
But the saved image does not contain the circle that was drawn. If I replace kAlpha_8_SkColorType with kN32_SkColorType I get the expected result. How can I draw the circle onto a 8 bit grayscale image? I'm working with Visual Studio 2013 on a 64bit Windows machine.
kN32_SkColorType type result
kAlpha_8_SkColorType result
You should use kGray_8_SkColorType than kAlpha_8_SkColorType.
The kAlpha_8_SkColorType used for bitmap mask.
I'm almost there with my little "window background from PNG image" project in Linux. I use pure X11 API and the minimal LodePNG to load the image. The problem is that the background is the negative of the original PNG image and I don't know what could be the problem.
This is basically the code that loads the image then creates the pixmap and applies the background to the window:
// required headers
// global variables
Display *display;
Window window;
int window_width = 600;
int window_height = 400;
// main entry point
// load the image with lodePNG (I didn't modify its code)
vector<unsigned char> image;
unsigned width, height;
//decode
unsigned error = lodepng::decode(image, width, height, "bg.png");
if(!error)
{
// And here is where I apply the image to the background
Screen* screen = NULL;
screen = DefaultScreenOfDisplay(display);
// Creating the pixmap
Pixmap pixmap = XCreatePixmap(
display,
XDefaultRootWindow(display),
width,
height,
DefaultDepth(display, 0)
);
// Creating the graphic context
XGCValues gr_values;
gr_values.function = GXcopy;
gr_values.background = WhitePixelOfScreen(display);
// Creating the image from the decoded PNG image
XImage *ximage = XCreateImage(
display,
CopyFromParent,
DisplayPlanes(display, 0),
ZPixmap,
0,
(char*)&image,
width,
height,
32,
4 * width
);
// Place the image into the pixmap
XPutImage(
display,
pixmap,
gr_context,
ximage,
0, 0,
0, 0,
window_width,
window_height
);
// Set the window background
XSetWindowBackgroundPixmap(display, window, pixmap);
// Free up used resources
XFreePixmap(display, pixmap);
XFreeGC(display, gr_context);
}
The image is decoded (and there's the possibility to be badly decoded) then it is applied to the background but, as I said, the image colors are inversed and I don't know why.
MORE INFO
After decoding I encoded the same image into a PNG file which is identical to the decoded one, so it looks like the problem is not related to LodePNG but to the way I play with XLib in order to place it on the window.
EVEN MORE INFO
Now I compared the inverted image with the original one and found out that somewhere in my code the RGB is converted to BGR. If one pixel on the original image is 95, 102, 119 on the inverted one it is 119, 102, 95.
I found the solution here. I am not sure if is the best way but the simpler for sure.
In my MFC project, I need to read and convert a Monochrome bitmap file into CByteArray. While reading the bitmap file by using 'CFile' class with the mode of 'Read', it seems like it gives more length than its original.
My MFC code:-
CFile ImgFile;
CFileException FileExcep;
CByteArray* pBinaryImage = NULL;
strFilePath.Format("%s", "D:\\Test\\Graphics0.bmp");
if(!ImgFile.Open((LPCTSTR)strFilePath,CFile::modeReadWrite,&FileExcep))
{
return NULL;
}
pBinaryImage = new CByteArray();
pBinaryImage->SetSize(ImgFile.GetLength());
// get the byte array's underlying buffer pointer
LPVOID lpvDest = pBinaryImage->GetData();
// perform a massive copy from the file to byte array
if(lpvDest)
{
ImgFile.Read(lpvDest,pBinaryImage->GetSize());
}
ImgFile.Close();
Note: File length is been set to bytearray obj.
I checked with C# with the following sample:-
Bitmap bmpImage = (Bitmap)Bitmap.FromFile("D:\\Test\\Graphics0.bmp");
ImageConverter ic = new ImageConverter();
byte[] ImgByteArray = (byte[])ic.ConvertTo(bmpImage, typeof(byte[]));
While comparing the size of "pBinaryImage" and "ImgByteArray", its not same and I guess "ImgByteArray" size is the correct one since from this array value, I can get my original bitmap back.
As I noted in comments, by reading the whole file with CFile, you are also reading the bitmap headers, which will be corrupting your data.
Here is an example function, showing how to load a monochrome bitmap from file, wrap it in MFC's CBitmap object, query the dimensions etc. and read the pixel data into an array:
void LoadMonoBmp(LPCTSTR szFilename)
{
// load bitmap from file
HBITMAP hBmp = (HBITMAP)LoadImage(NULL, szFilename, IMAGE_BITMAP, 0, 0,
LR_LOADFROMFILE | LR_MONOCHROME);
// wrap in a CBitmap for convenience
CBitmap *pBmp = CBitmap::FromHandle(hBmp);
// get dimensions etc.
BITMAP pBitMap;
pBmp->GetBitmap(&pBitMap);
// allocate a buffer for the pixel data
unsigned int uBufferSize = pBitMap.bmWidthBytes * pBitMap.bmHeight;
unsigned char *pPixels = new unsigned char[uBufferSize];
// load the pixel data
pBmp->GetBitmapBits(uBufferSize, pPixels);
// ... do something with the data ....
// release pixel data
delete [] pPixels;
pPixels = NULL;
// free the bmp
DeleteObject(hBmp);
}
The BITMAP structure will give you information about the bitmap (MSDN here) and, for a monochrome bitmap, the bits will be packed into the bytes you read. This may be another difference with the C# code, where it is possible that each bit is unpacked into a whole byte. In the MFC version, you will need to interpret this data correctly.
I am new to working with MFC and bitmaps. I have a HWND, which I want to print onto a bitmap using WM_PRINTCLIENT. This is what I have thus far:
EDIT:
CRect rcWindow;
GetClientRect(hWnd, &rcWindow);
HDC hDC = GetDC(hWnd);
HDC hBitmapDC = CreateCompatibleDC(hDC);
HBITMAP hBitmap = CreateCompatibleBitmap(hDC, rcWindow.Width(), rcWindow.Height());
SelectObject(hBitmapDC, hBitmap);
SendMessage(hWnd, WM_PRINTCLIENT, (WPARAM)hBitmapDC, PRF_CHILDREN | PRF_CLIENT | PRF_NONCLIENT);
CImage image;
image.Attach(hBitmap);
image.Save(_T("C:\\Test.bmp"), Gdiplus::ImageFormatBMP);
This however results in a bitmap that is all black. Can anyone see what I am doing wrong?
Try the following :
HDC hBitmapDC = ::CreateCompatibleDC(hDC);
HBITMAP hBitmap = ::CreateCompatibleBitmap(hDC, rcWindow.Width(), rcWindow.Height());
::SelectObject(hBitmapDC, hBitmap);
// Blt the existing background into the bitmap DC
::BitBlt(hBitmapDC,
0, 0, rcWindow.Width(), rcWindow.Height(),
hDC, rcWindow.left, rcWindow.top, SRCCOPY);
Don't forget to delete the bitmap object using ::DeleteObject, and the bitmap DC using DeleteDC, when you've finished with them...
Hope this helps
GetDIBits: trying to modify the bitmap, but not sure how to go about it? I tried lpvBits but it crashes out in the comparison in the "pig" area. How should I do this? thx
LPVOID lpvBits=NULL; // pointer to bitmap bits array
BITMAPINFO bi;
ZeroMemory(&bi.bmiHeader, sizeof(BITMAPINFOHEADER));
bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
if (!GetDIBits(dc, m_bmp, 0, 400, lpvBits, &bi, DIB_RGB_COLORS))
AfxMessageBox("1");
char *pig = (char*)lpvBits;
for (int m=0;m<100;m++)
{
if (pig[m] > 100)
{
pig[m] = 250;
}
}
SetDIBits( dc, m_bmp, 0, 400, (void *)pig, &bi, DIB_RGB_COLORS );
http://msdn.microsoft.com/en-us/library/dd144879(v=vs.85).aspx
lpvBits [out]
A pointer to a buffer to receive the bitmap data. If this parameter is NULL, the function passes the dimensions and format of the bitmap to the BITMAPINFO structure pointed to by the lpbi parameter.
example found here:
http://msdn.microsoft.com/en-us/library/dd183402(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/ms969901.aspx
http://www.codeproject.com/KB/graphics/drawing2bitmap.aspx
http://www.cplusplus.com/forum/general/28469/
Read the documentation for GetDIBits carefully - the lpvBits pointer is not returned to you - you need to allocate enough memory for the bitmap data you want to fetch, and pass it to GetDIBits to fill it in with image data.