Exception when converting to image from Base-64 string - javascript

I am trying to send a Highcharts chart via image on ASP.NET button click.
What I am trying to do is:
Convert the chart to base64 image, the code is the following :
var chart = $('#main-content').highcharts();
EXPORT_WIDTH = 1000;
var render_width = EXPORT_WIDTH;
var render_height = render_width * chart.chartHeight / chart.chartWidth;
var svg = chart.getSVG({
exporting: {
sourceWidth: chart.chartWidth,
sourceHeight: chart.chartHeight
}
});
var contentToSend = 'data:image/svg+xml;base64,' + window.btoa(svg);
var hdnField = document.getElementById("MainContent_ChartImage");
hdnField.value = contentToSend;
Next step is taking the base64 image value, convert it to image an attach it to the mail, the code is:
string textImage = ChartImage.Value;
var imageData = Convert.FromBase64String(HttpUtility.UrlDecode(data));
System.Net.Mail.LinkedResource res;
AlternateView htmlView;
using (MemoryStream ms = new MemoryStream(imageData, true))
{
ms.Position = 0;
ms.Write(imageData, 0, imageData.Length);
ms.Seek(0, SeekOrigin.Begin);
res = new System.Net.Mail.LinkedResource(ms);
htmlView = AlternateView.CreateAlternateViewFromString("<html><body><img src='cid:imageReport' width='100%' ></body></html>", null, "text/html");
res.ContentId = "imageReport";
htmlView.LinkedResources.Add(res);
MailMessage mailMsg = new MailMessage();
SmtpClient client = new SmtpClient();
// ...
mailMsg.IsBodyHtml = true;
mailMsg.AlternateViews.Add(htmlView);
client.Send(mailMsg);
}
but the method Convert.FromBase64String throws an exception
{"The input is not a valid Base-64 string as it contains a non-base 64
character, more than two padding characters, or an illegal character
among the padding characters. "}
However when I remove 'data:image/svg+xml;base64,' then convert it, it doesn't throw an exception but the image will not appear. What should I do?
Thank you

Get rid of the beginning part of the string: "data:image/svg+xml;base64," that part is not base64, just the remainder is. You don't need to use HttpUtility.UrlDecode either.
You should specify the TransferEncoding as Base64:
res.TransferEncoding = System.Net.Mime.TransferEncoding.Base64;
However with all that said, there are some strong caveats to using SVG in email. So you may want to consider a different format such as JPG or PNG. If that's the route you take, you will need to use a library to convert formats.

After many researches I found the solution , the main problem was that not all client email support data URI :
What is Data URI support like in major email client software?
i was trying to open the mail from the outlook 2016 however it is not supported , when i opened from hotmail.com it worked..
the code is :
MailMessage mailMsg = new MailMessage();
SmtpClient client = new SmtpClient();
var imageData = Convert.FromBase64String(data);
var contentId = Guid.NewGuid().ToString();
var linkedResource = new LinkedResource(new MemoryStream(imageData), "image/svg+xml");
linkedResource.ContentId = contentId;
linkedResource.TransferEncoding = TransferEncoding.Base64;
var body = string.Format("<img src=\"cid:{0}\" />", contentId);
var htmlView = AlternateView.CreateAlternateViewFromString(body, null, "text/html");
htmlView.LinkedResources.Add(linkedResource);
mailMsg.AlternateViews.Add(htmlView);

Related

Change segment text before processing using hls.js

so due to some security reason i want to add some extra text to .ts file in the begining of so when parsing it causes buffering issues
to fix this i decided to removed that 'extra' text i added before processing the segment issue is i dont know how to manipulate arraybuffer so i can remove that text since i am not that knowledgable on js
I tried many things including just download hlsjs file directly then edit readystatechange
// >= HEADERS_RECEIVED
if (readyState >= 2) {
....
if (isArrayBuffer)
{
console.log(xhr.response);
var ress = xhr.response;
//console.log(ress.replace('FFmpeg',''));
var enc = new TextDecoder('ASCII');
var seg = enc.decode(ress);
//var binaryArray = new Uint8Array(this.response.slice(0)); // use UInt8Array for binary
//var blob = new Blob([seg], { type: "video/MP2T" });
var enc = new TextEncoder(); // always utf-8
var newww = enc.encode(enc.encode(seg));
var ddd = newww.buffer;
console.debug( newww );
console.debug( newww.buffer);
//dec = dec.replace('ÿØÿà �JFIF','') ;
//xhr.response = Array.from(newww) ;
data = ddd;
len = data.byteLength;
the idea was to convert arraybuffer to string remove that text then convert it back to arraybuffer

Filename issue in Photoshop script that put multiple PNGs on mockups

I am using JS with Photoshop to put multiple PNGs on the mockup and export them as JPGs. Everything is working fine except for the exported file name. It names the file with the current date and time.
var filename = docPath + '/' + basename + "#" + getTime() + '.jpg';
I want it to name the files in a sequence like, Mockup 1, Mockup 2, Mockup 3 ...
Is there any way to do it?
Any help will be highly appreciated.
Example to gain correct Filename:
docPath = "/myProjectFolder/img"; //set the path / maindirectory you need
basename = "myFileprimaryName"; // set the primary Name you want to use
//getDate ist a function of the Date object - you need to instance it to call
var myDate = new Date();
var filename = docPath + '/' + basename + "#" + myDate.getTime() + '.jpg';
//Following Lines will just give you an output, to check if variables
//are set correct - you will not need them in final code
const data = {
message: filename,
}
$('#msg').html(data.message)
Note: Not sure if '#' is really the best sign to use to set in Filenames, I would rather preferre to use "_" instead, due to interoperability on different filesystems.
To save the file you will need to create a new File-Object, assign the Filename to it and save the file through the .saveAs() function, like in the following.
Example to save File:
var newFile = new File(filename);
var saveOptions = new JPEGSaveOptions();
saveOptions.embedColorProfile = true;
saveOptions.formatOptions = FormatOptions.STANDARDBASELINE;
saveOptions.matte = MatteType.NONE;
saveOptions.quality = quality;
document.saveAs(newFile, saveOptions, true, Extension.LOWERCASE);
Now if you want to generate and save multiple files, it's pretty basic for you just jave to combine the two snipplets in a for-Loop.
Example to generate multiple files / filenames - out of one source file:
docPath = "/myProjectFolder/img";
basename = "myFileprimaryName";
var filename;
var saveOptions = new JPEGSaveOptions();
saveOptions.embedColorProfile = true;
saveOptions.formatOptions = FormatOptions.STANDARDBASELINE;
saveOptions.matte = MatteType.NONE;
saveOptions.quality = quality;
var myDate = new Date();
var i;
for (i = 0; i < cars.length; i++) {
filename = docPath + '/' + basename + +"#" + i + myDate.getTime() +'.jpg';
var newFile = new File(filename);
document.saveAs(newFile, saveOptions, true, Extension.LOWERCASE);
}
Note: this will create the same file with the same content multiple times (e.g. if you are a teacher who wants to handle working copies of the same file to multiple students. If you instead want to save different files, I would rather do the following: Check the Maximum Count of Basename#Count of existing files in directory, increment it and save lateron new file with incremented Count.

Return text from output stream in c#

I have a scenario where i need to get string as output stream in c#. I need to get those string value in javascript. Following is code
JS
var timestampUrl : "getTime.aspx" // Used somewhere in plugin. Syntax is fine
Originally was written as var timestampUrl : "getTime.php" but i changed it to work in .aspx also
getTime.php code
<?php
echo time();
?>
getTime.aspx.cs
var ts = ((long)(DateTime.Now - new DateTime(1970, 1, 1)).TotalMilliseconds) / 1000;
Response.ContentType = "text/plain";
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(ts.ToString());
Response.OutputStream.Write(bytes, 0, bytes.Length);
But i get the output as
1436538190%3C!DOCTYPE%20html%3E%3Chtml%20xmlns=%22http://www.w3.org/1999/xhtml%22%3E%3Chead%3E%3Ctitle%3E%3C/title%3E%3C/head%3E%3Cbody%3E%20%20%20%20%3Cform%20method=%22post%22%20action=%22getTime.aspx%22%20id=%22form1%22%3E%3Cdiv%20class=%22aspNetHidden%22%3E%3Cinput%20type=%22hidden%22%20name=%22__VIEWSTATE%22%20id=%22__VIEWSTATE%22%20value=%22oyHYMIrhkYo9Ho3QkkQWovQ9tbRhQ2wRTHQfGgw4jJwaPeQsTPcZzR1s5K/dHFoH+p82j3XOogiKTqnH0MB/T9K/8kizxTDiLPwKPNWHHp0=%22%20/%3E%3C/div%3E%20%20%20%20%3Cdiv%3E%20%20%20%20%20%20%20%20%3C/div%3E%20%20%20%20%3Cdiv%20class=%22aspNetHidden%22%3E%3Cinput%20type=%22hidden%22%20name=%22__VIEWSTATEGENERATOR%22%20id=%22__VIEWSTATEGENERATOR%22%20value=%22EA09725A%22%20/%3E%3C/div%3E%3C/form%3E%3C!--%20Visual%20Studio%20Browser%20Link%20--%3E%3Cscript%20type=%22application/json%22%20id=%22__browserLink_initializationData%22%3E%20%20%20%20%7B%22appName%22:%22InternetExplorer%22,%22requestId%22:%22f532ae409a044422a3178fdad51fb6a0%22%7D%3C/script%3E%3Cscript%20type=%22text/javascript%22%20src=%22http://localhost:62796/df94eb33421548aca703559a9bdf2a2c/browserLink%22%20async=%22async%22%3E%3C/script%3E%3C!--%20End%20Browser%20Link%20--%3E%3C/body%3E%3C/html%3E
Instead of only 436538190
What could be the cause ?
You need to close off the stream.
var ts = ((long)(DateTime.Now - new DateTime(1970, 1, 1)).TotalMilliseconds) / 1000;
Response.ContentType = "text/plain";
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(ts.ToString());
Response.OutputStream.Write(bytes, 0, bytes.Length);
Response.Flush();
//now signal the httpapplication to stop processing the request.
HttpContext.Current.ApplicationInstance.CompleteRequest();
See: issue with Response.OutputStream.Write adding html code in the resulting file

Convert inline SVG to Base64 string

I want to send an inline SVG image to a PHP script to Convert it to PNG with Imagick. For that I have to know how to get a base64 String out on an inline SVG. For canvas objects its a simple ".toDataURL()" but that doesn't work with inline SVGs, because its not a global function of elements.
test = function(){
var b64 = document.getElementById("svg").toDataURL();
alert(b64);
}
http://jsfiddle.net/nikolang/ccx195qj/1/
But how to do it for inline SVGs?
Use XMLSerializer to convert the DOM to a string
var s = new XMLSerializer().serializeToString(document.getElementById("svg"))
and then btoa can convert that to base64
var encodedData = window.btoa(s);
Just prepend the data URL intro i.e. data:image/svg+xml;base64, and there you have it.
I just try to collect and explain all great ideas on this issue. This works on both Chrome 76 and Firefox 68
var svgElement = document.getElementById('svgId');
// Create your own image
var img = document.createElement('img');
// Serialize the svg to string
var svgString = new XMLSerializer().serializeToString(svgElement);
// Remove any characters outside the Latin1 range
var decoded = unescape(encodeURIComponent(svgString));
// Now we can use btoa to convert the svg to base64
var base64 = btoa(decoded);
var imgSource = `data:image/svg+xml;base64,${base64}`;
img.setAttribute('src', imgSource);
You can do it relatively straightforwardly as follows. The short version is
Make an image not attached to the dom
Set its size to match the source svg
base64 encode the source svg, append the relevant data, set img src
Get the canvas context; .drawImage the image
<script type="text/javascript">
window.onload = function() {
paintSvgToCanvas(document.getElementById('source'), document.getElementById('tgt'));
}
function paintSvgToCanvas(uSvg, uCanvas) {
var pbx = document.createElement('img');
pbx.style.width = uSvg.style.width;
pbx.style.height = uSvg.style.height;
pbx.src = 'data:image/svg+xml;base64,' + window.btoa(uSvg.outerHTML);
uCanvas.getContext('2d').drawImage(pbx, 0, 0);
}
</script>
<svg xmlns="http://www.w3.org/2000/svg" width="467" height="462" id="source">
<rect x="80" y="60" width="250" height="250" rx="20" style="fill:#ff0000; stroke:#000000;stroke-width:2px;" />
<rect x="140" y="120" width="250" height="250" rx="40" style="fill:#0000ff; stroke:#000000; stroke-width:2px; fill-opacity:0.7;" />
</svg>
<canvas height="462px" width="467px" id="tgt"></canvas>
JSFiddle: https://jsfiddle.net/oz3tjnk7/
I had the same problem while working on SVG based Floorplan Editor, after drawing a floorplan we have to save it for later use. Long story, code is better than talking, Here is the final code which worked for me:
async saveFloorplan() {
const svgElem = document.querySelector('#svg-element');
let xmlSource = new XMLSerializer().serializeToString(svgElem);
if (!xmlSource.match(/^<svg[^>]+xmlns="http:\/\/www\.w3\.org\/2000\/svg"/)) {
xmlSource = xmlSource.replace(/^<svg/, '<svg xmlns="http://www.w3.org/2000/svg"');
}
if (!xmlSource.match(/^<svg[^>]+"http:\/\/www\.w3\.org\/1999\/xlink"/)) {
xmlSource = xmlSource.replace(/^<svg/, '<svg xmlns:xlink="http://www.w3.org/1999/xlink"');
}
// add xml declaration
xmlSource = `<?xml version="1.0" standalone="no"?>\r\n${xmlSource}`;
const svg64 = encodeURIComponent(xmlSource);
const b64Start = 'data:image/svg+xml;charset=utf-8,';
const imgEl = new Image();
const image64 = b64Start + svg64;
imgEl.src = image64;
const blobResp = await fetch(imgEl.src);
const blob = await blobResp.blob();
const payload = {...}
payload.fileExtension = 'svg';
payload.fileSize = blob.size;
const formData = new FormData();
formData.append('file', blob);
const uploaded = await api.uploadFile(formData);
}
This line will perform the conversion:
window.btoa($("svg").wrap("<div id='xyz'/>").parent().html());
Make sure that the proper charset/encoding has been selected!
// 1. get the element
let e = document.getElementById("svg");
// 2. get the string representation of the element
var s = new XMLSerializer().serializeToString(e);
// or
var s = e.outerHTML;
// 3. convert the string to url
// convert to utf8
var url = "data:image/svg+xml;utf8," + encodeURIComponent(s);
// convert to base64
var url = "data:image/svg+xml;base64," + window.btoa(unescape(encodeURIComponent(s)));
// or
var url = "data:image/svg+xml;base64," + Buffer.from(s, "utf-8").toString("base64")

Opening PDF String in new window with javascript

I have a formatted PDF string that looks like
%PDF-1.73 0 obj<<< /Type /Group /S /Transparency /CS /DeviceRGB >> /Resources 2 0 R/Contents 4 0 R>> endobj4 0 obj<> streamx��R=o�0��+��=|vL�R���l�-��ځ,���Ge�JK����{���Y5�����Z˯k�vf�a��`G֢ۢ��Asf�z�ͼ��`%��aI#�!;�t���GD?!���<�����B�b��
...
00000 n 0000000703 00000 n 0000000820 00000 n 0000000926 00000 n 0000001206 00000 n 0000001649 00000 n trailer << /Size 11 /Root 10 0 R /Info 9 0 R >>startxref2015%%EOF
I am trying to open up this string in a new window as a PDF file. Whenever I use window.open() and write the string to the new tab it thinks that the text should be the contents of an HTML document. I want it to recognize that this is a PDF file.
Any help is much appreciated
Just for information, the below
window.open("data:application/pdf," + encodeURI(pdfString));
does not work anymore in Chrome. Yesterday, I came across with the same issue and tried this solution, but did not work (it is 'Not allowed to navigate top frame to data URL'). You cannot open the data URL directly in a new window anymore.
But, you can wrap it in iframe and make it open in a new window like below. =)
let pdfWindow = window.open("")
pdfWindow.document.write(
"<iframe width='100%' height='100%' src='data:application/pdf;base64, " +
encodeURI(yourDocumentBase64VarHere) + "'></iframe>"
)
var byteCharacters = atob(response.data);
var byteNumbers = new Array(byteCharacters.length);
for (var i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
var byteArray = new Uint8Array(byteNumbers);
var file = new Blob([byteArray], { type: 'application/pdf;base64' });
var fileURL = URL.createObjectURL(file);
window.open(fileURL);
You return a base64 string from the API or another source. You can also download it.
You might want to explore using the data URI. It would look something like.
window.open("data:application/pdf," + escape(pdfString));
I wasn't immediately able to get this to work, possible because formating of the binary string provided. I also usually use base64 encoded data when using the data URI. If you are able to pass the content from the backend encoded you can use..
window.open("data:application/pdf;base64, " + base64EncodedPDF);
Hopefully this is the right direction for what you need. Also note this will not work at all in IE6/7 because they do not support Data URIs.
window.open("data:application/pdf," + escape(pdfString));
The above one pasting the encoded content in URL. That makes restriction of the content length in URL and hence PDF file loading failed (because of incomplete content).
This one worked for me.
window.open("data:application/octet-stream;charset=utf-16le;base64,"+data64);
This one worked too
let a = document.createElement("a");
a.href = "data:application/octet-stream;base64,"+data64;
a.download = "documentName.pdf"
a.click();
I realize this is a pretty old question, but I had the same thing come up today and came up with the following solution:
doSomethingToRequestData().then(function(downloadedFile) {
// create a download anchor tag
var downloadLink = document.createElement('a');
downloadLink.target = '_blank';
downloadLink.download = 'name_to_give_saved_file.pdf';
// convert downloaded data to a Blob
var blob = new Blob([downloadedFile.data], { type: 'application/pdf' });
// create an object URL from the Blob
var URL = window.URL || window.webkitURL;
var downloadUrl = URL.createObjectURL(blob);
// set object URL as the anchor's href
downloadLink.href = downloadUrl;
// append the anchor to document body
document.body.appendChild(downloadLink);
// fire a click event on the anchor
downloadLink.click();
// cleanup: remove element and revoke object URL
document.body.removeChild(downloadLink);
URL.revokeObjectURL(downloadUrl);
});
An updated version of answer by #Noby Fujioka:
function showPdfInNewTab(base64Data, fileName) {
let pdfWindow = window.open("");
pdfWindow.document.write("<html<head><title>"+fileName+"</title><style>body{margin: 0px;}iframe{border-width: 0px;}</style></head>");
pdfWindow.document.write("<body><embed width='100%' height='100%' src='data:application/pdf;base64, " + encodeURI(base64Data)+"#toolbar=0&navpanes=0&scrollbar=0'></embed></body></html>");
}
I just want to add with #Noby Fujioka's response, Edge will not support following
window.open("data:application/pdf," + encodeURI(pdfString));
For Edge we need to convert it to blob and this is something like following
//If Browser is Edge
if (window.navigator && window.navigator.msSaveOrOpenBlob) {
var byteCharacters = atob(<Your_base64_Report Data>);
var byteNumbers = new Array(byteCharacters.length);
for (var i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
var byteArray = new Uint8Array(byteNumbers);
var blob = new Blob([byteArray], {
type: 'application/pdf'
});
window.navigator.msSaveOrOpenBlob(blob, "myreport.pdf");
} else {
var pdfWindow = window.open("", '_blank');
pdfWindow.document.write("<iframe width='100%' style='margin: -8px;border: none;' height='100%' src='data:application/pdf;base64, " + encodeURI(<Your_base64_Report Data>) + "'></iframe>");
}
Based off other old answers:
escape() function is now deprecated,
Use encodeURI() or encodeURIComponent() instead.
Example that worked in my situation:
window.open("data:application/pdf," + encodeURI(pdfString));
Happy Coding!
I had this problem working with a FedEx shipment request. I perform the request with AJAX. The response includes tracking #, cost, as well as pdf string containing the shipping label.
Here's what I did:
Add a form:
<form id='getlabel' name='getlabel' action='getlabel.php' method='post' target='_blank'>
<input type='hidden' id='pdf' name='pdf'>
</form>
Use javascript to populate the hidden field's value with the pdf string and post the form.
Where getlabel.php:
<?
header('Content-Type: application/pdf');
header('Content-Length: '.strlen($_POST["pdf"]));
header('Content-Disposition: inline;');
header('Cache-Control: private, max-age=0, must-revalidate');
header('Pragma: public');
print $_POST["pdf"];
?>
//for pdf view
let pdfWindow = window.open("");
pdfWindow.document.write("<iframe width='100%' height='100%' src='data:application/pdf;base64," + data.data +"'></iframe>");
One suggestion is that use a pdf library like PDFJS.
Yo have to append, the following "data:application/pdf;base64" + your pdf String, and set the src of your element to that.
Try with this example:
var pdfsrc = "data:application/pdf;base64" + "67987yiujkhkyktgiyuyhjhgkhgyi...n"
<pdf-element id="pdfOpen" elevation="5" downloadable src="pdfsrc" ></pdf-element>
Hope it helps :)
Just encode your formatted PDF string in base 64. Then you should do:
$pdf = 'data:application/pdf;base64,'.$base64EncodedString;
return this to javascript and open in a new window:
window.open(return);
use function "printPreview(binaryPDFData)" to get print preview dialog of binary pdf data.
printPreview = (data, type = 'application/pdf') => {
let blob = null;
blob = this.b64toBlob(data, type);
const blobURL = URL.createObjectURL(blob);
const theWindow = window.open(blobURL);
const theDoc = theWindow.document;
const theScript = document.createElement('script');
function injectThis() {
window.print();
}
theScript.innerHTML = `window.onload = ${injectThis.toString()};`;
theDoc.body.appendChild(theScript);
};
b64toBlob = (content, contentType) => {
contentType = contentType || '';
const sliceSize = 512;
// method which converts base64 to binary
const byteCharacters = window.atob(content);
const byteArrays = [];
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
const slice = byteCharacters.slice(offset, offset + sliceSize);
const byteNumbers = new Array(slice.length);
for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
const blob = new Blob(byteArrays, {
type: contentType
}); // statement which creates the blob
return blob;
};
for the latest Chrome version, this works for me :
var win = window.open("", "Title", "toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=yes,resizable=yes,width=780,height=200,top="+(screen.height-400)+",left="+(screen.width-840));
win.document.body.innerHTML = 'iframe width="100%" height="100%" src="data:application/pdf;base64,"+base64+"></iframe>';
Thanks

Categories

Resources