From db50b97c9ef69331c4a3cabc7be3552d28cb1ac0 Mon Sep 17 00:00:00 2001 From: robertoffmoura Date: Sun, 4 Aug 2024 17:51:32 +0100 Subject: [PATCH] Use built-in 'matlab.net.base64decode' (introduced in R2016b) instead of vendoring 'base64decode' --- plotly/export_fig2/write_image.m | 198 ++++++++++++++++--------------- plotly/plotly_aux/base64decode.m | 117 ------------------ 2 files changed, 102 insertions(+), 213 deletions(-) delete mode 100644 plotly/plotly_aux/base64decode.m diff --git a/plotly/export_fig2/write_image.m b/plotly/export_fig2/write_image.m index bf84f72e..921ef066 100644 --- a/plotly/export_fig2/write_image.m +++ b/plotly/export_fig2/write_image.m @@ -1,111 +1,117 @@ function output = write_image(pfObj, imageFormat, filename, height, width, scale) + % Function to write plotly figures to a supported image format, which + % are the following: "png", "jpg", "jpeg", "webp", "svg", "pdf", "eps", + % "json". + + debug=0; + if nargin < 2 + imageFormat = "png"; + filename = "figure.png"; + height = pfObj.layout.height; + width = pfObj.layout.width; + scale = 1; + elseif nargin < 3 + filename = "figure." + imageFormat; + height = pfObj.layout.height; + width = pfObj.layout.width; + scale = 1; + elseif nargin < 4 + height = pfObj.layout.height; + width = pfObj.layout.width; + scale = 1; + elseif nargin < 5 + width = pfObj.layout.width; + scale = 1; + elseif nargin < 6 + scale = 1; + end -% Function to write plotly figures to a supported image format, which are the following: "png", "jpg", "jpeg", "webp", "svg", "pdf", "eps", "json" - -debug=0; -if nargin < 2 - imageFormat="png"; - filename='figure.png'; - height=pfObj.layout.height; - width=pfObj.layout.width; - scale=1; -elseif nargin < 3 - filename=['figure.',char(imageFormat)]; - height=pfObj.layout.height; - width=pfObj.layout.width; - scale=1; -elseif nargin < 4 - height=pfObj.layout.height; - width=pfObj.layout.width; - scale=1; -elseif nargin < 5 - width=pfObj.layout.width; - scale=1; -elseif nargin < 6 - scale=1; -end - -if strcmpi(imageFormat,'jpg') - imageFormat = "jpeg"; -end - -wd=fileparts(fileparts(mfilename('fullpath'))); -output=[]; - -if ~isa(pfObj,'plotlyfig') - fprintf('\nError: Input is not a plotlyfig object.\n\n'); - return -end - -if isunix() - kExec = string(fullfile(wd,'kaleido','kaleido')); - cc="cat"; -else - kExec = string(fullfile(wd,'kaleido','kaleido.cmd')); - cc="type"; -end -plyJsLoc = string(fullfile(wd,'kaleido','plotly-latest.min.js')); + if strcmpi(imageFormat, "jpg") + imageFormat = "jpeg"; + end -if ~isfile(kExec) || ~isfile(plyJsLoc) - status=getKaleido(); -else - status=1; -end + wd = fileparts(fileparts(mfilename("fullpath"))); + output = []; -if status == 0 - return -end + if ~isa(pfObj, "plotlyfig") + fprintf("\nError: Input is not a plotlyfig object.\n\n"); + return + end -mjLoc = replace(string(fullfile(wd,'kaleido','etc','mathjax','MathJax.js')),'\','/'); -scope="plotly"; + if isunix() + kExec = string(fullfile(wd,"kaleido", "kaleido")); + cc = "cat"; + else + kExec = string(fullfile(wd,"kaleido", "kaleido.cmd")); + cc = "type"; + end + plyJsLoc = string(fullfile(wd,"kaleido", "plotly-latest.min.js")); + if ~isfile(kExec) || ~isfile(plyJsLoc) + status = getKaleido(); + else + status = 1; + end -% Prepare input plotly object for Kaleido -q=struct(); -q.data.data = pfObj.data; -q.data.layout = pfObj.layout; -q.data.layout = rmfield(q.data.layout,'height'); -q.data.layout = rmfield(q.data.layout,'width'); -q.format = string(imageFormat); -q.height = height; -q.scale = scale; -q.width = width; + if status == 0 + return + end -pfJson = native2unicode(jsonencode(q),'UTF-8'); -tFile = string(fullfile(wd,'kaleido','temp.txt')); -f=fopen(tFile,'w'); -fprintf(f,"%s",pfJson); -fclose(f); + mjLoc = replace(string(fullfile( ... + wd, "kaleido", "etc", "mathjax", "MathJax.js")), "\", "/"); + scope="plotly"; + + % Prepare input plotly object for Kaleido + q = struct(); + q.data.data = pfObj.data; + q.data.layout = pfObj.layout; + q.data.layout = rmfield(q.data.layout, "height"); + q.data.layout = rmfield(q.data.layout, "width"); + q.format = string(imageFormat); + q.height = height; + q.scale = scale; + q.width = width; + + pfJson = native2unicode(jsonencode(q), "UTF-8"); + tFile = string(fullfile(wd, "kaleido", "temp.txt")); + f = fopen(tFile, "w"); + fprintf(f, "%s", pfJson); + fclose(f); -cmd=[cc," ",tFile," | ",kExec," ",scope," --plotlyjs='",plyJsLoc,"' ","--mathjax='file:///",mjLoc,"' --no-sandbox --disable-gpu --allow-file-access-from-files --disable-breakpad --disable-dev-shm-usage"]; + cmd = [cc, " ", tFile, " | ", kExec, " ", scope, " --plotlyjs='", ... + plyJsLoc, "' ", "--mathjax='file:///",mjLoc,"' " ... + + "--no-sandbox --disable-gpu " ... + + "--allow-file-access-from-files --disable-breakpad " ... + + "--disable-dev-shm-usage"]; -if debug - inputCmd=char(join(cmd,'')); - fprintf('\nDebug info:\n%s\n\n',inputCmd); -end + if debug + inputCmd = char(join(cmd, "")); + fprintf("\nDebug info:\n%s\n\n", inputCmd); + end -[code,out]=system(char(join(cmd,''))); -if debug - disp(out); -end + [code,out] = system(char(join(cmd, ""))); + if debug + disp(out); + end -if code ~= 0 - fprintf('\nFatal: Failed to run Kaleido.\n\n'); - return; -else - a=string(split(out,newline)); - if a(end)=="" - a(end)=[]; + if code ~= 0 + fprintf("\nFatal: Failed to run Kaleido.\n\n"); + return; + else + a = string(split(out,newline)); + if a(end) == "" + a(end) = []; + end + output = jsondecode(a(end)); end - output = jsondecode(a(end)); -end -if output.code ~= 0 - fprintf('\nError: %s\n',output.message); -else - out=unicode2native(output.result,'UTF-8'); - out=base64decode(out); - f=fopen(char(filename),'wb'); - fwrite(f,out); - fclose(f); + if output.code ~= 0 + fprintf("\nError: %s\n", output.message); + else + out = unicode2native(output.result, "UTF-8"); + out = matlab.net.base64decode(out); + f = fopen(char(filename), "wb"); + fwrite(f, out); + fclose(f); + end end diff --git a/plotly/plotly_aux/base64decode.m b/plotly/plotly_aux/base64decode.m deleted file mode 100644 index 949a075a..00000000 --- a/plotly/plotly_aux/base64decode.m +++ /dev/null @@ -1,117 +0,0 @@ -function y = base64decode(x, outfname, alg) -%BASE64DECODE Perform base64 decoding on a string. -% -% INPUT: -% x - block of data to be decoded. Can be a string or a numeric -% vector containing integers in the range 0-255. Any character -% not part of the 65-character base64 subset set is silently -% ignored. Characters occuring after a '=' padding character are -% never decoded. If the length of the string to decode (after -% ignoring non-base64 chars) is not a multiple of 4, then a -% warning is generated. -% -% outfname - if provided the binary date from decoded string will be -% saved into a file. Since Base64 coding is often used to embbed -% binary data in xml files, this option can be used to extract and -% save them. -% -% alg - Algorithm to use: can take values 'java' or 'matlab'. Optional -% variable defaulting to 'java' which is a little faster. If -% 'java' is chosen than core of the code is performed by a call to -% a java library. Optionally all operations can be performed using -% matleb code. -% -% OUTPUT: -% y - array of binary data returned as uint8 -% -% This function is used to decode strings from the Base64 encoding specified -% in RFC 2045 - MIME (Multipurpose Internet Mail Extensions). The Base64 -% encoding is designed to represent arbitrary sequences of octets in a form -% that need not be humanly readable. A 65-character subset ([A-Za-z0-9+/=]) -% of US-ASCII is used, enabling 6 bits to be represented per printable -% character. -% -% See also BASE64ENCODE. -% -% Written by Jarek Tuszynski, SAIC, jaroslaw.w.tuszynski_at_saic.com -% -% Matlab version based on 2004 code by Peter J. Acklam -% E-mail: pjacklam@online.no -% URL: http://home.online.no/~pjacklam -% http://home.online.no/~pjacklam/matlab/software/util/datautil/base64encode.m - -if nargin<3, alg='java'; end -if nargin<2, outfname=''; end - -%% if x happen to be a filename than read the file -if (numel(x)<256) - if (exist(x, 'file')==2) - fid = fopen(x,'rb'); - x = fread(fid, 'uint8'); - fclose(fid); - end -end -x = uint8(x(:)); % unify format - -%% Perform conversion -switch (alg) - case 'java' - base64 = org.apache.commons.codec.binary.Base64; - y = base64.decode(x); - y = mod(int16(y),256); % convert from int8 to uint8 - case 'matlab' - %% Perform the mapping - % A-Z -> 0 - 25 - % a-z -> 26 - 51 - % 0-9 -> 52 - 61 - % + - -> 62 '-' is URL_SAFE alternative - % / _ -> 63 '_' is URL_SAFE alternative - map = uint8(zeros(1,256)+65); - map(uint8(['A':'Z', 'a':'z', '0':'9', '+/=']))= 0:64; - map(uint8('-_'))= 62:63; % URL_SAFE alternatives - x = map(x); % mapping - - x(x>64)=[]; % remove non-base64 chars - if rem(numel(x), 4) - warning('Length of base64 data not a multiple of 4; padding input.'); - end - x(x==64)=[]; % remove padding characters - - %% add padding and reshape - nebytes = length(x); % number of encoded bytes - nchunks = ceil(nebytes/4); % number of chunks/groups - if rem(nebytes, 4)>0 - x(end+1 : 4*nchunks) = 0; % add padding - end - x = reshape(uint8(x), 4, nchunks); - y = repmat(uint8(0), 3, nchunks); % for the decoded data - - %% Rearrange every 4 bytes into 3 bytes - % 00aaaaaa 00bbbbbb 00cccccc 00dddddd - % to form - % aaaaaabb bbbbcccc ccdddddd - y(1,:) = bitshift(x(1,:), 2); % 6 highest bits of y(1,:) - y(1,:) = bitor(y(1,:), bitshift(x(2,:), -4)); % 2 lowest bits of y(1,:) - y(2,:) = bitshift(x(2,:), 4); % 4 highest bits of y(2,:) - y(2,:) = bitor(y(2,:), bitshift(x(3,:), -2)); % 4 lowest bits of y(2,:) - y(3,:) = bitshift(x(3,:), 6); % 2 highest bits of y(3,:) - y(3,:) = bitor(y(3,:), x(4,:)); % 6 lowest bits of y(3,:) - - %% remove extra padding - switch rem(nebytes, 4) - case 2 - y = y(1:end-2); - case 3 - y = y(1:end-1); - end -end - -%% reshape to a row vector and make it a character array -y = uint8(reshape(y, 1, numel(y))); - -%% save to file if needed -if ~isempty(outfname) - fid = fopen(outfname,'wb'); - fwrite(fid, y, 'uint8'); - fclose(fid); -end \ No newline at end of file