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

feat: resize oversize images before sending #235

Merged
merged 15 commits into from
Aug 5, 2024
7 changes: 7 additions & 0 deletions docs/de-DE/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@

设置输出的图片尺寸。

### autoResize

- 类型: `boolean`
- 默认值: `false`

根据preferSize自动缩小过大的图片(需要canvas服务(比如[puppeteer](https://puppeteer.koishi.chat/)、[skia-canvas](https://github.com/Kokoro-js/koishi-plugin-skia-canvas)),且需开启assets或者base64)。

### asset

- 类型: `boolean`
Expand Down
7 changes: 7 additions & 0 deletions docs/en-US/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@

设置输出的图片尺寸。

### autoResize

- 类型: `boolean`
- 默认值: `false`

根据preferSize自动缩小过大的图片(需要canvas服务(比如[puppeteer](https://puppeteer.koishi.chat/)、[skia-canvas](https://github.com/Kokoro-js/koishi-plugin-skia-canvas)),且需开启assets或者base64)。

### asset

- 类型: `boolean`
Expand Down
7 changes: 7 additions & 0 deletions docs/fr-FR/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@

设置输出的图片尺寸。

### autoResize

- 类型: `boolean`
- 默认值: `false`

根据preferSize自动缩小过大的图片(需要canvas服务(比如[puppeteer](https://puppeteer.koishi.chat/)、[skia-canvas](https://github.com/Kokoro-js/koishi-plugin-skia-canvas)),且需开启assets或者base64)。

### asset

- 类型: `boolean`
Expand Down
7 changes: 7 additions & 0 deletions docs/ja-JP/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@

设置输出的图片尺寸。

### autoResize

- 类型: `boolean`
- 默认值: `false`

根据preferSize自动缩小过大的图片(需要canvas服务(比如[puppeteer](https://puppeteer.koishi.chat/)、[skia-canvas](https://github.com/Kokoro-js/koishi-plugin-skia-canvas)),且需开启assets或者base64)。

### asset

- 类型: `boolean`
Expand Down
7 changes: 7 additions & 0 deletions docs/ru-RU/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@

设置输出的图片尺寸。

### autoResize

- 类型: `boolean`
- 默认值: `false`

根据preferSize自动缩小过大的图片(需要canvas服务(比如[puppeteer](https://puppeteer.koishi.chat/)、[skia-canvas](https://github.com/Kokoro-js/koishi-plugin-skia-canvas)),且需开启assets或者base64)。

### asset

- 类型: `boolean`
Expand Down
7 changes: 7 additions & 0 deletions docs/zh-CN/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@

设置输出的图片尺寸。

### autoResize

- 类型: `boolean`
- 默认值: `false`

根据preferSize自动缩小过大的图片(需要canvas服务(比如[puppeteer](https://puppeteer.koishi.chat/)、[skia-canvas](https://github.com/Kokoro-js/koishi-plugin-skia-canvas)),且需开启assets或者base64)。

### asset

- 类型: `boolean`
Expand Down
7 changes: 7 additions & 0 deletions docs/zh-TW/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@

设置输出的图片尺寸。

### autoResize

- 类型: `boolean`
- 默认值: `false`

根据preferSize自动缩小过大的图片(需要canvas服务(比如[puppeteer](https://puppeteer.koishi.chat/)、[skia-canvas](https://github.com/Kokoro-js/koishi-plugin-skia-canvas)),且需开启assets或者base64)。

### asset

- 类型: `boolean`
Expand Down
4 changes: 3 additions & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@
"booru"
],
"optional": [
"assets"
"assets",
"canvas"
]
}
},
Expand All @@ -50,6 +51,7 @@
"devDependencies": {
"@cordisjs/plugin-proxy-agent": ">=0.3.3",
"@koishijs/assets": "^1.0.2",
"@koishijs/canvas": "^0.2.0",
"koishi": "^4.17.0"
},
"dependencies": {
Expand Down
15 changes: 12 additions & 3 deletions packages/core/src/command.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable no-fallthrough */
import { Channel, Context, Random, Session, User } from 'koishi'

import { Config, OutputType, SpoilerType, preferSizes } from '.'
import { Config, OutputType, SpoilerType, preferSizes, preferSizesToSize } from '.'

export const inject = {
required: ['booru'],
Expand Down Expand Up @@ -84,13 +84,22 @@ export function apply(ctx: Context, config: Config) {
url ||= image.url

if (config.asset && ctx.assets) {
url = await ctx.booru.imgUrlToAssetUrl(url)
if (config.autoResize && config.preferSize !== 'original') {
url = await ctx.booru.imgResize(url, preferSizesToSize[config.preferSize])
}
if (url) {
url = await ctx.booru.imgUrlToAssetUrl(url)
}
if (!url) {
children.unshift(<i18n path='commands.booru.messages.no-image'></i18n>)
continue
}
} else if (config.base64) {
url = await ctx.booru.imgUrlToBase64(url)
if (config.autoResize && config.preferSize !== 'original') {
url = await ctx.booru.imgResize(url, preferSizesToSize[config.preferSize])
} else if (url && !url.startsWith('data:')) {
url = await ctx.booru.imgUrlToBase64(url)
}
if (!url) {
children.unshift(<i18n path='commands.booru.messages.no-image'></i18n>)
continue
Expand Down
54 changes: 52 additions & 2 deletions packages/core/src/index.ts
SkyTNT marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import LanguageDetect from 'languagedetect'

import * as Command from './command'
import { ImageSource } from './source'
import {} from '@koishijs/assets'
import { } from '@koishijs/assets'
import { } from '@koishijs/canvas'

export * from './source'

Expand All @@ -18,7 +19,7 @@ declare module 'koishi' {
class ImageService extends Service {
static inject = {
required: [],
optional: ['assets'],
optional: ['assets', 'canvas'],
}

private sources: ImageSource[] = []
Expand Down Expand Up @@ -90,6 +91,48 @@ class ImageService extends Service {
return undefined
}

async imgResize(url: string, size: number): Promise<string> {
if (!this.ctx.canvas || size < 0) {
return url
}
try {
const resp = await this.ctx.http(url, { method: 'GET', responseType: 'arraybuffer', proxyAgent: '' })
SkyTNT marked this conversation as resolved.
Show resolved Hide resolved
let contentType = resp.headers.get('content-type')
let buffer = Buffer.from(resp.data)
const img = await this.ctx.canvas.loadImage(buffer)
let width = img.naturalWidth
let height = img.naturalHeight
const ratio = size / Math.max(width, height)
if (ratio < 1) {
width = Math.floor(width * ratio)
height = Math.floor(height * ratio)
const canvas = await this.ctx.canvas.createCanvas(width, height)
const ctx2d = canvas.getContext('2d')
ctx2d.drawImage(img, 0, 0, width, height)
buffer = await canvas.toBuffer('image/png')
contentType = 'image/png'
if (canvas.dispose) {
// skia-canvas does not have this method
await canvas.dispose()
}
}
if (img.dispose) {
await img.dispose()
}
return `data:${contentType};base64,${buffer.toString('base64')}`
} catch (err) {
if (Quester.Error.is(err)) {
logger.warn(
`Resize images failed with HTTP status ${err.response?.status}: ${JSON.stringify(err.response?.data)}.`,
)
return null
} else {
logger.error(`Resize images failed with error: ${err.message}.`)
}
return url
}
}

async imgUrlToAssetUrl(url: string): Promise<string> {
return await this.ctx.assets.upload(url, Date.now().toString()).catch(() => {
logger.warn('Request failed when trying to store image with assets service.')
Expand Down Expand Up @@ -144,6 +187,7 @@ export interface Config {
output: OutputType
outputMethod: 'one-by-one' | 'merge-multiple' | 'forward-all' | 'forward-multiple'
preferSize: ImageSource.PreferSize
autoResize: boolean
nsfw: boolean
asset: boolean
base64: boolean
Expand Down Expand Up @@ -199,6 +243,12 @@ export const Config = Schema.intersect([
])
.description('优先使用图片的最大尺寸。')
.default('large'),
autoResize: Schema.boolean()
.default(false)
.description(
'根据 preferSize 自动缩小过大的图片<br/> - 需要 canvas 服务(比如[ puppeteer ](https://puppeteer.koishi.chat/)或' +
'[ skia-canvas ](https://github.com/Kokoro-js/koishi-plugin-skia-canvas))<br/> - 需开启 assets 或者 base64。',
),
asset: Schema.boolean().default(false).description('优先使用 [assets服务](https://assets.koishi.chat/) 转存图片。'),
base64: Schema.boolean().default(false).description('使用 base64 发送图片。'),
spoiler: Schema.union([
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,4 @@ export namespace ImageSource {
}

export const preferSizes = ['thumbnail', 'large', 'medium', 'small', 'original'] as const
export const preferSizesToSize = { thumbnail: 128, large: 1280, medium: 640, small: 320, original: -1 } as const
Loading