dk / Prima

prima.eu.org
Other
108 stars 27 forks source link

Multiple discrepancies between Subcanvas wrapped vs non-Subcanvas wrapped in postscript output #18

Closed run4flat closed 10 years ago

run4flat commented 10 years ago

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

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: font-dimensions


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

which looks like this; font-dimensions-subcanvas

dk commented 10 years ago

Now I think it should be fixed!

run4flat commented 10 years ago

I am pretty sure this fixes it. I just created an eps figure using the latest Prima. It is beautiful! Wow!