mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-03-06 20:41:17 +01:00
feat: allow converting pasted images, closes #10352
This commit is contained in:
@@ -57,6 +57,7 @@
|
|||||||
"rejectImageWidth": 5000,
|
"rejectImageWidth": 5000,
|
||||||
"rejectImageHeight": 5000,
|
"rejectImageHeight": 5000,
|
||||||
"resizeImageQuality": 80,
|
"resizeImageQuality": 80,
|
||||||
|
"convertPastedImageTo": "image/jpeg",
|
||||||
"topicThumbSize": 512,
|
"topicThumbSize": 512,
|
||||||
"minimumTitleLength": 3,
|
"minimumTitleLength": 3,
|
||||||
"maximumTitleLength": 255,
|
"maximumTitleLength": 255,
|
||||||
|
|||||||
@@ -21,6 +21,11 @@
|
|||||||
"reject-image-width-help": "Images wider than this value will be rejected.",
|
"reject-image-width-help": "Images wider than this value will be rejected.",
|
||||||
"reject-image-height": "Maximum Image Height (in pixels)",
|
"reject-image-height": "Maximum Image Height (in pixels)",
|
||||||
"reject-image-height-help": "Images taller than this value will be rejected.",
|
"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",
|
"allow-topic-thumbnails": "Allow users to upload topic thumbnails",
|
||||||
"show-post-uploads-as-thumbnails": "Show post uploads as thumbnails",
|
"show-post-uploads-as-thumbnails": "Show post uploads as thumbnails",
|
||||||
"topic-thumb-size": "Topic Thumb Size",
|
"topic-thumb-size": "Topic Thumb Size",
|
||||||
|
|||||||
@@ -87,6 +87,8 @@ get:
|
|||||||
type: number
|
type: number
|
||||||
maximumFileSize:
|
maximumFileSize:
|
||||||
type: number
|
type: number
|
||||||
|
convertPastedImageTo:
|
||||||
|
type: string
|
||||||
theme:id:
|
theme:id:
|
||||||
type: string
|
type: string
|
||||||
theme:src:
|
theme:src:
|
||||||
|
|||||||
@@ -123,25 +123,43 @@ define('uploadHelpers', ['alerts'], function (alerts) {
|
|||||||
|
|
||||||
uploadHelpers.handlePaste = function (options) {
|
uploadHelpers.handlePaste = function (options) {
|
||||||
const container = options.container;
|
const container = options.container;
|
||||||
container.on('paste', function (event) {
|
container.on('paste', async function (event) {
|
||||||
const items = (event.clipboardData || event.originalEvent.clipboardData || {}).items;
|
const items = (event.clipboardData || event.originalEvent.clipboardData || {}).items;
|
||||||
const files = [];
|
const files = [];
|
||||||
const fileNames = [];
|
const fileNames = [];
|
||||||
let formData = null;
|
const formData = window.FormData ? new FormData() : null;
|
||||||
if (window.FormData) {
|
|
||||||
formData = new FormData();
|
function addFile(file, fileName) {
|
||||||
}
|
files.push(file);
|
||||||
[].forEach.call(items, function (item) {
|
fileNames.push(fileName);
|
||||||
const file = item.getAsFile();
|
if (formData) {
|
||||||
if (file) {
|
formData.append('files[]', file, fileName);
|
||||||
const fileName = utils.generateUUID() + '-' + file.name;
|
|
||||||
if (formData) {
|
|
||||||
formData.append('files[]', file, fileName);
|
|
||||||
}
|
|
||||||
files.push(file);
|
|
||||||
fileNames.push(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) {
|
if (files.length) {
|
||||||
options.callback({
|
options.callback({
|
||||||
@@ -217,5 +235,34 @@ define('uploadHelpers', ['alerts'], function (alerts) {
|
|||||||
options.uploadForm.submit();
|
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;
|
return uploadHelpers;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ apiController.loadConfig = async function (req) {
|
|||||||
topicsPerPage: meta.config.topicsPerPage || 20,
|
topicsPerPage: meta.config.topicsPerPage || 20,
|
||||||
postsPerPage: meta.config.postsPerPage || 20,
|
postsPerPage: meta.config.postsPerPage || 20,
|
||||||
maximumFileSize: meta.config.maximumFileSize,
|
maximumFileSize: meta.config.maximumFileSize,
|
||||||
|
convertPastedImageTo: meta.config.convertPastedImageTo,
|
||||||
'theme:id': meta.config['theme:id'],
|
'theme:id': meta.config['theme:id'],
|
||||||
'theme:src': meta.config['theme:src'],
|
'theme:src': meta.config['theme:src'],
|
||||||
defaultLang: meta.config.defaultLang || 'en-GB',
|
defaultLang: meta.config.defaultLang || 'en-GB',
|
||||||
|
|||||||
@@ -83,12 +83,22 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</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">
|
<div class="form-check form-switch mb-3">
|
||||||
<input class="form-check-input" type="checkbox" id="allowTopicsThumbnail" data-field="allowTopicsThumbnail">
|
<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>
|
<label for="allowTopicsThumbnail" class="form-check-label">[[admin/settings/uploads:allow-topic-thumbnails]]</label>
|
||||||
</div>
|
</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">
|
<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>
|
<label for="showPostUploadsAsThumbnails" class="form-check-label">[[admin/settings/uploads:show-post-uploads-as-thumbnails]]</label>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user