works except for upload progress
This commit is contained in:
@@ -119,87 +119,6 @@ export function imageScaled(file, maxWidth, maxHeight, maxSize, forceSquare, onS
|
|||||||
img.src = URL.createObjectURL(file);
|
img.src = URL.createObjectURL(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert uploaded image into a base64-encoded string possibly scaling
|
|
||||||
// linear dimensions or constraining to a square.
|
|
||||||
export function imageFileScaledToBase64(file, width, height, forceSquare, onSuccess, onError) {
|
|
||||||
const img = new Image();
|
|
||||||
img.crossOrigin = 'Anonymous';
|
|
||||||
img.onerror = function(err) {
|
|
||||||
onError("Image format unrecognized");
|
|
||||||
}
|
|
||||||
img.onload = function() {
|
|
||||||
var dim = fitImageSize(this.width, this.height, width, height, forceSquare);
|
|
||||||
if (!dim) {
|
|
||||||
onError("Invalid image");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var canvas = document.createElement('canvas');
|
|
||||||
canvas.width = dim.dstWidth;
|
|
||||||
canvas.height = dim.dstHeight;
|
|
||||||
var ctx = canvas.getContext('2d');
|
|
||||||
ctx.imageSmoothingEnabled = true;
|
|
||||||
ctx.drawImage(this, dim.xoffset, dim.yoffset, dim.srcWidth, dim.srcHeight,
|
|
||||||
0, 0, dim.dstWidth, dim.dstHeight);
|
|
||||||
|
|
||||||
var mime = (this.width != dim.dstWidth ||
|
|
||||||
this.height != dim.dstHeight ||
|
|
||||||
SUPPORTED_IMAGE_FORMATS.indexOf(file.type) < 0) ? 'image/jpeg' : file.type;
|
|
||||||
var imageBits = canvas.toDataURL(mime);
|
|
||||||
var parts = imageBits.split(',');
|
|
||||||
// Get actual image type: 'data:image/png;base64,'
|
|
||||||
mime = getMimeType(parts[0]);
|
|
||||||
if (!mime) {
|
|
||||||
onError("Unsupported image format");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Ensure the image is not too large
|
|
||||||
let quality = 0.78;
|
|
||||||
if (base64DecodedLen(imageBits.length) > MAX_INBAND_ATTACHMENT_SIZE) {
|
|
||||||
mime = 'image/jpeg';
|
|
||||||
}
|
|
||||||
if (mime == 'image/jpeg') {
|
|
||||||
// Reduce size of the jpeg by reducing image quality
|
|
||||||
while (base64DecodedLen(imageBits.length) > MAX_INBAND_ATTACHMENT_SIZE && quality > 0.45) {
|
|
||||||
imageBits = canvas.toDataURL(mime, quality);
|
|
||||||
quality *= 0.84;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (base64DecodedLen(imageBits.length) > MAX_INBAND_ATTACHMENT_SIZE) {
|
|
||||||
onError("The image size " + bytesToHumanSize(base64DecodedLen(imageBits.length)) +
|
|
||||||
" exceeds the " + bytesToHumanSize(MAX_INBAND_ATTACHMENT_SIZE) + " limit.", "err");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
canvas = null;
|
|
||||||
onSuccess(imageBits.split(',')[1], mime, dim.dstWidth, dim.dstHeight, fileNameForMime(file.name, mime));
|
|
||||||
};
|
|
||||||
img.src = URL.createObjectURL(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert uploaded image file to base64-encoded string without scaling/converting the image
|
|
||||||
export function imageFileToBase64(file, onSuccess, onError) {
|
|
||||||
var reader = new FileReader();
|
|
||||||
reader.addEventListener('load', function() {
|
|
||||||
var parts = reader.result.split(',');
|
|
||||||
var mime = getMimeType(parts[0]);
|
|
||||||
if (!mime) {
|
|
||||||
onError("Failed to process image file");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get image size.
|
|
||||||
var img = new Image();
|
|
||||||
img.crossOrigin = 'Anonymous';
|
|
||||||
img.onload = function() {
|
|
||||||
onSuccess(parts[1], mime, this.width, this.height, fileNameForMime(file.name, mime));
|
|
||||||
}
|
|
||||||
img.onerror = function(err) {
|
|
||||||
onError("Image format not recognized");
|
|
||||||
}
|
|
||||||
img.src = URL.createObjectURL(file);
|
|
||||||
}, false);
|
|
||||||
reader.readAsDataURL(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert File to base64 string.
|
// Convert File to base64 string.
|
||||||
export function fileToBase64(file, onSuccess) {
|
export function fileToBase64(file, onSuccess) {
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
|
|||||||
+7
-6
@@ -93,8 +93,8 @@ export function isUrlRelative(url) {
|
|||||||
|
|
||||||
// Ensure URL does not present an XSS risk. Optional allowedSchemes may contain an array of
|
// Ensure URL does not present an XSS risk. Optional allowedSchemes may contain an array of
|
||||||
// strings with permitted URL schemes, such as ['ftp', 'ftps']; otherwise accept http and https only.
|
// strings with permitted URL schemes, such as ['ftp', 'ftps']; otherwise accept http and https only.
|
||||||
// If apikey is defined, it's appended to relative URL.
|
// If apikey and/or token is defined, it's appended to relative URL.
|
||||||
export function sanitizeUrl(url, apikey) {
|
export function sanitizeUrl(url) {
|
||||||
if (!url) {
|
if (!url) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -107,6 +107,7 @@ export function sanitizeUrl(url, apikey) {
|
|||||||
if (!/^([a-z][a-z0-9+.-]*:|\/\/)/i.test(url)) {
|
if (!/^([a-z][a-z0-9+.-]*:|\/\/)/i.test(url)) {
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Blob URLs are safe.
|
// Blob URLs are safe.
|
||||||
if (/^blob:http/.test(url)) {
|
if (/^blob:http/.test(url)) {
|
||||||
return url;
|
return url;
|
||||||
@@ -123,15 +124,15 @@ export function sanitizeUrl(url, apikey) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Ensure URL is suitable for <img src="url"> field: the URL must be a relative URL or
|
// Ensure URL is suitable for <img src="url"> field: the URL must be a relative URL or
|
||||||
// have http:, https:, or data: scheme.
|
// have http:, https:, blob: or data: scheme.
|
||||||
// The relative URL is appended with the API key.
|
// The relative URL is appended with the API key and/or auth token.
|
||||||
// In case of data: scheme, the URL must start with a 'data:image/XXXX;base64,'.
|
// In case of data: scheme, the URL must start with a 'data:image/XXXX;base64,'.
|
||||||
export function sanitizeImageUrl(url, apikey) {
|
export function sanitizeImageUrl(url) {
|
||||||
if (!url) {
|
if (!url) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const sanitizedUrl = sanitizeUrl(url, apikey);
|
const sanitizedUrl = sanitizeUrl(url);
|
||||||
if (sanitizedUrl) {
|
if (sanitizedUrl) {
|
||||||
return sanitizedUrl;
|
return sanitizedUrl;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import SendMessage from '../widgets/send-message.jsx';
|
|||||||
|
|
||||||
import { DEFAULT_P2P_ACCESS_MODE, KEYPRESS_DELAY, MESSAGES_PAGE, MAX_EXTERN_ATTACHMENT_SIZE,
|
import { DEFAULT_P2P_ACCESS_MODE, KEYPRESS_DELAY, MESSAGES_PAGE, MAX_EXTERN_ATTACHMENT_SIZE,
|
||||||
MAX_IMAGE_DIM, MAX_INBAND_ATTACHMENT_SIZE, READ_DELAY } from '../config.js';
|
MAX_IMAGE_DIM, MAX_INBAND_ATTACHMENT_SIZE, READ_DELAY } from '../config.js';
|
||||||
import { SUPPORTED_IMAGE_FORMATS, blobToBase64, filePasted, fileToBase64, imageFileToBase64,
|
import { SUPPORTED_IMAGE_FORMATS, blobToBase64, filePasted, fileToBase64,
|
||||||
imageScaled, makeImageUrl } from '../lib/blob-helpers.js';
|
imageScaled, makeImageUrl } from '../lib/blob-helpers.js';
|
||||||
import HashNavigation from '../lib/navigation.js';
|
import HashNavigation from '../lib/navigation.js';
|
||||||
import { bytesToHumanSize, shortDateFormat } from '../lib/strformat.js';
|
import { bytesToHumanSize, shortDateFormat } from '../lib/strformat.js';
|
||||||
@@ -559,7 +559,9 @@ class MessagesView extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleClosePreview() {
|
handleClosePreview() {
|
||||||
|
if (this.state.imagePreview && this.state.imagePreview.url) {
|
||||||
URL.revokeObjectURL(this.state.imagePreview.url);
|
URL.revokeObjectURL(this.state.imagePreview.url);
|
||||||
|
}
|
||||||
this.setState({ imagePostview: null, imagePreview: null, docPreview: null });
|
this.setState({ imagePostview: null, imagePreview: null, docPreview: null });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ function draftyFormatter(style, data, values, key) {
|
|||||||
dim = dim || {dstWidth: BROKEN_IMAGE_SIZE, dstHeight: BROKEN_IMAGE_SIZE};
|
dim = dim || {dstWidth: BROKEN_IMAGE_SIZE, dstHeight: BROKEN_IMAGE_SIZE};
|
||||||
attr.style = { width: dim.dstWidth + 'px', height: dim.dstHeight + 'px' };
|
attr.style = { width: dim.dstWidth + 'px', height: dim.dstHeight + 'px' };
|
||||||
if (!uploading) {
|
if (!uploading) {
|
||||||
attr.src = sanitizeImageUrl(attr.src);
|
attr.src = this.props.tinode.authorizeURL(sanitizeImageUrl(attr.src));
|
||||||
if (attr.src) {
|
if (attr.src) {
|
||||||
attr.onClick = this.handleImagePreview;
|
attr.onClick = this.handleImagePreview;
|
||||||
attr.className += ' image-clickable';
|
attr.className += ' image-clickable';
|
||||||
|
|||||||
+6
-87
@@ -200,7 +200,7 @@ react_dom__WEBPACK_IMPORTED_MODULE_1___default.a.render(react__WEBPACK_IMPORTED_
|
|||||||
/*!*********************************!*\
|
/*!*********************************!*\
|
||||||
!*** ./src/lib/blob-helpers.js ***!
|
!*** ./src/lib/blob-helpers.js ***!
|
||||||
\*********************************/
|
\*********************************/
|
||||||
/*! exports provided: SUPPORTED_IMAGE_FORMATS, MIME_EXTENSIONS, makeImageUrl, fitImageSize, fileNameForMime, imageScaled, imageFileScaledToBase64, imageFileToBase64, fileToBase64, blobToBase64, filePasted, getMimeType, base64EncodedLen, base64DecodedLen, base64ReEncode */
|
/*! exports provided: SUPPORTED_IMAGE_FORMATS, MIME_EXTENSIONS, makeImageUrl, fitImageSize, fileNameForMime, imageScaled, fileToBase64, blobToBase64, filePasted, getMimeType, base64EncodedLen, base64DecodedLen, base64ReEncode */
|
||||||
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
@@ -211,8 +211,6 @@ __webpack_require__.r(__webpack_exports__);
|
|||||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fitImageSize", function() { return fitImageSize; });
|
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fitImageSize", function() { return fitImageSize; });
|
||||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fileNameForMime", function() { return fileNameForMime; });
|
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fileNameForMime", function() { return fileNameForMime; });
|
||||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "imageScaled", function() { return imageScaled; });
|
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "imageScaled", function() { return imageScaled; });
|
||||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "imageFileScaledToBase64", function() { return imageFileScaledToBase64; });
|
|
||||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "imageFileToBase64", function() { return imageFileToBase64; });
|
|
||||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fileToBase64", function() { return fileToBase64; });
|
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fileToBase64", function() { return fileToBase64; });
|
||||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "blobToBase64", function() { return blobToBase64; });
|
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "blobToBase64", function() { return blobToBase64; });
|
||||||
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "filePasted", function() { return filePasted; });
|
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "filePasted", function() { return filePasted; });
|
||||||
@@ -321,88 +319,6 @@ function imageScaled(file, maxWidth, maxHeight, maxSize, forceSquare, onSuccess,
|
|||||||
|
|
||||||
img.src = URL.createObjectURL(file);
|
img.src = URL.createObjectURL(file);
|
||||||
}
|
}
|
||||||
function imageFileScaledToBase64(file, width, height, forceSquare, onSuccess, onError) {
|
|
||||||
const img = new Image();
|
|
||||||
img.crossOrigin = 'Anonymous';
|
|
||||||
|
|
||||||
img.onerror = function (err) {
|
|
||||||
onError("Image format unrecognized");
|
|
||||||
};
|
|
||||||
|
|
||||||
img.onload = function () {
|
|
||||||
var dim = fitImageSize(this.width, this.height, width, height, forceSquare);
|
|
||||||
|
|
||||||
if (!dim) {
|
|
||||||
onError("Invalid image");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var canvas = document.createElement('canvas');
|
|
||||||
canvas.width = dim.dstWidth;
|
|
||||||
canvas.height = dim.dstHeight;
|
|
||||||
var ctx = canvas.getContext('2d');
|
|
||||||
ctx.imageSmoothingEnabled = true;
|
|
||||||
ctx.drawImage(this, dim.xoffset, dim.yoffset, dim.srcWidth, dim.srcHeight, 0, 0, dim.dstWidth, dim.dstHeight);
|
|
||||||
var mime = this.width != dim.dstWidth || this.height != dim.dstHeight || SUPPORTED_IMAGE_FORMATS.indexOf(file.type) < 0 ? 'image/jpeg' : file.type;
|
|
||||||
var imageBits = canvas.toDataURL(mime);
|
|
||||||
var parts = imageBits.split(',');
|
|
||||||
mime = getMimeType(parts[0]);
|
|
||||||
|
|
||||||
if (!mime) {
|
|
||||||
onError("Unsupported image format");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let quality = 0.78;
|
|
||||||
|
|
||||||
if (base64DecodedLen(imageBits.length) > _config_js__WEBPACK_IMPORTED_MODULE_0__["MAX_INBAND_ATTACHMENT_SIZE"]) {
|
|
||||||
mime = 'image/jpeg';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mime == 'image/jpeg') {
|
|
||||||
while (base64DecodedLen(imageBits.length) > _config_js__WEBPACK_IMPORTED_MODULE_0__["MAX_INBAND_ATTACHMENT_SIZE"] && quality > 0.45) {
|
|
||||||
imageBits = canvas.toDataURL(mime, quality);
|
|
||||||
quality *= 0.84;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (base64DecodedLen(imageBits.length) > _config_js__WEBPACK_IMPORTED_MODULE_0__["MAX_INBAND_ATTACHMENT_SIZE"]) {
|
|
||||||
onError("The image size " + Object(_strformat_js__WEBPACK_IMPORTED_MODULE_1__["bytesToHumanSize"])(base64DecodedLen(imageBits.length)) + " exceeds the " + Object(_strformat_js__WEBPACK_IMPORTED_MODULE_1__["bytesToHumanSize"])(_config_js__WEBPACK_IMPORTED_MODULE_0__["MAX_INBAND_ATTACHMENT_SIZE"]) + " limit.", "err");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas = null;
|
|
||||||
onSuccess(imageBits.split(',')[1], mime, dim.dstWidth, dim.dstHeight, fileNameForMime(file.name, mime));
|
|
||||||
};
|
|
||||||
|
|
||||||
img.src = URL.createObjectURL(file);
|
|
||||||
}
|
|
||||||
function imageFileToBase64(file, onSuccess, onError) {
|
|
||||||
var reader = new FileReader();
|
|
||||||
reader.addEventListener('load', function () {
|
|
||||||
var parts = reader.result.split(',');
|
|
||||||
var mime = getMimeType(parts[0]);
|
|
||||||
|
|
||||||
if (!mime) {
|
|
||||||
onError("Failed to process image file");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var img = new Image();
|
|
||||||
img.crossOrigin = 'Anonymous';
|
|
||||||
|
|
||||||
img.onload = function () {
|
|
||||||
onSuccess(parts[1], mime, this.width, this.height, fileNameForMime(file.name, mime));
|
|
||||||
};
|
|
||||||
|
|
||||||
img.onerror = function (err) {
|
|
||||||
onError("Image format not recognized");
|
|
||||||
};
|
|
||||||
|
|
||||||
img.src = URL.createObjectURL(file);
|
|
||||||
}, false);
|
|
||||||
reader.readAsDataURL(file);
|
|
||||||
}
|
|
||||||
function fileToBase64(file, onSuccess) {
|
function fileToBase64(file, onSuccess) {
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
reader.addEventListener('load', function () {
|
reader.addEventListener('load', function () {
|
||||||
@@ -811,7 +727,7 @@ function asEmail(val) {
|
|||||||
function isUrlRelative(url) {
|
function isUrlRelative(url) {
|
||||||
return !/^\s*([a-z][a-z0-9+.-]*:|\/\/)/im.test(url);
|
return !/^\s*([a-z][a-z0-9+.-]*:|\/\/)/im.test(url);
|
||||||
}
|
}
|
||||||
function sanitizeUrl(url, allowedSchemes) {
|
function sanitizeUrl(url) {
|
||||||
if (!url) {
|
if (!url) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -3481,7 +3397,10 @@ class MessagesView extends react__WEBPACK_IMPORTED_MODULE_0___default.a.Componen
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleClosePreview() {
|
handleClosePreview() {
|
||||||
|
if (this.state.imagePreview && this.state.imagePreview.url) {
|
||||||
URL.revokeObjectURL(this.state.imagePreview.url);
|
URL.revokeObjectURL(this.state.imagePreview.url);
|
||||||
|
}
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
imagePostview: null,
|
imagePostview: null,
|
||||||
imagePreview: null,
|
imagePreview: null,
|
||||||
@@ -6751,7 +6670,7 @@ function draftyFormatter(style, data, values, key) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (!uploading) {
|
if (!uploading) {
|
||||||
attr.src = Object(_lib_utils_js__WEBPACK_IMPORTED_MODULE_7__["sanitizeImageUrl"])(attr.src);
|
attr.src = this.props.tinode.authorizeURL(Object(_lib_utils_js__WEBPACK_IMPORTED_MODULE_7__["sanitizeImageUrl"])(attr.src));
|
||||||
|
|
||||||
if (attr.src) {
|
if (attr.src) {
|
||||||
attr.onClick = this.handleImagePreview;
|
attr.onClick = this.handleImagePreview;
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+58
-14
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user