#!/usr/bin/perl -w

#
# Computes the bounding box of an EPS file and generates a new EPS with
# the computed bounding box. It can add a margin, do in-place modification
# or just compute the bounding box without producing a modified EPS file.
#
# By Diego Santa Cruz <Diego,SantaCruz@epfl.ch>, Wed Sep  3 2002
#

# the version of this script
$ver = 0.1;

# main options to ghostscript
$gs_opts = "-q -dNOPAUSE -dBATCH -dSAFER";

# the help message
$help_msg = <<EOS;
usage: $0 [options] <input eps file>

Computes the true bounding box of an EPS file and outputs the EPS file to
stdout with the bounding box information replaced. In addition the computed
bounding box is printed on stderr. Ghostscript is used to do the bounding box
computation.

options:
  -fast  use ghostscript\'s bbox driver to get the bounding box. This is fast,
         but sometimes it gives a totally bogus bounding box. This is the
         default.
  -best  use ghostscript\'s epswrite driver to get the bounding box. This can
         be slow, but it should always provide correct results.
  -m x   leaves a margin of x points on each side of the bounding box. Zero by
         default. If the lower left corner coordinates become negative because
         of the margin, the margin value is reduced to avoid it.
  -n     do not output the new EPS file to stdout, just print the true bounding
         box on stderr.
  -r     replace mode. Instead of outputting the new EPS file to stdout, it
         renames the original file with the \'.orig\' extension appended and
         writes the new EPS file with the name of the original one. The -n
         option inhibits this one.
  -q     do not print true bounding box on stderr.
  -h     print\'s this help message and exits.

version: $ver
EOS

if ($#ARGV < 0) {
  print STDERR "ERROR: missing input filename, use -h for help\n";
  exit 1;
}

# Parse command line options
$gs_dev = "bbox";
$do_new = 1;
$do_replace = 0;
$print_bbox = 1;
$margin = 0;
while ($ARGV[0] =~ /^\-/) {
  if ($ARGV[0] eq '-best') {
    $gs_dev = "epswrite";
  } elsif ($ARGV[0] eq '-fast') {
    $gs_dev = "bbox";
  } elsif ($ARGV[0] eq '-m') {
    $margin = $ARGV[1];
    if ($margin !~ /^[0-9]+$/) {
      die "ERROR: illegal marging value\n";
    }
    shift;
  } elsif ($ARGV[0] eq '-n') {
    $do_new = 0;
  } elsif ($ARGV[0] eq '-r') {
    $do_replace = 1;
  } elsif ($ARGV[0] eq '-q') {
    $print_bbox = 0;
  } elsif ($ARGV[0] eq '-h') {
    print STDOUT $help_msg;
    exit 0;
  } elsif ($ARGV[0] ne '--') {
    print STDERR "ERROR: unknown option specified\n";
    exit 1;
  }
  shift;
}

# Verify remaining arguments
($#ARGV < 0) && die "ERROR: missing input filename\n";
($#ARGV > 0) && die "ERROR: too many input parameters\n";
($print_bbox || $do_new) || die "ERROR: nothing to do\n";
if (!$do_new) {
  $do_replace = 0;
}
$infile = $ARGV[0];

# Construct ghostscript command line
$gs_comm = "gs " . $gs_opts . " -sOutputFile=- -sDEVICE=" . $gs_dev;

# Read header
open(IN,'<',$infile) || die "ERROR: could not open input file\n";

# Verify header of input file
$header = <IN>;
$header =~ /^%!PS/ || die "ERROR: input is not a PostScript file\n";

# Run ghostscript to get bounding box
open(GS,'-|',"$gs_comm '" . $infile . "' 2>&1");
while (<GS>) {
  if (/^%%BoundingBox:\s+([0-9]+)\s+([0-9]+)\s+([0-9]+)\s+([0-9]+)\s*$/) {
    $llx = $1;
    $lly = $2;
    $urx = $3;
    $ury = $4;
  } elsif (/^%%HiResBoundingBox:\s+([0-9.]+)\s+([0-9.]+)\s+([0-9.]+)\s+([0-9.]+)\s*$/) {
    $hrllx = $1;
    $hrlly = $2;
    $hrurx = $3;
    $hrury = $4;
  }
}
close(GS);

# Verify we got bounding box (ghostscript always outputs normal and hires)
(defined($ury) && defined($hrury)) || die "ERROR: could not get bounding box\n";

# Construct new bounding box
$m = $margin;
$m = ($llx < $m) ? $llx : $m;
$m = ($lly < $m) ? $lly : $m;
$m = ($hrllx < $m) ? $hrllx : $m;
$m = ($hrlly < $m) ? $hrlly : $m;
$m = int($m);
if ($m != $margin) {
  print STDERR "WARNING: margin reduced to $m (from $margin specified)\n";
}
$llx = $llx - $m;
$lly = $lly - $m;
$urx = $urx - $m;
$ury = $ury - $m;
$hrllx = $hrllx - $m;
$hrlly = $hrlly - $m;
$hrurx = $hrurx - $m;
$hrury = $hrury - $m;

$bbox = "%%BoundingBox: $llx $lly $urx $ury\n";
$hiresbbox = "%%HiResBoundingBox: $hrllx $hrlly $hrurx $hrury\n";


# Print informational bounding box
if ($print_bbox) {
  print STDERR $bbox,$hiresbbox;
}

# Ready to output, take action is replacing
if ($do_replace) {
  $origfile = $infile;
  $infile = $infile . ".orig";
  rename($origfile,$infile) || die "ERROR: could not rename input file\n";
  if (!open(OUT,">",$origfile)) {
    rename($infile,$origfile);
    die "ERROR: could not open output file\n";
  }
} else {
  open(OUT,">-") || die "ERROR: could not open stdout\n";
}

# print out input file, replacing bounding box information
if ($do_new) {
  print OUT $header,$bbox,$hiresbbox;
  while(<IN>) {
    if (! (/^%%BoundingBox:/ || /^%%HiResBoundingBox:/)) {
      print OUT;
    }
  }
}

close(IN);
close(OUT);

