#!/usr/bin/perl


BEGIN {
    die "GSDLHOME not set\n" unless defined $ENV{'GSDLHOME'};
    unshift (@INC, "$ENV{'GSDLHOME'}/perllib");
}


use Image::Magick;
use parsargv;


sub main
{
    # Parse command line arguments
    if (!parsargv::parse(\@ARGV,
			 'background_image/.*/xc:white', \$background_image,
			 'image_width/^\d+$/', \$image_width,
			 'image_height/^\d+$/', \$image_height,
			 'stretchable_width', \$stretchable_width,
			 'stretchable_height', \$stretchable_height,
			 'note_if_stretched', \$note_if_stretched,
			 'no_text_height_warnings', \$no_text_height_warnings,
			 'h_align/.*/center', \$h_align,
			 'v_align/.*/bottom', \$v_align,
			 'padding_left/^\d+$/1', \$padding_left,
			 'padding_right/^\d+$/1', \$padding_right,
			 'padding_top/^(\\\-)?\d+$/0', \$padding_top,
			 'padding_bottom/^(\\\-)?\d+$/0', \$padding_bottom,
			 'baseline_offset/^(\\\-)?\d+$/0', \$baseline_offset,
			 'font/.*/', \$font,
			 'font_size/^\d+$/10', \$font_size,
			 'text/.*/', \$text,
			 'text_colour/.*/black', \$text_colour,
			 'output_file/.*/', \$output_file,
			 'verbose', \$verbose)) {
	print STDERR "Error: Bad command line arguments...\n";
	die "\n";
    }


    # Create a new image, basing it on the background image
    my $image = Image::Magick->new(font => $font, pointsize => $font_size);
    $res = $image->Read($background_image);
    die "$res" if $res;

    # Check required parameter values are set
    if (!$image_width) {
	$image_width = $image->Get('width');
    }
    if (!$image_height) {
	$image_height = $image->Get('height');
    }
    if ($h_align ne "left" && $h_align ne "center" && $h_align ne "right") {
	die "Error: Bad h_align $h_align...\n";
    }
    if ($v_align ne "top" && $v_align ne "center" && $v_align ne "bottom") {
	die "Error: Bad v_align $v_align...\n";
    }

    # Negative padding values (only top and bottom make sense) must be parsed specially
    if ($padding_top =~ /^\\\-(\d+)$/) {
	$padding_top = -$1;
    }
    if ($padding_bottom =~ /^\\\-(\d+)$/) {
	$padding_bottom = -$1;
    }

    # The baseline offset may be negative also...
    if ($baseline_offset =~ /^\\\-(\d+)$/) {
	$baseline_offset = -$1;
    }

    if (!$font) {
	die "Error: Font not specified...\n";
    }
    if (!$text) {
	die "Error: Text not specified...\n";
    }
    if (!$output_file) {
	die "Error: Output file not specified...\n";
    }

    $output_file =~ /\/([^\/]+)$/;
    my $output_file_name = $1;

    # Calculate the usable image area
    my $usable_image_width = $image_width - $padding_left - $padding_right;
    my $usable_image_height = $image_height - $padding_top - $padding_bottom;

    if ($verbose) {
	print STDERR "\nGenerating: $output_file\n";
	print STDERR "Pasting \"$text\" ($text_colour) in font $font ($font_size pt) onto $background_image\n";
	print STDERR "Basic size of $image_width x $image_height minus padding (LRTB: $padding_left $padding_right $padding_top $padding_bottom) gives usable area $usable_image_width x $usable_image_height\n";
    }

    # Resize the image to the desired size (it may be increased later)
    $res = $image->Resize(width => $image_width, height => $image_height);
    die "$res" if $res;

    # Convert the (escaped) text string into a Unicode string
    my $text_unicode = $text;
    $text_unicode =~ s/\\(0x([0-9A-F]){4})/chr(oct($1))/ieg;

    # Determine the space required to display the text
    my $text_width = 0;
    my $text_height = 0;
    foreach $line (split(/\\n/, $text_unicode)) {
	($x_ppem, $y_ppem, $ascender, $descender, $line_width, $line_height, $max_advance) =
	    $image->QueryFontMetrics(text => $line);
	$line_height = $line_height - $baseline_offset;

	# Use the longest line as the text width
	if ($line_width > $text_width) {
	    $text_width = $line_width;
	}
	$text_height += $line_height;
    }
    print STDERR "Text size is $text_width x $text_height\n" if $verbose;

    # If necessary, expand the image horizontally to fit the text...
    if ($text_width > $usable_image_width) {
	# ...provided that 'stretchable_width' has been specified
	if ($stretchable_width) {
	    $usable_image_width = $text_width;
	    $image_width = $usable_image_width + $padding_left + $padding_right;
	    $res = $image->Resize(width => $image_width);
	    die "$res" if $res;

	    if ($note_if_stretched) {
		print STDERR "NOTE: Image width of $output_file_name was stretched to $image_width...\n";
	    }
	}
	else {
	    print STDERR "WARNING: Text width ($text_width) is greater than usable image width ($usable_image_width) for $output_file_name...\n";
	}
    }

    # If necessary, expand the image vertically to fit the text...
    if ($text_height > $usable_image_height) {
	# ...provided that 'stretchable_height' has been specified
	if ($stretchable_height) {
	    $usable_image_height = $text_height;
	    $image_height = $usable_image_height + $padding_top + $padding_bottom;
	    $res = $image->Resize(height => $image_height);
	    die "$res" if $res;

	    if ($note_if_stretched) {
		print STDERR "NOTE: Image height of $output_file_name was stretched to $image_height...\n";
	    }
	}
	else {
	    print STDERR "WARNING: Text height ($text_height) is greater than usable image height ($usable_image_height) for $output_file_name...\n" unless $no_text_height_warnings;
	}
    }

    # Determine where the text should be placed in the y dimension, based on v_align
    if ($v_align eq "top") {
	$ypos = $font_size - 1;
    }
    elsif ($v_align eq "center") {
	$ypos = (($usable_image_height - $text_height) / 2) + $font_size - 1;
    }
    elsif ($v_align eq "bottom") {
	$ypos = $usable_image_height - $text_height + $font_size - 1;
    }
    $ypos = $ypos + $padding_top;

    # Draw each line of the text onto the image
    foreach $line (split(/\\n/, $text_unicode)) {
	($x_ppem, $y_ppem, $ascender, $descender, $line_width, $line_height, $max_advance) =
	    $image->QueryFontMetrics(text => $line);
	$line_height = $line_height - $baseline_offset;

	# Determine where the text should be placed in the x dimension, based on h_align
	if ($h_align eq "left") {
	    $xpos = 0;
	}
	elsif ($h_align eq "center") {
	    $xpos = ($usable_image_width - $line_width) / 2;
	}
	elsif ($h_align eq "right") {
	    $xpos = $usable_image_width - $line_width;
	}
	$xpos = $xpos + $padding_left;

	if ($xpos < 0) {
	    $xpos = 0;
	}

	# print STDERR "Line coordinates: ($xpos, $ypos)\n";

	# Why, why, oh why it is necessary to do this under Windows?
	# if ($ENV{'GSDLOS'} =~ /windows/i) {
	# $res = $image->Annotate(text => $line, encoding => 'UTF-8', fill => $text_colour,
	# 			x => -$xpos, y => -$ypos, undercolor => 'white');
	# die "$res" if $res;
	# }

	# Draw the line text onto the image
	$res = $image->Annotate(text => $line, encoding => 'UTF-8', fill => $text_colour,
				x => $xpos, y => $ypos);
	die "$res" if $res;

	$ypos = $ypos + $line_height;
    }

    # Save the image to file
    $res = $image->Write($output_file);
    die "$res" if $res;
}


&main();
