wip: adding out of band image sending
This commit is contained in:
+50
-2
@@ -66,10 +66,58 @@ export function fileNameForMime(fname, mime) {
|
|||||||
return fname + '.' + ext;
|
return fname + '.' + ext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Scale uploaded image to fit under certain dimensions or byte size, optionally constraining to a square.
|
||||||
|
export function imageFileScaled(file, maxWidth, maxHeight, maxSize, forceSquare, onSuccess, onError) {
|
||||||
|
const img = new Image();
|
||||||
|
img.crossOrigin = 'Anonymous';
|
||||||
|
img.onerror = function(err) {
|
||||||
|
onError("Image format unrecognized");
|
||||||
|
}
|
||||||
|
img.onload = function() {
|
||||||
|
// Once the image is loaded, the URL is no longer needed.
|
||||||
|
URL.revokeObjectURL(img.src);
|
||||||
|
|
||||||
|
// Calculate the desired image dimensions.
|
||||||
|
const dim = fitImageSize(this.width, this.height, maxWidth, maxHeight, forceSquare);
|
||||||
|
if (!dim) {
|
||||||
|
onError("Invalid image");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let canvas = document.createElement('canvas');
|
||||||
|
canvas.width = dim.dstWidth;
|
||||||
|
canvas.height = dim.dstHeight;
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
ctx.imageSmoothingEnabled = true;
|
||||||
|
ctx.drawImage(this, dim.xoffset, dim.yoffset, dim.srcWidth, dim.srcHeight,
|
||||||
|
0, 0, dim.dstWidth, dim.dstHeight);
|
||||||
|
|
||||||
|
let mime = SUPPORTED_IMAGE_FORMATS.indexOf(file.type) < 0 ? 'image/jpeg' : file.type;
|
||||||
|
let imageBits = canvas.toDataURL(mime);
|
||||||
|
const 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. Shrink the image keeping the aspect ratio.
|
||||||
|
while (base64DecodedLen(imageBits.length) > maxSize && quality > 0.45) {
|
||||||
|
imageBits = canvas.toDataURL(mime, quality);
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas.toBlob((blob) => {
|
||||||
|
onSuccess(blob, mime, dim.dstWidth, dim.dstHeight, fileNameForMime(file.name, mime));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
canvas = null;
|
||||||
|
};
|
||||||
|
img.src = URL.createObjectURL(file);
|
||||||
|
}
|
||||||
|
|
||||||
// Convert uploaded image into a base64-encoded string possibly scaling
|
// Convert uploaded image into a base64-encoded string possibly scaling
|
||||||
// linear dimensions or constraining to a square.
|
// linear dimensions or constraining to a square.
|
||||||
export function imageFileScaledToBase64(file, width, height, forceSquare, onSuccess, onError) {
|
export function imageFileScaledToBase64(file, width, height, forceSquare, onSuccess, onError) {
|
||||||
var img = new Image();
|
const img = new Image();
|
||||||
img.crossOrigin = 'Anonymous';
|
img.crossOrigin = 'Anonymous';
|
||||||
img.onerror = function(err) {
|
img.onerror = function(err) {
|
||||||
onError("Image format unrecognized");
|
onError("Image format unrecognized");
|
||||||
@@ -100,7 +148,7 @@ export function imageFileScaledToBase64(file, width, height, forceSquare, onSucc
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Ensure the image is not too large
|
// Ensure the image is not too large
|
||||||
var quality = 0.78;
|
let quality = 0.78;
|
||||||
if (base64DecodedLen(imageBits.length) > MAX_INBAND_ATTACHMENT_SIZE) {
|
if (base64DecodedLen(imageBits.length) > MAX_INBAND_ATTACHMENT_SIZE) {
|
||||||
mime = 'image/jpeg';
|
mime = 'image/jpeg';
|
||||||
}
|
}
|
||||||
|
|||||||
+32
-11
@@ -624,6 +624,9 @@ class MessagesView extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Send attachment as Drafty message:
|
||||||
|
// - if file is too large, upload it and send a s link.
|
||||||
|
// - if file is small enough, just send it in-band.
|
||||||
sendFileAttachment(file) {
|
sendFileAttachment(file) {
|
||||||
if (file.size > MAX_INBAND_ATTACHMENT_SIZE) {
|
if (file.size > MAX_INBAND_ATTACHMENT_SIZE) {
|
||||||
// Too large to send inband - uploading out of band and sending as a link.
|
// Too large to send inband - uploading out of band and sending as a link.
|
||||||
@@ -647,6 +650,7 @@ class MessagesView extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handleAttachFile method is called when [Attach file] button is clicked.
|
||||||
handleAttachFile(file) {
|
handleAttachFile(file) {
|
||||||
if (file.size > MAX_EXTERN_ATTACHMENT_SIZE) {
|
if (file.size > MAX_EXTERN_ATTACHMENT_SIZE) {
|
||||||
// Too large.
|
// Too large.
|
||||||
@@ -662,16 +666,9 @@ class MessagesView extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sendImageAttachment(caption, mime, bits, width, height, fname) {
|
// sendImageAttachment sends the image bits inband as Drafty message.
|
||||||
let msg = Drafty.insertImage(null, 0, mime, bits, width, height, fname);
|
sendImageAttachment(objectUrl, caption, mime, width, height, fname) {
|
||||||
if (caption) {
|
// Upload or scale the image.
|
||||||
msg = Drafty.appendLineBreak(msg);
|
|
||||||
msg = Drafty.append(msg, Drafty.init(caption));
|
|
||||||
}
|
|
||||||
this.props.sendMessage(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleAttachImage(file) {
|
|
||||||
// Check if the uploaded file is indeed an image and if it isn't too large.
|
// Check if the uploaded file is indeed an image and if it isn't too large.
|
||||||
if (file.size > MAX_INBAND_ATTACHMENT_SIZE || SUPPORTED_IMAGE_FORMATS.indexOf(file.type) < 0) {
|
if (file.size > MAX_INBAND_ATTACHMENT_SIZE || SUPPORTED_IMAGE_FORMATS.indexOf(file.type) < 0) {
|
||||||
// Convert image for size or format.
|
// Convert image for size or format.
|
||||||
@@ -680,7 +677,6 @@ class MessagesView extends React.Component {
|
|||||||
(bits, mime, width, height, fname) => {
|
(bits, mime, width, height, fname) => {
|
||||||
this.setState({imagePreview: {
|
this.setState({imagePreview: {
|
||||||
url: URL.createObjectURL(file),
|
url: URL.createObjectURL(file),
|
||||||
bits: bits,
|
|
||||||
filename: fname,
|
filename: fname,
|
||||||
width: width,
|
width: width,
|
||||||
height: height,
|
height: height,
|
||||||
@@ -713,6 +709,31 @@ class MessagesView extends React.Component {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let msg = Drafty.insertImage(null, 0, mime, bits, width, height, fname);
|
||||||
|
if (caption) {
|
||||||
|
msg = Drafty.appendLineBreak(msg);
|
||||||
|
msg = Drafty.append(msg, Drafty.init(caption));
|
||||||
|
}
|
||||||
|
this.props.sendMessage(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleAttachImage method is called when [Attach image] button is clicked.
|
||||||
|
handleAttachImage(file) {
|
||||||
|
let size = file.size;
|
||||||
|
// If image is too big scale it down before previewing.
|
||||||
|
if (size > MAX_EXTERN_ATTACHMENT_SIZE) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Launch image preview screen.
|
||||||
|
this.setState({imagePreview: {
|
||||||
|
url: URL.createObjectURL(file),
|
||||||
|
filename: fname,
|
||||||
|
width: width, // FIXME: width is not defined.
|
||||||
|
height: height, // FIXME: height is not defined.
|
||||||
|
size: size,
|
||||||
|
type: mime // FIXME: mime type is not defined.
|
||||||
|
}});
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export default class ImagePreview extends React.PureComponent {
|
|||||||
|
|
||||||
handleSendImage(caption) {
|
handleSendImage(caption) {
|
||||||
this.props.onClose();
|
this.props.onClose();
|
||||||
this.props.onSendMessage(caption, this.props.content.type, this.props.content.bits,
|
this.props.onSendMessage(caption, this.props.content.type,
|
||||||
this.props.content.width, this.props.content.height, this.props.content.filename);
|
this.props.content.width, this.props.content.height, this.props.content.filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@ export default class ImagePreview extends React.PureComponent {
|
|||||||
size.maxHeight = '100%';
|
size.maxHeight = '100%';
|
||||||
|
|
||||||
let filename = this.props.content.filename;
|
let filename = this.props.content.filename;
|
||||||
// Averate font aspect ratio is ~0.5; File name takes 1/3 of the viewport width.
|
// Average font aspect ratio is ~0.5; File name takes 1/3 of the viewport width.
|
||||||
const maxlength = Math.max(((this.state.width / REM_SIZE / 1.5) | 0) - 2, 12);
|
const maxlength = Math.max(((this.state.width / REM_SIZE / 1.5) | 0) - 2, 12);
|
||||||
if (filename.length > maxlength) {
|
if (filename.length > maxlength) {
|
||||||
filename = filename.slice(0, maxlength/2 - 1) + '…' + filename.slice(1 - maxlength/2);
|
filename = filename.slice(0, maxlength/2 - 1) + '…' + filename.slice(1 - maxlength/2);
|
||||||
|
|||||||
Reference in New Issue
Block a user