Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enhance: AVIF support #9281

Merged
merged 12 commits into from
Dec 8, 2022
1 change: 1 addition & 0 deletions packages/backend/src/const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export const FILE_TYPE_BROWSERSAFE = [
'image/gif',
'image/jpeg',
'image/webp',
'image/avif',
'image/apng',
'image/bmp',
'image/tiff',
Expand Down
9 changes: 5 additions & 4 deletions packages/backend/src/core/DriveService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ export class DriveService {
if (type === 'image/jpeg') ext = '.jpg';
if (type === 'image/png') ext = '.png';
if (type === 'image/webp') ext = '.webp';
if (type === 'image/avif') ext = '.avif';
if (type === 'image/apng') ext = '.apng';
if (type === 'image/vnd.mozilla.apng') ext = '.apng';
}
Expand Down Expand Up @@ -262,7 +263,7 @@ export class DriveService {
}
}

if (!['image/jpeg', 'image/png', 'image/webp', 'image/svg+xml'].includes(type)) {
if (!['image/jpeg', 'image/png', 'image/webp', 'image/avif', 'image/svg+xml'].includes(type)) {
this.registerLogger.debug('web image and thumbnail not created (not an required file)');
return {
webpublic: null,
Expand All @@ -287,7 +288,7 @@ export class DriveService {
}

satisfyWebpublic = !!(
type !== 'image/svg+xml' && type !== 'image/webp' &&
type !== 'image/svg+xml' && type !== 'image/webp' && type !== 'image/avif' &&
!(metadata.exif ?? metadata.iptc ?? metadata.xmp ?? metadata.tifftagPhotoshop) &&
metadata.width && metadata.width <= 2048 &&
metadata.height && metadata.height <= 2048
Expand All @@ -307,7 +308,7 @@ export class DriveService {
this.registerLogger.info('creating web image');

try {
if (['image/jpeg', 'image/webp'].includes(type)) {
if (['image/jpeg', 'image/webp', 'image/avif'].includes(type)) {
webpublic = await this.imageProcessingService.convertSharpToJpeg(img, 2048, 2048);
} else if (['image/png'].includes(type)) {
webpublic = await this.imageProcessingService.convertSharpToPng(img, 2048, 2048);
Expand All @@ -329,7 +330,7 @@ export class DriveService {
let thumbnail: IImage | null = null;

try {
if (['image/jpeg', 'image/webp', 'image/png', 'image/svg+xml'].includes(type)) {
if (['image/jpeg', 'image/webp', 'image/avif', 'image/png', 'image/svg+xml'].includes(type)) {
thumbnail = await this.imageProcessingService.convertSharpToWebp(img, 498, 280);
} else {
this.registerLogger.debug('thumbnail not created (not an required file)');
Expand Down
29 changes: 26 additions & 3 deletions packages/backend/src/core/FileInfoService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,18 @@ export class FileInfoService {
let height: number | undefined;
let orientation: number | undefined;

if (['image/jpeg', 'image/gif', 'image/png', 'image/apng', 'image/webp', 'image/bmp', 'image/tiff', 'image/svg+xml', 'image/vnd.adobe.photoshop'].includes(type.mime)) {
if ([
'image/png',
'image/gif',
'image/jpeg',
'image/webp',
'image/avif',
'image/apng',
'image/bmp',
'image/tiff',
'image/svg+xml',
'image/vnd.adobe.photoshop',
].includes(type.mime)) {
const imageSize = await this.detectImageSize(path).catch(e => {
warnings.push(`detectImageSize failed: ${e}`);
return undefined;
Expand All @@ -100,7 +111,15 @@ export class FileInfoService {

let blurhash: string | undefined;

if (['image/jpeg', 'image/gif', 'image/png', 'image/apng', 'image/webp', 'image/svg+xml'].includes(type.mime)) {
if ([
'image/jpeg',
'image/gif',
'image/png',
'image/apng',
'image/webp',
'image/avif',
'image/svg+xml',
].includes(type.mime)) {
blurhash = await this.getBlurhash(path).catch(e => {
warnings.push(`getBlurhash failed: ${e}`);
return undefined;
Expand Down Expand Up @@ -156,7 +175,11 @@ export class FileInfoService {
return [sensitive, porn];
}

if (['image/jpeg', 'image/png', 'image/webp'].includes(mime)) {
if ([
'image/jpeg',
'image/png',
'image/webp',
].includes(mime)) {
const result = await this.aiService.detectSensitive(source);
if (result) {
[sensitive, porn] = judgePrediction(result);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export class DriveFileEntityService {
}
}

const isImage = file.type && ['image/png', 'image/apng', 'image/gif', 'image/jpeg', 'image/webp', 'image/svg+xml'].includes(file.type);
const isImage = file.type && ['image/png', 'image/apng', 'image/gif', 'image/jpeg', 'image/webp', 'image/avif', 'image/svg+xml'].includes(file.type);

return thumbnail ? (file.thumbnailUrl ?? (isImage ? (file.webpublicUrl ?? file.url) : null)) : (file.webpublicUrl ?? file.url);
}
Expand Down
2 changes: 1 addition & 1 deletion packages/backend/src/misc/is-mime-image.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { FILE_TYPE_BROWSERSAFE } from '@/const.js';

const dictionary = {
'safe-file': FILE_TYPE_BROWSERSAFE,
'sharp-convertible-image': ['image/jpeg', 'image/png', 'image/gif', 'image/apng', 'image/vnd.mozilla.apng', 'image/webp', 'image/svg+xml'],
'sharp-convertible-image': ['image/jpeg', 'image/png', 'image/gif', 'image/apng', 'image/vnd.mozilla.apng', 'image/webp', 'image/avif', 'image/svg+xml'],
};

export const isMimeImage = (mime: string, type: keyof typeof dictionary): boolean => dictionary[type].includes(mime);
2 changes: 1 addition & 1 deletion packages/backend/src/server/FileServerService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export class FileServerService {

const convertFile = async () => {
if (isThumbnail) {
if (['image/jpeg', 'image/webp', 'image/png', 'image/svg+xml'].includes(mime)) {
if (['image/jpeg', 'image/webp', 'image/avif', 'image/png', 'image/svg+xml'].includes(mime)) {
return await this.imageProcessingService.convertToWebp(path, 498, 280);
} else if (mime.startsWith('video/')) {
return await this.videoProcessingService.generateVideoThumbnail(path);
Expand Down
1 change: 1 addition & 0 deletions packages/client/src/const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export const FILE_TYPE_BROWSERSAFE = [
'image/gif',
'image/jpeg',
'image/webp',
'image/avif',
'image/apng',
'image/bmp',
'image/tiff',
Expand Down
2 changes: 2 additions & 0 deletions packages/client/src/pages/user/index.photos.vue
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ function thumbnail(image: misskey.entities.DriveFile): string {
onMounted(() => {
const image = [
'image/jpeg',
'image/webp',
'image/avif',
'image/png',
'image/gif',
'image/apng',
Expand Down