Here is a small sample program that actually creates the HTML file in the current app's AFiles. I've made the screen capture simple so the speed is pretty good for demonstration purposes. With more complex screen content of course it gets more involved and slower.
Code:
WriteBase64();
BinaryString();
EXPORT base64img()
BEGIN
LOCAL fname:="b64img.html",htmlcontent,fsize,fiter,cur_chunk,j;
RECT_P(G0,0,0,319,239,#000000h,#CCCCCCh);
TEXTOUT_P("Sample Screen Capture",G0,5,10,3,#000000h);
AFiles(fname):=G0;
htmlcontent:="<!doctype html><html lang=\"en\"><head><meta charset=\"utf-8\"><title>Base64 Screen Capture</title></head><body><body><div><img style=\"display:block; margin:0 auto;\" src=\"data:image/png;base64,"+WriteBase64(fname)+"\" alt=\"Sample Screen Capture\" /></div></body></html>";
DelAFiles(fname);
fsize:=DIM(htmlcontent);
IF fsize>10000 THEN // again max of 10000
fiter:=IP(fsize/10000);
FOR j FROM 1 TO fiter DO
cur_chunk:=ASC(MID(htmlcontent,(j-1)*10000+1,10000));
AFilesB(fname,(j-1)*10000):=cur_chunk;
END;
IF FP(fsize/10000) THEN
cur_chunk:=ASC(MID(htmlcontent,fiter*10000+1));
AFilesB(fname,fiter*10000):=cur_chunk;
END;
ELSE
AFilesB(fname,0):=ASC(htmlcontent);
END;
END;
WriteBase64(fname)
BEGIN
LOCAL mylst,mystr:="",mylen,mysubstr,newlst,i,j,b64str:="";
LOCAL fsize,fiter,fcontent,padsz,cur_chunk;
LOCAL dict:={"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","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","0","1","2","3","4","5","6","7","8","9","+","/"};
fsize:=AFilesB(fname);
IF fsize>10000 THEN // lists can not be longer than 10000 items so it's necessary to process in chunks if longer
fiter:=IP(fsize/10000);
FOR j FROM 1 TO fiter DO
fcontent:=AFilesB(fname,(j-1)*10000,10000);
mystr:=mystr+BinaryString(fcontent);
END;
IF FP(fsize/10000) THEN
fcontent:=AFilesB(fname,fiter*10000,fsize-(fiter*10000));
mystr:=mystr+BinaryString(fcontent);
END;
ELSE
fcontent:=AFilesB(fname,0,fsize);
mystr:=mystr+BinaryString(fcontent);
END;
mylen:=DIM(mystr);
FOR i FROM 1 TO IP(mylen/24) DO // iterate over 24-bit increments, construct the 6-bit integers as strings
mysubstr:=MID(mystr,(i-1)*24+1,24);
newlst:=EXPR("{#"+MID(mysubstr,1,6)+"b,#"+MID(mysubstr,7,6)+"b,#"+MID(mysubstr,13,6)+"b,#"+MID(mysubstr,19,6)+"b}");
newlst:=SETBASE(newlst,3);
b64str:=b64str+dict(newlst(1)+1)+dict(newlst(2)+1)+dict(newlst(3)+1)+dict(newlst(4)+1);
END;
IF FP(mylen/24) THEN // deal with partial remainders of less than 24 bits
mysubstr:=MID(mystr,(i-1)*24+1);
padsz:=6-(DIM(mysubstr) MOD 6);
IF padsz THEN
FOR i FROM 1 TO padsz DO
mysubstr:=mysubstr+"0";
END;
END;
newlst:="{";
FOR i FROM 1 TO DIM(mysubstr)/6 DO
newlst:=newlst+IFTE(i>1,",","");
newlst:=newlst+"#"+MID(mysubstr,(i-1)*6+1,6)+"b";
END;
newlst:=EXPR(newlst+"}");
newlst:=SETBASE(newlst,3);
FOR i FROM 1 TO SIZE(newlst) DO
b64str:=b64str+dict(newlst(i)+1);
END;
padsz:=4-(SIZE(newlst) MOD 4);
IF padsz THEN // pad if necessary
FOR i FROM 1 TO padsz DO
b64str:=b64str+"=";
END;
END;
END;
RETURN b64str;
END;
// returns a string of sequential binary integers from a list of decimal integers
BinaryString(declist)
BEGIN
LOCAL binlist,k,curstr,binstr:="";
binlist:=SETBASE(declist,1);
FOR k FROM 1 TO SIZE(declist) DO
curstr:=STRING(binlist(k));
binstr:=binstr+RIGHT("0000000"+MID(curstr,2,DIM(curstr)-2),8);
END;
RETURN binstr;
END;
I'll follow up in the next post about the challenge to make this program faster.