I am currently working with images in C & WinAPI, and I want to generate an HBITMAP from a given image path (of a .png picture, for example).
I have managed to write the function solution using GDI+:
#include <windows.h>
#include <gdiplus.h>
#pragma comment(lib, "gdiplus.lib")
HBITMAP generateBitmap(const char* filePath)
{
HBITMAP res = NULL;
std::string fileNameStr = filePath; //convert from char* to std::string
std::wstring unicodeFileName(fileNameStr.begin(), fileNameStr.end()); //convert from string to wstring
GdiPlus::Bitmap bitmap(unicodeFileName.c_str(), false); //gets bitmap from path
bitmap.GetHBITMAP(0, &res);
return res;
}
The problem with this solution, however, is that it requires the GDI+ library, which does not have (as far as I know) a C-compatible version (as it uses features such as classes and templates, it is for C++ only).
Is there any way to implement the function generateBitmap in C, without using C++?
Related
I'm using some C code to take a screenshot of a window, translated directly from a PowerBuilder sample that works perfectly. Here's the part up to where there's a problem:
extern "C" __declspec(dllexport) BOOL __stdcall WindowScreenShot(const wchar_t* fileName, unsigned long x, unsigned long y,
unsigned long width, unsigned long height)
{
HWND ll_hWnd;
HDC ll_hdc, ll_hdcMem;
HBITMAP ll_hBitmap;
HANDLE hDib = NULL, hFile = NULL;
char* lpBitmap = NULL;
BOOL lb_result, lb_ok = FALSE;
BITMAPINFO lstr_Info;
BITMAPFILEHEADER lstr_Header;
int li_pixels;
DWORD dwBmpSize, dwBytesWritten;
// get handle to windows background
ll_hWnd = GetDesktopWindow();
// Get the device context of window and allocate memory
ll_hdc = GetDC(ll_hWnd);
ll_hdcMem = CreateCompatibleDC(ll_hdc);
ll_hBitmap = CreateCompatibleBitmap(ll_hdc, width, height);
if (ll_hBitmap != 0)
{
// Select an object into the specified device context
SelectObject(ll_hdcMem, ll_hBitmap);
// Copy the bitmap from the source to the destination
lb_result = BitBlt(ll_hdcMem, 0, 0, width, height, ll_hdc, x, y, SRCCOPY);
lstr_Info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
// Get the bitmapinfo (THIS LINE IS FAILING CURRENTLY)
if (GetDIBits(ll_hdcMem, ll_hBitmap, 0, height, NULL, &lstr_Info, DIB_RGB_COLORS) > 0)
{ ...
That last call to GetDIBits always fails with the only documented error that it can give, ERROR_INVALID_PARAMETER. Since this code is basically absolutely identical to the PowerBuilder code, in terms of the structures used and Windows APIs called, I just have no idea how to resolve it. I've also read the API docs carefully and it all looks like it should work.
Any bright ideas? Thanks.
Paul Ogilvie's answer resolved it - I was using uninitialized structures because they were automatic variables. As soon as I fixed that the code worked.
I am using WIN32 and C programming to do a window dialog in Visual Studio 2008 in the Windows CE OS using Windows 5.0 Mobile SDK. I insert my two picture boxes using the Resource Dialog Editor and ensure they are allocated IDs in the window resource. I am using SHLoadDIBitmap to display the image. My code compiles without errors but when I run the program, no images appear in the two picture boxes. What am I doing wrong?
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <windowsx.h>
#include <winuser.h>
#include "ScanCAPI.h"
#include "resource.h"
#pragma comment(lib, "Kernel32.lib")
HBITMAP hImage;
HBITMAP hImage1;
.
.
.
switch(uMsg)
{
case WM_INITDIALOG:
hImage = SHLoadDIBitmap(TEXT("\\My Documents\\image1.bmp"));
hImage1 = SHLoadDIBitmap(TEXT("\\My Documents\\image2.bmp"));
if (hImage==NULL) {
MessageBox(0,"hImage returned null",0,0);
} else {
hnd_pic1 = GetDlgItem(hwnd,IDC_STATIC8);
SendMessage(hnd_pic1, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hImage);
}
hnd_pic2 = GetDlgItem(hwnd,IDC_STATIC9);
if (hImage1==NULL) {
MessageBox(0,"hImage1 returned null",0,0);
} else {
SendMessage(hnd_pic2, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hImage1);
}
The following code sample works for me on Windows 10 (SHLoadDIBitmap API seems not valid for Windows 10. I use LoadImage API instead.). You can refer to.
C++ code in dialog box procedure:
case WM_INITDIALOG:
hImage = LoadImage(NULL, L"full_path_to\\image3.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE);
if (NULL == hImage)
errCode = GetLastError();
hwd_static_img = GetDlgItem(hDlg, IDC_STATIC6);
SendMessage(hwd_static_img, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hImage);
return (INT_PTR)TRUE;
Resource script in project_name.rc file:
CONTROL "",IDC_STATIC6,"Static", SS_BITMAP,37,133,136,109
Two notes:
Make sure the image file is a valid bitmap file. For example, you can draw a picture and save as a bitmap using mspaint.exe. If you rename a file from .PNG to .BMP, LoadImage will return a NULL handle but GetLastError return 0 which indicate no error.
Make sure set SS_BITMAP static control style for picture control (IDC_STATIC6).
BTW, no need to put image file in same directory with your project or EXE. Specify the valid full path of the image file will work.
We have a legacy code that draws header parts using the current Windows visual style. The drawing is performed on a GDI+ Graphics object but using the WinAPI DrawThemeBackground function. The core part of this code looks like this:
[DllImport("uxtheme.dll", EntryPoint = "DrawThemeBackground")]
public static extern int DrawThemeBackground(IntPtr hTheme, IntPtr hdc, int iPartId, int iStateId, ref iGRECT pRect, ref iGRECT pClipRect);
IntPtr myHdc = graphics.GetHdc();
DrawThemeBackground(
GetThemeData(themeClass),
myHdc,
themePart,
themeState,
ref myRect, ref myRect);
Now we need to mirror the drawing part for the right-to-left interface. How to do that for the WinForms Graphics object if we draw with WinAPI functions? Is there a GDI+ or GDI instruction or setting that can flip the output from DrawThemeBackground on-the-fly?
P.S. I do know that I can prepare a temporary bitmap with the mirrored output:
using (Bitmap myBitmap = new Bitmap(width, height, graphics))
{
using (Graphics myGraphics = Graphics.FromImage(myBitmap))
{
DrawTheme(myGraphics, ThemeClasses.header, myPart, myState, 0, 0, width, height);
}
myBitmap.RotateFlip(RotateFlipType.RotateNoneFlipX);
graphics.DrawImage(myBitmap, x, y);
}
My intention is to use a GDI+ transformation or something similar that can flip all drawing to the Graphics on-the-fly.
HBITMAP DisplayMap(HDC hThisDC){
HDC hDC=CreateCompatibleDC(hThisDC);
BITMAPINFOHEADER bi;
bi.biSize=sizeof(BITMAPINFOHEADER);
bi.biWidth=670;
bi.biHeight=540;
bi.biPlanes=1;
bi.biBitCount=24;
bi.biCompression=BI_RGB;
int lineSize=((((bi.biWidth*bi.biBitCount)+31)&~31)>>3);
bi.biSizeImage=lineSize*bi.biHeight;
unsigned char* data=(unsigned char*)malloc(bi.biSizeImage);
int off=0;
for(int y=0;y<bi.biHeight;y++){
for(int x=0;x<bi.biWidth;x++){
data[off+3*x]=255;
data[off+3*x+1]=0;
data[off+3*x+2]=127;
}
off+=lineSize;
}
HBITMAP hBitmap=CreateDIBitmap(hDC,&bi,CBM_INIT,data,(BITMAPINFO*)&bi,DIB_RGB_COLORS);
SetDIBits(hDC,hBitmap,0,bi.biHeight,data,(BITMAPINFO*)&bi,DIB_RGB_COLORS);
return hBitmap;
}
//
HBITMAP hBitmap=DisplayMap(GetDC(hwnd));
if(hBitmap==NULL||true){
char* str=(char*)malloc(15);
sprintf(str,"ERROR: %d!",GetLastError());
MessageBox(NULL,str,"ALERT",MB_OK|MB_ICONEXCLAMATION);
}
ShowWindow (hwnd, nFunsterStil);
SendMessage(hFrame, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hBitmap);
//
If I use "(HBITMAP)LoadImage()" to display it, it shows no problem. But as I'm using my function "DisplayMap()" which is supposed to create a HBITMAP out of nothing it doesn't work. The script shows no erros and the "hBitmap" return a valid HBITMAP (not NULL), but don't matter the color I choose to fill the bitmap, it keeps displaying the same full-black image.
I searched for a solution in Google through many sources and I wasn't able to figure out the problem. I thank for any help, has been a long time I don't work with c.The idea is to create and display an image sequence which shall be generate just in time without loading anything from files.
Why do you GetDC from hwnd, but STM_SETIMAGE to hFrame. Try GetDC from hFrame.
I am making a game for my CS class and the sprites I have found online are too small. How do you 'stretch' a bitmap... make them bigger using SDL? (I need to increase there size 50%, there all the same size.) A snippet of example code would be appreciated.
This question does not specify SDL version, and even though SDL2 was not available when the question was written, an SDL2 answer would add completeness here i believe.
Unlike SDL1.2, scaling is possible in SDL2 using the API method SDL_RenderCopyEx. No additional libs besides the basic SDL2 lib are needed.
int SDL_RenderCopyEx(SDL_Renderer* renderer,
SDL_Texture* texture,
const SDL_Rect* srcrect,
const SDL_Rect* dstrect,
const double angle,
const SDL_Point* center,
const SDL_RendererFlip flip)
By setting the size of dstrect one can scale the texture to an integer number of pixels. It is also possible to rotate and flip the texture at the same time.
Reference: https://wiki.libsdl.org/SDL_RenderCopyEx
Create your textures as usual:
surface = IMG_Load(filePath);
texture = SDL_CreateTextureFromSurface(renderer, surface);
And when it's time to render it, call SDL_RenderCopyEx instead of SDL_RenderCopy
You're going to get a better looking result using software that is designed for this task. A good option is ImageMagick. It can be used from the command line or programatically.
For example, from the command line you just enter:
convert sprite.bmp -resize 150% bigsprite.bmp
If for some strange reason you want to write your own bilinear resize, this guy looks like he knows what he is doing.
have you tried?
SDL_Rect src, dest;
src.x = 0;
src.y = 0;
src.w = image->w;
src.h = image->h;
dest.x = 100;
dest.y = 100;
dest.w = image->w*1.5;
dest.h = image->h*1.5;
SDL_BlitSurface(image, &src, screen, &dest);
Use for stretch the undocumented function of SDL:
extern DECLSPEC int SDLCALL SDL_SoftStretch(SDL_Surface *src, SDL_Rect *srcrect,
SDL_Surface *dst, SDL_Rect *dstrect);
Like:
SDL_SoftStretch(image, &src, screen, &dest);