#!/usr/bin/perl -w

# This program determines the geometry for acroread so that only the 
# bounding box of a pdf file is displayed. This allows the text of an 
# entire page to be visible at the largest font size.

#
# There are several reasons that this program may not work correctly
#
# 1. The page size of pdf files reported by pdfinfo can be incorrect.
#    Currently, I use page size and media box reported by pdfinfo
#    but these numbers may not be correct.
# 2. When there are bookmarks in the pdf file, acroread (or is 
#    it the window manager) does not seem to place the window correctly 
#    along the y axis
# 3. Landscape mode doesn't work well since acroread (or is it the
#    window manager) doesn't honor -ve X geometry
# 4. The test for landscape files won't work on compressed pdf files
# 5. Redhat's default window manager doesn't allow placing a window
#    with -ve Y geometry. Use a window manager such as openbox
#    that does allow this operation. 
# 6. Acroread version 7.0 doesn't seem to honor the geometry argument
#    correctly

if ($#ARGV != 0) {
        die "Usage: bbacroread pdffile";
}


@resolution = `xrdb -symbols | egrep '(WIDTH|HEIGHT)' | awk -F= '{print \$2}'`;

chop($resolution[0]);
chop($resolution[1]);

$x_res = $resolution[0];
$y_res = $resolution[1];

# make this number ($iterations) smaller
# if you don't want to wait too long to calculate the bounding box.
$iterations = 7;

# size of frame in pixels around acroread's display window.
# the rough estimate below works okay.
$xadd = 50;
$yadd = 45;

$file = $ARGV[0];

$file =~ s/(\W)/\\$1/g;

sub min {
        ($a, $b) = @_;
        if ($a < $b) {
                return $a;
        } else {
                return $b;
        }
}

sub max {
        ($a, $b) = @_;
        if ($a < $b) {
                return $b;
        } else {
                return $a;
        }
}

# some error occured. just use acroread.
sub backoff {
        ($file, $error) = @_;
        print "$error";
        exec "acroread $file";
        exit 0;
}

#
# use pdfinfo to get page size of pdf file in pixels
#
open(FP, "pdfinfo -box $file |") or &backoff($file, "pdfinfo not found: $!");

$x_size = 0;
$y_size = 0;
while (<FP>) {
        if (/^Page size:\s+([\d\.]+) x ([\d\.]+)/) {
                $x_size = &max($x_size, $1);
                $y_size = &max($y_size, $2);
        }
        if (/^MediaBox:\s+([\d\.]+)\s+([\d\.]+)\s+([\d\.]+)\s+([\d\.]+)/) {
                $x_size = &max($x_size, $3 - $1);
                $y_size = &max($y_size, $4 - $2); 
        }
}
close(FP);

if ($x_size == 0) {
        &backoff($file, "x_size is not defined");
}

#
# Use gs (ghostscript) to get bounding box of pdf file
#
open(GS, "gs -q -sDEVICE=bbox -dBATCH -dNOPAUSE -c save pop -f $file 2>&1 |") or
        &backoff($file, "gs: $!");

$nr = 0;
$x1 = $y1 = &max($x_res, $y_res);
$x2 = $y2 = 0;
$loops = 0;

#
# Heuristically find maximal bounding box of file
#
while (<GS>) {
        if (/\%\%BoundingBox:\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/) {
                $changed = 0;
                if ($x1 > $1) {
                        $changed = 1;
                        $x1 = $1;
                }
                if ($y1 > $2) {
                        $changed = 1;
                        $y1 = $2;
                }
                if ($x2 < $3) {
                        $changed = 1;
                        $x2 = $3;
                }
                if ($y2 < $4) {
                        $changed = 1;
                        $y2 = $4;
                }
                $loops++;
                if ($changed == 0) {
                        $nr++;
                } else {
                        $nr = 0;
                }
                # the maximal bounding box has not changed for $iterations pages
                # get out of loop!
                if ($nr >= $iterations) {
                        last;
                }
        }
}

close(GS);

if ($loops < 1) {
        &backoff($file, "bounding box is not defined");
}

$landscape = 0;

# check for landscape mode
`grep -L "/Rotate 90" $file > /dev/null 2>&1`;
if ($? == 0) {
        $landscape = 1;
        print "found landscape mode\n";
}

#
# If landscape mode, switch x and y coordinates
#
if ($landscape == 1) {
        ($x_size, $y_size) = ($y_size, $x_size);
        ($x1, $y1) = ($y1, $x1);
        ($x2, $y2) = ($y2, $x2);
}

#
# Based on bounding box and screen resolution, find the zoom factor ($scale)
#
$scale = &min($y_res / ($y2 - $y1), $x_res / ($x2 - $x1));

#
# X takes specification in the form of WIDTHxHEIGHT+XOFF+YOFF
#
# $X and $Y are the WIDTH and HEIGTH of the window.
# We add $xadd and $yadd since acroread takes space around the display window.
#
$X = int(($x_size) * $scale  + $xadd);
$Y = int(($y_size) * $scale  + $yadd);

#
# $Xs and $Ys are the XOFF and YOFF values of the window.
# Somewhat tricky calcualation.
# The calculations should center the window on the desktop.
#
$Xs = int(($x_res - ($x1 + $x2) * $scale - $xadd)/2);
$Ys = int(($y_res - ($y1 + $y2) * $scale - $yadd)/2);

if ($landscape) {
        $sign = "+";
} else {
        $sign = "-";
}

print "$nr, $loops, $X, $Y, $x1, $y1, $x2, $y2, $x_size, $y_size, $scale\n";

# For version 7.0.0, the geometry seems to be broken
# we need to do the following
# $X -= 150;
# $Y -= 100;
# also acroread doesn't honor -Ys geometry

$arg = "acroread -geometry " . $X . "x" . $Y . "+" . "$Xs" . $sign . "$Ys" .
       " $file";

print $arg, "\n";
exec $arg;
