Fixed minor avatar cropping bug in avatars.js (#4192) * Fixed avatar cropping bug in avatars.js Persona icons/profile pictures were forced to a 2:3 ratio despite "Never resize avatars" being enabled. Moved a misplaced line of code inside the crop condition to fix this behavior. * Fix indentation for ESLint compliance **Attempted** to correct indentation on line 49 of avatars.js to pass ESLint check. * Update avatars.js Gave my best to fix it :( At the very least the issue is known now. * Update avatars.js Removed empty characters (formatting) * Fixed avatars.js Fixed the issue of avatar's not changing after my recent revision. * Update avatars.js Accidentally left a duplicate line; removed it now * Extract reusable function for avatar resize --------- Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>
Signed| @@ -3,12 +3,12 @@ import fs from 'node:fs'; | ||
| 3 | 3 | |
| 4 | 4 | import express from 'express'; |
| 5 | 5 | import sanitize from 'sanitize-filename'; |
| 6 | 6 | import { Jimp, JimpMime } from '../jimp.js'; |
| 7 | 7 | import { sync as writeFileAtomicSync } from 'write-file-atomic'; |
| 8 | 8 | |
| 9 | -import { AVATAR_WIDTH, AVATAR_HEIGHT } from '../constants.js'; | |
| 10 | 9 | import { getImages, tryParse } from '../util.js'; |
| 11 | 10 | import { getFileNameValidationFunction } from '../middleware/validateFileName.js'; |
| 11 | +import { applyAvatarCropResize } from './characters.js'; | |
| 12 | 12 | |
| 13 | 13 | export const router = express.Router(); |
| 14 | 14 | |
| @@ -42,13 +42,7 @@ router.post('/upload', getFileNameValidationFunction('overwrite_name'), async (r | ||
| 42 | 42 | const pathToUpload = path.join(request.file.destination, request.file.filename); |
| 43 | 43 | const crop = tryParse(request.query.crop); |
| 44 | 44 | const rawImg = await Jimp.read(pathToUpload); |
| 45 | - | |
| 45 | + const image = await applyAvatarCropResize(rawImg, crop); | |
| 46 | - if (typeof crop == 'object' && [crop.x, crop.y, crop.width, crop.height].every(x => typeof x === 'number')) { | |
| 47 | - rawImg.crop({ w: crop.width, h: crop.height, x: crop.x, y: crop.y }); | |
| 48 | - } | |
| 49 | - | |
| 50 | - rawImg.cover({ w: AVATAR_WIDTH, h: AVATAR_HEIGHT }); | |
| 51 | - const image = await rawImg.getBuffer(JimpMime.png); | |
| 52 | 46 | |
| 53 | 47 | const filename = request.body.overwrite_name || `${Date.now()}.png`; |
| 54 | 48 | const pathToNewFile = path.join(request.user.directories.avatars, filename); |
| @@ -270,13 +270,14 @@ async function writeCharacterData(inputFile, data, outputFile, request, crop = u | ||
| 270 | 270 | */ |
| 271 | 271 | |
| 272 | 272 | /** |
| 273 | 273 | * Parses anApplies imageavatar buffercrop and appliesresize cropoperations ifto definedan image. |
| 274 | - * @param {Buffer} buffer Buffer of the image | |
| 274 | + * I couldn't fix the type issue, so the first argument has {any} type. | |
| 275 | + * @param {object} jimp Jimp image instance | |
| 275 | 276 | * @param {Crop|undefined} [crop] Crop parameters |
| 276 | 277 | * @returns {Promise<Buffer>} ImageProcessed image buffer |
| 277 | 278 | */ |
| 278 | 279 | export async function parseImageBufferapplyAvatarCropResize(bufferjimp, crop) { |
| 279 | - const image = await Jimp.fromBuffer(buffer); | |
| 280 | + const image = /** @type {InstanceType<typeof import('../jimp.js').Jimp>} */ (jimp); | |
| 280 | 281 | let finalWidth = image.bitmap.width, finalHeight = image.bitmap.height; |
| 281 | 282 | |
| 282 | 283 | // Apply crop if defined |
| @@ -297,6 +298,17 @@ async function parseImageBuffer(buffer, crop) { | ||
| 297 | 298 | } |
| 298 | 299 | |
| 299 | 300 | /** |
| 301 | + * Parses an image buffer and applies crop if defined. | |
| 302 | + * @param {Buffer} buffer Buffer of the image | |
| 303 | + * @param {Crop|undefined} [crop] Crop parameters | |
| 304 | + * @returns {Promise<Buffer>} Image buffer | |
| 305 | + */ | |
| 306 | +async function parseImageBuffer(buffer, crop) { | |
| 307 | + const image = await Jimp.fromBuffer(buffer); | |
| 308 | + return await applyAvatarCropResize(image, crop); | |
| 309 | +} | |
| 310 | + | |
| 311 | +/** | |
| 300 | 312 | * Reads an image file and applies crop if defined. |
| 301 | 313 | * @param {string} imgPath Path to the image file |
| 302 | 314 | * @param {Crop|undefined} crop Crop parameters |
| @@ -305,23 +317,7 @@ async function parseImageBuffer(buffer, crop) { | ||
| 305 | 317 | async function tryReadImage(imgPath, crop) { |
| 306 | 318 | try { |
| 307 | 319 | const rawImg = await Jimp.read(imgPath); |
| 308 | - let finalWidth = rawImg.bitmap.width, finalHeight = rawImg.bitmap.height; | |
| 320 | + return await applyAvatarCropResize(rawImg, crop); | |
| 309 | - | |
| 310 | - // Apply crop if defined | |
| 311 | - if (typeof crop == 'object' && [crop.x, crop.y, crop.width, crop.height].every(x => typeof x === 'number')) { | |
| 312 | - rawImg.crop({ x: crop.x, y: crop.y, w: crop.width, h: crop.height }); | |
| 313 | - // Apply standard resize if requested | |
| 314 | - if (crop.want_resize) { | |
| 315 | - finalWidth = AVATAR_WIDTH; | |
| 316 | - finalHeight = AVATAR_HEIGHT; | |
| 317 | - } else { | |
| 318 | - finalWidth = crop.width; | |
| 319 | - finalHeight = crop.height; | |
| 320 | - } | |
| 321 | - } | |
| 322 | - | |
| 323 | - rawImg.cover({ w: finalWidth, h: finalHeight }); | |
| 324 | - return await rawImg.getBuffer(JimpMime.png); | |
| 325 | 321 | } |
| 326 | 322 | // If it's an unsupported type of image (APNG) - just read the file as buffer |
| 327 | 323 | catch (error) { |