函数样式宏

时间:2016-01-18 17:55:27

标签: sas base64 sas-macro

这是this question的后续问题。

我正在尝试简化将图片嵌入HTML结果的方式。这个想法的灵感来自this other question

基本上我要做的是编写一个函数式宏(称为%html_embed_image())来获取图像,并将其转换为适合在HTML <img src="">块中使用的base64格式

给出如下图像:

enter image description here

用法是:

data _null_;
  file _webout;
  put "<img src=""%html_embed_image(iFileName=hi.png)"" />";
run;

最终输出将是:

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAIAAAAC64paAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAABaSURBVDhP5YxbCsAgDAS9/6XTvJTWNUSIX3ZAYXcdGxW4QW6Khw42Axne81LG0shlRvVVLyeTI2aZ2fcPyXwPdBI8B999NK/gKTaGyxaMX8gTJRkpyREFmegBTt8lFJjOey0AAAAASUVORK5CYII=" />

question linked above 显示了如何在常规datastep代码中执行此操作,但我在使用函数样式宏时遇到问题。我posted a simplified problem我之前遇到过,Tom能够解决这个简化的问题,但它似乎并没有在函数式​​宏的更大的上下文中工作。

到目前为止,这是我的代码(导致问题的行包含两个put语句,表明它是问题):

option mprint symbolgen;

%macro html_embed_image(iFileName=);

  %local rc fid rc2 str str_length format_length format_mod base64_format base64_string;

  /* ONLY READ IN 16K CHUNKS AS CONVERTING TO BASE64  */
  /* INCREASES SIZE AND DONT WANT TO EXCEED 32K. */
  %let rc  = %sysfunc(filename(filrf, &iFileName, , lrecl=16000));
  %let fid = %sysfunc(fopen(&filrf, i, 16000, b));

  %if &fid > 0 %then %do;

    %let rc = %sysfunc(fread(&fid));
    %do %while(&rc eq 0);  
      %let rc2 = %sysfunc(fget(&fid,str,16000));
      %let str = %superq(str);

      /* FORMAT LENGTH NEEDS TO BE 4n/3 ROUNDED UP TO NEAREST MULTIPLE OF 4 */
      %let str_length = %length(&str);
      %let format_length = %sysevalf(4*(&str_length/3));
      %let format_mod = %sysfunc(mod(&format_length,4));
      %if &format_mod ne 0 %then %do;
        %let format_length = %sysevalf(&format_length - &format_mod + 4);
      %end;
      %let base64_format = %sysfunc(cats($base64x,&format_length,.));
      %put &=base64_format;

      /* CONVERT THE BINARY DATA TO BASE64 USING THE CALCULATED FORMAT */
      %put PROBLEM START;
      %let base64_string = %sysfunc(putc(&str,&base64_format));
      %put PROBLEM END;


      %put &=base64_string;
      /*&base64_string*/ /* RETURN RESULT HERE - COMMENTED OUT UNTIL WORKING */

      %let rc = %sysfunc(fread(&fid)); 
    %end;

  %end;
  %else %do;
    %put %sysfunc(sysmsg());
  %end;

  %let rc=%sysfunc(fclose(&fid));
  %let rc=%sysfunc(filename(filrf));
%mend;

测试代码:

%put %html_embed_image(iFileName=hi.png);

结果:

ERROR: Expected close parenthesis after macro function invocation not found.

有关如何解决此问题的任何提示或建议的解决方法都会很棒。

1 个答案:

答案 0 :(得分:0)

只需使用数据步骤编写文本。

public String saveImage(MultipartFile file, String imageName) {
    try {
        String bucketName = "bucket";
        AmazonS3 s3client = new AmazonS3Client(
                new BasicAWSCredentials("*****", "******"));
        TransferManager transferManager = new TransferManager(s3client);
        // Otherwise: (Service: Amazon S3; Status Code: 301; Error Code:
        // PermanentRedirect)
        // s3client.setRegion(Region.getRegion(Regions.EU_WEST_1));
        ObjectMetadata objectMetadata = new ObjectMetadata();
        objectMetadata.setContentDisposition("attachment; filename=" + file.getOriginalFilename());
        Upload upload = transferManager.upload(bucketName, imageName, file.getInputStream(), objectMetadata);
        upload.waitForUploadResult();
        return "https://path-region/" + bucketName + "/" + imageName;
    } catch (Exception e) {
        return "You failed to upload " + e.getMessage();
    }
}




10:31:00,313 WARN  [com.amazonaws.services.s3.AmazonS3Client] (s3-transfer-manag
er-worker-1) No content length specified for stream data.  Stream contents will
be buffered in memory and could result in out of memory errors.

如果你真的想在线生成文本,最好添加引号,这样你就可以在PUT语句的中间调用宏而不用担心达到最大字符串长度。

%let fname=hi.png;
data _null_;
  file _webout recfm=n;
  if _n_=1 then put '<img src="data:image/png;base64,';
  length str $60 coded $80 ;
  infile "&fname" recfm=n eof=eof;
  do len=1 to 60;
    input ch $char1.;
    substr(str,len,1)=ch;
  end;
  put str $base64x80.;
return;
eof:
  len=len-1;
  clen=4*ceil(len/3);
  coded = putc(substr(str,1,len),cats('$base64x',clen,'.'));
  put coded $varying80. clen ;
  put '" />';
run;

那么你的示例数据步骤就像这样:

%macro base64(file);
%local filerc fileref rc fid text len ;

%*----------------------------------------------------------------------
Assign fileref and open the file.
-----------------------------------------------------------------------;
%let fileref = _fread;
%let filerc = %sysfunc(filename(fileref,&file));
%let fid = %sysfunc(fopen(&fileref,s,60,b));

%*----------------------------------------------------------------------
Read file and dump as quoted BASE64 text.
-----------------------------------------------------------------------;
%if (&fid > 0) %then %do;
  %do %while(%sysfunc(fread(&fid)) = 0);
    %do %while(not %sysfunc(fget(&fid,text,60)));
      %let len = %eval(4*%sysfunc(ceil(%length(%superq(text))/3)));
      %if (&len) %then "%sysfunc(putc(%superq(text),$base64x&len..))" ;
    %end;
  %end;
  %let rc = %sysfunc(fclose(&fid));
%end;

%*----------------------------------------------------------------------
Clear fileref assigned by macro,
-----------------------------------------------------------------------;
%if ^(&filerc) %then %let rc = %sysfunc(filename(fileref));

%mend base64;