I have been looking into font setting issues and have come across a few discrepancies in font widths and positioning for postscript rendered under Subcanvas vs not under Subcanvas. This script reproduces the discrepancies. It also monkey-patches some Prima::PS::Drawable methods to print diagnostic output. The patch to emit gives a stack trace when it sees a zoom that's not simply 1 1 Z. The patch to text_out prints the font width and fontWidthDivisor just before performing the text_out, and indicates if the canvas being drawn things it has textOutBaseline set to true.
In short
Postscript drawables seem to have a true textOutBaseline, which disagrees with the documentation in Prima::Drawable (and is not mentioned in Prima::PS::Drawable). I don't mind adapting to this, but it should probably be documented.
Font configuration by Subcanvas seems to mess up the width of the font.
There are other interesting discrepancies, such as an additional font encoding in the Subcanvas produced output, and the use of Helvetica-Narrow by the non-Subcanvas vs Helvetica by the Subcanvas. I think those are optimizations, however, and are not major concerns of mine for this issue.
use strict;
use warnings;
use Prima qw(Application);
use Prima::PS::Drawable;
use Prima::Drawable::Subcanvas;
use Carp qw(cluck);
my $old_emit = \&Prima::PS::Drawable::emit;
*Prima::PS::Drawable::emit = sub {
my $to_print = $_[1];
cluck() if $to_print =~ /0.\d+ 1 Z/;
goto &$old_emit;
};
my $old_text_out = \&Prima::PS::Drawable::text_out;
*Prima::PS::Drawable::text_out = sub {
my $self = $_[0];
print "Just before text out operation, font width is $self->{font}{width}, and font width divisor is $self->{fontWidthDivisor}\n";
print "baseline is true\n" if $self-> textOutBaseline;
goto &$old_text_out;
};
my $subcanvas = grep { /subcanvas/i } @ARGV;
my $base_filename = 'font-dimensions';
$base_filename .= '-subcanvas' if $subcanvas;
$base_filename .= '.eps';
my $window = Prima::MainWindow->new(
size => [50, 50],
onPaint => sub {
my ($self, $canvas) = @_;
$canvas->text_out('foo', 10, 10);
},
);
my $scaling_ratio = 72.27 / 100;
my $width = $window->width * $scaling_ratio;
my $height = $window->height * $scaling_ratio;
my $ps = Prima::PS::Drawable-> create( onSpool => sub {
open my $fh, ">>", $base_filename;
print $fh $_[1];
close $fh;
},
pageSize => [$width, $height],
pageMargins => [0, 0, 0, 0],
isEPS => 1,
useDeviceFontsOnly => 1,
);
$ps->resolution($window->resolution);
$ps->font(height => $window->font->height);
# Set the font, set the baseline, etc
$ps->begin_doc or die "Error generating Postscript output: $@";
if ($subcanvas) {
$window->paint_with_widgets($ps);
}
else {
$window->push_event;
$window->begin_paint_info;
$window->notify('Paint', $ps);
$window->end_paint_info;
$window->pop_event;
}
$ps->end_doc;
print "Window has baseline\n" if $window->textOutBaseline;
run Prima;
When run with no arguments, the script gives the following output:
$ perl ps-subcanvas-font-dimensions.pl
Subroutine Prima::PS::Drawable::emit redefined at ps-subcanvas-font-dimensions.pl line 13.
Subroutine Prima::PS::Drawable::text_out redefined at ps-subcanvas-font-dimensions.pl line 21.
Just before text out operation, font width is 16, and font width divisor is 16
baseline is true
and produces this eps file:
%!PS-Adobe-2.0 EPSF-2.0
%%Title: Prima
%%Creator: Prima::PS::Drawable
%%CreationDate: Wed Jun 11 16:49:30 2014
%%Pages: (atend)
%%BoundingBox: 0 0 36 36
%%LanguageLevel: 2
%%DocumentNeededFonts: (atend)
%%DocumentSuppliedFonts: (atend)
%%EndComments
/d/def load def/,/load load d/~/exch , d/S/show , d/:/gsave , d/;/grestore ,
d/N/newpath , d/M/moveto , d/L/rlineto , d/X/closepath , d/C/clip ,
d/T/translate , d/R/rotate , d/P/showpage , d/Z/scale , d/I/imagemask ,
d/@/dup , d/G/setgray , d/A/setrgbcolor , d/l/lineto , d/F/fill ,
d/FF/findfont , d/XF/scalefont , d/SF/setfont ,
d/O/stroke , d/SD/setdash , d/SL/setlinecap , d/SW/setlinewidth ,
d/SJ/setlinejoin , d/E/eofill ,
d/SS/setcolorspace , d/SC/setcolor , d/SM/setmatrix , d/SPD/setpagedevice ,
d/SP/setpattern , d/CP/currentpoint , d/MX/matrix , d/MP/makepattern ,
d/b/begin , d/e/end , d/t/true , d/f/false , d/?/ifelse , d/a/arc ,
d/dummy/_dummy
%%BeginSetup
%%EndSetup
%%Page: 1 1
/reencode_font { ~ /enco ~ d
@ @ FF @ length dict b { 1 index
/FID ne{d}{pop pop}?} forall /Encoding
enco d currentdict e definefont } bind d
/Encoding_Latin1 [
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/space/exclam/quotedbl/numbersign/dollar/percent/ampersand/quotesingle/parenleft/parenright/asterisk/plus/comma/minus/period/slash
/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon/less/equal/greater/question
/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O
/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright/asciicircum/underscore
/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o
/p/q/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/asciitilde/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/dotlessi/grave/acute/circumflex/tilde/macron/breve/dotaccent/dieresis/.notdef/ring/cedilla/.notdef/hungarumlaut/ogonek/caron
/.notdef/exclamdown/cent/sterling/currency/yen/brokenbar/section/dieresis/copyright/ordfeminine/guillemotleft/logicalnot/hyphen/registered/macron
/degree/plusminus/twosuperior/threesuperior/acute/mu/paragraph/periodcentered/cedilla/onesuperior/ordmasculine/guillemotright/onequarter/onehalf/threequarters/questiondown
/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex/Idieresis
/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls
/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla/egrave/eacute/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis
/eth/ntilde/ograve/oacute/ocircumflex/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex/udieresis/yacute/thorn/ydieresis
] d
0 0 T
N 0 0 M 0 36.135 L 36.135 0 L 0 -36.135 L X C
:
1 1 Z
Encoding_Latin1 /Helvetica-Narrow reencode_font
/Helvetica-Narrow FF 14 XF SF
: 7.53 7.45 T
0 0 M
0 0 0 A
(f) S
3.24 0 M
(o) S
9.74 0 M
(o) S
;
; P
%%Trailer
%%DocumentNeededFonts:
%%DocumentSuppliedFonts:
%%Pages: 1
%%EOF
which looks like this:
When run with the subcanvas argument, it prints the following output:
$ perl ps-subcanvas-font-dimensions.pl subcanvas
Subroutine Prima::PS::Drawable::emit redefined at ps-subcanvas-font-dimensions.pl line 13.
Subroutine Prima::PS::Drawable::text_out redefined at ps-subcanvas-font-dimensions.pl line 21.
Just before text out operation, font width is 10, and font width divisor is 19
at ps-subcanvas-font-dimensions.pl line 11.
main::__ANON__('Prima::PS::Drawable=HASH(0x7f84694d9c78)', '0.526315789473684 1 Z') called at /Users/dcmertens/perl5/perlbrew/perls/perl-5.18.1-thread-multi/lib/site_perl/5.18.1/darwin-thread-multi-2level/Prima/PS/Drawable.pm line 926
Prima::PS::Drawable::text_out('Prima::PS::Drawable=HASH(0x7f84694d9c78)', 'foo', 10, 10) called at /Users/dcmertens/perl5/perlbrew/perls/perl-5.18.1-thread-multi/lib/site_perl/5.18.1/darwin-thread-multi-2level/Prima/Drawable/Subcanvas.pm line 124
Prima::Drawable::Subcanvas::text_out('Prima::Drawable::Subcanvas=HASH(0x7f846956f788)', 'foo', 10, 10) called at ps-subcanvas-font-dimensions.pl line 32
main::__ANON__('Prima::MainWindow=HASH(0x7f84694d2548)', 'Prima::Drawable::Subcanvas=HASH(0x7f846956f788)') called at /Users/dcmertens/perl5/perlbrew/perls/perl-5.18.1-thread-multi/lib/site_perl/5.18.1/darwin-thread-multi-2level/Prima/Drawable/Subcanvas.pm line 265
eval {...} called at /Users/dcmertens/perl5/perlbrew/perls/perl-5.18.1-thread-multi/lib/site_perl/5.18.1/darwin-thread-multi-2level/Prima/Drawable/Subcanvas.pm line 265
Prima::Drawable::Subcanvas::paint_widgets('Prima::Drawable::Subcanvas=HASH(0x7f846956f788)', 'Prima::MainWindow=HASH(0x7f84694d2548)', 0, 0) called at /Users/dcmertens/perl5/perlbrew/perls/perl-5.18.1-thread-multi/lib/site_perl/5.18.1/darwin-thread-multi-2level/Prima/Drawable/Subcanvas.pm line 293
Prima::Drawable::paint_with_widgets('Prima::MainWindow=HASH(0x7f84694d2548)', 'Prima::PS::Drawable=HASH(0x7f84694d9c78)') called at ps-subcanvas-font-dimensions.pl line 55
and produces this eps file:
%!PS-Adobe-2.0 EPSF-2.0
%%Title: Prima
%%Creator: Prima::PS::Drawable
%%CreationDate: Wed Jun 11 16:49:11 2014
%%Pages: (atend)
%%BoundingBox: 0 0 36 36
%%LanguageLevel: 2
%%DocumentNeededFonts: (atend)
%%DocumentSuppliedFonts: (atend)
%%EndComments
/d/def load def/,/load load d/~/exch , d/S/show , d/:/gsave , d/;/grestore ,
d/N/newpath , d/M/moveto , d/L/rlineto , d/X/closepath , d/C/clip ,
d/T/translate , d/R/rotate , d/P/showpage , d/Z/scale , d/I/imagemask ,
d/@/dup , d/G/setgray , d/A/setrgbcolor , d/l/lineto , d/F/fill ,
d/FF/findfont , d/XF/scalefont , d/SF/setfont ,
d/O/stroke , d/SD/setdash , d/SL/setlinecap , d/SW/setlinewidth ,
d/SJ/setlinejoin , d/E/eofill ,
d/SS/setcolorspace , d/SC/setcolor , d/SM/setmatrix , d/SPD/setpagedevice ,
d/SP/setpattern , d/CP/currentpoint , d/MX/matrix , d/MP/makepattern ,
d/b/begin , d/e/end , d/t/true , d/f/false , d/?/ifelse , d/a/arc ,
d/dummy/_dummy
%%BeginSetup
%%EndSetup
%%Page: 1 1
/reencode_font { ~ /enco ~ d
@ @ FF @ length dict b { 1 index
/FID ne{d}{pop pop}?} forall /Encoding
enco d currentdict e definefont } bind d
/Encoding_Latin1 [
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/space/exclam/quotedbl/numbersign/dollar/percent/ampersand/quotesingle/parenleft/parenright/asterisk/plus/comma/minus/period/slash
/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon/less/equal/greater/question
/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O
/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright/asciicircum/underscore
/quoteleft/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o
/p/q/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/asciitilde/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/dotlessi/grave/acute/circumflex/tilde/macron/breve/dotaccent/dieresis/.notdef/ring/cedilla/.notdef/hungarumlaut/ogonek/caron
/.notdef/exclamdown/cent/sterling/currency/yen/brokenbar/section/dieresis/copyright/ordfeminine/guillemotleft/logicalnot/hyphen/registered/macron
/degree/plusminus/twosuperior/threesuperior/acute/mu/paragraph/periodcentered/cedilla/onesuperior/ordmasculine/guillemotright/onequarter/onehalf/threequarters/questiondown
/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex/Idieresis
/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls
/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla/egrave/eacute/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis
/eth/ntilde/ograve/oacute/ocircumflex/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex/udieresis/yacute/thorn/ydieresis
] d
0 0 T
N 0 0 M 0 36.135 L 36.135 0 L 0 -36.135 L X C
:
1 1 Z
;
:
1 1 Z
/Encoding_iso8859-1 [
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/space/exclam/quotedbl/numbersign/dollar/percent/ampersand/quotesingle/parenleft/parenright/asterisk/plus/comma/minus/period/slash
/zero/one/two/three/four/five/six/seven/eight/nine/colon/semicolon/less/equal/greater/question
/at/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O
/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backslash/bracketright/asciicircum/underscore
/grave/a/b/c/d/e/f/g/h/i/j/k/l/m/n/o
/p/q/r/s/t/u/v/w/x/y/z/braceleft/bar/braceright/asciitilde/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef/.notdef
/space/exclamdown/cent/sterling/currency/yen/brokenbar/section/dieresis/copyright/ordfeminine/guillemotleft/logicalnot/hyphen/registered/macron
/degree/plusminus/twosuperior/threesuperior/acute/mu/paragraph/periodcentered/cedilla/onesuperior/ordmasculine/guillemotright/onequarter/onehalf/threequarters/questiondown
/Agrave/Aacute/Acircumflex/Atilde/Adieresis/Aring/AE/Ccedilla/Egrave/Eacute/Ecircumflex/Edieresis/Igrave/Iacute/Icircumflex/Idieresis
/Eth/Ntilde/Ograve/Oacute/Ocircumflex/Otilde/Odieresis/multiply/Oslash/Ugrave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls
/agrave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla/egrave/eacute/ecircumflex/edieresis/igrave/iacute/icircumflex/idieresis
/eth/ntilde/ograve/oacute/ocircumflex/otilde/odieresis/divide/oslash/ugrave/uacute/ucircumflex/udieresis/yacute/thorn/ydieresis
] d
;
:
1 1 Z
;
:
N 0 0 M 0 36.51 L 36.89 0 L 0 -36.51 L X C
1 1 Z
Encoding_iso8859-1 /Helvetica reencode_font
/Helvetica FF 14 XF SF
: 7.53 10.43 T
0.526315789473684 1 Z
0 0 M
0 0 0 A
(f) S
3.96 0 M
(o) S
11.9 0 M
(o) S
;
; P
%%Trailer
%%DocumentNeededFonts:
%%DocumentSuppliedFonts:
%%Pages: 1
%%EOF
I have been looking into font setting issues and have come across a few discrepancies in font widths and positioning for postscript rendered under Subcanvas vs not under Subcanvas. This script reproduces the discrepancies. It also monkey-patches some Prima::PS::Drawable methods to print diagnostic output. The patch to
emit
gives a stack trace when it sees a zoom that's not simply1 1 Z
. The patch totext_out
prints the font width andfontWidthDivisor
just before performing thetext_out
, and indicates if the canvas being drawn things it hastextOutBaseline
set to true.In short
textOutBaseline
, which disagrees with the documentation inPrima::Drawable
(and is not mentioned inPrima::PS::Drawable
). I don't mind adapting to this, but it should probably be documented.There are other interesting discrepancies, such as an additional font encoding in the Subcanvas produced output, and the use of Helvetica-Narrow by the non-Subcanvas vs Helvetica by the Subcanvas. I think those are optimizations, however, and are not major concerns of mine for this issue.
When run with no arguments, the script gives the following output:
and produces this eps file:
which looks like this:![font-dimensions](https://cloud.githubusercontent.com/assets/260215/3250847/979a8bca-f1aa-11e3-8696-d4acfb5a0402.png)
When run with the
subcanvas
argument, it prints the following output:and produces this eps file:
which looks like this;![font-dimensions-subcanvas](https://cloud.githubusercontent.com/assets/260215/3250869/d0caecc8-f1aa-11e3-9c70-bfa42e016e49.png)