forked from goranristov/ImagePicker
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added browser support (Telerik-Verified-Plugins#172)
- Added browser support.
- Loading branch information
1 parent
bbc1631
commit 94f0aac
Showing
3 changed files
with
258 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,213 @@ | ||
const cacheDirectory = (require('./isChrome')()) ? 'filesystem:' + window.location.origin + '/temporary/' : 'file:///temporary/'; | ||
const nonScalableTypes = ['video', 'gif']; | ||
|
||
//Edge needs its own stuff | ||
if (!HTMLCanvasElement.prototype.toBlob) { | ||
Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', { | ||
value: function (callback, type, quality) { | ||
var canvas = this; | ||
setTimeout(function() { | ||
var binStr = atob( canvas.toDataURL(type, quality).split(',')[1] ), | ||
len = binStr.length, | ||
arr = new Uint8Array(len); | ||
|
||
for (var i = 0; i < len; i++ ) { | ||
arr[i] = binStr.charCodeAt(i); | ||
} | ||
|
||
callback( new Blob( [arr], {type: type || 'image/png'} ) ); | ||
}); | ||
} | ||
}); | ||
} | ||
|
||
async function getPictures(successCallback, errorCallback, data) { | ||
//Set default params just in case | ||
var params = { | ||
maximumImagesCount: 20, | ||
width: 0, | ||
height: 0, | ||
quality: 100, | ||
outputType: 0, | ||
allow_video: false | ||
} | ||
|
||
//Read params from cordova | ||
if (data[0].maximumImagesCount) params.maximumImagesCount = data[0].maximumImagesCount; | ||
if (data[0].width) params.width = data[0].width; | ||
if (data[0].height) params.height = data[0].height; | ||
if (data[0].quality) params.quality = data[0].quality; | ||
if (data[0].outputType) params.outputType = data[0].outputType; | ||
if (data[0].allow_video) params.allow_video = data[0].allow_video; | ||
|
||
openImagePicker(params.maximumImagesCount, params.width, params.height, params.quality, params.outputType, params.allow_video).then((images) => { | ||
successCallback(images); | ||
}).catch((error) => { | ||
errorCallback(error); | ||
}); | ||
} | ||
|
||
//hasReadPermission is not relevant in browsers, let's just return a success so everyone is happy | ||
async function hasReadPermission(successCallback, errorCallback, data) { | ||
successCallback(); | ||
} | ||
|
||
//requestReadPermission is not relevant in browsers, let's just return a success so everyone is happy | ||
async function requestReadPermission(successCallback, errorCallback, data) { | ||
successCallback(); | ||
} | ||
|
||
function openImagePicker(maximumImagesCount, desiredWidth, desiredHeight, quality, outputType, allowVideo) { | ||
return new Promise((resolve, reject) => { | ||
let fileChooser = document.createElement('input'); | ||
|
||
fileChooser.type = 'file'; | ||
fileChooser.accept = 'image/png, image/jpeg, image/gif'; | ||
if (allowVideo) fileChooser.accept += ', video/mp4, video/webm, video/ogg'; | ||
|
||
if (maximumImagesCount > 1) { | ||
fileChooser.setAttribute('multiple', ''); | ||
} | ||
|
||
fileChooser.onchange = (event) => { | ||
let resizeImagePromises = []; | ||
let fileNames = []; //We need to store filenames as chrome deletes event.target.files to quickly | ||
|
||
if (event.target.files.length <= maximumImagesCount) { | ||
for (let file of event.target.files) { | ||
fileNames.push('tmp_' + getDateTimeString() + '_' + file.name); | ||
resizeImagePromises.push(resizeImage(file, desiredWidth, desiredHeight, quality, outputType)); | ||
} | ||
|
||
Promise.all(resizeImagePromises).then((images) => { | ||
if (outputType == 0) { | ||
//If we need FILE_URI, we need to store the files in the temporary dir of the browser | ||
//So we need to write the files there Before | ||
let saveBlobPromises = []; | ||
|
||
for (let i = 0; i < images.length; i++) { | ||
saveBlobPromises.push(saveBlobToTemporaryFileSystem(images[i], fileNames[i])); | ||
} | ||
|
||
Promise.all(saveBlobPromises).then((fileURIs) => { | ||
resolve(fileURIs); | ||
}).catch((error) => { | ||
reject('ERROR_WHILE_CREATING_FILES ' + error); | ||
}); | ||
} else { | ||
//resizeImages returns the images in base64, so no need to do anything | ||
resolve(images); | ||
} | ||
}).catch((error) => { | ||
reject('ERROR_WHILE_RESIZING ' + error); | ||
}); | ||
} else { | ||
reject('TO_MANY_IMAGES'); | ||
} | ||
}; | ||
|
||
//Now that the event is hooked we can click it | ||
fileChooser.click(); | ||
}); | ||
} | ||
|
||
//Promise resolving either a blob or a base64 string depending on outputType | ||
function resizeImage(file, desiredWidth, desiredHeight, quality, outputType) { | ||
return new Promise((resolve, reject) => { | ||
if (outputType == 1 || ( (desiredWidth != 0 || desiredHeight != 0) && !nonScalableTypes.some(type => file.type.includes(type)) ) ) { | ||
//BASE64_STRING required or | ||
//Scaling required | ||
//Base64 string needs to be jpeg formated so even if no scaling is required we need to do the conversion | ||
let reader = new FileReader(); | ||
reader.readAsDataURL(file); | ||
|
||
reader.onload = (e) => { | ||
let img = new Image(); | ||
img.src = e.target.result; | ||
img.onload = (pic) => { | ||
let canvas = document.createElement('canvas'); | ||
|
||
if ((img.height > desiredHeight || img.width > desiredWidth) && (desiredWidth != 0 || desiredHeight != 0)) { | ||
if ((img.height / desiredHeight) > (img.width / desiredWidth)) { | ||
canvas.width = img.width / (img.height / desiredHeight) | ||
canvas.height = desiredHeight; | ||
} else { | ||
canvas.width = desiredWidth | ||
canvas.height = img.height / (img.width / desiredWidth) ; | ||
} | ||
} else { | ||
canvas.width = img.width; | ||
canvas.height = img.height; | ||
} | ||
|
||
let ctx = canvas.getContext('2d'); | ||
ctx.drawImage(img, 0, 0, canvas.width, canvas.height); | ||
|
||
if (outputType == 0) { | ||
//FILE_URI required, resolve with a blob | ||
ctx.canvas.toBlob((blob) => { | ||
resolve(blob); | ||
}, 'image/jpeg', (quality / 100)); | ||
|
||
} else { | ||
//BASE64_STRING required, resolve with a string | ||
//To be consistent with Android (and iOS) we remove the base64 header from the string | ||
resolve(ctx.canvas.toDataURL('image/jpeg', (quality / 100)).replace('data:image/jpeg;base64,', '')); | ||
} | ||
}; | ||
}; | ||
|
||
reader.onerror = (error) => { | ||
reject(error); | ||
} | ||
} else { | ||
//No scaling required and FILE_URI required? | ||
//FILE_URI required, resolve with a blob (a file is a blob) | ||
resolve(file); | ||
} | ||
}); | ||
} | ||
|
||
function saveBlobToTemporaryFileSystem(blob, fileName) { | ||
return new Promise((resolve, reject) => { | ||
//Just make sure file extensions matches file type if possible | ||
var ext = fileName.split('.').pop(); | ||
|
||
if (blob.type && ext) { | ||
if (!blob.type.includes(ext.toLowerCase())) fileName = fileName.replace(ext, blob.type.split('/').pop()); | ||
} | ||
|
||
window.requestFileSystem(window.TEMPORARY, blob.size, (fs) => { | ||
fs.root.getFile(fileName, {create: true, exclusive: false}, (fileEntry) => { | ||
fileEntry.createWriter((fileWriter) => { | ||
fileWriter.onwriteend = (e) => { | ||
resolve(cacheDirectory + fileName); | ||
}; | ||
|
||
fileWriter.onerror = (error) => { | ||
reject(error); | ||
}; | ||
|
||
if (blob) { | ||
fileWriter.write(blob); | ||
} else { | ||
reject('ERROR_NO_DATA_TO_WRITE'); | ||
} | ||
}); | ||
}); | ||
}); | ||
}); | ||
} | ||
|
||
function getDateTimeString() { | ||
let d = new Date(); | ||
return d.getDate().toString() + d.getMonth().toString() + d.getFullYear().toString() + '_' + d.getHours().toString() + d.getMinutes().toString() + d.getSeconds().toString(); | ||
} | ||
|
||
module.exports = { | ||
getPictures: getPictures, | ||
hasReadPermission: hasReadPermission, | ||
requestReadPermission: requestReadPermission | ||
}; | ||
|
||
require( "cordova/exec/proxy" ).add( "ImagePicker", module.exports ); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
/* | ||
* | ||
* Licensed to the Apache Software Foundation (ASF) under one | ||
* or more contributor license agreements. See the NOTICE file | ||
* distributed with this work for additional information | ||
* regarding copyright ownership. The ASF licenses this file | ||
* to you under the Apache License, Version 2.0 (the | ||
* "License"); you may not use this file except in compliance | ||
* with the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, | ||
* software distributed under the License is distributed on an | ||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
* KIND, either express or implied. See the License for the | ||
* specific language governing permissions and limitations | ||
* under the License. | ||
* | ||
*/ | ||
|
||
module.exports = function () { | ||
// window.webkitRequestFileSystem and window.webkitResolveLocalFileSystemURL are available only in Chrome and | ||
// possibly a good flag to indicate that we're running in Chrome | ||
return window.webkitRequestFileSystem && window.webkitResolveLocalFileSystemURL; | ||
}; |