Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

Centering Text with GD::Image

by djlerman (Sexton)
on Nov 03, 2021 at 19:28 UTC ( [id://11138402]=perlquestion: print w/replies, xml ) Need Help??

djlerman has asked for the wisdom of the Perl Monks concerning the following question:

I am seeking wisdom.
I desire to center text on an image. My searches are not being fruitful.
I can find the image width & height:
($width, $height) = $im->getBounds();
I can get the center of the image:
$centerX = $width / 2; $centerY = $height / 2;
I do not know how to get the size of the text box.
$black = $im->colorAllocate(0,0,0); $font_file = gdGiantFont; $text = "test"; $im->string($font_file, 400, 240, $text, $black);
What are some suggestions or pointers? Thank You.

Replies are listed 'Best First'.
Re: Centering Text with GD::Image
by tangent (Parson) on Nov 03, 2021 at 19:40 UTC
    You can get the bounds of the text box using the stringFT() method, but you will need to load up a truetype font first - see the "Character and String Drawing" section in the GD docs.
      Will this not work with the built in fonts? I am using gdGiantFont.
        According to GD#Font-Utilities, gdGiantFont is a fixed width (monospace) 9x15 font, so unless I'm very much mistaken, it's just 9*nChars to get the width, and the height is a fixed 15 per line of text.

        edit and it's got the width and height methods to tell you those numbers in the code.

Re: Centering Text with GD::Image
by Fletch (Bishop) on Nov 03, 2021 at 19:45 UTC

    Prossibly you could use GD::Text::Wrap and/or reimplement what it does (which looks to be what I vaguely recall was the unfortunatly kludgy procedure: draw (but don't really draw) the text into a test image and then ask for the bounds afterwards).

    Edit: Actually I think I'm misremembering something from ancient PostScript where that was the way to get the bounding box. Other answers using the font info are much better.

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

Re: Centering Text with GD::Image
by Bod (Parson) on Nov 03, 2021 at 22:45 UTC

    Here is some code that does just what you want...it centres two lines of text, one a watermark and one a copyright message, over a GD::Image object $full. It should get you started:

    # Centre text components on image my $colour = $full->colorAllocate(0, 0, 0); my @bounds = new GD::Image->stringFT($colour, "Image/outline.ttf", +90, 0.18, 0, 0, $watermark_text); my $left = ($full->width() / 2) - (($bounds[2] - $bounds[0]) / 2 +) + 5; my $top = ($full->height() / 2) - ($bounds[7] - $bounds[1]) / 2 +; $full->stringFT($colour, "/Image/outline.ttf", 90, 0.18, $left, $top, +$watermark_text); @bounds = new GD::Image->stringFT($colour, "Image/watermark.ttf +", 95, 0.18, 0, 0, $copyright); $left = ($full->width() / 2) - (($bounds[2] - $bounds[0]) / 2) + + 5; $full->stringFT($colour, "Image/watermark.ttf", 95, 0.18, $left, $top ++ 160, $copyright_text);

      G'day Bod,

      I recall this (or very similar) code from various questions you were asking some months ago. In isolation, this could be quite confusing; consider labelling it as an extract and then adding a link back to the original code to provide more context. However, that's the least of my issues with your post.

      Of far greater concern, is posting code like:

      new GD::Image->stringFT(...)

      Please read "perlobj: Invoking Class Methods" in general; and specifically the "Indirect Object Syntax" subsection. Note the emboldened "use of this syntax is discouraged"; and later "We recommend that you avoid this syntax". Reasons are given later in that subsection.

      I don't recall your original code in any detail which makes suggesting an absolute fix impossible. Maybe replace both lines with something closer to:

      GD::Image::->new()->stringFT(...)

      Or perhaps create one generic, reuseable object:

      my $generic_gd_img = GD::Image::->new(); $generic_gd_img->stringFT(...)

      There's potentially other ways to handle this, such as returning @bounds from a subroutine; however, please avoid the indirect syntax in your own code and don't suggest its use to others.

      — Ken

        avoid the indirect syntax in your own code and don't suggest its use to others.

        While I agree with the advice, don't be too hard on people who use that notation for GD -- the GD POD shows indirect object notation in their SYNOPSIS and most () of their code snippets where they show using the new or newFromXXX class methods, even when they show correct method-notation just above the example. Given that poor documentation choice, I can understand why users would pick up the indirect object notation (for those who don't know that indirect object syntax is just an alternate, they might reasonably interpret that the indirect object syntax is required for GD, since so many examples show that syntax).

        : but not quite all: the code snippets in newFromGd2Part and gifanimbegin each show one instance of method-style notation. But those are the only two instances of ->new* that I could find in the main GD POD code snippets. The rest are all indirect object syntax.

        --

        edit: created issue rt://139961

        Of far greater concern, is posting code like:
        new GD::Image->stringFT(...)

        Hi Ken,

        Thanks for your wise words and useful link. I don't write this form in code that I formulate from scratch...but, no doubt it came from the GD Documentation. I think, but I'm not sure, that this code actually came from an example somewhere on the web rather than directly from the documentation.

        Your memory serves you well!
        I did post Adding a watermark to an image with GD::Image some time ago and the code I posted was the same code shared above. The indirect syntax was in the original part and you did mention it at the time...I had no idea what the term meant then and didn't get around to looking at it further as getting the watermark colours (the subject of the question) showing correctly was the priority.

        I wouldn't use indirect syntax in code I produce from scratch. I don't know why...I just wouldn't do it that way. I will be sure to look more at the links you shared to find out why I shouldn't do it that way...

        Fortunately, the code was helpful to djlerman. Hopefully, he will also look into your links...

      @Bod This worked perfectly. Thank You!
        This worked perfectly. Thank You!

        Glad it worked for you.

        Now you may want to rewrite your working code so that it is improved working code by adopting the great advice from kcott. I shall be modifying the code from which that snippet is taken when I next look at that site. Very soon I expect as we are doing quite a bit of development there!

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://11138402]
Approved by kcott
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others admiring the Monastery: (5)
As of 2024-07-19 12:48 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?
    erzuuli‥ 🛈The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.