#!/usr/bin/env perl # $Id: motivator.pl,v 1.12 2008/01/01 19:53:57 kevinr Exp $ # motivator.pl -- Render Motivational Posters with the GIMP 2 # # Adds a menu entry under Xtns->Render->Motivational Poster... # # You will need the GIMP and GIMP-perl 2 (a test release of which can be # found at http://search.cpan.org/~sjburges/Gimp-2.0/) installed in order # to use this script. # # To install, run: # gimptool-2.0 --install-bin motivator.pl # # Copyright 2007 Kevin Riggle # # This program is free software: you can redistribute it and/or modify # it under the terms of version 2 of the GNU General Public License as # published by the Free Software Foundation. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program (see the file COPYING). If not, see # . use strict; use warnings; use Gimp qw(:consts main xlfd_size :auto); use Gimp::Fu; my %poster_hz = ( hmargin => 0.1, # relative to width vmargin => 0.0833, # measured from the top, relative to poster height txtmargin => 0.25, # measured from the bottom relative to poster height titleht => 0.0833, # relative to poster height textht => 0.0250, # relative to poster height titley => 0.7750, # measured from the top, relative to poster height texty => 0.8833, # measured from the top, relative to poster height ); my %poster_vt = ( hmargin => 0.1308, # relative to width vmargin => 0.0603, # measured from the top, relative to poster height txtmargin => 0.2294, # measured from the bottom relative to poster height titleht => 0.0748, # relative to poster height textht => 0.0169, # relative to poster height titley => 0.7922, # measured from the top, relative to poster height texty => 0.8913, # measured from the top, relative to poster height ); sub img_motivator { my ($mtvl_image, $is_portrait, $preserve_scale, $make_largest, $width, $height, $bdr_width, $bg_color, $tb_color, $mtvl_color, $title_text, $title_font, $mtvl_text, $mtvl_font, ) = @_; # copy motivational image to a new temporary image my $tmp_image; $tmp_image = gimp_image_duplicate($mtvl_image); # extract font names my ($title_font_name, $mtvl_font_name); $title_font =~ /^(\D+)/; $title_font_name = $1; $mtvl_font =~ /^(\D+)/; $mtvl_font_name = $1; # set the margin proportions my $margins = $is_portrait ? \%poster_vt : \%poster_hz; # if make_largest is set, calculate the size of poster which would # accomadate an image the size of the selected image if ($make_largest) { $width = int( $tmp_image->width / (1 - (2 * $margins->{'hmargin'})) ); $height = int( $tmp_image->height / (1 - ($margins->{'vmargin'} + $margins->{'txtmargin'})) ); } # calculate sizes my ($img_x, $img_y, $img_w, $img_h, $title_h, $mtvl_h, $title_y, $mtvl_y); my ($bdr_grow, $bdr_r); $img_x = int($width * $margins->{'hmargin'}); $img_y = int($height * $margins->{'vmargin'}); $img_w = int($width * (1 - (2 * $margins->{'hmargin'}))); $img_h = int($height * (1 - ($margins->{'vmargin'} + $margins->{'txtmargin'}))); $title_h = int($height * $margins->{'titleht'}); $mtvl_h = int($height * $margins->{'textht'}); $title_y = int($height * $margins->{'titley'}); $mtvl_y = int($height * $margins->{'texty'}); $bdr_grow = $bdr_width * 1.5; $bdr_r = $bdr_width * 0.5; print "\nPos: $img_x x $img_y; Size: $img_w x $img_h\n"; print "Title font name: $title_font_name; Mtvl font name: $mtvl_font_name\n"; print "Border grow: $bdr_grow; Border radius: $bdr_r\n"; my ($bdr_x_i, $bdr_y_i, $bdr_w_i, $bdr_h_i); my ($bdr_x_o, $bdr_y_o, $bdr_w_o, $bdr_h_o); $bdr_x_o = int($img_x - ($bdr_grow + $bdr_r)); $bdr_y_o = int($img_y - ($bdr_grow + $bdr_r)); $bdr_w_o = int($img_w + 2*($bdr_grow + $bdr_r)); $bdr_h_o = int($img_h + 2*($bdr_grow + $bdr_r)); print "border outside pos: $bdr_x_o x $bdr_y_o; Size: $bdr_w_o x $bdr_h_o\n"; $bdr_x_i = $img_x - ($bdr_grow - $bdr_r); $bdr_y_i = $img_y - ($bdr_grow - $bdr_r); $bdr_w_i = $img_w + 2*($bdr_grow - $bdr_r); $bdr_h_i = $img_h + 2*($bdr_grow - $bdr_r); print "border inside pos: $bdr_x_i x $bdr_y_i; Size: $bdr_w_i x $bdr_h_i\n"; my ($poster_image, $bg_layer, $txt_layer); # Create a new image for the poster $poster_image = gimp_image_new($width, $height, RGB); # Create the background layer $bg_layer = gimp_layer_new($poster_image, $width, $height, RGB, "Background", 100, NORMAL_MODE); print "tmp_image: $tmp_image; poster_image: $poster_image; bg_layer: $bg_layer\n"; gimp_image_add_layer($poster_image, $bg_layer, -1); gimp_palette_set_background($bg_color); gimp_edit_fill($bg_layer, BACKGROUND_FILL); # Create the border gimp_palette_set_foreground($tb_color); gimp_selection_none($poster_image); gimp_rect_select($poster_image, $bdr_x_o, $bdr_y_o, $bdr_w_o, $bdr_h_o, 0, 0, 0); gimp_edit_bucket_fill($bg_layer, FG_BUCKET_FILL, NORMAL_MODE, 100, 0, 0, 0, 0); gimp_selection_none($poster_image); gimp_rect_select($poster_image, $bdr_x_i, $bdr_y_i, $bdr_w_i, $bdr_h_i, 0, 0, 0); gimp_edit_bucket_fill($bg_layer, BG_BUCKET_FILL, NORMAL_MODE, 100, 0, 0, 0, 0); # Resize the motivational image properly if ($preserve_scale) { my $tmp_scale = $tmp_image->width / $tmp_image->height; my $img_scale = $img_w / $img_h; print "current scale: $tmp_scale; new scale $img_scale\n"; my ($new_x, $new_y, $new_w, $new_h); if ($tmp_scale > $img_scale) { #image is too wide, needs horiz. cropping my $crop_w = $tmp_image->height * ($tmp_scale - $img_scale); $new_x = int($crop_w / 2); $new_y = 0; $new_w = int($tmp_image->width - $crop_w); $new_h = $tmp_image->height; } else { #image is too tall, needs vert. cropping my $crop_h = $tmp_image->height * ($img_scale - $tmp_scale); $new_x = 0; $new_y = int($crop_h / 2); $new_w = $tmp_image->width; $new_h = int($tmp_image->height - $crop_h); } print "New pos $new_x x $new_y; size $new_w x $new_h\n"; gimp_image_crop($tmp_image, $new_w, $new_h, $new_x, $new_y); } gimp_image_scale($tmp_image, $img_w, $img_h); # place the motivational image my $float; gimp_selection_all($tmp_image); gimp_edit_copy_visible($tmp_image); $float = gimp_edit_paste($bg_layer, 0); gimp_layer_set_offsets($float, $img_x, $img_y); gimp_floating_sel_anchor($float); # Create and place the title text gimp_palette_set_foreground($tb_color); my ($title_w, $title_h_o, $title_a, $title_d) = gimp_text_get_extents_fontname($title_text, $title_h, PIXELS, $title_font_name); my $title_x = int(($width - $title_w) / 2); print("Title text pos: $title_x x $title_y; size: $title_w x $title_h; ascenders $title_a, descenders $title_d\n"); $float = gimp_text_fontname($poster_image, $bg_layer, $title_x, $title_y, $title_text, -1, TRUE, $title_h, PIXELS, $title_font_name); gimp_floating_sel_anchor($float); # Create and place the motivational text gimp_palette_set_foreground($mtvl_color); my ($mtvl_w, $mtvl_h_o, $mtvl_a, $mtvl_d) = gimp_text_get_extents_fontname($mtvl_text, $mtvl_h, PIXELS, $mtvl_font_name); my $mtvl_x = int(($width - $mtvl_w) / 2); print("Motivational text pos: $mtvl_x x $mtvl_y; size: $mtvl_w x $mtvl_h; ascenders $mtvl_a, descenders $mtvl_d\n"); $float = gimp_text_fontname($poster_image, $bg_layer, $mtvl_x, $mtvl_y, $mtvl_text, -1, TRUE, $mtvl_h, PIXELS, $mtvl_font_name); gimp_floating_sel_anchor($float); #clean up gimp_selection_none($poster_image); gimp_image_delete($tmp_image); # Return the image gimp_displays_flush(); return $poster_image; } register "img_motivator", # fill in name "Create a (de)motivational poster", # a small description "Create a (de)motivational poster from an image", # a help text "Kevin Riggle", # Your name "Kevin Riggle (c)", # Your copyright "2007-12-25", # Date "/Xtns/Render/Motivational Poster...", # menu path "*", # Image types [ [PF_IMAGE, "image", "", undef], [PF_TOGGLE,"is_portrait", "Use portrait proportions?", 0], #Width and height are interpreted the same way as with landscape #posters, but the proportions of the text and picture are adjusted #to better fit portrait orientation. [PF_TOGGLE, "preserve_scale", "Preserve image scale?", 1], #Crop the selected image if necessary to preserve its scale? #Preserves the center of the image. If not selected, the image #may be smushed to fit in the box." [PF_TOGGLE, "make_largest", "Make the largest possible poster?", 0], #If selected, ignores the selected width and height and makes the #largest poster possible from the selected image. Automatically #preserves scale. [PF_INT, "width", "", 640], [PF_INT, "height", "", 480], [PF_INT, "border_width", "", 2], [PF_COLOR, "background_color", "", [0,0,0]], [PF_COLOR, "title_and_border_color", "", [255,255,255]], [PF_COLOR, "motivational_text_color", "", [255,255,255]], [PF_STRING,"title_text", "'Real' (de)motivational posters use a small caps font with the first and last letter capitalized. I don't have the font (Caslon Three), and it's harder to do small caps in software, so I just capitalize each letter. In the font I'm using, the title looks better if I put a space between each letter too.", "L A Z I N E S S"], [PF_FONT, "title_font", "Defaults to Caslon Three, the title font of 'real' (de)motivational posters. The selected font size doesn't actually matter; the text will be sized appropriately for the selected poster size.", "Caslon Three"], [PF_STRING,"motivational_text", "'Real' (de)motivational posters use small caps with each word capitalized. It's harder to do small caps in software, so I just capitalize each word.", "One Of The Three Great Virtues Of A Programmer."], [PF_FONT, "motivational_text_font", "Defaults to Futura, the motivational text font of 'real' (de)motivational posters. The selected font size doesn't actually matter; the text will be sized appropriately for the selected poster size.", "Futura"], ], \&img_motivator; exit main(); # $Id: motivator.pl,v 1.12 2008/01/01 19:53:57 kevinr Exp $