Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

Automagic text-to-image border calculations

by hacker (Priest)
on Apr 05, 2004 at 16:29 UTC ( [id://342671]=perlquestion: print w/replies, xml ) Need Help??

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

I'm working on a script to turn HTML + CSS content into rendered images, for an application that doesn't (yet) support CSS directly. To start with, I'm using Advogato's Recent Log output as a test bed for this.

What I'm trying to do, is put a border around each of the text strings I output, with a bit of padding around them. I can figure this out manually, by loading the image up in Gimp and checking the x,y, and applying that value to the rectangle() I draw, but that doesn't scale well, if the user changes font faces or font sizes.

This is as close as I could get, but it puts the border right up against the image text. No way to pad it as I see it.

Also, this can probably be refactored to push the levels and colors into a loop. I'm not good with that kind of construct in perl. Any help there?

Working code so far below:

use warnings; use strict; use GD; use Color::Rgb; # Font you wish to use for this output image my $fontpath = '/usr/share/fonts/truetype/'; my $font = $fontpath . 'ttf-bitstream-vera/VeraSeBd.ttf'; my $rgb = new Color::Rgb(rgb_txt=>'/usr/X11R6/lib/X11/rgb.txt'); # Create a new image my $width = 200; my $height = 200; my $im = new GD::Image($width, $height); $im->colorAllocate(0,0,0); my $white = $im->colorAllocate($rgb->hex2rgb('#ffffff')); my $black = $im->colorAllocate($rgb->hex2rgb('#000000')); # Allocate colors for rated levels # From: http://advogato.org/css/global.css my $level0 = $im->colorAllocate($rgb->hex2rgb('#c1c1c1')); my $level1 = $im->colorAllocate($rgb->hex2rgb('#c0ffc8')); my $level2 = $im->colorAllocate($rgb->hex2rgb('#c0d0ff')); my $level3 = $im->colorAllocate($rgb->hex2rgb('#e0d0ff')); my $level4 = $im->colorAllocate($rgb->hex2rgb('#e0d0c0')); my $level0_bord = $im->colorAllocate($rgb->hex2rgb('#606060')); my $level1_bord = $im->colorAllocate($rgb->hex2rgb('#008000')); my $level2_bord = $im->colorAllocate($rgb->hex2rgb('#2040ff')); my $level3_bord = $im->colorAllocate($rgb->hex2rgb('#8000c0')); my $level4_bord = $im->colorAllocate($rgb->hex2rgb('#804020')); # Make the background transparent and interlaced $im->interlaced('false'); # Create a Border around the image $im->rectangle(0, 0, $width-1, $height-1, $level0_bord); my $x1 = 50; my $y1 = 20; # Can I put all of this in a "smarter" loop? my @bounds = $im->stringFT($level0, $font, 10, 0, $x1, $y1, 'Neophyte' +); # This is ugly, but does work for now. This needs a loop. $bounds[2] += 3; $bounds[3] += 3; $bounds[6] += -5; $bounds[7] += -5; $im->rectangle(@bounds[6,7], @bounds[2,3], $level0_bord); $im->stringFT($level1, $font, 10, 0, $x1, $y1 + 40, 'Apprentice'); $im->stringFT($level2, $font, 10, 0, $x1, $y1 + 80, 'Journeyer'); $im->stringFT($level3, $font, 10, 0, $x1, $y1 + 120, 'Master'); $im->stringFT($level4, $font, 10, 0, $x1, $y1 + 160, 'Undefined'); open(IMG, ">picture.png") or die("Cannot open file!"); binmode IMG; print IMG $im->png; close IMG;
Update: on Apr 5 14:54:17 EDT 2004

I think I solved most of this now.. except the ability to resize the image itself to match the width and height of the text. I think I have to create the image larger than I need, and crop it down, using @bounds. This code shows that, but for some reason, some images are cropped more than others. There doesn't seem to be any reason why. Suggestions?

use warnings; use strict; use GD; use GD::Text; use Color::Rgb; # Font you wish to use for this output image my $fontpath = '/usr/share/fonts/truetype/'; my $font = $fontpath . 'ttf-bitstream-vera/VeraSe.ttf'; my $fontsize = '10'; my $rgb = new Color::Rgb(rgb_txt=>'/usr/X11R6/lib/X11/rgb.txt'); # Create a new image my $width = 200; my $height = 200; # Allocate colors for rated levels # From: http://advogato.org/css/global.css my @advo = ( {name => 'Neophyte', color => '#c1c1c1', border => '#606060'}, {name => 'Apprentice', color => '#c0ffc8', border => '#008000'}, {name => 'Journeyer', color => '#c0d0ff', border => '#2040ff'}, {name => 'Master', color => '#e0d0ff', border => '#8000c0'}, {name => 'Undefined', color => '#e0d0c0', border => '#804020'}, ); for my $certs (@advo) { my $gd_text = GD::Text->new() or die GD::Text::error(); $gd_text->set_font($font, $fontsize) or die $gd_text->error; $gd_text->set_text($certs->{name}); my ($w, $h) = $gd_text->get('width', 'height'); my $im = new GD::Image($w+11, $h+6); my $x1 = 5; my $y1 = 15; $im->colorAllocate($rgb->hex2rgb("$certs->{color}")); my $black = $im->colorAllocate(0,0,0); my $color = $im->colorAllocate($rgb->hex2rgb("$certs->{color} +")); my $border = $im->colorAllocate($rgb->hex2rgb("$certs->{border +}")); my @bounds = $im->stringFT($black, $font, $fontsize, 0, $x1, $ +y1, $certs->{name}); $bounds[2] += 3; $bounds[3] += 3; $bounds[6] += -5; $bounds[7] += -5; $im->rectangle(@bounds[6,7], @bounds[2,3], $border); open(IMG, ">$certs->{name}.png") or die("Cannot open file!"); binmode IMG; print IMG $im->png; close IMG; }

Replies are listed 'Best First'.
Re: Automagic text-to-image border calculations
by waswas-fng (Curate) on Apr 05, 2004 at 16:57 UTC
    It may be worthwhile to take a look at Gecko, you may be able to use it via XS to render and spit out a very good looking image of a fully rendered page with CSS. The XS module would probably be a welcome addition to CPAN as well.


    -Waswas
      A good idea, however, I'm not trying to render the entire page as an image, only the portions which cannot be properly parsed due to their CSS components. In the case of Advogato, that would be only the user's names as they show up in the recentlog output.
Re: Automagic text-to-image border calculations
by elwarren (Priest) on Apr 05, 2004 at 18:02 UTC
    Checkout Imager::Font::Wrap. Might save some time.

    Imager::Font will return the size you're looking for with this snippet (from cpan)
    $blue = Imager::Color->new("#0000FF"); $font = Imager::Font->new(file => 'pathtofont.ttf', color => $blue, size => 30); ($neg_width, $global_descent, $pos_width, $global_ascent, $descent, $ascent) = $font->bounding_box(string=>"Foo");
Re: Automagic text-to-image border calculations
by zentara (Archbishop) on Apr 06, 2004 at 15:04 UTC
    Hi, I'm not sure what you are trying to do exactly, but the GDTextUtil module seems to do waht you are asking.
    #!/usr/bin/perl -w use strict; use GD; use GD::Text::Wrap; my $outfile = shift || "GDWrap.png"; my $gd = GD::Image->new(400,240); my $white = $gd->colorAllocate(255,255,255); my $black = $gd->colorAllocate( 0, 0, 0); my $blue = $gd->colorAllocate(127,127,255); my $red = $gd->colorAllocate(127, 0, 0); #print "No colours: $black ", $gd->colorsTotal, "\n"; my $text = 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit, + sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.'; my $wp = GD::Text::Wrap->new($gd, width => 180, line_space => 4, color => $black, text => $text, ); $wp->set(align => 'left'); $gd->rectangle($wp->get_bounds(10,10), $blue); $wp->draw(10,10); $wp->set(para_space => 5, preserve_nl => 1); $wp->set_font('cetus', 10); $wp->set(align => 'justified', line_space => 0); $gd->rectangle($wp->get_bounds(210,10), $blue); $wp->draw(210,10); $wp->set(para_space => 10, preserve_nl => 0); $wp->font_path('/usr/share/fonts/ttfonts'); $wp->set_font(['Arialn', 'cetus'], 10); $wp->set(align => 'right'); $gd->rectangle($wp->get_bounds(10,120), $blue); $wp->draw(10,120); $text =~ tr/\n//d; $wp->set(text => $text); $wp->set(colour => $white, align => 'center', line_space => 2); $wp->set_font(gdMediumBoldFont, 12); $gd->filledRectangle($wp->get_bounds(210,120), $red); $wp->draw(210,120); print "Writing $outfile\n"; open(GD, ">$outfile") or die "Cannot open '$outfile' for write: $!"; binmode GD ; print GD $gd->png(); close GD;

    I'm not really a human, but I play one on earth. flash japh

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://342671]
Approved by Limbic~Region
Front-paged by asarih
help
Chatterbox?
and the web crawler heard nothing...

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

    No recent polls found