Saturday, September 11, 2021

Asymptote and opacity

 I am a terrible draw-er.  When I first started using computers, I got a tutorial for MS Paint, which wanted to walk me through drawing a picture of a magician's hat and wand.  "First use the Ellipse Tool to draw an ellipse" it said, and there was an accompanying picture.  I complied and got a pretty good copy.  "Now extend to get the body of the hat."  I could not.  No matter how many times I followed the steps, the body of the hat did not look right and I was unable to figure out how to change it to make it look like, you know, a hat body. In between my ears, where there ought to be a place to draw pictures, there is a gap.  A hole.  A yawing chasm.

I now rely on using systems where you say, "Put the camera at (10,5,4), point it at the origin, and show the extended elliptical surface."  This way, I am sure I get a good picture.  Specifically, I use AsymptoteIt is a programming language that outputs graphics, which are suitable for mathematics writing (including that it integrates with LaTeX).  One of its strengths is a great tutorial.

But all software has glitches and there has been an issue with opacity.  Opacity is partial transparency.  An example of using it is when you draw a plane in 3-space and you want see the axes when they are behind the plane.

Asymptote relies on Ghostscript as a back end, to handle the initial graphical output.  Some time ago, years ago, Ghostscript had a security issue affecting the Asymptote graphics that use opacity.  For a few years, the workaround was to call Asymptote with `asy -nosafe filename'.  No longer.  Here is part of a post I recently made to the Asymptote mailing list.

With this test.asy,

import settings;
settings.outformat="pdf";
settings.render=0;

unitsize(1pt);

draw((0,0)--(1,1), red+opacity(0.7));
// draw((0,0)--(1,1), red);

I get the GS failure

Loading test from test.asy
gs -q -dNOPAUSE -dBATCH -P -dALLOWPSTRANSPARENCY -sDEVICE=pdfwrite -dEPSCrop -dSubsetFonts=true -dEmbedAllFonts=true -dMaxSubsetPct=100 -dEncodeColorImages=true -dEncodeGrayImages=true -dCompatibilityLevel=1.4 -dAutoRotatePages=/None -g612x792 -dDEVICEWIDTHPOINTS=3 -dDEVICEHEIGHTPOINTS=3 -sOutputFile=test.pdf test_.eps
Error: /undefined in .setfillconstantalpha
Operand stack:
   0.7
Execution stack:
   %interp_exit   .runexec2   --nostringval--   --nostringval--   --nostringval--   2   %stopped_push   --nostringval--   --nostringval--   --nostringval--   false   1   %stopped_push   1990   1   3   %oparray_pop   1989   1   3   %oparray_pop   1988   1   3   %oparray_pop   --nostringval--   1977   1   3   %oparray_pop   1833   1   3   %oparray_pop   --nostringval--   %errorexec_pop   .runexec2   --nostringval--   --nostringval--   --nostringval--   2   %stopped_push   --nostringval--
Dictionary stack:
   --dict:739/1123(ro)(G)--   --dict:0/20(G)--   --dict:79/200(L)--
Current allocation mode is local
Current file position is 284
GPL Ghostscript 9.50: Unrecoverable error, exit code 1
  _shipout(prefix,f,currentpatterns,format,wait,view,t);
          ^
/usr/local/texlive/2021/texmf-dist/asymptote/plain_shipout.asy: 104.11: runtime: shipout failed

The error happens whether I use the -nosafe option or not. If I comment out the opacity-containing line and uncomment the other, then the error goes away and a correct .pdf comes out.

I recognized the `Error: /undefined in .setfillconstantalpha'.  My old nemesis is back.  Turns out, recently the Ghostscript people have implemented different operators to avoid the security issues.  So the option `-nosafe' no longer works, because you can't just ignore the security issues with the operators, since those operators are gone.  Instead, you have to worry about using specific versions of Ghostscript.  Yech. 

Anyway, the point of this post is to spread spread the word from the mailing list about the work-around.  (1) Download a known-good Ghostscript, as with gs 9.52 (watch out, 9.54 is back to not working, for instance).  Then for compiling with Asymptote, you can specify an alternate ghostscript location with settings.gs, or with the -gs command line option, or with the ASYMPTOTE_GS environment variable.  

Thanks to John and the other Asymptote folks for really useful software!