mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-03-03 11:01:20 +01:00
feat: allow converting pasted images, closes #10352
This commit is contained in:
@@ -57,6 +57,7 @@
|
||||
"rejectImageWidth": 5000,
|
||||
"rejectImageHeight": 5000,
|
||||
"resizeImageQuality": 80,
|
||||
"convertPastedImageTo": "image/jpeg",
|
||||
"topicThumbSize": 512,
|
||||
"minimumTitleLength": 3,
|
||||
"maximumTitleLength": 255,
|
||||
|
||||
@@ -21,6 +21,11 @@
|
||||
"reject-image-width-help": "Images wider than this value will be rejected.",
|
||||
"reject-image-height": "Maximum Image Height (in pixels)",
|
||||
"reject-image-height-help": "Images taller than this value will be rejected.",
|
||||
"convert-pasted-images-to": "Convert pasted images to:",
|
||||
"convert-pasted-images-to-default": "No Conversion (Keep Original Format)",
|
||||
"convert-pasted-images-to-png": "PNG",
|
||||
"convert-pasted-images-to-jpeg": "JPEG",
|
||||
"convert-pasted-images-to-webp": "WebP",
|
||||
"allow-topic-thumbnails": "Allow users to upload topic thumbnails",
|
||||
"show-post-uploads-as-thumbnails": "Show post uploads as thumbnails",
|
||||
"topic-thumb-size": "Topic Thumb Size",
|
||||
|
||||
@@ -87,6 +87,8 @@ get:
|
||||
type: number
|
||||
maximumFileSize:
|
||||
type: number
|
||||
convertPastedImageTo:
|
||||
type: string
|
||||
theme:id:
|
||||
type: string
|
||||
theme:src:
|
||||
|
||||
@@ -123,25 +123,43 @@ define('uploadHelpers', ['alerts'], function (alerts) {
|
||||
|
||||
uploadHelpers.handlePaste = function (options) {
|
||||
const container = options.container;
|
||||
container.on('paste', function (event) {
|
||||
container.on('paste', async function (event) {
|
||||
const items = (event.clipboardData || event.originalEvent.clipboardData || {}).items;
|
||||
const files = [];
|
||||
const fileNames = [];
|
||||
let formData = null;
|
||||
if (window.FormData) {
|
||||
formData = new FormData();
|
||||
}
|
||||
[].forEach.call(items, function (item) {
|
||||
const file = item.getAsFile();
|
||||
if (file) {
|
||||
const fileName = utils.generateUUID() + '-' + file.name;
|
||||
if (formData) {
|
||||
formData.append('files[]', file, fileName);
|
||||
}
|
||||
files.push(file);
|
||||
fileNames.push(fileName);
|
||||
const formData = window.FormData ? new FormData() : null;
|
||||
|
||||
function addFile(file, fileName) {
|
||||
files.push(file);
|
||||
fileNames.push(fileName);
|
||||
if (formData) {
|
||||
formData.append('files[]', file, fileName);
|
||||
}
|
||||
});
|
||||
}
|
||||
const { convertPastedImageTo } = config;
|
||||
for (const item of items) {
|
||||
const file = item.getAsFile();
|
||||
if (!file) continue;
|
||||
try {
|
||||
if (convertPastedImageTo && file.type.match(/image./) && file.type !== convertPastedImageTo) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const convertedBlob = await convertImage(file, convertPastedImageTo, 0.9);
|
||||
const ext = convertedBlob.type.split('/')[1];
|
||||
const fileName = `${utils.generateUUID()}-image.${ext}`;
|
||||
|
||||
const convertedFile = new File([convertedBlob], fileName, {
|
||||
type: convertedBlob.type,
|
||||
});
|
||||
addFile(convertedFile, fileName);
|
||||
} else {
|
||||
const fileName = utils.generateUUID() + '-' + file.name;
|
||||
addFile(file, fileName);
|
||||
}
|
||||
} catch (err) {
|
||||
alerts.error(err);
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
if (files.length) {
|
||||
options.callback({
|
||||
@@ -217,5 +235,34 @@ define('uploadHelpers', ['alerts'], function (alerts) {
|
||||
options.uploadForm.submit();
|
||||
};
|
||||
|
||||
function convertImage(file, mime, quality = 0.9) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const img = new Image();
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onload = e => {
|
||||
img.onload = () => {
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = img.width;
|
||||
canvas.height = img.height;
|
||||
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.drawImage(img, 0, 0);
|
||||
|
||||
canvas.toBlob(blob => {
|
||||
if (!blob) return reject(new Error('Conversion failed'));
|
||||
resolve(blob);
|
||||
}, mime, quality);
|
||||
};
|
||||
|
||||
img.onerror = reject;
|
||||
img.src = e.target.result;
|
||||
};
|
||||
|
||||
reader.onerror = reject;
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
}
|
||||
|
||||
return uploadHelpers;
|
||||
});
|
||||
|
||||
@@ -64,6 +64,7 @@ apiController.loadConfig = async function (req) {
|
||||
topicsPerPage: meta.config.topicsPerPage || 20,
|
||||
postsPerPage: meta.config.postsPerPage || 20,
|
||||
maximumFileSize: meta.config.maximumFileSize,
|
||||
convertPastedImageTo: meta.config.convertPastedImageTo,
|
||||
'theme:id': meta.config['theme:id'],
|
||||
'theme:src': meta.config['theme:src'],
|
||||
defaultLang: meta.config.defaultLang || 'en-GB',
|
||||
|
||||
@@ -83,12 +83,22 @@
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="convertPastedImageTo">[[admin/settings/uploads:convert-pasted-images-to]]</label>
|
||||
<select id="convertPastedImageTo" class="form-select" data-field="convertPastedImageTo">
|
||||
<option value="">[[admin/settings/uploads:convert-pasted-images-to-default]]</option>
|
||||
<option value="image/png">[[admin/settings/uploads:convert-pasted-images-to-png]]</option>
|
||||
<option value="image/jpeg">[[admin/settings/uploads:convert-pasted-images-to-jpeg]]</option>
|
||||
<option value="image/webp">[[admin/settings/uploads:convert-pasted-images-to-webp]]</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-check form-switch mb-3">
|
||||
<input class="form-check-input" type="checkbox" id="allowTopicsThumbnail" data-field="allowTopicsThumbnail">
|
||||
<label for="allowTopicsThumbnail" class="form-check-label">[[admin/settings/uploads:allow-topic-thumbnails]]</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check form-switch mb-3">
|
||||
<div class="form-check form-switch mb-3">
|
||||
<input class="form-check-input" type="checkbox" id="showPostUploadsAsThumbnails" data-field="showPostUploadsAsThumbnails">
|
||||
<label for="showPostUploadsAsThumbnails" class="form-check-label">[[admin/settings/uploads:show-post-uploads-as-thumbnails]]</label>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user