I am trying to add a background image to a X11 window, in Linux. I use the simple LodePNG to decode the PNG image into raw data (RGBA) then I try to set the window background.
What happens is that the window shows up for a while then it unexpectedly closes back. If I comment out the XCreateImage and XPutImage function (including the destructors) the window shows up correctly, so the window creation is not a problem.
My code looks like this:
// Headers here (xlib, lodepng) ...
// Global vars ...
Display *display;
Window window;
int window_width = 640;
int window_height = 480;
// Entry point, initialization, window creation ...
int main(int argc, char* argv[]) {
vector<unsigned char> image; //the raw pixels
unsigned width, height;
// Decode
unsigned error = lodepng::decode(image, width, height, "bg.png");
// If there's no error continue
if(!error)
{
Pixmap pixmap = XCreatePixmap
(
display,
XDefaultRootWindow(display),
width,
height,
DefaultDepth(display, 0)
);
XGCValues gr_values;
GC gr_context = XCreateGC
(
display,
window,
GCBackground,
&gr_values
);
// Here is where it fails !!!
unsigned rowbytes = 0;
XImage *ximage = XCreateImage
(
display,
CopyFromParent,
32,
XYPixmap,
0,
(char*)image.data(),
width,
height,
32,
rowbytes
);
XPutImage(
display,
pixmap,
gr_context,
ximage,
0, 0,
0, 0,
window_width,
window_height
);
XSetWindowBackgroundPixmap(display, window, pixmap);
XFreePixmap(display, pixmap);
XFreeGC(display, gr_context);
XDestroyImage(ximage);
}
}
After I decode the PNG I can see that I get the correct width and height of the image. The size of the raw data (image variable) is always 819200, no matter what image I choose, which is a bit weird and I wonder if LodePNG is not loading the image correctly (yet it gives no error and correct width and height). Other causes of this problem, I don't know. I don't get any error message, the window just closes after being saw a little bit. Maybe some of the arguments of XCreateImage is wrong but I can't figure out which.
Related
I wanted to create a separate function where I could just send a string and it will render the text appropriately so that I didn't need to copy-paste same stuff. The function I came up with is in the following.
void renderText(SDL_Renderer* renderer, char* text,
char* font_name, int font_size,
SDL_Color color, SDL_Rect text_area)
{
/* If TTF was not initialized initialize it */
if (!TTF_WasInit()) {
if (TTF_Init() < 0) {
printf("Error initializing TTF: %s\n", SDL_GetError());
return EXIT_FAILURE;
}
}
TTF_Font* font = TTF_OpenFont(font_name, font_size);
if (font == NULL) {
printf("Error opening font: %s\n", SDL_GetError());
return;
}
SDL_Surface* surface = TTF_RenderText_Blended(font, text, color);
SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface);
if (!texture) {
printf("error creating texture: %s\n", SDL_GetError());
TTF_CloseFont(font);
return;
}
SDL_RenderCopy(renderer, message, NULL, &text_area);
SDL_FreeSurface(surface);
SDL_DestroyTexture(texture);
TTF_CloseFont(font);
}
Now, sometimes I want to align the text with the window for which I need to know the height and width of the surface that contains the text so that I can use something like (WINDOW_WIDTH - surfaceText->w) / 2 or (WINDOW_HEIGHT - surfaceText->h) / 2. But there is no way to know the height and width of the surface containing the text without creating the surface. And if I end up needing to create the surface then the separation of this function would not live upto its objective.
How do I find out the height and width of the surface containing the text without actually creating the surface in SDL2_ttf library?
You can pass the string to the TTF_SizeText() function, which is defined:
int TTF_SizeText(TTF_Font *font, const char *text, int *w, int *h)
The documentation for this function states:
Calculate the resulting surface size of the LATIN1 encoded text rendered using font. No actual rendering is done, however correct kerning is done to get the actual width. The height returned in h is the same as you can get using 3.3.10 TTF_FontHeight.
Then, once you have the dimensions of the string, you can call your rendering function with the necessary information to align it.
There are also TTF_SizeUTF8() and TTF_SizeUNICODE() versions for different encodings.
Currently I have generated the PDF page as bitmap by using FPDF_RenderPageBitmap method.
is there any method for rendering the PDF page as EMF or as metafile in PDFium?
In the pdfium project there is a sample folder that has a pdfium_test.cc file that has examples of output in different formats. PNG, EMF, BMP, TXT, and PPM are all in the at the present time.
The current code to render an EMF
void WriteEmf(FPDF_PAGE page, const char* pdf_name, int num) {
int width = static_cast<int>(FPDF_GetPageWidth(page));
int height = static_cast<int>(FPDF_GetPageHeight(page));
char filename[256];
snprintf(filename, sizeof(filename), "%s.%d.emf", pdf_name, num);
HDC dc = CreateEnhMetaFileA(nullptr, filename, nullptr, nullptr);
HRGN rgn = CreateRectRgn(0, 0, width, height);
SelectClipRgn(dc, rgn);
DeleteObject(rgn);
SelectObject(dc, GetStockObject(NULL_PEN));
SelectObject(dc, GetStockObject(WHITE_BRUSH));
// If a PS_NULL pen is used, the dimensions of the rectangle are 1 pixel less.
Rectangle(dc, 0, 0, width + 1, height + 1);
FPDF_RenderPage(dc, page, 0, 0, width, height, 0,
FPDF_ANNOT | FPDF_PRINTING | FPDF_NO_CATCH);
DeleteEnhMetaFile(CloseEnhMetaFile(dc));
}
On Windows, you want to call FPDF_RenderPage and pass in the HDC this should allow you to get the EMF data out. You can see the chromium printing code for example usage. There is also FPDF_SetPrintMode which lets you set different modes.
I have read a lot of Stack Overflow over the years when struggling with making sense of Microsoft Windows' strange world of CreateWindowEx() .. etc. This question, when originally asked was "What is the best way to create a fluidly resizable OpenGL window in WinAPI?"
I've been struggling with getting WinAPI to make a window that:
Has an OpenGL context
Is properly centered on the main monitor (or any monitor determined by command line signal) in both multi-monitor and single-monitor displays when in "Windowed" mode or in "Fullscreen" mode
Has a fixed internal client screen size (viewport 2d)
Doesn't allow you to click outside causing it to lose focus at the wrong times or in special cases for multi-monitor
Can be resized fluidly, but doesn't change internal "client size" (meaning that it stretches the OpenGL content which is a fixed size to the new screen size) ... the idea here is to add a layer of virtualization, so that all pixels are expressed in the same 1920x1080 (1080p) coordinate system. This part is no problem for me.
Correctly handles mouse event translation from screen_size -> client_size equivalent via the screen->client ratio
In my homegrown App framework, I have to set the display size, and even then, Windows doesn't give me the right sized window. (Sometimes the title bar is subtracted, sometimes the scrollbars are subtracted, but the context draws under the title bar, for example.)
Also, recently when moving from 2010 EE (Win32 / Windows 7) to 2015 (win32 / Windows 10), I had to change the parameters to recenter the view because it was off-centered on the main display. Now, only sometimes are these values correct or incorrect. If I go "fullscreen" for example, the same values will draw above the top of the screen such that there is an area at the bottom of the screen that shows the "gl clear color" (in my case, orange)
I can play with these things by providing the following command line parameters:
-bordered (default, and has no effect really, is the default windowed mode with the title bar and such)
-borderless (seems to go into fullscreen mode, with the app off-center where win 0,0 is actually in screen center)
-windowed (or -window)
If I don't provide -window, it defaults to "full screen" resolution-adjusted (but only if supported I assume, otherwise it might throw an error).
Anyway, all of this is very bad because
a) I have to write a bajillion cases for each resolution I'm working in, rather than write everything for 1080p and have it adjust to display size, which is what i want because it handles most new displays on laptops and desktops (this is Windows remember) (and only slightly squishes things in those corner cases)
b) I cannot resize the window fluidly, also i have to trap the mouse at center and recalculate the mouse position, so I record only the deltas -- this is to avoid the mouse leaving the window and clicking the desktop, or floating off the monitor to some other monitor, even when it is hidden. I also have to make the mouse cursor invisible so the user doesn't see this, then show a simulated mouse cursor.
c) Users who don't support specifically 1920x1080 won't be able to use full screen mode
Someone pointed this article out in another question (window border width and height in Win32 - how do I get it?):
https://web.archive.org/web/20120716062211/http://suite101.com/article/client-area-size-with-movewindow-a17846
And I've read through this, learning that AdjustWindowRectEx() has some issues:
AdjustWindowRectEx() and GetWindowRect() give wrong size with WS_OVERLAPPED
I don't use WS_OVERLAPPED, so this was only moderately helpful:
AdjustWindowRectEx() and GetWindowRect() give wrong size with WS_OVERLAPPED
Here's how I do it now:
display.Resized(display.w,display.h);
// Fill in the window class structure for testing display type.
winclass.cbSize = sizeof(WNDCLASSEX);
winclass.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
winclass.lpfnWndProc = WinProc;
winclass.cbClsExtra = 0;
winclass.cbWndExtra = 0;
winclass.hInstance = hinstance;
winclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
winclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
winclass.hCursor = LoadCursor(NULL, IDC_ARROW);
winclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
winclass.lpszMenuName = NULL;
winclass.lpszClassName = WINDOW_CLASS_NAME;
// Save the game instance handle
display.hinstance = game_instance = hinstance;
// Register the window class
if (!RegisterClassEx(&winclass)) return(0);
if (!gl.Init(hinstance, display.bits)) {
return(0);
}
// Detect the display size and create the final display profile
DWORD winStyle=
WS_EX_APPWINDOW |
WS_EX_TOPMOST /*|
WS_EX_ACCEPTFILES*/ ;
// Adjust Window, Account For Window Borders
int xPos = GetSystemMetrics(SM_CXSCREEN) - display.w;
int yPos = GetSystemMetrics(SM_CYSCREEN) - display.h;
RECT windowRect = {0, 0, display.w, display.h}; // Define Our Window Coordinates
AdjustWindowRectEx (&windowRect, WS_POPUP, 0, winStyle );
// Create the window
if (!(hwnd = CreateWindowEx(
winStyle, // extended style
WINDOW_CLASS_NAME, // class
gl.winTitle.c_str(), // title
( gl.borderless || CmdLine.Option("-borderless") ) ? (WS_POPUPWINDOW | WS_VISIBLE)
: (gl.noFullscreen ? ((CmdLine.Option("-bordered") ? WS_BORDER : 0) | WS_VISIBLE)
: (WS_POPUP | WS_VISIBLE)), // use POPUP for full screen
gl.noFullscreen && !CmdLine.Option("-recenter") ? xPos / 2 : 0,
gl.noFullscreen && !CmdLine.Option("-recenter") ? yPos / 2 : 0, // initial game window x,y
display.w, // initial game width
display.h, // initial game height
HWND_DESKTOP, // handle to parent
NULL, // handle to menu
hinstance, // instance of this application
NULL)
) // extra creation parms
) {
OUTPUT("WinAPI ERROR: Could not open window.\n");
return(0);
}
if (gl.borderless || CmdLine.Option("-borderless") ) {
LONG lStyle = GetWindowLong(hwnd, GWL_STYLE);
lStyle &= ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZE | WS_MAXIMIZE | WS_SYSMENU);
SetWindowLong(hwnd, GWL_STYLE, lStyle);
LONG lExStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
lExStyle &= ~(WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE);
SetWindowLong(hwnd, GWL_EXSTYLE, lExStyle);
SetWindowPos(hwnd, NULL, 0, 0, display.w, display.h, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER);
}
// Temporary change to full screen mode
ZeroMemory(&game_screen, sizeof(game_screen)); // clear out size of DEVMODE struct
game_screen.dmSize = sizeof(game_screen);
game_screen.dmPelsWidth = display.w;
game_screen.dmPelsHeight = display.h;
game_screen.dmBitsPerPel = display.bits;
game_screen.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;
ChangeDisplaySettings(&game_screen, CDS_FULLSCREEN);
// save the game window handle
display.hwnd = game_window = hwnd;
display.hdc = game_dc = GetDC(display.hwnd = game_window); // get the GDI device context
// set up the pixel format desc struct
pfd = {
sizeof(PIXELFORMATDESCRIPTOR), // size of this PFD
1, // version number
PFD_DRAW_TO_WINDOW | // supports window
PFD_SUPPORT_OPENGL | // supports OpenGL
PFD_DOUBLEBUFFER, // support double buff
PFD_TYPE_RGBA, // request RGBA format
(BYTE)display.bits, // select color depth
0, 0, 0, 0, 0, 0, // color bits ignored
0, // no alpha buff
0, // shift bit ignored
0, // no accum buff
0, 0, 0, 0, // accum bits ignored
16, // 16-bit Z-buff (depth buff)
0, // no stencil buff
0, // no aux buff
PFD_MAIN_PLANE, // main drawing layer
0, // reserved
0, 0, 0 // layer masks ignored
};
int pf; // pixel format
if (!gl.arbMultisampleSupported) {
if (!(pf = ChoosePixelFormat(game_dc, &pfd))) // match the pixel format
{
MessageBox(game_window, "OpenGL could not be initialized -- ChoosePixelFormat Error ; report this to program authors for help!", "OpenGL Error", MB_OK);
return FALSE; // error returned
}
} else {
pf = gl.arbMultisampleFormat;
}
if (!SetPixelFormat(game_dc, pf, &pfd)) // set the pixel format
{
MessageBox(game_window, "OpenGL could not be initialized -- SetPixelFormat Error ; report this to program authors for help!", "OpenGL Error", MB_OK);
return FALSE; // error returned
}
if (!(game_rc = wglCreateContext(game_dc))) // create the rendering context
{
MessageBox(game_window, "OpenGL could not be initialized -- CreateContext Error ; report this to program authors for help!", "OpenGL Error", MB_OK);
return FALSE; // error returned
}
if (!(upload_rc = wglCreateContext(game_dc))) // create the rendering context
{
MessageBox(game_window, "Multiple OpenGL contexts could not be initialized -- CreateContext Error ; report this to program authors for help!", "OpenGL Error", MB_OK);
return FALSE; // error returned
} else { // Share as much as you can between two contexts
if (!wglShareLists(game_rc, upload_rc)) {
// could use GetLastError here
MessageBox(game_window, "wglShareLists -- Error ; report this to program authors for help!", "OpenGL Error", MB_OK);
return FALSE; // error returned
}
}
if (!wglMakeCurrent(game_dc, display.hglrc = game_rc)) // make it current
{
MessageBox(game_window, "OpenGL could not be initialized -- MakeCurrent Error ; report this to program authors for help!", "OpenGL Error", MB_OK);
return FALSE; // error returned
}
ShowCursor(false);
ShowWindow(game_window, SW_SHOWNORMAL);
SetForegroundWindow(game_window);
In the above code, what I get is a window that has no resize functionality, hides the OS mouse cursor, and can only be exitted with ALT-TAB (or ALT-F4), and when it is exitted appears at the back of the windows Z-order. I always open my window using a parameter that sets display.w to 1920 and display.h to 1080, either in full screen or in Windowed mode. WM_SIZE is then called to adjust it to the client area.
Please note that the following WM_SIZE is called during the WinProc right after the initial time I set display.Resized(w,h):
case WM_SIZE:
{
display.Resized(LOWORD(lparam), HIWORD(lparam));
return (0);
}
break;
This is executed exactly once during app load, and in the first case it looks like the values are: 1918,1078
UPDATE: If I use the result of GetWindowRect() here, or GetClientRect() as shown below, the window mysteriously moves to Center-X,Center-Y of screen! What gives??
// RECT rect;
// if ( GetClientRect(hwnd,&rect) ) {
// display.Resized((int)rect.right,(int)rect.bottom);
// }
//if ( GetWindowRect( hwnd, &rect ) ) {
// display.Resized((int)ADIFF(rect.left,rect.right),(int)ADIFF(rect.top,rect.bottom));
//}
display.Resized(LOWORD(lparam), HIWORD(lparam));
return (0);
What steps do I need to take to make the window stretchable such that the context is resized to the view, and the mouse is properly adjusted based on the screen ratio?
Basically, there are too many edge cases to make sense of all of this. As time has gone on since the 2 years ago that I asked this question, I've had other inconsistencies between full screen and window emerge.
From what I understand there are basically 3 types of windows:
Your normal on-screen moveable/resizable window for windowing GUIs, like this browser window (if you are not on mobile)
One matched to a display's resolution support (including resolutions smaller than its native) -- we call this "Full screen" (or Fullscreen, which isn't even a word)
One that is a normal on-screen window, but lacks a title bar, borders and scroll bars, and appears as large as the screen. Referred to "on the street" as a "Borderless Window"
I want to master all of these but in a way that makes them all accessible and doesn't require special cases. I've basically given up on doing so with WinAPI, but obviously multiple companies do this. Following Microsoft's documentation isn't very helpful, and I've experimented with a lot of different CreateWindow CreateWindowEx -- many of these features are deprecated by the way, or don't work at all.
(Maybe the best question is, WHEN WILL MICROSOFT CLEAN UP THIS CRAP? But I think we all know the answer.) .. any help to get it working would be appreciated.
I'm now working in: C++, Windows API, OpenGL 3.x / 4.x, Windows 10.
Background
I am working on a rendering client that draws graphical information it receives from a server. The server sends packets containing non-overlapping rectangles with different solid colors at a frame rate variably defined on the server. I currently have it configured so that the size of the screen being transmitted by the server is different than the size of the window onto which the client is drawing, so scaling is done. I need the client to draw these rectangles as quickly as possible to not fall behind the server's stream.
Currently, I am using SDL 2.0. I am using the streaming texture technique described in the SDL 2 Migration Guide to draw the rectangles onto an SDL_Surface. When the time to display a frame arrives, I calll SDL_UpdateTexture() to overwrite the pixel data for an SDL_Texture, and then I use SDL_RenderCopyEx() to copy the texture to the renderer. I need this function instead of SDL_RenderCopy() so I can specify SDL_FLIP_VERTICAL to account for the fact that the coordinates passed are bitmap-style.
Question
My current approach does not render the rectangles quickly enough. To get the client to be able to keep up with the server, I currently have to reduce the server's upload rate from 30+ FPS to 15- FPS. Even then, I have to make the socket's buffer dangerously large, and I end up getting to watch the client's rendering slowly fall behind and eventually result in packet loss.
What is the fastest way to get SDL to render these rectangles? If I am currently using the fastest method, what other APIs would others recommend to make a client that can keep up?
I have included a stripped-down version of my source code so others can look for improvements/mistakes.
Technical Details
I am using C++11, MinGW32, and SDL2 with Eclipse Kepler CDT and GCC 4.8.2 on Window 7 64-bit.
Stripped Code
int main(int argc, char** args) {
// omitted initialization code
SDL_Init(SDL_INIT_VIDEO);
SDL_Window* window = SDL_CreateWindow(
"RTSC",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
windowWidth,
windowHeight,
SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE
);
SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, 0);
SDL_Surface* surface = SDL_CreateRGBSurface(
0,
sourceWidth,
sourceHeight,
24,
0xFF << 16,
0xFF << 8,
0xFF,
0
);
SDL_FillRect(surface, nullptr, 0);
SDL_Texture* texture = SDL_CreateTexture(
renderer,
surface->format->format,
SDL_TEXTUREACCESS_STREAMING,
sourceWidth,
sourceHeight
);
bool running {true};
while (running) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_QUIT:
running = false;
break;
case SDL_WINDOWEVENT:
switch (event.windowevent.event) {
case SDL_WINDOWEVENT_CLOSE:
running = false;
break;
default:
break;
}
break;
default:
break;
}
}
// omitted packet reception and interpretation code
for (uint32_t i {0}; i < receivedRegions; ++i) {
Region& region = regions[i];
SDL_Rect rect {
(int) region.x,
(int) region.y,
(int) region.width,
(int) region.height
};
uint32_t color =
(region.red << 16) +
(region.green << 8) +
region.blue;
SDL_FillRect(surface, &rect, color);
}
// omitted logic for determining whether to present the frame
SDL_RenderClear(renderer);
SDL_UpdateTexture(texture, nullptr, surface->pixels, surface->pitch);
SDL_RenderCopyEx(
renderer,
texture,
nullptr,
nullptr,
0,
nullptr,
SDL_FLIP_VERTICAL
);
SDL_RenderPresent(renderer);
SDL_FillRect(surface, nullptr, 0);
}
// omitted clean-up and return code
}
This is embarassing. Because of earlier instrumentation I had done on my server, I assumed all the problem was with the SDL rendering client. However, it turns out the client slows only when the server does. It has nothing to do with SDL at all. Sorry.
I want to convert a UINT16 monochrome image to a 8 bits image, in C++.
I have that image in a
char *buffer;
I'd like to give the new converted buffer to a QImage (Qt).
I'm trying with freeImagePlus
fipImage fimage;
if (fimage.loadfromMemory(...) == false)
//error
loadfromMemory needs a fipMemoryIO adress:
loadfromMemory(fipMemoryIO &memIO, int flag = 0)
So I do
fipImage fimage;
BYTE *buf = (BYTE*)malloc(gimage.GetBufferLength() * sizeof(BYTE));
// 'buf' is empty, I have to fill it with 'buffer' content
// how can I do it?
fipMemoryIO memIO(buf, gimage.GetBufferLength());
fimage.loadFromMemory(memIO);
if (fimage.convertTo8Bits() == true)
cout << "Good";
Then I would do something like
fimage.saveToMemory(...
or
fimage.saveToHandle(...
I don't understand what is a FREE_IMAGE_FORMAT, which is the first argument to any of those two functions. I can't find information of those types in the freeImage documentation.
Then I'd finish with
imageQt = new QImage(destiny, dimX, dimY, QImage::Format_Indexed8);
How can I fill 'buf' with the content of the initial buffer?
And get the data from the fipImage to a uchar* data for a QImage?
Thanks.
The conversion is simple to do in plain old C++, no need for external libraries unless they are significantly faster and you care about such a speedup. Below is how I'd do the conversion, at least as a first cut. The data is converted inside of the input buffer, since the output is smaller than the input.
QImage from16Bit(void * buffer, int width, int height) {
int size = width*height*2; // length of data in buffer, in bytes
quint8 * output = reinterpret_cast<quint8*>(buffer);
const quint16 * input = reinterpret_cast<const quint16*>(buffer);
if (!size) return QImage;
do {
*output++ = *input++ >> 8;
} while (size -= 2);
return QImage(output, width, height, QImage::Format_Indexed8);
}