I want to create an image from the desktop and set it to gray using BITMAPINFO, but it keeps showing me the warning, "Warning C6255 _alloca indicates failure by raising a stack overflow exception. Consider using _malloca instead".
I would appreciate any advice.
HBITMAP CreateGreyscaleBitmap(int cx, int cy)
{
BITMAPINFO* pbmi = (BITMAPINFO*)alloca(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256);
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pbmi->bmiHeader.biWidth = cx;
pbmi->bmiHeader.biHeight = cy;
pbmi->bmiHeader.biPlanes = 1;
pbmi->bmiHeader.biBitCount = 8;
pbmi->bmiHeader.biCompression = BI_RGB;
pbmi->bmiHeader.biSizeImage = 0;
pbmi->bmiHeader.biXPelsPerMeter = 14173;
pbmi->bmiHeader.biYPelsPerMeter = 14173;
pbmi->bmiHeader.biClrUsed = 0;
pbmi->bmiHeader.biClrImportant = 0;
for (int i = 0; i < 256; i++)
{
pbmi->bmiColors[i].rgbRed = i;
pbmi->bmiColors[i].rgbGreen = i;
pbmi->bmiColors[i].rgbBlue = i;
pbmi->bmiColors[i].rgbReserved = 0;
}
PVOID pv;
return CreateDIBSection(NULL, pbmi, DIB_RGB_COLORS, &pv, NULL, 0);
}
Trying to convert 32 bit image B8R8G8A8 to 24bit image R8G8B8 and 16bit R5G5B5.
But result is very strange, maybe I do not understand how to convert image properly. How to do it properly and fix colors?
Input image:
After Convert32to16():
After Convert32to24():
stdafx.h
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//
#pragma once
#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
#include <iostream>
#include <fstream>
#include <windows.h>
// TODO: reference additional headers your program requires here
ImageConverter.cpp
#include "stdafx.h"
using std::cout;
using std::endl;
using std::ofstream;
using std::ifstream;
void Convert32to24(void* B8G8R8A8, BYTE* R8G8B8, int width, int height)
{
long B8G8R8A8Size = (width * height * 4);
long j = 0;
for (long i = 0; i < (B8G8R8A8Size - 3); i = i + 4)
{
BYTE Red = ((PBYTE)B8G8R8A8)[i + 2];
BYTE Green = ((PBYTE)B8G8R8A8)[i + 1];
BYTE Blue = ((PBYTE)B8G8R8A8)[i];
BYTE Alpha = ((PBYTE)B8G8R8A8)[i + 3];
R8G8B8[j] = Red;
R8G8B8[j + 1] = Green;
R8G8B8[j + 2] = Blue;
j = j + 3;
}
}
void Convert32to16(void* B8G8R8A8, BYTE* R5G5B5, int width, int height)
{
long B8G8R8A8Size = (width * height * 4);
long j = 0;
for (long i = 0; i < (B8G8R8A8Size - 3); i = i + 4)
{
BYTE Red = ((PBYTE)B8G8R8A8)[i + 2] >> 3;
BYTE Green = ((PBYTE)B8G8R8A8)[i + 1] >> 3;
BYTE Blue = ((PBYTE)B8G8R8A8)[i] >> 3;
BYTE Alpha = ((PBYTE)B8G8R8A8)[i + 3];
uint16_t RGB565 = ((Red >> 3) << 11) | ((Green >> 2) << 5) | (Blue >> 3);
R5G5B5[j] = RGB565 >> 8;
R5G5B5[j + 1] = RGB565 & 0xFF;
j = j + 2;
}
}
void WriteDataToBmp(const WCHAR *filename, void *imageData, int width, int height, int BitCount, int bytesPerPixel)
{
HANDLE hdl = INVALID_HANDLE_VALUE;
DWORD bytesWritten;
BITMAPFILEHEADER fileHeader;
BITMAPINFOHEADER fileInfo;
fileInfo.biSize = sizeof(BITMAPINFOHEADER);
fileInfo.biBitCount = BitCount;
fileInfo.biCompression = BI_RGB;
fileInfo.biWidth = width;
fileInfo.biHeight = 0 - height;
fileInfo.biPlanes = 1;
fileInfo.biSizeImage = (width * height * bytesPerPixel);
fileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + fileInfo.biSizeImage;
fileHeader.bfType = 'MB';
fileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
hdl = CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
if (hdl == INVALID_HANDLE_VALUE)
{
return;
}
WriteFile(hdl, &fileHeader, sizeof(fileHeader), &bytesWritten, NULL);
WriteFile(hdl, &fileInfo, sizeof(fileInfo), &bytesWritten, NULL);
WriteFile(hdl, imageData, fileInfo.biSizeImage, &bytesWritten, NULL);
CloseHandle(hdl);
}
unsigned char* ReadDataFromBmp(char* filename)
{
FILE* f = fopen(filename, "rb");
unsigned char info[54];
fread(info, sizeof(unsigned char), 54, f);
int width = *(int*)&info[18];
int height = *(int*)&info[22];
int size = abs(4 * width * height);
unsigned char* data = new unsigned char[size];
fread(data, sizeof(unsigned char), size, f);
fclose(f);
return data;
}
int main(int args, char** cat) {
int width = 1440;
int height = 900;
int bytesOnPixel;
BYTE *OutputImage24Bit = new BYTE[width * height * 3];
BYTE *OutputImage16Bit = new BYTE[width * height * 2];
unsigned char* inputImage32Bit = ReadDataFromBmp((char*)"E:/TestImage.bmp");
bytesOnPixel = 2;
Convert32to16(inputImage32Bit, OutputImage16Bit, width, height);
WriteDataToBmp(L"E:/TestImage16bit.bmp", OutputImage16Bit, width, height, 8 * bytesOnPixel, bytesOnPixel);
bytesOnPixel = 3;
Convert32to24(inputImage32Bit, OutputImage24Bit, width, height);
WriteDataToBmp(L"E:/TestImage24bit.bmp", OutputImage24Bit, width, height, 8 * bytesOnPixel, bytesOnPixel);
return 1;
}
fileInfo.biCompression = BI_RGB;
16-bit bitmap uses BI_BITFIELDS compression. In addition 16-bit bitmap has to populate the color table to show if it is using 555 format, 565 format, or a different format.
24-bit and 16-bit bitmap need padding. Albeit, that's not an issue if the width in bytes is a multiple of 4. In general you cannot read/write pixel after pixel because the padding can throw everything off. Instead make 2 loops to go through the height and width. Pixel size would also depend on padding.
Note that you can do the same with or GDI+ or WIC. You can change the bitmap to different formats PixelFormat16bppRGB555, PixelFormat16bppRGB565, PixelFormat16bppARGB1555, PixelFormat24bppRGB...
GDI+ example:
int main()
{
Gdiplus::GdiplusStartupInput tmp;
ULONG_PTR token;
Gdiplus::GdiplusStartup(&token, &tmp, NULL);
auto *source = Gdiplus::Bitmap::FromFile(L"test.bmp");
auto *destination = source->Clone(0, 0, source->GetWidth(), source->GetHeight(),
PixelFormat16bppRGB565);
CLSID clsid_bmp;
CLSIDFromString(L"{557cf400-1a04-11d3-9a73-0000f81ef32e}", &clsid_bmp);
destination->Save(L"copy.bmp", &clsid_bmp);
delete destination;
delete source;
Gdiplus::GdiplusShutdown(token);
return 0;
}
Home made version: (using std::vector for memory, instead of new/delete)
void Convert32to24(const wchar_t* file, std::vector<BYTE> &src, int width, int height)
{
int width_in_bytes_32 = width * 4;
int width_in_bytes_24 = ((width * 24 + 31) / 32) * 4;
DWORD size = width_in_bytes_24 * height;
std::vector<BYTE> dst(size);
for(int h = 0; h < height; h++)
for(int w = 0; w < width; w++)
{
int i = h * width_in_bytes_32 + w * 4;
int j = h * width_in_bytes_24 + w * 3;
dst[j + 0] = src[i + 0];
dst[j + 1] = src[i + 1];
dst[j + 2] = src[i + 2];
}
BITMAPFILEHEADER bf = { 'MB', 54 + size, 0, 0, 54 };
BITMAPINFOHEADER bi = { sizeof(bi), width, height, 1, 24, BI_RGB };
std::ofstream fout(file, std::ios::binary);
fout.write((char*)&bf, sizeof(bf));
fout.write((char*)&bi, sizeof(bi));
fout.write((char*)&dst[0], size);
}
void Convert32to16(const wchar_t* file, std::vector<BYTE> &src, int width, int height)
{
int width_in_bytes_32 = width * 4;
int width_in_bytes_16 = ((width * 16 + 31) / 32) * 4;
DWORD size = width_in_bytes_16 * height;
std::vector<BYTE> dst(size);
for(int h = 0; h < height; h++)
for(int w = 0; w < width; w++)
{
int i = h * width_in_bytes_32 + w * 4;
int j = h * width_in_bytes_16 + w * 2;
//555 format, each color is from 0 to 32, instead of 0 to 256
uint16_t blu = (uint16_t)(src[i + 0] * 31.f / 255.f);
uint16_t grn = (uint16_t)(src[i + 1] * 31.f / 255.f);
uint16_t red = (uint16_t)(src[i + 2] * 31.f / 255.f);
uint16_t sum = (red) | (grn << 5) | (blu << 10);
memcpy(&dst[j], &sum, 2);
}
BITMAPFILEHEADER bf = { 'MB', 54 + size, 0, 0, 54 };
BITMAPINFOHEADER bi = { sizeof(bi), width, height, 1, 16, BI_BITFIELDS };
std::ofstream fout(file, std::ios::binary);
fout.write((char*)&bf, sizeof(bf));
fout.write((char*)&bi, sizeof(bi));
//555 format
COLORREF color[]{
0b0000000000011111,//31
0b0000001111100000,//31 << 5
0b0111110000000000 //31 << 10
};
fout.write((char*)&color, sizeof(color));
fout.write((char*)&dst[0], size);
}
int main()
{
const wchar_t* file_32 = L"E:\\TestImage.bmp";
const wchar_t* file_16 = L"E:\\OutputImage16Bit.bmp";
const wchar_t* file_24 = L"E:\\OutputImage24Bit.bmp";
BITMAPFILEHEADER bh;
BITMAPINFOHEADER bi;
std::ifstream fin(file_32, std::ios::binary);
if(!fin)
return 0;
fin.read((char*)&bh, sizeof(bh));
fin.read((char*)&bi, sizeof(bi));
if(bi.biBitCount != 32)
return 0;
std::vector<BYTE> source(bh.bfSize);
fin.read((char*)&source[0], bh.bfSize);
Convert32to16(file_16, source, bi.biWidth, bi.biHeight);
Convert32to24(file_24, source, bi.biWidth, bi.biHeight);
return 0;
}
After i draw many circle i want handle collisions between a circle but i don't know how to do it . And I want the color of the circle is random . I use function RGB() but it doesn't work . Please help me ! . Thanks .
My code
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
HBRUSH brush;
HBRUSH hBrush;
HPEN hPen;
static int dX[10] , dY[10] ;
static int x[10], y[10], oldX[10], oldY[10];
switch (message)
{
case WM_CREATE:
SetTimer(hWnd, 1, 3, NULL);
Beep(750, 300);
for (int i = 0; i < 10; i++){
dX[i] = rand() % 15 + 0;
dY[i] = rand() % 15 + 0;
x[i] = rand() % 15 + 0;
y[i] = rand() % 15 + 0;
oldX[i] = x[i];
oldY[i] = y[i];
}
break;
case WM_TIMER:
hdc = GetDC(hWnd);
brush = (HBRUSH)SelectObject(hdc, GetStockObject(WHITE_BRUSH));
RECT temp[10];
RECT rect;
GetClientRect(hWnd, &rect);
brush = (HBRUSH)SelectObject(hdc, GetStockObject(RGB(rand() % 255 + 0, rand() % 255 + 0, rand() % 255 + 0)));
for (int i = 0; i <10; i++){
temp[i].left = oldX[i];
temp[i].top = oldY[i];
temp[i].right = oldX[i] + 30;
temp[i].bottom = oldY[i] + 30;
FillRect(hdc, &temp[i], brush);
Ellipse(hdc, x[i], y[i], 30 + x[i], 30 + y[i]);
oldX[i] = x[i];
oldY[i] = y[i];
x[i] += dX[i];
y[i] += dY[i];
if (x[i] + 30 > rect.right || x[i] < 0)
{
dX[i] = -dX[i];
}
if (y[i] + 30 > rect.bottom || y[i] < 0)
{
dY[i] = -dY[i];
}
}
SelectObject(hdc, brush);
ReleaseDC(hWnd, hdc);
break;
My picture Demo here .
http://www.upsieutoc.com/images/2014/07/14/289ccd.jpg
I'm resizing a bird image using the following code:
private Image resizeImage(Image src) {
int srcWidth = src.getWidth();
int srcHeight = src.getHeight();
int screenWidth=getWidth()/3;
int screenHeight=getHeight()/3;
Image tmp = Image.createImage(screenWidth, srcHeight);
Graphics g = tmp.getGraphics();
int ratio = (srcWidth << 16) / screenWidth;
int pos = ratio/2;
//Horizontal Resize
for (int x = 0; x < screenWidth; x++) {
g.setClip(x, 0, 1, srcHeight);
g.drawImage(src, x - (pos >> 16), 0, Graphics.LEFT | Graphics.TOP);
pos += ratio;
}
Image resizedImage = Image.createImage(screenWidth, screenHeight);
g = resizedImage.getGraphics();
ratio = (srcHeight << 16) / screenHeight;
pos = ratio/2;
//Vertical resize
for (int y = 0; y < screenHeight; y++) {
g.setClip(0, y, screenWidth, 1);
g.drawImage(tmp, 0, y - (pos >> 16), Graphics.LEFT | Graphics.TOP);
pos += ratio;
}
return resizedImage;
}
The image is resized but it has white background along with it as shown. How to get only resized image with transparent background..?
Here is an Image scaling function I've been using. Includes transparency. Found here: http://willperone.net/Code/codescaling.php
public Image scale(Image original, int newWidth, int newHeight) {
int[] rawInput = new int[original.getHeight() * original.getWidth()];
original.getRGB(rawInput, 0, original.getWidth(), 0, 0, original.getWidth(), original.getHeight());
int[] rawOutput = new int[newWidth * newHeight];
// YD compensates for the x loop by subtracting the width back out
int YD = (original.getHeight() / newHeight) * original.getWidth() - original.getWidth();
int YR = original.getHeight() % newHeight;
int XD = original.getWidth() / newWidth;
int XR = original.getWidth() % newWidth;
int outOffset = 0;
int inOffset = 0;
for (int y = newHeight, YE = 0; y > 0; y--) {
for (int x = newWidth, XE = 0; x > 0; x--) {
rawOutput[outOffset++] = rawInput[inOffset];
inOffset += XD;
XE += XR;
if (XE >= newWidth) {
XE -= newWidth;
inOffset++;
}
}
inOffset += YD;
YE += YR;
if (YE >= newHeight) {
YE -= newHeight;
inOffset += original.getWidth();
}
}
rawInput = null;
return Image.createRGBImage(rawOutput, newWidth, newHeight, true);
}
This code works perfect on 32 bit system color (Windows 7),
but it doesn't work on 16 bit color - menu bitmaps not transparent!!!:
...
HBITMAP rv = rgb(hsrc, 16);
...
HBITMAP rgb(HBITMAP hsrc, WORD wBitsPixel) {
HBITMAP hold = NULL;
HDC hdcsrc = NULL, hdc = NULL;
BITMAP bmp = {0};
HBITMAP dib = NULL;
UCHAR *dst = NULL, *src = NULL, *tmp = NULL;
UCHAR alpha;
int bpl;
ULONG x, y;
DWORD bmp_size = 0;
HANDLE hdib = NULL;
char *lpbitmap = NULL;
int rv = 0;
hdc = GetDC(m_hMainDlg);
hdcsrc = CreateCompatibleDC(hdc);
hold = (HBITMAP)SelectObject(hdcsrc, hsrc);
rv = GetObject(hsrc, sizeof(BITMAP), &bmp);
BITMAPINFOHEADER bi = {0};
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = bmp.bmWidth;;
bi.biHeight = bmp.bmHeight;
bi.biPlanes = 1;
bi.biBitCount = wBitsPixel;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
bmp_size = ((bmp.bmWidth * bi.biBitCount + 31) / 32) * 4 * bmp.bmHeight;
hdib = GlobalAlloc(GHND, bmp_size);
lpbitmap = (char *)GlobalLock(hdib);
/* Get bits of source bitmap. */
GetDIBits(hdcsrc, hsrc, 0, bmp.bmHeight, lpbitmap, (BITMAPINFO *)&bi, DIB_RGB_COLORS);
/* For destination bitmap */
BITMAPINFO bmi = {0};
bmi.bmiHeader.biSize = sizeof(BITMAPINFO);
bmi.bmiHeader.biWidth = bmp.bmWidth;
bmi.bmiHeader.biHeight = bmp.bmHeight;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = wBitsPixel;
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biSizeImage = 0;
bmi.bmiHeader.biXPelsPerMeter = 0;
bmi.bmiHeader.biYPelsPerMeter = 0;
bmi.bmiHeader.biClrUsed = 0;
bmi.bmiHeader.biClrImportant = 0;
dib = CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, (void **)&dst, NULL, 0);
bpl = 4 * bmp.bmWidth; /* bytes per line */
src = (UCHAR *)lpbitmap;
for (y = 0; y < bmp.bmHeight; y++, src += bpl) {
tmp = src;
for (x = 0; x < bmp.bmWidth; x++) {
alpha = tmp[3];
dst[0] = tmp[0] * alpha / 255;
dst[1] = tmp[1] * alpha / 255;
dst[2] = tmp[2] * alpha / 255;
dst[3] = alpha;
dst += 4;
tmp += 4;
}
}
// free resources
ReleaseDC(m_hMainDlg, hdc);
SelectObject(hdcsrc, hold);
DeleteDC(hdcsrc);
GlobalUnlock(hdib);
GlobalFree(hdib);
return dib;
}