I've used the following code in an embedded code field on Google Sites to display images on my website, it's all going well on my Windows, Linux and Android devices, but they don't show up on the iPhone (whether using Chrome or Safari)!
<form name="submit-to-google-sheet">
<img id="img1" width=163 height=227>
</form>
<script>
const img1 = document.getElementById('img1');
img1.src = "https://docs.google.com/uc?export=view&id={imageGoogleDriveID}";
</script>
some context/constraints: I'm pulling my images from my Google Drive. They are ~80kb JPEGs. I'm using a HTML form as I have other elements (buttons, fields) which I've removed from the code extract below to focus on the issue. I need to keep this form.
I've explored the Base64 format which does allow to display the images on iOS-operated devices (or so I understood). It works if I just set the image source to a Base64 URI:
imgBase64.src = "data:image/jpeg;base64,/9j/4 [...] //9k=";
But I can't call a Base64 file from Drive as conveniently as a JPEG.
I'm manipulating 250+ images so I can't either have the base64 strings in the middle of the code, it'd be too large to work with.
I've come up with the piece of code below, and I end up getting:
on Android/Windows: a nice image for img1 and a simple black square for imgBase64
on iOS: an empty box for img1 (my issue in the first place) and a simple black square for imgBase64
After investigation, it seems that the URI I get out of canvas.toDataURL("image/jpeg") is not at all the same thing as what I get out of an encoder (such as base64.guru/converter/encode/url). It is very short and I get a lot of As. It seems that the canvas is not loading the image correctly:
data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wAARCADjAKMDAREAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAv/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhEDEQA/AJ/4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//Z
Any idea why the conversion doesn't work?
<form name="myForm">
<img id="img1" width=163 height=227>
<img id="imgBase64" width=163 height=227>
</form>
<script>
const form = document.forms['myForm'];
var imageUrl = "https://docs.google.com/uc?export=view&id={imageGoogleDriveID}";
const img1 = document.getElementById('img1');
img1.src=imageUrl;
const imgBase64 = document.getElementById('imgBase64');
const canvas = document.createElement("canvas");
canvas.width = 163;
canvas.height = 227;
img1.onload = function() {
canvas.getContext("2d").drawImage(img1, 0, 0);
}
var dataURL = canvas.toDataURL("image/jpeg");
imgBase64.src = dataURL; //gives me a black square
imgBase64.src = "data:image/jpeg;base64,/9j/4 [...] //9k="; //works fine!
</script>
We just found the fix for iOS: when third-party cookies and cross-site tracking are blocked, the images don't load. The settings to toggle are explained here.
Base64 wasn't the solution, since the issue was coming from pulling images from my Google Drive, i.e. a different domain from my website. However I still haven't found why drawImage() doesn't work.
I have jqplot and I want to download it once click a button as a jpg or png. I can do it using
$('#chartdiv').jqplotSaveImage();
(chartdiv is the div with plot)
It is working in chrome and firefox only. In IE it is not working.I tried in IE 11.
And I have another problem in chrome the downloaded image file name is 'download' and in firefox it is some wired name with .part extension (ex :- ka8ShgKH.part). Is there a way to put plot title as the download file name ?
thank you.
$("#btnSaveImg").on("click", LoadImage);
LoadImage = function(){
$('#chartdiv').jqplotSaveImage();
}
EDIT
jqplotsaveimage function
$.fn.jqplotSaveImage = function() {
var imgData = $(this).jqplotToImageStr({});
if (imgData) {
window.location.href = imgData.replace("image/png", "image/octet-stream");
}
};
I'm using jqPlot and I had issues using the above in IE and even if it worked in Chrome I could not name the downloaded image.
I found this case force download base64 image and the http://danml.com/download.html . That's working both in later versions of IE and Chrome and you can save the image with your own filename. The download.js can be used for more than just images.
//include the downoad.js file from http://danml.com/download.html
<button id="dwnl-chart-1" onClick="$.fn.jqplotSaveImage('chart-1', 'chart_name">Download as image</button>
$.fn.jqplotSaveImage = function(id, filename) {
var imgData = $('#'+id+'-parent').jqplotToImageStr({});
if (imgData) {
download(imgData, filename+'.png', "image/png");
}
};
I originally created a button that changed the src based on mouseup and mousedown to give it the appearance of being depressed when clicked as well as playing a click sound. This worked out fine until I tried to force PDF download through MVC action. I've tried to skin this cat a few different ways but I've settled on using the mouseup function to set the window location to my pdf download action passing in the needed file download path information. Now when I click the button it depresses (correctly executing mousedown), then on mouseup it correctly plays the click sound and also downloads the pdf file as I want, but makes the button image appear to be broken.
When I first load the page and the button hasn't been clicked yet the image looks like it's supposed to. Then after running mouseup it's broken (using Chrome or disappears or appears garbled in IE and Safari) but when I inspect the source the src attribute looks to be identical so I'm not sure why it's returning a broken image if the src is the same as it was before.
Code-
View jquery:
var audio = document.getElementsByTagName("audio")[0];
$('#MAAX-DGB-Button').mouseup(function () {
$(this).attr('src', '../../Content/Images/AdLandingViews/MAAX-DGB.png');
audio.play();
var pdfDownload = '/Locator/ForcePDFDownload?PDFURL=<file location info>';
window.location = pdfDownload;
});
$('#MAAX-DGB-Button').mousedown(function () {
$(this).attr('src', '../../Content/Images/AdLandingViews/MAAX-DGB_press.png');
});
View HTML:
<img src="../../Content/Images/AdLandingViews/MAAX-DGB.png" alt="Download MAAX Collection Brochure" id="MAAX-DGB-Button" />
ForcePDFDownload MVC Action:
public ActionResult ForcePDFDownload(string PDFURL)
{
string path = #"\\<server location>\" + PDFURL;
string filename = Path.GetFileName(PDFURL);
Response.AppendHeader("Content-Disposition", "attachment; filename=" + filename);
return File(path, "application/pdf");
}
You can test the code here:
https://maaxspasportal.com/Locator/AdLandingLocate/MAAXCollection but you'll have to fill in some dummy data and submit the form to get to the results page where this issue is occurring on the "Download Green Brochure" button.
Tested Browsers:
Chrome Version 28.0.1500.95 - Image appears broken.
IE 10 - Image disappears or looks garbled.
Safari 6.0.5 - Image disappears.
FireFox 22.0 - Works!
Thanks for any help getting this to work correctly.
Well I never determined the exact root cause for the issues, however I did find a way to fix the problem.
On mouseup I applied a setTimeout delay on the forced pdf download function:
var audio = document.getElementsByTagName("audio")[0];
$('#MAAX-DGB-Button').mouseup(function () {
$(this).attr('src', '../../Content/Images/AdLandingViews/MAAX-DGB.png');
audio.play();
var pdfDownload = '/Locator/ForcePDFDownload?PDFURL=assets.maaxspas.com/docsources/1/138ee0a8-e0f0-47d5-9447-fca6f538d74f.pdf';
setTimeout(function() { window.location = pdfDownload }, 1000);
});
$('#MAAX-DGB-Button').mousedown(function () {
$(this).attr('src', '../../Content/Images/AdLandingViews/MAAX-DGB_press.png');
});
Would still be interested to know what was going wrong but at least it's functioning the way I want now.
Thanks.
I want to be able to copy an image from clipboard, specifically screenshots, and paste them right into a rich text editor, and/or have that file uploaded. We only use chrome so it only has to work for chrome.
http://gmailblog.blogspot.com/2011/06/pasting-images-into-messages-just-got.html
Now, when you’re running the latest version of Google Chrome, you can paste images right from your clipboard too. So if you copy an image from the web or another email, you can paste it right into your message.
Does anyone know if this new gmail feature is something javascript that Id be able to implement myself? Or any other insight into this?
I believe Na7coldwater is correct. The event.clipboardData is being utilised. Please see the following proof of concept:
<html>
<body>
<div id="rte" contenteditable="true" style="height: 100%; width: 100%; outline: 0; overflow: auto"></div>
<script type="text/javascript">
document.getElementById("rte").focus();
document.body.addEventListener("paste", function(e) {
for (var i = 0; i < e.clipboardData.items.length; i++) {
if (e.clipboardData.items[i].kind == "file" && e.clipboardData.items[i].type == "image/png") {
// get the blob
var imageFile = e.clipboardData.items[i].getAsFile();
// read the blob as a data URL
var fileReader = new FileReader();
fileReader.onloadend = function(e) {
// create an image
var image = document.createElement("IMG");
image.src = this.result;
// insert the image
var range = window.getSelection().getRangeAt(0);
range.insertNode(image);
range.collapse(false);
// set the selection to after the image
var selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
};
// TODO: Error Handling!
// fileReader.onerror = ...
fileReader.readAsDataURL(imageFile);
// prevent the default paste action
e.preventDefault();
// only paste 1 image at a time
break;
}
}
});
</script>
</body>
Gmail uploads the image via XMLHttpRequest instead of embedding it directly as a data URL. A search on Google or SO for drag & drop file uploads should reveal how this can be achieved.
Please bare in mind that this is just a proof of concept. Error handling and browser/feature detection code is not included.
Hope this helps!
In Internet Explorer I can use the clipboardData object to access the clipboard. How can I do that in FireFox, Safari and/or Chrome?
For security reasons, Firefox doesn't allow you to place text on the clipboard. However, there is a workaround available using Flash.
function copyIntoClipboard(text) {
var flashId = 'flashId-HKxmj5';
/* Replace this with your clipboard.swf location */
var clipboardSWF = 'http://appengine.bravo9.com/copy-into-clipboard/clipboard.swf';
if(!document.getElementById(flashId)) {
var div = document.createElement('div');
div.id = flashId;
document.body.appendChild(div);
}
document.getElementById(flashId).innerHTML = '';
var content = '<embed src="' +
clipboardSWF +
'" FlashVars="clipboard=' + encodeURIComponent(text) +
'" width="0" height="0" type="application/x-shockwave-flash"></embed>';
document.getElementById(flashId).innerHTML = content;
}
The only disadvantage is that this requires Flash to be enabled.
The source is currently dead: http://bravo9.com/journal/copying-text-into-the-clipboard-with-javascript-in-firefox-safari-ie-opera-292559a2-cc6c-4ebf-9724-d23e8bc5ad8a/ (and so is its Google cache)
There is now a way to easily do this in most modern browsers using
document.execCommand('copy');
This will copy currently selected text. You can select a textArea or input field using
document.getElementById('myText').select();
To invisibly copy text you can quickly generate a textArea, modify the text in the box, select it, copy it, and then delete the textArea. In most cases this textArea wont even flash onto the screen.
For security reasons, browsers will only allow you copy if a user takes some kind of action (ie. clicking a button). One way to do this would be to add an onClick event to a html button that calls a method which copies the text.
A full example:
function copier(){
document.getElementById('myText').select();
document.execCommand('copy');
}
<button onclick="copier()">Copy</button>
<textarea id="myText">Copy me PLEASE!!!</textarea>
Online spreadsheet applications hook Ctrl + C and Ctrl + V events and transfer focus to a hidden TextArea control and either set its contents to desired new clipboard contents for copy or read its contents after the event had finished for paste.
See also Is it possible to read the clipboard in Firefox, Safari and Chrome using JavaScript?.
It is summer 2015, and with so much turmoil surrounding Flash, here is how to avoid its use altogether.
clipboard.js is a nice utility that allows copying of text or html data to the clipboard. It's very easy to use, just include the .js and use something like this:
<button id='markup-copy'>Copy Button</button>
<script>
document.getElementById('markup-copy').addEventListener('click', function() {
clipboard.copy({
'text/plain': 'Markup text. Paste me into a rich text editor.',
'text/html': '<i>here</i> is some <b>rich text</b>'
}).then(
function(){console.log('success'); },
function(err){console.log('failure', err);
});
});
</script>
clipboard.js is also on GitHub.
As of 2017, you can do this:
function copyStringToClipboard (string) {
function handler (event){
event.clipboardData.setData('text/plain', string);
event.preventDefault();
document.removeEventListener('copy', handler, true);
}
document.addEventListener('copy', handler, true);
document.execCommand('copy');
}
And now to copy copyStringToClipboard('Hello, World!')
If you noticed the setData line, and wondered if you can set different data types, the answer is yes.
Firefox does allow you to store data in the clipboard, but due to security implications it is disabled by default. See how to enable it in "Granting JavaScript access to the clipboard" in the Mozilla Firefox knowledge base.
The solution offered by amdfan is the best if you are having a lot of users and configuring their browser isn't an option. Though you could test if the clipboard is available and provide a link for changing the settings, if the users are tech savvy. The JavaScript editor TinyMCE follows this approach.
The copyIntoClipboard() function works for Flash 9, but it appears to be broken by the release of Flash player 10. Here's a solution that does work with the new flash player:
http://bowser.macminicolo.net/~jhuckaby/zeroclipboard/
It's a complex solution, but it does work.
I have to say that none of these solutions really work. I have tried the clipboard solution from the accepted answer, and it does not work with Flash Player 10. I have also tried ZeroClipboard, and I was very happy with it for awhile.
I'm currently using it on my own site (http://www.blogtrog.com), but I've been noticing weird bugs with it. The way ZeroClipboard works is that it puts an invisible flash object over the top of an element on your page. I've found that if my element moves (like when the user resizes the window and i have things right aligned), the ZeroClipboard flash object gets out of whack and is no longer covering the object. I suspect it's probably still sitting where it was originally. They have code that's supposed to stop that, or restick it to the element, but it doesn't seem to work well.
So... in the next version of BlogTrog, I guess I'll follow suit with all the other code highlighters I've seen out in the wild and remove my Copy to Clipboard button. :-(
(I noticed that dp.syntaxhiglighter's Copy to Clipboard is broken now also.)
Check this link:
Granting JavaScript access to the clipboard
Like everybody said, for security reasons, it is by default disabled. The page above shows the instructions of how to enable it (by editing about:config in Firefox or the user.js file).
Fortunately, there is a plugin called "AllowClipboardHelper" which makes things easier with only a few clicks. however you still need to instruct your website's visitors on how to enable the access in Firefox.
Use the modern document.execCommand("copy") and jQuery. See this Stack Overflow answer.
var ClipboardHelper = { // As Object
copyElement: function ($element)
{
this.copyText($element.text())
},
copyText:function(text) // Linebreaks with \n
{
var $tempInput = $("<textarea>");
$("body").append($tempInput);
$tempInput.val(text).select();
document.execCommand("copy");
$tempInput.remove();
}
};
How to call it:
ClipboardHelper.copyText('Hello\nWorld');
ClipboardHelper.copyElement($('body h1').first());
// jQuery document
;(function ( $, window, document, undefined ) {
var ClipboardHelper = {
copyElement: function ($element)
{
this.copyText($element.text())
},
copyText:function(text) // Linebreaks with \n
{
var $tempInput = $("<textarea>");
$("body").append($tempInput);
//todo prepare Text: remove double whitespaces, trim
$tempInput.val(text).select();
document.execCommand("copy");
$tempInput.remove();
}
};
$(document).ready(function()
{
var $body = $('body');
$body.on('click', '*[data-copy-text-to-clipboard]', function(event)
{
var $btn = $(this);
var text = $btn.attr('data-copy-text-to-clipboard');
ClipboardHelper.copyText(text);
});
$body.on('click', '.js-copy-element-to-clipboard', function(event)
{
ClipboardHelper.copyElement($(this));
});
});
})( jQuery, window, document );
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<span data-copy-text-to-clipboard=
"Hello
World">
Copy Text
</span>
<br><br>
<span class="js-copy-element-to-clipboard">
Hello
World
Element
</span>
I've used GitHub's Clippy for my needs and is a simple Flash-based button. It works just fine if one doesn't need styling and is pleased with inserting what to paste on the server-side beforehand.
http://www.rodsdot.com/ee/cross_browser_clipboard_copy_with_pop_over_message.asp works with Flash 10 and all Flash enabled browsers.
Also ZeroClipboard has been updated to avoid the bug mentioned about page scrolling causing the Flash movie to no longer be in the correct place.
Since that method "Requires" the user to click a button to copy this is a convenience to the user and nothing nefarious is occurring.
A slight improvement on the Flash solution is to detect for Flash 10 using swfobject:
http://code.google.com/p/swfobject/
And then if it shows as Flash 10, try loading a Shockwave object using JavaScript. Shockwave can read/write to the clipboard (in all versions) as well using the copyToClipboard() command in Lingo.
Try creating a memory global variable storing the selection. Then the other function can access the variable and do a paste. For example,
var memory = ''; // Outside the functions but within the script tag.
function moz_stringCopy(DOMEle, firstPos, secondPos) {
var copiedString = DOMEle.value.slice(firstPos, secondPos);
memory = copiedString;
}
function moz_stringPaste(DOMEle, newpos) {
DOMEle.value = DOMEle.value.slice(0, newpos) + memory + DOMEle.value.slice(newpos);
}
If you support Flash, you can use https://everyplay.com/assets/clipboard.swf and use the flashvars text to set the text.
https://everyplay.com/assets/clipboard.swf?text=It%20Works
That’s the one I use to copy and you can set as extra if it doesn't support these options. You can use:
For Internet Explorer:
window.clipboardData.setData(DataFormat, Text) and window.clipboardData.getData(DataFormat)
You can use the DataFormat's Text and URL to getData and setData.
And to delete data:
You can use the DataFormat's File, HTML, Image, Text and URL. PS: You need to use window.clipboardData.clearData(DataFormat);.
And for other that’s not support window.clipboardData and swf Flash files you can also use Control + C button on your keyboard for Windows and for Mac its Command + C.
From addon code:
For how to do it from Chrome code, you can use the nsIClipboardHelper interface as described here: https://developer.mozilla.org/en-US/docs/Using_the_Clipboard
Use document.execCommand('copy'). It is supported in the latest versions of Chrome, Firefox, Edge, and Safari.
function copyText(text){
function selectElementText(element) {
if (document.selection) {
var range = document.body.createTextRange();
range.moveToElementText(element);
range.select();
} else if (window.getSelection) {
var range = document.createRange();
range.selectNode(element);
window.getSelection().removeAllRanges();
window.getSelection().addRange(range);
}
}
var element = document.createElement('DIV');
element.textContent = text;
document.body.appendChild(element);
selectElementText(element);
document.execCommand('copy');
element.remove();
}
var txt = document.getElementById('txt');
var btn = document.getElementById('btn');
btn.addEventListener('click', function(){
copyText(txt.value);
})
<input id="txt" value="Hello World!" />
<button id="btn">Copy To Clipboard</button>
Clipboard API is designed to supersede document.execCommand. Safari is still working on support, so you should provide a fallback until the specification settles and Safari finishes implementation.
const permalink = document.querySelector('[rel="bookmark"]');
const output = document.querySelector('output');
permalink.onclick = evt => {
evt.preventDefault();
window.navigator.clipboard.writeText(
permalink.href
).then(() => {
output.textContent = 'Copied';
}, () => {
output.textContent = 'Not copied';
});
};
Permalink
<output></output>
For security reasons clipboard Permissions may be necessary to read and write from the clipboard. If the snippet doesn't work on Stack Overflow give it a shot on localhost or an otherwise trusted domain.
Building off the excellent answer from David from Studio.201, this works in Safari, Firefox, and Chrome. It also ensures no flashing could occur from the textarea by placing it off-screen.
// ================================================================================
// ClipboardClass
// ================================================================================
var ClipboardClass = (function() {
function copyText(text) {
// Create temp element off-screen to hold text.
var tempElem = $('<textarea style="position: absolute; top: -8888px; left: -8888px">');
$("body").append(tempElem);
tempElem.val(text).select();
document.execCommand("copy");
tempElem.remove();
}
// ============================================================================
// Class API
// ============================================================================
return {
copyText: copyText
};
})();