canvas is throw error of tainted after LoadFromJson - json

I am using fabric js version 1.7.22
when image set in a repetitive manner in a rectangle of fabric js, at
the first time it will be loaded and saved into JSON using toJSON()
and save an image using todataUrl() method, but when cal canvas a loadFromJson method at that time, this canvas not savable, because it throws tainted canvas error.
Please help me,
I already set crossOrigin in a pattern but it not working. and not
added in canvas JSON.
I have made one Fiddle For Generate Issue :
[http://jsfiddle.net/Mark_1998/kt387vLc/1/][1]
Steps to generate issue :
click on 'set pattern'
then click on 'save canvas'
then click on 'reload canvas' // load canvas from JSON
then click on 'save canvas' // cause issue of tainted canvas

This issue is fixed in new version of fabricjs already. If you are still using 1.7.20 the override fabric.Pattern.prototype.toObject and fabric.Pattern.prototype.initialize, find code in snippet.
var canvas = new fabric.Canvas('canvas', {
height: 500,
width: 500,
});
canvas.backgroundColor = '#ff0000';
canvas.renderAll();
var canvasJSON = {};
document.getElementById('setPat').addEventListener('click', function() {
fabric.util.loadImage('https://cdn.dribbble.com/assets/icon-backtotop-1b04df73090f6b0f3192a3b71874ca3b3cc19dff16adc6cf365cd0c75897f6c0.png', function(image) {
var pattern = new fabric.Pattern({
source: image,
repeat: 'repeat',
crossOrigin: 'Anonymous'
});
var patternObject = new fabric.Rect({
left: 0,
top: 0,
height: canvas.height,
width: canvas.width,
angle: 0,
fill: pattern,
objectCaching: false
})
canvas.add(patternObject);
}, null, {
crossOrigin: 'Anonymous'
});
})
document.getElementById('saveCanvas').addEventListener('click', function() {
console.log('save canvas');
canvasJSON = canvas.toJSON();
var image = canvas.toDataURL("image/png", {
crossOrigin: 'Anonymous'
}); // don't remove this, i need it as thumbnail.
//console.log('canvas.Json', canvasJSON);
//console.log('image', image);
canvas.clear();
canvas.backgroundColor = '#ff0000';
canvas.renderAll();
});
document.getElementById('reloadCanvas').addEventListener('click', function() {
console.log('save canvas');
canvas.loadFromJSON(canvasJSON, function() {
canvas.set({
crossOrigin: 'Anonymous'
})
});
console.log('canvas.Json', canvasJSON);
});
//cross origin was not added in toObject JSON
fabric.Pattern.prototype.toObject = (function(toObject) {
return function() {
return fabric.util.object.extend(toObject.call(this), {
crossOrigin: this.crossOrigin,
patternTransform: this.patternTransform ? this.patternTransform.concat() : null
});
};
})(fabric.Pattern.prototype.toObject);
//cross origin was not added while creating image
fabric.Pattern.prototype.initialize = function(options, callback) {
options || (options = {});
this.id = fabric.Object.__uid++;
this.setOptions(options);
if (!options.source || (options.source && typeof options.source !== 'string')) {
callback && callback(this);
return;
}
// function string
if (typeof fabric.util.getFunctionBody(options.source) !== 'undefined') {
this.source = new Function(fabric.util.getFunctionBody(options.source));
callback && callback(this);
} else {
// img src string
var _this = this;
this.source = fabric.util.createImage();
fabric.util.loadImage(options.source, function(img) {
_this.source = img;
callback && callback(_this);
}, null, this.crossOrigin);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.20/fabric.js"></script>
<button id="setPat">
Set pattern
</button>
<button id="saveCanvas">
Save canvas
</button>
<button id="reloadCanvas">
Reload CAnvas
</button>
<canvas id="canvas"></canvas>

Related

Validate height width with bootstrap validator

$('#ad_pd_form').bootstrapValidator({
fields: {
ad_pd_image: {
validators: {
file: {
extension: 'jpg,png',
type: 'image/jpg,image/png',
maxSize: 30(Height) * 30 (width),
message: 'The selected file is not valid'
}
}
}
}
});
Friends i'm validating an image in bootstrap validator , I have to validate the height and width of the uploaded image , how to achieve this concept by using bootstrap validator . I need to upload only the image with size of 30 * 30 .
You Need to Suppurate validation function for the Image upload Check Dimension.
Here is the Sample Code:
$(function () {
$("#upload").bind("click", function () {
//Get reference of FileUpload.
var fileUpload = $("#fileUpload")[0];
//Check whether the file is valid Image.
var regex = new RegExp("([a-zA-Z0-9\s_\\.\-:])+(.jpg|.png|.gif)$");
if (regex.test(fileUpload.value.toLowerCase())) {
//Check whether HTML5 is supported.
if (typeof (fileUpload.files) != "undefined") {
//Initiate the FileReader object.
var reader = new FileReader();
//Read the contents of Image File.
reader.readAsDataURL(fileUpload.files[0]);
reader.onload = function (e) {
//Initiate the JavaScript Image object.
var image = new Image();
//Set the Base64 string return from FileReader as source.
image.src = e.target.result;
image.onload = function () {
//Determine the Height and Width.
var height = this.height;
var width = this.width;
if (height > 100 || width > 100) {
alert("Height and Width must not exceed 100px.");
return false;
}
alert("Uploaded image has valid Height and Width.");
return true;
};
}
} else {
alert("This browser does not support HTML5.");
return false;
}
} else {
alert("Please select a valid Image file.");
return false;
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<input type="file" id="fileUpload" />
<input id="upload" type="button" value="Upload" />

In chrome App, video file is not saved with its original data/size

In appCtrl.js, for saving video file -
$('#save_file').click(function(e) {
var config = {type: 'saveFile', suggestedName: chosenEntry.name};
chrome.fileSystem.chooseEntry(config, function(writableEntry) {
//blob content is the DataUrl
var blob = new Blob([$scope.blobContent], {type: 'video/mp4'});
$scope.writeFileEntry(writableEntry, blob, function(e) {
console.log('Write complete :)');
});
});
});
$scope.writeFileEntry = function(writableEntry, opt_blob, callback) {
if (!writableEntry) {
console.log('Nothing selected.');
return;
}
writableEntry.createWriter(function(writer) {
writer.onerror = $scope.errorHandler;
writer.onwriteend = callback;
// If we have data, write it to the file. Otherwise, just use the file we
// loaded.
if (opt_blob) {
writer.truncate(opt_blob.size);
$scope.waitForIO(writer, function() {
writer.seek(0);
writer.write(opt_blob);
});
}
else {
chosenEntry.file(function(file) {
writer.truncate(file.fileSize);
waitForIO(writer, function() {
writer.seek(0);
writer.write(file);
});
});
}
}, $scope.errorHandler);
}
$scope.waitForIO = function(writer, callback) {
// set a watchdog to avoid eventual locking:
var start = Date.now();
// wait for a few seconds
var reentrant = function() {
if (writer.readyState===writer.WRITING && Date.now()-start<4000) {
setTimeout(reentrant, 100);
return;
}
if (writer.readyState===writer.WRITING) {
console.error("Write operation taking too long, aborting!"+
" (current writer readyState is "+writer.readyState+")");
writer.abort();
}
else {
callback();
}
};
setTimeout(reentrant, 100);
};
In above code the video file is saved but when i tried to play that saved file in Window Media Player or VLC player , it prompt me as Window media player cannot play the file.The player might not support the file type or might not support the codec that was used to compress the file.
Can u please guide me where m getting wrong, as its my first chrome app.
Thanks in advance.
Change the method to store blob like this.
function dataURItoBlob(dataURI, callback) {
// convert base64 to raw binary data held in a string
// doesn't handle URLEncoded DataURIs
var byteString = atob(dataURI.split(',')[1]);
// separate out the mime component
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]
// write the bytes of the string to an ArrayBuffer
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ab], {type: 'video/mp4'});
};
To handle click.
$('#save_file').click(function(e) {
var config = {type: 'saveFile', suggestedName: chosenEntry.name};
chrome.fileSystem.chooseEntry(config, function(writableEntry) {
var blob = dataURItoBlob($scope.blobContent);
$scope.writeFileEntry(writableEntry, blob, function(e) {
console.log('Write complete :)');
});
});
});

Code to take snapshot of a html page? [duplicate]

Google's "Report a Bug" or "Feedback Tool" lets you select an area of your browser window to create a screenshot that is submitted with your feedback about a bug.
Screenshot by Jason Small, posted in a duplicate question.
How are they doing this? Google's JavaScript feedback API is loaded from here and their overview of the feedback module will demonstrate the screenshot capability.
JavaScript can read the DOM and render a fairly accurate representation of that using canvas. I have been working on a script which converts HTML into a canvas image. Decided today to make an implementation of it into sending feedbacks like you described.
The script allows you to create feedback forms which include a screenshot, created on the client's browser, along with the form. The screenshot is based on the DOM and as such may not be 100% accurate to the real representation as it does not make an actual screenshot, but builds the screenshot based on the information available on the page.
It does not require any rendering from the server, as the whole image is created on the client's browser. The HTML2Canvas script itself is still in a very experimental state, as it does not parse nearly as much of the CSS3 attributes I would want it to, nor does it have any support to load CORS images even if a proxy was available.
Still quite limited browser compatibility (not because more couldn't be supported, just haven't had time to make it more cross browser supported).
For more information, have a look at the examples here:
http://hertzen.com/experiments/jsfeedback/
edit
The html2canvas script is now available separately here and some examples here.
edit 2
Another confirmation that Google uses a very similar method (in fact, based on the documentation, the only major difference is their async method of traversing/drawing) can be found in this presentation by Elliott Sprehn from the Google Feedback team:
http://www.elliottsprehn.com/preso/fluentconf/
Your web app can now take a 'native' screenshot of the client's entire desktop using getUserMedia():
Have a look at this example:
https://www.webrtc-experiment.com/Pluginfree-Screen-Sharing/
The client will have to be using chrome (for now) and will need to enable screen capture support under chrome://flags.
PoC
As Niklas mentioned you can use the html2canvas library to take a screenshot using JS in the browser. I will extend his answer in this point by providing an example of taking a screenshot using this library ("Proof of Concept"):
function report() {
let region = document.querySelector("body"); // whole screen
html2canvas(region, {
onrendered: function(canvas) {
let pngUrl = canvas.toDataURL(); // png in dataURL format
let img = document.querySelector(".screen");
img.src = pngUrl;
// here you can allow user to set bug-region
// and send it with 'pngUrl' to server
},
});
}
.container {
margin-top: 10px;
border: solid 1px black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/html2canvas.min.js"></script>
<div>Screenshot tester</div>
<button onclick="report()">Take screenshot</button>
<div class="container">
<img width="75%" class="screen">
</div>
In report() function in onrendered after getting image as data URI you can show it to the user and allow him to draw "bug region" by mouse and then send a screenshot and region coordinates to the server.
In this example async/await version was made: with nice makeScreenshot() function.
UPDATE
Simple example which allows you to take screenshot, select region, describe bug and send POST request (here jsfiddle) (the main function is report()).
async function report() {
let screenshot = await makeScreenshot(); // png dataUrl
let img = q(".screen");
img.src = screenshot;
let c = q(".bug-container");
c.classList.remove('hide')
let box = await getBox();
c.classList.add('hide');
send(screenshot,box); // sed post request with bug image, region and description
alert('To see POST requset with image go to: chrome console > network tab');
}
// ----- Helper functions
let q = s => document.querySelector(s); // query selector helper
window.report = report; // bind report be visible in fiddle html
async function makeScreenshot(selector="body")
{
return new Promise((resolve, reject) => {
let node = document.querySelector(selector);
html2canvas(node, { onrendered: (canvas) => {
let pngUrl = canvas.toDataURL();
resolve(pngUrl);
}});
});
}
async function getBox(box) {
return new Promise((resolve, reject) => {
let b = q(".bug");
let r = q(".region");
let scr = q(".screen");
let send = q(".send");
let start=0;
let sx,sy,ex,ey=-1;
r.style.width=0;
r.style.height=0;
let drawBox= () => {
r.style.left = (ex > 0 ? sx : sx+ex ) +'px';
r.style.top = (ey > 0 ? sy : sy+ey) +'px';
r.style.width = Math.abs(ex) +'px';
r.style.height = Math.abs(ey) +'px';
}
//console.log({b,r, scr});
b.addEventListener("click", e=>{
if(start==0) {
sx=e.pageX;
sy=e.pageY;
ex=0;
ey=0;
drawBox();
}
start=(start+1)%3;
});
b.addEventListener("mousemove", e=>{
//console.log(e)
if(start==1) {
ex=e.pageX-sx;
ey=e.pageY-sy
drawBox();
}
});
send.addEventListener("click", e=>{
start=0;
let a=100/75 //zoom out img 75%
resolve({
x:Math.floor(((ex > 0 ? sx : sx+ex )-scr.offsetLeft)*a),
y:Math.floor(((ey > 0 ? sy : sy+ey )-b.offsetTop)*a),
width:Math.floor(Math.abs(ex)*a),
height:Math.floor(Math.abs(ex)*a),
desc: q('.bug-desc').value
});
});
});
}
function send(image,box) {
let formData = new FormData();
let req = new XMLHttpRequest();
formData.append("box", JSON.stringify(box));
formData.append("screenshot", image);
req.open("POST", '/upload/screenshot');
req.send(formData);
}
.bug-container { background: rgb(255,0,0,0.1); margin-top:20px; text-align: center; }
.send { border-radius:5px; padding:10px; background: green; cursor: pointer; }
.region { position: absolute; background: rgba(255,0,0,0.4); }
.example { height: 100px; background: yellow; }
.bug { margin-top: 10px; cursor: crosshair; }
.hide { display: none; }
.screen { pointer-events: none }
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/html2canvas.min.js"></script>
<body>
<div>Screenshot tester</div>
<button onclick="report()">Report bug</button>
<div class="example">Lorem ipsum</div>
<div class="bug-container hide">
<div>Select bug region: click once - move mouse - click again</div>
<div class="bug">
<img width="75%" class="screen" >
<div class="region"></div>
</div>
<div>
<textarea class="bug-desc">Describe bug here...</textarea>
</div>
<div class="send">SEND BUG</div>
</div>
</body>
Get screenshot as Canvas or Jpeg Blob / ArrayBuffer using getDisplayMedia API:
FIX 1: Use the getUserMedia with chromeMediaSource only for Electron.js
FIX 2: Throw error instead return null object
FIX 3: Fix demo to prevent the error: getDisplayMedia must be called from a user gesture handler
// docs: https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia
// see: https://www.webrtc-experiment.com/Pluginfree-Screen-Sharing/#20893521368186473
// see: https://github.com/muaz-khan/WebRTC-Experiment/blob/master/Pluginfree-Screen-Sharing/conference.js
function getDisplayMedia(options) {
if (navigator.mediaDevices && navigator.mediaDevices.getDisplayMedia) {
return navigator.mediaDevices.getDisplayMedia(options)
}
if (navigator.getDisplayMedia) {
return navigator.getDisplayMedia(options)
}
if (navigator.webkitGetDisplayMedia) {
return navigator.webkitGetDisplayMedia(options)
}
if (navigator.mozGetDisplayMedia) {
return navigator.mozGetDisplayMedia(options)
}
throw new Error('getDisplayMedia is not defined')
}
function getUserMedia(options) {
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
return navigator.mediaDevices.getUserMedia(options)
}
if (navigator.getUserMedia) {
return navigator.getUserMedia(options)
}
if (navigator.webkitGetUserMedia) {
return navigator.webkitGetUserMedia(options)
}
if (navigator.mozGetUserMedia) {
return navigator.mozGetUserMedia(options)
}
throw new Error('getUserMedia is not defined')
}
async function takeScreenshotStream() {
// see: https://developer.mozilla.org/en-US/docs/Web/API/Window/screen
const width = screen.width * (window.devicePixelRatio || 1)
const height = screen.height * (window.devicePixelRatio || 1)
const errors = []
let stream
try {
stream = await getDisplayMedia({
audio: false,
// see: https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamConstraints/video
video: {
width,
height,
frameRate: 1,
},
})
} catch (ex) {
errors.push(ex)
}
// for electron js
if (navigator.userAgent.indexOf('Electron') >= 0) {
try {
stream = await getUserMedia({
audio: false,
video: {
mandatory: {
chromeMediaSource: 'desktop',
// chromeMediaSourceId: source.id,
minWidth : width,
maxWidth : width,
minHeight : height,
maxHeight : height,
},
},
})
} catch (ex) {
errors.push(ex)
}
}
if (errors.length) {
console.debug(...errors)
if (!stream) {
throw errors[errors.length - 1]
}
}
return stream
}
async function takeScreenshotCanvas() {
const stream = await takeScreenshotStream()
// from: https://stackoverflow.com/a/57665309/5221762
const video = document.createElement('video')
const result = await new Promise((resolve, reject) => {
video.onloadedmetadata = () => {
video.play()
video.pause()
// from: https://github.com/kasprownik/electron-screencapture/blob/master/index.js
const canvas = document.createElement('canvas')
canvas.width = video.videoWidth
canvas.height = video.videoHeight
const context = canvas.getContext('2d')
// see: https://developer.mozilla.org/en-US/docs/Web/API/HTMLVideoElement
context.drawImage(video, 0, 0, video.videoWidth, video.videoHeight)
resolve(canvas)
}
video.srcObject = stream
})
stream.getTracks().forEach(function (track) {
track.stop()
})
if (result == null) {
throw new Error('Cannot take canvas screenshot')
}
return result
}
// from: https://stackoverflow.com/a/46182044/5221762
function getJpegBlob(canvas) {
return new Promise((resolve, reject) => {
// docs: https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob
canvas.toBlob(blob => resolve(blob), 'image/jpeg', 0.95)
})
}
async function getJpegBytes(canvas) {
const blob = await getJpegBlob(canvas)
return new Promise((resolve, reject) => {
const fileReader = new FileReader()
fileReader.addEventListener('loadend', function () {
if (this.error) {
reject(this.error)
return
}
resolve(this.result)
})
fileReader.readAsArrayBuffer(blob)
})
}
async function takeScreenshotJpegBlob() {
const canvas = await takeScreenshotCanvas()
return getJpegBlob(canvas)
}
async function takeScreenshotJpegBytes() {
const canvas = await takeScreenshotCanvas()
return getJpegBytes(canvas)
}
function blobToCanvas(blob, maxWidth, maxHeight) {
return new Promise((resolve, reject) => {
const img = new Image()
img.onload = function () {
const canvas = document.createElement('canvas')
const scale = Math.min(
1,
maxWidth ? maxWidth / img.width : 1,
maxHeight ? maxHeight / img.height : 1,
)
canvas.width = img.width * scale
canvas.height = img.height * scale
const ctx = canvas.getContext('2d')
ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, canvas.width, canvas.height)
resolve(canvas)
}
img.onerror = () => {
reject(new Error('Error load blob to Image'))
}
img.src = URL.createObjectURL(blob)
})
}
DEMO:
document.body.onclick = async () => {
// take the screenshot
var screenshotJpegBlob = await takeScreenshotJpegBlob()
// show preview with max size 300 x 300 px
var previewCanvas = await blobToCanvas(screenshotJpegBlob, 300, 300)
previewCanvas.style.position = 'fixed'
document.body.appendChild(previewCanvas)
// send it to the server
var formdata = new FormData()
formdata.append("screenshot", screenshotJpegBlob)
await fetch('https://your-web-site.com/', {
method: 'POST',
body: formdata,
'Content-Type' : "multipart/form-data",
})
}
// and click on the page
Here is a complete screenshot example that works with chrome in 2021. The end result is a blob ready to be transmitted. Flow is: request media > grab frame > draw to canvas > transfer to blob. If you want to do it more memory efficient explore OffscreenCanvas or possibly ImageBitmapRenderingContext
https://jsfiddle.net/v24hyd3q/1/
// Request media
navigator.mediaDevices.getDisplayMedia().then(stream =>
{
// Grab frame from stream
let track = stream.getVideoTracks()[0];
let capture = new ImageCapture(track);
capture.grabFrame().then(bitmap =>
{
// Stop sharing
track.stop();
// Draw the bitmap to canvas
canvas.width = bitmap.width;
canvas.height = bitmap.height;
canvas.getContext('2d').drawImage(bitmap, 0, 0);
// Grab blob from canvas
canvas.toBlob(blob => {
// Do things with blob here
console.log('output blob:', blob);
});
});
})
.catch(e => console.log(e));
Heres an example using: getDisplayMedia
document.body.innerHTML = '<video style="width: 100%; height: 100%; border: 1px black solid;"/>';
navigator.mediaDevices.getDisplayMedia()
.then( mediaStream => {
const video = document.querySelector('video');
video.srcObject = mediaStream;
video.onloadedmetadata = e => {
video.play();
video.pause();
};
})
.catch( err => console.log(`${err.name}: ${err.message}`));
Also worth checking out is the Screen Capture API docs.
You can try my new JS library: screenshot.js.
It's enable to take real screenshot.
You load the script:
<script src="https://raw.githubusercontent.com/amiad/screenshot.js/master/screenshot.js"></script>
and take screenshot:
new Screenshot({success: img => {
// callback function
myimage = img;
}});
You can read more options in project page.

Display image with requestFileSystem and toUrl() function

I made an application who use requestFileSystem. Everything works fine.
Add a new image and store it in an persistent local file system.
Does anybody know how to display an image with toUrl() ?
...
window.requestFileSystem(window.PERSISTENT, 5*1024*1024, function(fs){
fs.root.getDirectory(itemId, {create: false}, function(dirEntry) {
var dirReader = dirEntry.createReader();
var entries = [];
var readEntries = function() {
dirReader.readEntries (function(results) {
if (!results.length) {
listResults(entries.sort(), itemId);
} else {
entries = entries.concat(fsdatas.dir.toArray(results));
readEntries();
}
}, errorHandler);
};
readEntries();
});
}, errorHandler);
...
And
function listResults(entries, itemId) {
document.querySelector('#listRecordFiles-'+itemId).innerHTML = '';
var fragment = document.createDocumentFragment();
var i = 0;
entries.forEach(function(entry, i) {
i++;
var img = document.createElement('img');
img.src = entry.toURL();
fragment.appendChild(img);
});
document.querySelector('#listRecordFiles-'+itemId).appendChild(fragment);
}
The output is :
<img src="filesystem:http://domain.tld/persistent/1/image-test.jpg">
But nothing is displayed on browser.
The example below is a snippet of code responsible for reading the images saved in the application's root directory, and show in the document body.
Remember, in this case, I used navigator.camera.DestinationType.DATA_URL to open the PHOTOLIBRARY, and saved the image content using atob (ascii to binary), so carry the image with btoa (binary to ascii)
function myLoadFile(filename) {
var myDocument = document.querySelector("body");
filesystem.root.getFile(filename, {}, function(fileEntry) {
fileEntry.file(function(file) {
var reader = new FileReader();
reader.onload = function(e) {
var img = document.createElement('img');
// if you save the file with atob (ascii to binary), then:
img.src = "data:image/jpeg;base64,"+btoa(this.result);
// if you don't save the file without atob, then:
// img.src = "data:image/jpeg;base64,"+this.result;
myDocument.appendChild(img)
};
reader.readAsText(file);
}, errorHandler);
}, errorHandler);
}

upload image from local into tinyMCE

tinyMCE has an insert image button, but how to handle its functionality
pls give some code
I have upvoted the code written by #pavanastechie, but I ended up rewriting it quite a lot. Here's a version that is far shorter, which might have value to some people
tinymce.init({
toolbar : "imageupload",
setup: function(editor) {
var inp = $('<input id="tinymce-uploader" type="file" name="pic" accept="image/*" style="display:none">');
$(editor.getElement()).parent().append(inp);
inp.on("change",function(){
var input = inp.get(0);
var file = input.files[0];
var fr = new FileReader();
fr.onload = function() {
var img = new Image();
img.src = fr.result;
editor.insertContent('<img src="'+img.src+'"/>');
inp.val('');
}
fr.readAsDataURL(file);
});
editor.addButton( 'imageupload', {
text:"IMAGE",
icon: false,
onclick: function(e) {
inp.trigger('click');
}
});
}
});
NOTE: this relies on jquery, and won't work without it. Also, it assumes that the browser supports window.FileReader, and doesn't check for it.
I used pavanastechie's and Chris Lear's solutions, which worked perfectly for me, and wanted to share a complete example built on theirs that uploads the image to the server and embeds the image using the URL provided back by the server:
tinymce.init({
toolbar: 'imageupload',
setup: function(editor) {
initImageUpload(editor);
}
});
function initImageUpload(editor) {
// create input and insert in the DOM
var inp = $('<input id="tinymce-uploader" type="file" name="pic" accept="image/*" style="display:none">');
$(editor.getElement()).parent().append(inp);
// add the image upload button to the editor toolbar
editor.addButton('imageupload', {
text: '',
icon: 'image',
onclick: function(e) { // when toolbar button is clicked, open file select modal
inp.trigger('click');
}
});
// when a file is selected, upload it to the server
inp.on("change", function(e){
uploadFile($(this), editor);
});
}
function uploadFile(inp, editor) {
var input = inp.get(0);
var data = new FormData();
data.append('image[file]', input.files[0]);
$.ajax({
url: '/admin/images',
type: 'POST',
data: data,
processData: false, // Don't process the files
contentType: false, // Set content type to false as jQuery will tell the server its a query string request
success: function(data, textStatus, jqXHR) {
editor.insertContent('<img class="content-img" src="' + data.url + '"/>');
},
error: function(jqXHR, textStatus, errorThrown) {
if(jqXHR.responseText) {
errors = JSON.parse(jqXHR.responseText).errors
alert('Error uploading image: ' + errors.join(", ") + '. Make sure the file is an image and has extension jpg/jpeg/png.');
}
}
});
}
!!!!ENJOY!!! here is the solution to load directly from local computer
JSFIDDLE DEMO
<textarea name="content"></textarea>
<title>Local image loading in to tinymce</title>
<br/>
<b>Image size should be lessthan 500kb</b>
JAVA SCRIPT CODE
`
tinymce.init({
selector: "textarea",
toolbar: "mybutton",
setup: function(editor) {
editor.addButton('mybutton', {
text:"IMAGE",
icon: false,
onclick: function(e) {
console.log($(e.target));
if($(e.target).prop("tagName") == 'BUTTON'){
console.log($(e.target).parent().parent().find('input').attr('id'));
if($(e.target).parent().parent().find('input').attr('id') != 'tinymce-uploader') {
$(e.target).parent().parent().append('<input id="tinymce-uploader" type="file" name="pic" accept="image/*" style="display:none">');
}
$('#tinymce-uploader').trigger('click');
$('#tinymce-uploader').change(function(){
var input, file, fr, img;
if (typeof window.FileReader !== 'function') {
write("The file API isn't supported on this browser yet.");
return;
}
input = document.getElementById('tinymce-uploader');
if (!input) {
write("Um, couldn't find the imgfile element.");
} else if (!input.files) {
write("This browser doesn't seem to support the `files` property of file inputs.");
} else if (!input.files[0]) {
write("Please select a file before clicking 'Load'");
} else {
file = input.files[0];
fr = new FileReader();
fr.onload = createImage;
fr.readAsDataURL(file);
}
function createImage() {
img = new Image();
img.src = fr.result;
editor.insertContent('<img src="'+img.src+'"/>');
}
});
}
if($(e.target).prop("tagName") == 'DIV'){
if($(e.target).parent().find('input').attr('id') != 'tinymce-uploader') {
console.log($(e.target).parent().find('input').attr('id'));
$(e.target).parent().append('<input id="tinymce-uploader" type="file" name="pic" accept="image/*" style="display:none">');
}
$('#tinymce-uploader').trigger('click');
$('#tinymce-uploader').change(function(){
var input, file, fr, img;
if (typeof window.FileReader !== 'function') {
write("The file API isn't supported on this browser yet.");
return;
}
input = document.getElementById('tinymce-uploader');
if (!input) {
write("Um, couldn't find the imgfile element.");
} else if (!input.files) {
write("This browser doesn't seem to support the `files` property of file inputs.");
} else if (!input.files[0]) {
write("Please select a file before clicking 'Load'");
} else {
file = input.files[0];
fr = new FileReader();
fr.onload = createImage;
fr.readAsDataURL(file);
}
function createImage() {
img = new Image();
img.src = fr.result;
editor.insertContent('<img src="'+img.src+'"/>');
}
});
}
if($(e.target).prop("tagName") == 'I'){
console.log($(e.target).parent().parent().parent().find('input').attr('id')); if($(e.target).parent().parent().parent().find('input').attr('id') != 'tinymce-uploader') { $(e.target).parent().parent().parent().append('<input id="tinymce-uploader" type="file" name="pic" accept="image/*" style="display:none">');
}
$('#tinymce-uploader').trigger('click');
$('#tinymce-uploader').change(function(){
var input, file, fr, img;
if (typeof window.FileReader !== 'function') {
write("The file API isn't supported on this browser yet.");
return;
}
input = document.getElementById('tinymce-uploader');
if (!input) {
write("Um, couldn't find the imgfile element.");
} else if (!input.files) {
write("This browser doesn't seem to support the `files` property of file inputs.");
} else if (!input.files[0]) {
write("Please select a file before clicking 'Load'");
} else {
file = input.files[0];
fr = new FileReader();
fr.onload = createImage;
fr.readAsDataURL(file);
}
function createImage() {
img = new Image();
img.src = fr.result;
editor.insertContent('<img src="'+img.src+'"/>');
}
});
}
}
});
}
});
`
Din't try iManager but found tinyFCK good and easy to configure which gives CKEditor's filemanager integrated with TinyMCE
1.Download TinyFCK
2.replace filemanger folder in tinyFCK with filemanager folder of ur CKEditor
3.code :
-
tinyMCE.init({
theme : "advanced",
file_browser_callback : "fileBrowserCallBack",
});
function fileBrowserCallBack(field_name, url, type, win) {
var connector = "../../filemanager/browser.html?Connector=connectors/php/connector.php";
var enableAutoTypeSelection = true;
var cType;
tinyfck_field = field_name;
tinyfck = win;
switch (type) {
case "image":
cType = "Image";
break;
case "flash":
cType = "Flash";
break;
case "file":
cType = "File";
break;
}
if (enableAutoTypeSelection && cType) {
connector += "?Type=" + cType;
}
window.open(connector, "tinyfck", "modal,width=600,height=400");
}
I know this post is old, but maybe this will help someone trying to find a open source file manager for tinymce:
https://github.com/2b3ez/FileManager4TinyMCE
This worked great for me.
Based on #Chris Lear's answer, I have re-modified the script so that it supports multiple file uploads to server, and removed the data image for preview after content is posted and before table is updated with a little php script
tinymce.init({
selector: 'textarea',
setup: function(editor) {
var n = 0;
var form = $('#form_id'); // your form id
editor.addButton( 'imageupload', {
text:"IMAGE",
icon: false,
onclick: function(e) {
$(form).append('<input id="tinymce-uploader_'+n+'" class="tinymce-uploader" type="file" name="pic['+n+']" mutliple accept="image/*" style="display: none;">');
$('#tinymce-uploader_'+n).trigger('click');
n++;
$('.tinymce-uploader').on("change",function(){
var input = $(this).get(0);
var file = input.files[0];
var filename = file.name;
var fr = new FileReader();
fr.onload = function() {
var img = new Image();
img.src = fr.result;
editor.insertContent('<img data-name="'+filename+'" src="'+img.src+'"/>');
}
fr.readAsDataURL(file);
});
}
});
},
And on php side inside the upload php file:
function data2src($content, $img_path ='') {
preg_match('/data\-name="([^"]+)/i',$content, $data_name);
$tmp = preg_replace('/src=["]data([^"]+)["]/i', '', $content);
$content = preg_replace('/data\-name\=\"/i', 'src="'.$img_path, $tmp);
return $content;
}
I know it is an old question. However, I think this answer may help somebody who wants to upload multiple images by using tinyMCE 5.xx.
Based on #Chris Lear's and #stephen.hanson's answer, I modify some code to support multiple images uploading. Here is my code. Hope it could help somebody.
tinymce.init({
toolbar: 'imageupload',
setup: function(editor) {
initImageUpload(editor);
}
});
function initImageUpload(editor) {
// create input and insert in the DOM
var inp = $(`<input id='tinymce-uploader' type='file' name='pic' accept='image/*' style='display:none' multiple>`);
$(editor.getElement()).parent().append(inp);
// add the image upload button to the editor toolbar
editor.addButton('imageupload', {
text:'IMAGE',
onAction: function(_) {
// when toolbar button is clicked, open file select modal
inp.trigger('click');
}
});
// when a file is selected, upload it to the server
inp.on('change',function(){
for(let i=0;i<inp[0].files.length;i++){
let file = inp[0].files[i];
let data = new FormData();
data.append('multipartFile',file);
axios.post('/upload/image/url',
data,
{
headers: {
'Content-Type': 'multipart/form-data'
}
}).then(res => {
if (res.status = 200) {
editor.insertContent('<img class="content-img" src="' + data.url + '"/>');
// clear data to avoid uploading same data not working in the second time
inp.val('');
}
})
}
It works for image upload.Is this possible for file upload ? I want to add a custom file upload option from local into tinyMCE and want to show it by url .
Code is something like below which not working:
ed.addButton('mybutton2', {
text:"File",
icon: false,
onclick: function(e) {
console.log($(e.target));
if($(e.target).prop("tagName") == 'BUTTON'){
console.log($(e.target).parent().parent().find('input').attr('id'));
if($(e.target).parent().parent().find('input').attr('id') !=
'tinymce-uploader') {
$(e.target).parent().parent().append('<input id="tinymce-
uploader" type="file" name="pic" accept="*" height="100" weidth="100"
style="display:none">');
}
$('#tinymce-uploader').trigger('click');
$('#tinymce-uploader').change(function(){
var input, file, fr, img;
if (typeof window.FileReader !== 'function') {
write("The file API isn't supported on this browser yet.");
return;
}
input = document.getElementById('tinymce-uploader');
// var URL = document.my_form.my_field.value;
alert(input.files[0]);
if (!input) {
write("Um, couldn't find the imgfile element.");
} else if (!input.files) {
write("This browser doesn't seem to support the `files`
property of file inputs.");
} else if (!input.files[0]) {
write("Please select a file before clicking 'Load'");
alert( input.files[0]);
} else {
file = input.files[0];
fr = new FileReader();
fr.onload = createFile;
fr.readAsDataURL(file);
// alert(fr.result);
}
function createFile() {
//what should I write here?
ed.insertContent('<a href="'+img.src+'">download
file_name</a>');
}
});
}
}
});