Option to send photos as high quality

This commit is contained in:
Josh Perez 2021-06-25 12:08:16 -04:00 committed by GitHub
parent 6c56d5a5f1
commit 01eabf9ec6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
44 changed files with 1263 additions and 363 deletions

View file

@ -1,43 +0,0 @@
// Copyright 2018-2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
const loadImage = require('blueimp-load-image');
const DEFAULT_JPEG_QUALITY = 0.85;
// File | Blob | URLString -> LoadImageOptions -> Promise<DataURLString>
//
// Documentation for `options` (`LoadImageOptions`):
// https://github.com/blueimp/JavaScript-Load-Image/tree/v2.18.0#options
exports.autoOrientImage = (fileOrBlobOrURL, options = {}) => {
const optionsWithDefaults = {
type: 'image/jpeg',
quality: DEFAULT_JPEG_QUALITY,
...options,
canvas: true,
orientation: true,
};
return new Promise((resolve, reject) => {
loadImage(
fileOrBlobOrURL,
canvasOrError => {
if (canvasOrError.type === 'error') {
const error = new Error('autoOrientImage: Failed to process image');
error.originalError = canvasOrError;
reject(error);
return;
}
const canvas = canvasOrError;
const dataURL = canvas.toDataURL(
optionsWithDefaults.type,
optionsWithDefaults.quality
);
resolve(dataURL);
},
optionsWithDefaults
);
});
};

View file

@ -3,16 +3,12 @@
const is = require('@sindresorhus/is');
const {
arrayBufferToBlob,
blobToArrayBuffer,
dataURLToBlob,
} = require('blob-util');
const { arrayBufferToBlob, blobToArrayBuffer } = require('blob-util');
const AttachmentTS = require('../../../ts/types/Attachment');
const GoogleChrome = require('../../../ts/util/GoogleChrome');
const MIME = require('../../../ts/types/MIME');
const { toLogFormat } = require('./errors');
const { autoOrientImage } = require('../auto_orient_image');
const { scaleImageToLevel } = require('../../../ts/util/scaleImageToLevel');
const {
migrateDataToFileSystem,
} = require('./attachment/migrate_data_to_file_system');
@ -54,7 +50,7 @@ exports.isValid = rawAttachment => {
// Upgrade steps
// NOTE: This step strips all EXIF metadata from JPEG images as
// part of re-encoding the image:
exports.autoOrientJPEG = async attachment => {
exports.autoOrientJPEG = async (attachment, _, message) => {
if (!MIME.isJPEG(attachment.contentType)) {
return attachment;
}
@ -68,24 +64,27 @@ exports.autoOrientJPEG = async attachment => {
attachment.data,
attachment.contentType
);
const newDataBlob = await dataURLToBlob(await autoOrientImage(dataBlob));
const newDataArrayBuffer = await blobToArrayBuffer(newDataBlob);
const xcodedDataBlob = await scaleImageToLevel(
dataBlob,
message.sendHQImages
);
const xcodedDataArrayBuffer = await blobToArrayBuffer(xcodedDataBlob);
// IMPORTANT: We overwrite the existing `data` `ArrayBuffer` losing the original
// image data. Ideally, wed preserve the original image data for users who want to
// retain it but due to reports of data loss, we dont want to overburden IndexedDB
// by potentially doubling stored image data.
// See: https://github.com/signalapp/Signal-Desktop/issues/1589
const newAttachment = {
const xcodedAttachment = {
...attachment,
data: newDataArrayBuffer,
size: newDataArrayBuffer.byteLength,
data: xcodedDataArrayBuffer,
size: xcodedDataArrayBuffer.byteLength,
};
// `digest` is no longer valid for auto-oriented image data, so we discard it:
delete newAttachment.digest;
delete xcodedAttachment.digest;
return newAttachment;
return xcodedAttachment;
};
const UNICODE_LEFT_TO_RIGHT_OVERRIDE = '\u202D';

View file

@ -170,7 +170,7 @@ exports._withSchemaVersion = ({ schemaVersion, upgrade }) => {
// Promise Message
exports._mapAttachments = upgradeAttachment => async (message, context) => {
const upgradeWithContext = attachment =>
upgradeAttachment(attachment, context);
upgradeAttachment(attachment, context, message);
const attachments = await Promise.all(
(message.attachments || []).map(upgradeWithContext)
);

View file

@ -1,15 +1,15 @@
// Copyright 2018-2020 Signal Messenger, LLC
// Copyright 2018-2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
/* global document, URL, Blob */
const loadImage = require('blueimp-load-image');
const dataURLToBlobSync = require('blueimp-canvas-to-blob');
const { blobToArrayBuffer } = require('blob-util');
const { toLogFormat } = require('./errors');
const {
arrayBufferToObjectURL,
} = require('../../../ts/util/arrayBufferToObjectURL');
const { canvasToBlob } = require('../../../ts/util/canvasToBlob');
exports.blobToArrayBuffer = blobToArrayBuffer;
@ -40,7 +40,7 @@ exports.makeImageThumbnail = ({
new Promise((resolve, reject) => {
const image = document.createElement('img');
image.addEventListener('load', () => {
image.addEventListener('load', async () => {
// using components/blueimp-load-image
// first, make the correct size
@ -63,9 +63,12 @@ exports.makeImageThumbnail = ({
minHeight: size,
});
const blob = dataURLToBlobSync(canvas.toDataURL(contentType));
resolve(blob);
try {
const blob = await canvasToBlob(canvas, contentType);
resolve(blob);
} catch (err) {
reject(err);
}
});
image.addEventListener('error', error => {
@ -88,7 +91,7 @@ exports.makeVideoScreenshot = ({
video.currentTime = 1.0;
}
function capture() {
async function capture() {
const canvas = document.createElement('canvas');
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
@ -96,12 +99,15 @@ exports.makeVideoScreenshot = ({
.getContext('2d')
.drawImage(video, 0, 0, canvas.width, canvas.height);
const image = dataURLToBlobSync(canvas.toDataURL(contentType));
video.addEventListener('loadeddata', seek);
video.removeEventListener('seeked', capture);
resolve(image);
try {
const image = canvasToBlob(canvas, contentType);
resolve(image);
} catch (err) {
reject(err);
}
}
video.addEventListener('loadeddata', seek);