Forum OpenACS Development: Re: Saving base64 url to a image file

Collapse
Posted by Steffen Tiedemann Christensen on

Hi Iuru,

There are a few quirks in your code sample (ns_mktemp takes a template argument; the switch statement shouldn't include the "case" part) -- but leaving that aside I think you need to switch your file socket to be binary using fconfigure.

This is probably a good starting point to solve your problem (with $raw being the data from the url):

 lassign [split $raw ","] header data
 
 # NOTE: Much better data validation is required here

 switch -exact $header {
   "data:image/png;base64" {
      set mime_type "image/png"
   }
   default {
     error "unsupported type"
   } 
 }

 set filename [ns_mktemp /tmp/base64-image-XXXXXX]

 set fd [open $filename w]
 fconfigure $fd -translation binary 
 package require base64
 puts $fd [base64::decode $data]
 close $fd

 ns_returnfile 200 $mime_type $filename
Collapse
Posted by Iuri Sampaio on
Thanks Steffen,
Yep, "fconfigure $fd -translation binary" was key in this process.
and not only file socket, but also switching ns_* procs to TCL libraries directly.

Indeed, your writing is much cleaner. And it works beautifuly! Thanks again!

Best wishes,
I

Collapse
Posted by Gustaf Neumann on

One can also use the built-in bas64decode, which is much faster:

  lappend _ [time {base64::decode $data} 1000]
  lappend _ [time {ns_base64decode -binary $data} 1000]

returns

{1757.215183 microseconds per iteration} {343.221319 microseconds per iteration}

In case, the content has just to be displayed, the file handing can be omitted.

 set r [ns_http run https://iurix.com/img.base64]
 lassign [split [dict get $r body] ,] header data

 switch -exact $header {
     "data:image/png;base64" { set mime_type "image/png" }
     default { error "unsupported type"} 
 }

 ns_return -binary 200 $mime_type [ns_base64decode -binary $data]
Collapse
Posted by Iuri Sampaio on
Hi Gustaf,
That was my very first attempt. The problem was exactly in the proc ns_base64decode.
...
[ns_base64decode -binary $data]
...

It returns an error regarding "-binary" switch (see logs bellow). Then I started to research for variations of that approach.

All them were frustrated because "-binary" switch is essential in the conversion process, whether at the creation of file descriptor
...
fconfigure $fd -translation binary
...

or at the data conversion itself

[ns_base64decode -binary $data]

NS realease is: NaviServer/4.99.18 (tar-4.99.18) running

Best wishes,
I

[02/Sep/2020:12:53:35][28801.7efbf3d70700][-conn:qonteo:0:742-] Error: wrong # args: should be "ns_base64decode string"
while executing
"ns_base64decode -binary $data"
("uplevel" body line 49)
invoked from within
"uplevel {

ns_log Notice "Running REST upload-image"

# Validate and Authenticate JWT
qt::rest::jwt::validation_p

if {[ns_conn method] eq "POST"..."
(procedure "code::tcl::/var/www/qonteo/oacs//packages/qt-rest/www/upload..." line 2)
invoked from within
"code::tcl::$__adp_stub"
("uplevel" body line 12)
invoked from within
"uplevel {

if { [file exists $__adp_stub.tcl] } {

# ensure that data source preparation procedure exists and is up-to-date
..."
(procedure "adp_prepare" line 2)
invoked from within
"adp_prepare"
invoked from within
"template::adp_parse $themed_template {}"
(procedure "adp_parse_ad_conn_file" line 14)
invoked from within
"$handler"
("uplevel" body line 2)
invoked from within
"uplevel $code"
invoked from within
"ad_try {
$handler
} ad_script_abort val {
# do nothing
}"
invoked from within
"rp_serve_concrete_file [ad_conn file]"
(procedure "::nsf::procs::rp_serve_abstract_file" line 60)
invoked from within

Collapse
Posted by Gustaf Neumann on
Use a more recent version: the "-binary" flag for ns_base64decode is supported since the release of 4.99.19 (Jan this year) [1].

-gn

[1] https://bitbucket.org/naviserver/naviserver/src/081829e43606b0e50baf3f258649ce4311358e10/NEWS#lines-220

Collapse
Posted by Iuri Sampaio on
Nice!
NS has been upgraded, and "-binary" works like a charm!
Best wishes,
I