How do I get the exact size in pixels (W&H) of a string, that does not use a font?

Evanski

Raccoon Lord
Forum Staff
Moderator
So I have a project that draws a string that the player types on the screen, this is drawn on top of a box that I'd like to match the size of the string + a buffer.

The text that is drawn does not use a font resource so by default GameMaker uses the Arial font to draw it on the screen.

The issue is: How do I get the the exact Hight and width of my string at all times so that I can change the size of the background box?

for an example lets use the sentence:
" The Quick Brown Fox Jumped Over The Lazy Dog "

My code can get this information from that string:
[*]How many Characters are in the string
[*]Where the current input is in the string ( the blinking bar when you type 's location in the string)

My code for this already
GML:
//DRAW BACKGROUND BOX
    draw_set_alpha(0.65);

    var background_width = 500;
    //AUTO RESIZE BACKGROUND WITH TEXT LENGTH
    if (string_width(text) > 500)
    {
        var background_width = string_width(text)+30*string_width("A");
    }
    if (string_width(input_suggestion_text) > 500)
    {
        var background_width = string_width(input_suggestion_text)+30*string_width("A");
    }
   
    //DEFAULT SIZE
    if (input_suggestion_text == "")
    {
        draw_rectangle(x-10,y-10,x+background_width,y+30,false);
    }else{
        //SIZE FOR AUTO TAB COMPLETE TEXT
        draw_rectangle(x-10,y-10,x+background_width,y+50,false);
    }

    draw_set_alpha(1);
text is the string we want to get the size of
input_suggestion_text is a different string, if we can figure out the size of the Text string we dont need to worry about this one

Currently im using string width but that is only returning the amount of characters not the exact size in pixels we need
we add 30 to that to get a nice buffer, then times it by the width of "A" ,

which works for small strings but as the string gets longer the background box breaks and becomes to long for its needed use

Any help is appreciated, Thanks
 

obscene

Member
I'm about 99 percent sure you can't. Seems too obvious, so maybe you have a speci reason, but set a font and the problem goes away, right?
 

Evanski

Raccoon Lord
Forum Staff
Moderator
I'm about 99 percent sure you can't. Seems too obvious, so maybe you have a speci reason, but set a font and the problem goes away, right?
Trying to make this all just be one object/resource so I dont want to add a font resource that needs to tag along with this
 
How do you get the area of a rectangle with a width and length of zero? You don't, because it doesn't exist. You have to either add a font resource, or just use string_width/_height with the exact string you're using and they will return values based off of the default font.
 

Sinryuko

Member
string_width(string) does indeed return the width of the input string in pixels. However, keep in mind it returns it based on the current font, which could be why it's incorrect. string_length(string) is what returns the number of characters in a string. You also have to consider any sort of scaling or extra spacing that happens. Your code doesn't draw the text itself, so I can't say for certain whether you are drawing it in a way that messes up string_width(). Maybe post the code that draws the text for people to see. Also a screenshot of the text being drawn would help. If you don't have any font resource set, maybe something odd is happening with the scaling.

I use 2.2.5, but I really doubt they changed string_width() in 2.3 (I did test my project there for a little and never noticed any font problems, which I use string_width() a lot).
 
Last edited:

obscene

Member
Trying to make this all just be one object/resource so I dont want to add a font resource that needs to tag along with this
Theoretically, you could assign the font to a texture group so GM has the info it needs and then delete it after compiling.
 

TsukaYuriko

☄️
Forum Staff
Moderator
I may be misunderstanding this, but "text that does not use a font" is text that won't be drawn as anything, ever, and therefore won't ever have a width or height. Whenever you draw text, this always uses a font. Drawing text without a font would be like drawing a pixel without a color.

Currently im using string width but that is only returning the amount of characters not the exact size in pixels we need
we add 30 to that to get a nice buffer, then times it by the width of "A" ,
Also, this is incorrect. string_width does return the width of a string drawn in the current font. string_length returns the amount of characters.
 

Padouk

Member
@EvanSki
You are not the first one to report that kind of issue (string_width_not_measuring_correctly)
I think it's hard to help you here.. we are either missing the problematic part of your inquiry or your are facing an issue outside of that snipped code.

The theory is all there though.
A) Yes you can get create a box around your text using string_width_ext and string_height_ext.
B) No you don't need to set a font ahead of time. It's recommended... but if don't it will fallback to Arial 12.
C) string_width, string_height, string_width_ext and string_height_ext give the pixel size of your text using the font configured in draw_set_font (with default to Arial 12)
D) I would encourage you to enforce draw_set_halign and draw_set_valign to top left since your code seems to assume top left.
F) You tagged this as GML 2.3 so tried your code snipped in a blank project and it does get the right dimension.

You can try it in a blank project with a single object and a Single DrawUI event...


GML:
var text = "Lorem ipsum...";

function draw_boxed_text(x, y, text, padding)
{
    draw_set_halign(fa_left);
    draw_set_valign(fa_top);

    var pixelWidth = string_width(text);
    var pixelHeight = string_height(text);
    draw_text(x, y, text);
    draw_rectangle(x-padding, y-padding, x+pixelWidth+padding, y+pixelHeight+padding, true);
}

function draw_boxed_text_ext(x, y, text, padding, box_width)
{
    draw_set_halign(fa_left);
    draw_set_valign(fa_top);

    var pixelWidth = string_width_ext(text, -1, box_width);
    var pixelHeight = string_height_ext(text, -1, box_width);
    draw_text_ext(x, y, text, -1, 100);
    draw_rectangle(x-padding, y-padding, x+pixelWidth+padding, y+pixelHeight+padding, true);
}

draw_boxed_text(20,20, text, 5);
draw_boxed_text_ext(120,120, text, 5, 100);

1603411410991.png
 

Evanski

Raccoon Lord
Forum Staff
Moderator
I may be misunderstanding this, but "text that does not use a font" is text that won't be drawn as anything, ever, and therefore won't ever have a width or height. Whenever you draw text, this always uses a font. Drawing text without a font would be like drawing a pixel without a color.
Open a project and make an object with a draw event, type Draw_text(x,y,"This is text.")
Game maker will draw it on the screen using default Arial font, even though you have not created or set a font resource
That is what this text is using


As for the rest:

string_width(string) does indeed return the width of the input string in pixels. However, keep in mind it returns it based on the current font, which could be why it's incorrect. string_length(string) is what returns the number of characters in a string. You also have to consider any sort of scaling or extra spacing that happens. Your code doesn't draw the text itself, so I can't say for certain whether you are drawing it in a way that messes up string_width(). Maybe post the code that draws the text for people to see. Also a screenshot of the text being drawn would help. If you don't have any font resource set, maybe something odd is happening with the scaling.

I use 2.2.5, but I really doubt they changed string_width() in 2.3 (I did test my project there for a little and never noticed any font problems, which I use string_width() a lot).
Also, this is incorrect. string_width does return the width of a string drawn in the current font. string_length returns the amount of characters.
@EvanSki
You are not the first one to report that kind of issue (string_width_not_measuring_correctly)
I think it's hard to help you here.. we are either missing the problematic part of your inquiry or your are facing an issue outside of that snipped code.

The theory is all there though.
A) Yes you can get create a box around your text using string_width_ext and string_height_ext.
B) No you don't need to set a font ahead of time. It's recommended... but if don't it will fallback to Arial 12.
C) string_width, string_height, string_width_ext and string_height_ext give the pixel size of your text using the font configured in draw_set_font (with default to Arial 12)
D) I would encourage you to enforce draw_set_halign and draw_set_valign to top left since your code seems to assume top left.
F) You tagged this as GML 2.3 so tried your code snipped in a blank project and it does get the right dimension.

You can try it in a blank project with a single object and a Single DrawUI event...


GML:
var text = "Lorem ipsum...";

function draw_boxed_text(x, y, text, padding)
{
    draw_set_halign(fa_left);
    draw_set_valign(fa_top);

    var pixelWidth = string_width(text);
    var pixelHeight = string_height(text);
    draw_text(x, y, text);
    draw_rectangle(x-padding, y-padding, x+pixelWidth+padding, y+pixelHeight+padding, true);
}

function draw_boxed_text_ext(x, y, text, padding, box_width)
{
    draw_set_halign(fa_left);
    draw_set_valign(fa_top);

    var pixelWidth = string_width_ext(text, -1, box_width);
    var pixelHeight = string_height_ext(text, -1, box_width);
    draw_text_ext(x, y, text, -1, 100);
    draw_rectangle(x-padding, y-padding, x+pixelWidth+padding, y+pixelHeight+padding, true);
}

draw_boxed_text(20,20, text, 5);
draw_boxed_text_ext(120,120, text, 5, 100);

View attachment 35219

I think the issue I have is the execution of the code

The draw event draws the box first but then draws the string

also I think my algorithm for spacing is off as well

var background_width = string_width(text)+30*string_width("A");


Then it switches to a different string after a set length


I'll try some tweaks with sorting and update it with the results later
 

TsukaYuriko

☄️
Forum Staff
Moderator
Open a project and make an object with a draw event, type Draw_text(x,y,"This is text.")
Game maker will draw it on the screen using default Arial font, even though you have not created or set a font resource
That is what this text is using
It's not using a font resource, but it is using a font - the default font.

If you're drawing text in the default font... does this issue also exist when using any other font? If so... don't draw text in the default font. ;) There are various known issues with it and it's first and foremost intended to be a fallback.
Make your own font resource that mimics the default font (sans kerning issues) and you're good to go if it happens to make text look the way you want it to look.

also I think my algorithm for spacing is off as well

var background_width = string_width(text)+30*string_width("A");
That will only work if all glyphs in the font have the same width, also known as a monospace font. If they don't... this will end up off the rails at some point.
Arial is not a monospace font, so unless the default font is rendered as monospace...
 
Top