1999-09-27 18:44:28 +00:00
|
|
|
# This file is part of reLyX
|
|
|
|
# Copyright (c) 1998-9 Amir Karger karger@post.harvard.edu
|
|
|
|
# You are free to use and modify this code under the terms of
|
|
|
|
# the GNU General Public Licence version 2 or later.
|
|
|
|
|
|
|
|
package RelyxFigure;
|
|
|
|
|
|
|
|
# This is a package to read LaTeX figures and print out LyX figures
|
|
|
|
|
|
|
|
|
|
|
|
# We declare here the sub-packages found in this package.
|
|
|
|
# This allows the parser to understand "indirect object" form of subroutines
|
|
|
|
#{
|
|
|
|
#package RelyxTable::Table;
|
|
|
|
#package RelyxTable::Column;
|
|
|
|
#package RelyxTable::Row;
|
|
|
|
#}
|
|
|
|
|
|
|
|
use strict;
|
|
|
|
|
|
|
|
# Variables used by other packages
|
|
|
|
use vars qw($EpsfYsize $EpsfXsize %HW_types);
|
|
|
|
|
|
|
|
# Debugging on?
|
|
|
|
my $debug_on;
|
|
|
|
|
|
|
|
# This means "display in monochrome" and "do translations", but who cares?
|
|
|
|
# It's just here because this is the default that LyX outputs.
|
|
|
|
my $Default_Flags = 9;
|
|
|
|
|
|
|
|
# Names for width_type & height_type fields.
|
|
|
|
%HW_types = (
|
|
|
|
"def" => 0,
|
|
|
|
"cm" => 1,
|
|
|
|
"in" => 2,
|
|
|
|
"per_page" => 3, # percent of the page
|
|
|
|
"per_col" => 4, # percent of a column (illegal for height_type)
|
|
|
|
);
|
|
|
|
|
|
|
|
# Parse \epsfxsize or \epsfysize command
|
|
|
|
# Return 0 if we can't convert the length (in which case we have to type
|
|
|
|
# the \epsf[xy]size command in tex mode).
|
|
|
|
sub parse_epsfsize {
|
|
|
|
# Command & length have already been "stringified" (they're not tokens)
|
|
|
|
my ($command, $length) = (shift,shift);
|
|
|
|
if ($command eq '\\epsfxsize') {
|
|
|
|
$EpsfXsize = $length;
|
|
|
|
my @dummy = &convert_length($EpsfXsize) || return 0;
|
|
|
|
} elsif ($command eq '\\epsfysize') {
|
|
|
|
$EpsfYsize = $length;
|
2000-03-29 23:02:36 +00:00
|
|
|
my @dummy = &convert_length($EpsfYsize) || return 0;
|
1999-09-27 18:44:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
} # end sub RelyxFIgure::Figure::parse_epsfig
|
|
|
|
|
|
|
|
sub convert_length {
|
|
|
|
# test if it's a valid LyX width/height.
|
|
|
|
# (But assume a person won't try to set width to \textheight,
|
|
|
|
# and that they won't have negative or otherwise weird lengths)
|
|
|
|
# Then convert to width & width_type (or height/height_type)
|
|
|
|
# Return empty list on error
|
|
|
|
my $size = shift;
|
|
|
|
|
2004-10-28 14:35:53 +00:00
|
|
|
# A length can be (optional plus followed by) (num)(unit) where
|
1999-09-27 18:44:28 +00:00
|
|
|
# num is a float number (possibly with European command) and unit
|
|
|
|
# is a size unit, either in,cm,pt etc. or \textwidth etc.
|
|
|
|
my %unit_convert = ( # 1 inch = 25.4 mm
|
|
|
|
"mm" => 25.4, "pt" => 72.27, "bp" => 72, "pc" => 72.27/12,
|
|
|
|
"dd" => 72.27*1157/1238, "cc" => 72.27*1157/(1238*12),
|
|
|
|
);
|
|
|
|
my ($number, $type);
|
|
|
|
if ($size =~ /^\+?([\d.,]+)(cm|in)$/) {
|
|
|
|
($number, $type) = ($1, $2);
|
|
|
|
$number =~ s/,/./; # Allow european numbers!
|
|
|
|
# print "length is $number '$type'";
|
|
|
|
} elsif ($size =~ /^\+?([\d.,]+)(mm|pt|bp|pc|dd|cc)$/) {
|
|
|
|
($number, $type) = ($1, $2);
|
|
|
|
$number =~ s/,/./;
|
|
|
|
$number = $number / $unit_convert{$type};
|
|
|
|
$type = "in";
|
|
|
|
} elsif ($size =~ /^\+?([\d.,]*)\s*\\text(height|width)$/) {
|
|
|
|
$number = $1 || 1;
|
|
|
|
$number =~ s/,/./;
|
|
|
|
$number *= 100;
|
|
|
|
$type = "per_page";
|
|
|
|
} elsif ($size =~ /^\+?([\d.,]*)\s*\\columnwidth$/) {
|
|
|
|
$number = $1 || 1;
|
|
|
|
$number =~ s/,/./;
|
|
|
|
$number *= 100;
|
|
|
|
$type = "per_col";
|
|
|
|
} else {
|
|
|
|
print "\ncannot translate length '$size' in Figure; ",
|
|
|
|
"copying in TeX mode\n" if $debug_on;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($number) {
|
|
|
|
return ($number, $type);
|
|
|
|
} else {
|
|
|
|
return ();
|
|
|
|
}
|
|
|
|
} # end sub convert_length
|
|
|
|
|
|
|
|
sub parse_keyval {
|
|
|
|
# Parse a string containing comma-separated "key=value" pairs
|
|
|
|
# Compare the keys with a list of known keys.
|
|
|
|
# If we know all keys, return a hash containing keys/values
|
|
|
|
# Else return undef.
|
|
|
|
my ($string, @known_keys) = @_;
|
|
|
|
my @fields = split(/\s*,\s*/,$string);
|
|
|
|
my %fighash;
|
|
|
|
foreach (@fields) { # split "key=val" into fighash{key}=val
|
|
|
|
my ($key,$val) = split(/\s*=\s*/,$_);
|
|
|
|
$val = "" unless defined $val; # e.g., 'clip='
|
|
|
|
$fighash{$key} = $val;
|
|
|
|
|
|
|
|
unless (grep /^$key$/, @known_keys) {
|
|
|
|
print "\nUntranslatable key '$key' to figure;",
|
|
|
|
" copying in TeX mode\n" if $debug_on;
|
|
|
|
return undef;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return \%fighash;
|
|
|
|
} # end sub parse_keyval
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
package RelyxFigure::Figure;
|
|
|
|
# reLyX figure class
|
|
|
|
# Fields:
|
|
|
|
# file - file name
|
|
|
|
# width - width
|
|
|
|
# height - height
|
|
|
|
# width_type - is width in cm, % of pagewidth, etc.?
|
|
|
|
# height_type - is height in cm, % of pagewidth, etc.?
|
|
|
|
# angle - rotate fig through angle
|
|
|
|
# flags - various flags for LyX display. Not important
|
|
|
|
|
|
|
|
sub new {
|
|
|
|
my $class = shift;
|
|
|
|
my $thisfig;
|
|
|
|
$thisfig->{'file'} = "";
|
|
|
|
$thisfig->{'width'} = 0;
|
|
|
|
$thisfig->{'height'} = 0;
|
|
|
|
$thisfig->{'width_type'} = "def";
|
|
|
|
$thisfig->{'height_type'} = "def";
|
|
|
|
$thisfig->{'angle'} = 0;
|
|
|
|
$thisfig->{'flags'} = $Default_Flags;
|
|
|
|
# This seems like a convenient place to declare this...
|
|
|
|
$debug_on= (defined($main::opt_d) && $main::opt_d);
|
|
|
|
|
|
|
|
bless $thisfig, $class;
|
|
|
|
} # end sub RelyxFigure::Figure::new
|
|
|
|
|
|
|
|
|
|
|
|
sub parse_pscommand {
|
|
|
|
# this sub is given the various arguments to a command & adds that
|
|
|
|
# information to the figure object.
|
|
|
|
# Return 0 if it can't read the command, or if LyX can't handle it. Else 1.
|
|
|
|
#
|
|
|
|
# command is the name of the postscript command
|
|
|
|
# optargs are optional arguments (TT:Tokens). For many of the commands,
|
|
|
|
# only one optarg is allowed. And of course, they may be empty tokens.
|
|
|
|
# reqarg is usually the filename (for (e)psfig, it's more)
|
|
|
|
#
|
|
|
|
# Currently, LyX can't handle bounding box, so we always return 0 if one
|
|
|
|
# is given.
|
|
|
|
my ($self, $command, $optarg1, $optarg2, $reqarg) = @_;
|
|
|
|
my (@known_keys, $filename, $keyval_string, %fighash);
|
|
|
|
|
|
|
|
for ($command) {
|
|
|
|
if (/^\\epsf(file|box)?$/) {
|
|
|
|
# syntax: \epsffile[bounding box]{filename.eps}
|
|
|
|
# epsffile is an older version of epsfbox
|
|
|
|
return 0 if $optarg1->print; # bounding box was given. Panic!
|
|
|
|
$filename = &recursive_print($reqarg);
|
|
|
|
# fighash key shouldn't exist if no size was given
|
2004-10-28 14:35:53 +00:00
|
|
|
$fighash{'height'} = $RelyxFigure::EpsfYsize
|
1999-09-27 18:44:28 +00:00
|
|
|
if $RelyxFigure::EpsfYsize;
|
|
|
|
$fighash{'width'} = $RelyxFigure::EpsfXsize
|
|
|
|
if $RelyxFigure::EpsfXsize;
|
|
|
|
# Once you use \epsf[xy]size, they get reset
|
|
|
|
$RelyxFigure::EpsfXsize = $RelyxFigure::EpsfYsize = "";
|
|
|
|
$keyval_string = ""; # no key/value pairs for this command
|
|
|
|
|
|
|
|
} elsif (/^\\e?psfig$/) {
|
|
|
|
# "silent" key doesn't do anything
|
|
|
|
@known_keys = qw(file figure rotate angle height width silent);
|
|
|
|
$keyval_string = &recursive_print($reqarg);
|
2004-10-28 14:35:53 +00:00
|
|
|
my $fighashref =
|
1999-09-27 18:44:28 +00:00
|
|
|
&RelyxFigure::parse_keyval($keyval_string, @known_keys);
|
|
|
|
return 0 unless defined $fighashref; # found unknown key...
|
|
|
|
%fighash = %$fighashref;
|
|
|
|
|
|
|
|
$filename = $fighash{'file'} || $fighash{'figure'} || warn
|
|
|
|
"no filename found in figure argument '$keyval_string'";
|
|
|
|
|
|
|
|
} elsif (/^\\includegraphics$/) {
|
|
|
|
# 0 optargs can be either graphics or graphicx. Doesn't
|
|
|
|
# matter, matter, it's just the filename.
|
|
|
|
# 1 optarg can either be graphicx (if arg contains '=') or
|
|
|
|
# graphics (optarg is upper right; lower left is 0,0).
|
|
|
|
# 2 optargs is graphics with bounding box.
|
|
|
|
|
|
|
|
# Optional arguments are always returned as single tokens,
|
|
|
|
# not groups. So we can use the print method instead of
|
|
|
|
# recursive_print.
|
|
|
|
$keyval_string = $optarg1->print;
|
|
|
|
if ($keyval_string) {
|
|
|
|
if ($keyval_string =~ /=/) { # graphicx form
|
|
|
|
$keyval_string =~ s/\[(.*)\]/$1/; # remove '[' and ']'
|
|
|
|
@known_keys = qw(rotate angle height width);
|
|
|
|
my $fighashref = &RelyxFigure::parse_keyval(
|
|
|
|
$keyval_string, @known_keys);
|
|
|
|
return 0 unless defined $fighashref; # found unknown key
|
|
|
|
%fighash = %$fighashref;
|
|
|
|
|
|
|
|
} else { # graphics form with bounding box
|
|
|
|
print "\nLyX cannot support bounding box; ",
|
|
|
|
"copying Figure in TeX mode\n" if $debug_on;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$filename = &recursive_print($reqarg);
|
|
|
|
|
|
|
|
}
|
|
|
|
} # end switch on command name
|
|
|
|
|
|
|
|
# Now set fields in the Figure object
|
|
|
|
$self->{'file'} = $filename;
|
|
|
|
$self->{'angle'} = $fighash{'rotate'} if exists $fighash{'rotate'};
|
|
|
|
$self->{'angle'} = $fighash{'angle'} if exists $fighash{'angle'};
|
|
|
|
if (exists $fighash{'height'}) {
|
|
|
|
my @heights = &RelyxFigure::convert_length($fighash{'height'});
|
|
|
|
return 0 unless @heights; # unconvertable length!
|
|
|
|
($self->{'height'},$self->{'height_type'}) = @heights;
|
|
|
|
}
|
|
|
|
if (exists $fighash{'width'}) {
|
|
|
|
my @widths = &RelyxFigure::convert_length($fighash{'width'});
|
|
|
|
return 0 unless @widths; # unconvertable length!
|
|
|
|
($self->{'width'},$self->{'width_type'}) = @widths;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1; # if we got here, we parsed correctly and LyX can handle it.
|
|
|
|
} # end sub RelyxFigure::Figure::parse_pscommand
|
|
|
|
|
|
|
|
sub recursive_print {
|
|
|
|
# if arg is a group, print its contents (i.e., ignore '{' and '}')
|
|
|
|
# otherwise, print arg
|
|
|
|
my $tok = shift;
|
|
|
|
my $filename = "";
|
|
|
|
my $type = ref($tok);
|
|
|
|
$type =~ s/Text::TeX::// or warn "weird group";
|
|
|
|
if ($type eq 'Group') {
|
|
|
|
foreach ($tok->contents) {$filename .= &recursive_print($_)}
|
|
|
|
} else {
|
|
|
|
$filename .= $tok->exact_print
|
|
|
|
}
|
|
|
|
return $filename;
|
|
|
|
}
|
|
|
|
|
|
|
|
sub print_info {
|
|
|
|
# LyX figure command -- return what to print; don't actually print it
|
|
|
|
my $self = shift;
|
|
|
|
|
|
|
|
my $to_print = "\n\\begin_inset Figure\n";
|
|
|
|
# (LyX fig. command has eps size here. But we don't know that, so
|
|
|
|
# we dont print it out.)
|
|
|
|
|
|
|
|
$to_print .= "file $self->{'file'}\n";
|
|
|
|
my ($size, $type) = ("","");
|
2004-10-28 14:35:53 +00:00
|
|
|
($size, $type) = ($self->{'width'},
|
1999-09-27 18:44:28 +00:00
|
|
|
$RelyxFigure::HW_types{$self->{'width_type'}});
|
|
|
|
$to_print .= "width $type $size\n" if $size;
|
|
|
|
($size, $type) = ("","");
|
2004-10-28 14:35:53 +00:00
|
|
|
($size, $type) = ($self->{'height'},
|
1999-09-27 18:44:28 +00:00
|
|
|
$RelyxFigure::HW_types{$self->{'height_type'}});
|
|
|
|
$to_print .= "height $type $size\n" if $size;
|
|
|
|
$to_print .= "angle $self->{'angle'}\n" if $self->{'angle'};
|
|
|
|
$to_print .= "flags $self->{'flags'}\n";
|
|
|
|
|
|
|
|
$to_print .= "\n\\end_inset \n\n";
|
2004-10-28 14:35:53 +00:00
|
|
|
|
1999-09-27 18:44:28 +00:00
|
|
|
} # end sub RelyxFigure::Figure::print
|
|
|
|
|
|
|
|
} # end of package RelyxFigure::Figure
|
|
|
|
|
|
|
|
1; # return true to calling package
|