Base64 image tag in safari did not showed up - html

I made a tsp which decode Image to base64 byte array String.
It works in Chrome and Firefox. However in safari 8.0, it does not work.
My jsp looks like below :
String sFileInfo = "";
String name = request.getHeader("file-name");
String ext = name.substring(name.lastIndexOf(".")+1);
InputStream is = request.getInputStream();
byte b[] = IOUtils.toByteArray(is);
String base64DataString = Base64.encodeBase64String(b);
base64DataString = "data:image/" + ext + ";base64," + base64DataString;
if(is != null) {
is.close();
}
And as result code below will be attached to browser.
<p><span style="font-size:48px"><img alt="" src="data:image/jpeg;base64,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" style="height:90px; width:169px" />1<span style="background-color:#00FFFF">zxczxczc</span></span></p>
I copy this code(part of after base64;) and put link below in safari.
http://base64online.org/decode/
and I got an image, so I assume that Safari also support base64 image.
However, when I put this on web with image tags, it does not work.
Thanks for answer :D
PS browser error message is
Failed to load resource: (kCFErrorDomainCFNetwork error -10.)

I know this question is pretty old but I've recently faced a similar problem on iOS' safari, and the problem seems to be that Safari will not render base64 images that does not have a number of character divisible by 4.
The solution to this problem is to pad your encoded string at the end using '=' characters. Here is a basic algorithm:
// b64str = 's/3eea4sp...' (or any base 64 encoded string)
while (b64str.length % 4 > 0) {
b64str += '=';
}
Hope this helps someone !

I was in a similar situation but the posted solution did not work for me. But I did come up with an alternative solution after some trial and error. Hope this helps out.
// Add an actual base64 string
var encodedImgString = 'data:image/png;base64,iVBORw0KGgoAAA...';
// Create an image, set img source and cross origin attribute
var iosImg = new Image;
iosImg.src = encodedImgString;
iosImg.crossOrigin = 'Anonymous';
// Change this to target your element and add it wherever you need it to appear
document.body.appendChild(iosImg);

#SylvainB - I think it needs to be divisible by 3 or 4 to render in Safari
#IHan - make sure to exlude 'data:image/png;base64,' part while doing the divisibility test

Not a fix but I think a more deeper look into this is that safari won't render the base64 at all with the dom loading but will work if you apply it using JS. You can go to inspect and remove your base64 and repost it in the image will load fine.

Related

Can't display base64 image retrieved from mongodb in React ERR_INVALID_URL

I am trying to display an image retrieved from mongodb, but I keep getting ERR_INVALID_URL: http://prntscr.com/tzyqtd
In mongodb it is defined as:
coverImage: {
type: Buffer,
},
In node I am reading the image with fs:
const img = fs.readFileSync(
path.resolve(__dirname, "../../images/img/grippers/gripper1.png"),
{ encoding: "base64" }
);
Then I save it in mongodb by simply giving that img to the coverImage field.
On my front end side when I make the request I do get the object with the image in it:
const retrievedConfig = await axios.get(
`http://localhost:3000/config/one/ROBOT_1`
);
console.log(retrievedConfig.data.Configs[0].Pallet.coverImage);
So this does output the image and the image contains two fields, {type: Buffer, data: Array[3750]}
Then when I try to render it:
<img src={`data:image/png;charset=utf-8;base64,${img.data.toString("base64")}`}/>
It gives me the ERR_INVALID_URL error.
Now, one thing I have noticed is that even with the toString("base64") I dont think it actually converts into base64 for some reason, because its still in 8 bit numbers (0 to 255). http://prntscr.com/tzysh5
But when I read it with fs on the backend it is in base64 http://prntscr.com/tzysrz (that is right after the fs.read and before the saving in the db)
EDIT: I tried using the btoa function on the front end and it did convert it into base64 (however I have no clue why the other way didnt work, I have the exact same code in another application working without btoa and images being displayed), but even after the conversion it was still not displaying the image (just showing a broken image http://prntscr.com/tzyw1m ), but no errors.
I was facing a similar issue recently - what worked for me is was to manually convert the data from a Uint8Array to base64:
function convertBufferToBase64(buffer) {
let binaryStr = '';
const byteArray = new Uint8Array(buffer);
for (let i = 0; i < byteArray.byteLength; i++) {
binaryStr += String.fromCharCode(bytes[i]);
}
return btoa(binary);
}
Use it like this:
<img src={`data:image/png;charset=utf-8;base64,${convertBufferToBase64(img.data)}`}/>
EDIT:
Since you're already reading the image using the { encoding: "base64" } option, there should be no need to convert between buffers. Changing the mongoose-datatype of coverImage to String and using its value in the frontend should fix the problem.

Cannot embed images in email with MailKit

This questions has been posed and answered several places on SO, specifically here : Issue with Gmail - Embedded images using MailKit
and handles my exact query, yet the answer doesn't seem to work for my case.
I've tried to build a simple mailer that embeds images in an HTML email, yet in several clients, all images still end up as attachments.
I suspect the fault to be in the way I handle the image attachments (one .gif and several .png) to be:
// Add pictures to embedded resources and replace links to pictures in the message
foreach (string imgpath in ImgPaths)
{
var image = builder.LinkedResources.Add(imgpath);
image.ContentId = MimeUtils.GenerateMessageId();
image.ContentDisposition = new ContentDisposition() { Disposition = ContentDisposition.Inline };
HtmlFormat = HtmlFormat.Replace(Path.GetFileName(imgpath), string.Format("cid:{0}", image.ContentId));
}
builder.HtmlBody = HtmlFormat;
message.Body = builder.ToMessageBody();
I can see from the emails (received in Gmail, for instance), do show that the images are being listed as:
src="images/cid:TPSXHQUDSAU4.JJRKUIEGLTZ5#Loralei"
All images are attached as attachments in both clients I've tried (gmail and roundcube). I've walked through your tutorials and checked out everything here: https://stackoverflow.com/search?q=Mailkit+Embed
Sadly, I just can't seem to find my error. Hopefully #jstedfast could see where I make my mistake?
UPDATE
As mentioned by #jstedfast, the corrected code should be (for my case anyway):
foreach (string imgpath in ImgPaths)
{
var test = Path.GetFileName(imgpath);
var image = builder.LinkedResources.Add(imgpath);
image.ContentId = MimeUtils.GenerateMessageId();
image.ContentDisposition = new ContentDisposition() { Disposition = ContentDisposition.Inline };
//HtmlFormat = HtmlFormat.Replace(Path.GetFileName(imgpath), string.Format("cid:{0}", image.ContentId));
HtmlFormat = HtmlFormat.Replace($"images/{test}", string.Format("cid:{0}", image.ContentId)); //use images/filename
}
This is a great guide to follow too, https://programming.vip/docs/5dac3983f0cd5.html
This looks like the problem:
<img src="images/cid:TPSXHQUDSAU4.JJRKUIEGLTZ5#Loralei" .../>
That needs to be:
<img src="cid:TPSXHQUDSAU4.JJRKUIEGLTZ5#Loralei" .../>
My guess is that in order to fix this, you'd change the following line of code:
HtmlFormat = HtmlFormat.Replace(Path.GetFileName(imgpath), string.Format("cid:{0}", image.ContentId));
to this:
HtmlFormat = HtmlFormat.Replace(imgpath, string.Format("cid:{0}", image.ContentId));
Hope that helps!

iOS - Safari - images not rendering fully / cut off

We are loading images in a popup, via an Ajax request, and they intermittently only partially render.
I've basically removed any weird Javascript/nonsense other than the core flow - just a basic HTML image, and it is still happening - only on iOS.
Once you 'rotate' the device, the image renders correctly - so, it's not a weird div floating above or anything (I can select the image in iOS debugger mode when attached to a Mac)
Any help would be most appreciated.
Setting decoding="sync" on the img tag didn't help in my case where a lot of images are loaded simultaneously. Loading the image manually before did the trick though.
const imageLoader = new Image();
imageLoader.src = url;
imageLoader.decoding = 'sync';
imageLoader.onload = () => {
// allow drawing image
};
For anyone who stumbles across this and is working in a react environment
const [didLoadMainImage, setDidLoadMainImage] = useState(false);
useMemo(() => {
setDidLoadMainImage(false);
const imageLoader = new Image();
imageLoader.src = url;
imageLoader.decoding = 'sync';
imageLoader.onload = () => {
setDidLoadMainImage(true);
};
}, [url]);
return (
<div>
{didLoadMainImage ? (
<img src={url} />
) : null}
</div>
);
It seems this is an issue within the iOS image decoder - some kind of race condition.
This has been fixed by forcing the decoder to operate on the main thread, using:
<img decoding="sync" src="#Url" />
Hopefully this helps someone else!
In my case, the solution was to decrease the size of the images I was displaying. Our images were about 10x the size of the HTML element they were displayed in.
Apple's developer document states:

Cross browser support for document.write()

I have an HTML Document object assigned to variable var doc. Using this document object i am rendering string values to a text file where values are getting rendered and written but in an improper format in IE11 browser but working fine in IE8,IE10,ff n chrome.Please find my below code:
function savecontent(str){
var filename = "data.txt";
var str=replaceAll(str,'<doublequote>','"');
var w = window.frames.w;
if( !w )
{
w = document.createElement( 'iframe' );
w.id = 'w';
w.style.display = 'none';
document.body.insertBefore( w,null );
w = window.frames.w;
if( !w )
{
w = window.open( '', '_temp', 'width=100,height=100' );
if( !w )
{
window.alert( 'Sorry, could not create file.' ); return false;
}
}
}
var doc = w.document;
doc.open('text/plain');
doc.charset="iso-8859-1";
doc.write(str);
doc.close(doc.write(str));
w.close();
if( doc.execCommand( 'SaveAs', false, filename ) )
{
window.alert("Please save the file.");
}
}
Where my str could be something like
employee_firstname,employee_lastname,employee_id,employee_salary,employee accountno,employee_dob etc..
which is rendered in IE11 as,
employee_firstname,employee_lastname,
employee_id,employee_salary,employee accountno,employee_dob
but where as expected is and data is rendered in IE8,ff n chrome in the below format:
employee_firstname,employee_lastname,employee_id,
employee_salary,employee accountno,employee_dob
The different i notice in other browser like IE8,FF n chrome is line break
happening differently in IE11 compared to other browsers.
Can anyone please tell me how to format rendering of data properly in text file in IE11 browser or any alternative to document.write()?
The problem cannot quite be reconstructed from the code supplied, but the heart of the problem seems to be that you are generating a new document to be displayed in an inline frame, using the open() method for a Document object. This is relatively well supported, but only when the created document is an HTML document, not a plain text document.
When you try to use text/plain format, browsers handle things differently. They actually create an HTML document, placed in the DOM tree of the creating document. It contains a body part that either has just the text you have written or a pre element wrapper around it, causing it to be displayed as-is. For example, old versions of IE generate the pre element, IE 11 does not. It might be argued that IE 11 does the right thing: being plain text does not mean that text should be rendered as-is with respect to division into lines.
Anyway, the way to avoid this is to generate an HTML document and insert the pre wrapper with your code, provided that you wish to display the text as-is:
doc.open('text/html');
doc.write('<pre>' + str + '</pre>');

printing just canvas element on a page

im a little stuck using the canvas element in html5, have scoured the net looking for a workable solution but to no avail!
the main issue is that I want to click a button and send just the canvas element on the page to the printer.
i have tried using toDataUrl() - but this just seems to be resulting in a blank white image which has none of the canvas content!
the other issue i am experiencing is that attempting to initiate any javascript functions using "onClick" attached to a form button seems to be being tempermental at best!
here is my current attempt - this works in the sense that it does open a new window and attempt to send it to printer and it does create a base64 string (tested this using the "dataUrl" output on the second lowest document.write line) but as previously mentioned the image appears to be completely blank! (the canvas itself is definitely filled, both with an imported image and some text)
function printCanv()
{
var dataUrl = document.getElementById('copy').toDataURL(); //attempt to save base64 string to server using this var
document.getElementById('testBox').value = dataUrl; //load data into textarea
//attempt open window and add canvas etc
win = window.open();
self.focus();
win.document.open();
win.document.write('<'+'html'+'><'+'head'+'><'+'style'+'>');
win.document.write('body, td { font-family: Verdana; font-size: 10pt;}');
win.document.write('<'+'/'+'style'+'><'+'/'+'head'+'><'+'body'+'>');
((image code is here but site will not let me post it for some reason?))
win.document.write(dataUrl);
win.document.write('<'+'/'+'body'+'><'+'/'+'html'+'>');
win.document.close();
win.print();
win.close();
}
note: the code from "win = window.open()" onwards is currently taken from a tutorial and not my own work!
it is currently being called using <body onload="printCanv";"> - for some reason I could not get this to work at all using a button (little chunk of code below is my attempt which seemed to fail)
<input type="button" id="test" value="click me" onClick="printCanv();"> </input>
apologies is this help request is all over the place! i haven't posted to a site like this before and it didn't like me posting some html/script!
thanks in advance for any help you may be able to offer :)
Edit: draw function:
function copydraw() { //function called "copydraw" (could be anything)
var testimage3 = document.getElementById('copy').getContext('2d'); //declare variable for canvas overall (inc paths)
var img3 = new Image(); //declare image variable called "img3"
var testVar = document.getElementById('userIn').value; //take value from userin box. only updating on browser refresh?
img3.onload = function(){ //when image has loaded (img.onload) run this function
testimage3.drawImage(img3,0,0); //draw "img" to testimage
testimage3.font = "30pt 'Arial'"; //font method varies font attrib (weight, size, face)
testimage3.fillStyle = "#000000"; //sets fill color
testimage3.fillText(testVar, 310, 360); //filltext method draws text (xup ydown)
}
img3.src = 'images/liecakeA4.jpg'; //source of image
}
This function works perfectly, it draws the object and adds text from the variable, but for some reason it seems to be preventing me from outputting it as an image. I'm really confused!
I'm not sure exactly what's wrong with your code, I suspect in your current version calling printCanv in the body load event will mean you're trying to print the canvas before it's drawn. Running it off the button should work better, I'm not sure why that wasn't working for you as there's no reason in principle why it shouldn't work.
To arrive at a working version I've modified your code slightly:
function printCanvas(el) {
var dataUrl = document.getElementById(el).toDataURL(); //attempt to save base64 string to server using this var
var windowContent = '<!DOCTYPE html>';
windowContent += '<html>'
windowContent += '<head><title>Print canvas</title></head>';
windowContent += '<body>'
windowContent += '<img src="' + dataUrl + '">';
windowContent += '</body>';
windowContent += '</html>';
var printWin = window.open('','','width=340,height=260');
printWin.document.open();
printWin.document.write(windowContent);
printWin.document.close();
printWin.focus();
printWin.print();
printWin.close();
}
This works for me in the Firefox 4.0 nightly.
One addition to the accepted-best-answer: It doesnt work here with Chrome 17.0.942.0 winvista, because the print-preview-dlg is shown within the website itself and printWin.close() will close the dlg too.
So printWin.close() must be delayed or initiated by the user, but those are no good solutions.
It would be best, if chrome printdlg could have a callback, sth. one knows, printing is done, and can close the window. If this is possible is another question.