How do find out the width and height of the text without using surface in SDL2? - sdl-2

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.

Related

Unexpected failure when using XCreateImage with LodePNG

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.

UINT16 monochrome image to 8bit monochrome Qimage using freeImage

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);
}

Controlling the size of an embedded Vim window (in plugin mode)

I am trying to embed a GVim window inside a Qt application on Windows by getting the winId of a QWidget and passing it to Vim using --windowid.
I have two problems:
The actual Vim window can only have certain sizes (because it has an integer number of columns and rows), so it will be smaller than the QWidget that embeds it. How can I get the allowed (font-dependent) sizes so I can size the QWidget accordingly?
The resize grip of Vim is still active, and resizes Vim inside the QWidget, of course without changing the size of the QWidget. How can I prevent this and disable the Vim resize grip?
EDIT: I am trying to bundle a Vim window together with a PDF viewer to be used as a LaTeX previewer
To embed your external application first remove the styles from the window, and only after that reparent it:
void CWinSystemTools::reparentWindow(HWND hWindow, QWidget *widget)
{
if (hWindow == 0)
return;
DWORD style = GetWindowLong(hWindow, GWL_STYLE);
style = style & ~(WS_POPUP);
style = style & ~(WS_OVERLAPPEDWINDOW);
style = style | WS_CHILD;
SetWindowLong(hWindow, GWL_STYLE, style);
SetParent(hWindow, widget->winId());
}
Now, to maintain the resizing correctly, implement the resize event:
void TrVisApp::resizeEvent(QResizeEvent *event)
{
resizeClients();
}
and further:
void TrVisApp::resizeClients()
{
if (hWndGvim != 0)
CWinSystemTools::resizeWindowToWidget(hWndGvim, ui.wdgGvim->geometry());
}
where:
void CWinSystemTools::resizeWindowToWidget(HWND hWnd, QRect geometry, bool moveToTopLeftCorner = true)
{
int x = geometry.left();
int y = geometry.top();
if (moveToTopLeftCorner)
{
x = 0;
y = 0;
}
int width = geometry.width();
int height = geometry.height();
SetWindowPos(hWnd, HWND_TOP, x, y, width, height, SWP_NOACTIVATE);
}
Works nicely for me :)

Mouse handling: printing pixel location

I've been trying to do some work with OpenCV in VS2010, specifically in the area of mouse handling. So far, I have this:
CV_EVENT_LBUTTONDOWN
:drawing_line = true;
cvLine( frame, cvPoint(x,y),cvPoint(350,500), CV_RGB(255,0,0), CV_AA, 15,0 );
fprintf( stdout, "Point found. %i, %i \n", object_x0, object_y0 );
break;
What I want it to do is return the location of the pixels that I clicked on but all it returns is "Point found. 0,0" instead of the actual location. Eventually, I would like to use the points with cvLine to draw a line but right now I would just like to get some values returned to me. Any suggestions would be much appreciated. Thanks!
You can obtain the position of a mouse-click by passing it as the parameter to the mouse callback function like so:
void onMouse(int evt, int x, int y, int flags, void* param) {
if(evt == CV_EVENT_LBUTTONDOWN) {
cv::Point* ptPtr = (cv::Point*)param;
ptPtr->x = x;
ptPtr->y = y;
}
}
int main() {
cv::Point2i pt(-1,-1);
cv::namedWindow("Output Window");
frame = cv::imread("image.jpg");
cv::imshow(winName, frame);
cv::setMouseCallback(winName, onMouse, (void*)&pt);
// Note that we passed '&pt' (a pointer
// to `pt`) to the mouse callback function.
// Therefore `pt` will update its [x,y] coordinates
// whenever user left-clicks on the image in "Output Window".
}
Points are passed in as arguments to the Mouse callback function.
void onMouse(int event, int x, int y, int flags, void* param)
You'll want to save those x, y into a global when you click down, then a different global when you click up, then draw a line between the two.

Getting the width of Win32 TreeView control

The Win32 TreeView control does not have a built-in message/macro to get its (scrollable) width, e.g. if want to set the TreeView's width so it won't need to have a scrollbar.
How can this be done?
Here's a C function to do this:
int TreeView_GetWidth(HWND hTreeWnd)
{
SCROLLINFO scrollInfo;
SCROLLBARINFO scrollBarInfo;
scrollInfo.cbSize = sizeof(scrollInfo);
scrollInfo.fMask = SIF_RANGE;
scrollBarInfo.cbSize = sizeof(scrollBarInfo);
// To find the whole (scrollable) width of the tree control,
// we determine the range of the scrollbar.
// Unfortunately when a scrollbar isn't needed (and is invisible),
// its range isn't zero (but rather 0 to 100),
// so we need to specifically ignore it then.
if (GetScrollInfo(hTreeWnd, SB_HORZ, &scrollInfo) &&
GetScrollBarInfo(hTreeWnd, OBJID_HSCROLL, &scrollBarInfo))
{
// Only if the scrollbar is displayed
if ((scrollBarInfo.rgstate[0] & STATE_SYSTEM_INVISIBLE) == 0)
{
int scrollBarWidth = GetSystemMetrics(SM_CXVSCROLL);
// This is a hardcoded value to accomodate some extra pixels.
// If you can find a cleaner way to account for them (e.g. through
// some extra calls to GetSystemMetrics), please do so.
// (Maybe less than 10 is also enough.)
const int extra = 10;
return (scrollInfo.nMax - scrollInfo.nMin) + scrollBarWidth + extra;
}
}
return 0;
}

Resources