In one of the many customer iterations I had recently, I was asked to help develop a solution to allow an image that was dynamically created by a third-party library/API to be embedded in a SAS Visual Analytics (VA) report. In addition to some input parameters passed to that external API that are irrelevant to our discussion, there was one in special that contained the full path and name of the output image to be generated. Although it seems a simple task, it doesn’t take too long to realize some of the challenges:
I’ve decided to use SAS code as a Viya Job to be able to deal with the constraints above. With the SAS code I’d be able to:
I only needed to find a way to transfer the image generated by the external API to the Viya Content Server, and it only took me one Google search for “sas copy binary files” to find the solution I was looking for in the first hit, a blog by Chris Hemedinger, more precisely the portion that uses the FCOPY function from SAS:
https://blogs.sas.com/content/sasdummy/2013/09/17/copy-file-macro/
This is the SAS code with the key elements:
* Close all ODS output;
ods _all_ close;
* Set the temporary file location;
filename _bcin TEMP recfm=n; * RECFM=N means that the input is read as a stream (there are no records);
* Obtain the temporary /path/file value;
%let tmpfile=%qsysfunc(pathname(_bcin));
* Here you would add the code to call the external API passing &tmpfile as parameter;
* Fileref _webout with name _webout.html is automatically assigned in Viya Jobs;
* If fileref with name _webout.* has an extension that the browser knows how to visualize, such as html, jpg, etc. it will display it;
* The pre-assigned fileref _webout is not needed, so we must delete it first;
%let RC=%sysfunc(fdelete(_webout));
* Set content server file location;
* We need a fileref with the image's extension (so the browser can display it) and add recfm=n;
* The fileref could be called anything you want;
filename _webout filesrvc parenturi="&SYS_JES_JOB_URI" name="_webout.jpg" recfm=n;
* Copy API output to Content Server;
data _null_;
length msg $ 384;
rc=fcopy('_bcin', '_webout');
if rc=0 then
put 'NOTE: Copied _bcin to _webout.';
else do;
msg=sysmsg();
put 'ERROR:' rc= msg=;
end;
run;
The code starts with closing all ODS outputs because we know we will be returning an image produced by an external API, so no ODS output is needed. Then we set the temporary file name and location using a TEMP fileref called _bcin and store its value in a macro variable. That macro variable is passed to the external API as the full path and name of the output image to be created. Next, we delete the existing fileref _webout. This fileref is automatically created for you in Viya Jobs with attribute name=_webout.html. All content of filerefs with name=_webout.* are automatically streamed back to the calling application, but we need a fileref that is slightly different. We need a fileref with RECFM=N, to indicate the file consists of a stream of bytes in binary format with no record boundaries, which is going to be necessary later when using the function FCOPY to copy the image generated by the API to the Content Server, and we want its name=_webout.jpg, so the browser knows it’s an image and therefore knows how to display it. The fileref itself does not need to be called _webout. The final data step copies the output image to Viya Content Server leveraging both filerefs. For the cleanup, the temporary file given by the TEMP fileref will be automatically disposed when the job finishes, and its copy in the _webout fileref will also be automatically deleted after some time.
If for some reason you want the name attribute of the fileref to be something other than _webout.*, or send back multiple files to the calling application, then you can call the Viya Job with _action=json. This makes the job return a list of output files in a json structure and the calling application has the freedom to decide what to do with each output file. This is explored in this other SAS Communities publication called Viya Jobs that Create Multiple Output Files.
In my final implementation, the code returned a couple of files (the output image and a small json file with information about the code execution status), simply because this is the template I’m currently leveraging for the Viya Jobs I develop. It also makes it simple to integrate the job with VA via DDC (Data-Driven Content), which is what I had to do for that customer. Indeed, I used that framework to provide a solution where the chart was being created in Python, using SAS PROC PYTHON, after receiving input parameters from VA, but this will be the topic for another blog.
April 27 – 30 | Gaylord Texan | Grapevine, Texas
Walk in ready to learn. Walk out ready to deliver. This is the data and AI conference you can't afford to miss.
Register now and lock in 2025 pricing—just $495!
The rapid growth of AI technologies is driving an AI skills gap and demand for AI talent. Ready to grow your AI literacy? SAS offers free ways to get started for beginners, business leaders, and analytics professionals of all skill levels. Your future self will thank you.