๋๋ ๊ทธ๊ฒ์ด ์ฌ์ด ์์ ์ด ์๋๋ผ๋ ๊ฒ์ ์๊ณ ์์ง๋ง webp ์ง์์ ์ ๊ณตํ๋ ๊ฒ์ ๊ฝค ๋ฉ์ง ๊ฒ์ ๋๋ค.
๊ฐ์ฌ ํด์.
์ด๋ป๊ฒ ํ ์ ์์ต๋๊น?
๊ธ์, ํ์ฌ ์ด๋ฏธ์ง๋ฅผ ํฝ์ ๋ฐฐ์ด๋ก ๋ณํํ๋ ๋ฐฉ๋ฒ์ ๋ฌด์์ ๋๊น?
๋ธ๋ผ์ฐ์ ์์๋ <canvas>
์ํด ์ํ๋ฉ๋๋ค. ๋ฐ๋ผ์ ๋ธ๋ผ์ฐ์ ๊ฐ ์ง์ํ๋ ํ์์ ๋ฌธ์ ์ผ ๋ฟ์
๋๋ค. [browser.ts]๋ฅผ ์ฐธ์กฐํ์ธ์.
node.js์์๋ ์์ํ JavaScript ๊ตฌํ์ด๊ธฐ ๋๋ฌธ์ [jimp]๊ฐ ์ฌ์ฉ๋ฉ๋๋ค. ์ผ๋ถ ํ๋ซํผ์์ ๊ธฐ๋ณธ ๊ตฌํ์ผ๋ก ์ค๋จ๋ ์ ์๋ ์ผ๋ถ ๋ฐ์ด๋๋ฆฌ/์ข
์์ฑ์ ๋์
ํ๊ณ ์ถ์ง ์์์ต๋๋ค. [node.ts]๋ฅผ ์ฐธ์กฐํ์ญ์์ค.
node-vibrant๋ ํ์ฅ ๊ฐ๋ฅํ๋๋ก ์ค๊ณ๋์์ต๋๋ค. ์ด๋ฏธ์ง ํ์ ์ง์์ ImageClass
๋ฅผ ํตํด ์ ๊ณต๋ฉ๋๋ค. ์์ ์ ImageClass
ํ๊ณ Vibrant.DefaultOpts.ImageClass = YourCustomImageClass
์ธํธ๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค.
ํ๋๋ฅผ ๊ตฌํํ๋ ค๋ฉด
ImageBase
]๋ฅผ ํ์ฅํฉ๋๋ค.Image
] ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํฉ๋๋ค.์ถ๋ ฅ ํฝ์
๋ฐฐ์ด์ [ ImageData.data
]์ ๊ฐ์ ํ์์ด์ด์ผ ํฉ๋๋ค. "0์์ 255(ํฌํจ) ์ฌ์ด์ ์ ์ ๊ฐ์ ๊ฐ๋ RGBA ์์๋ก ๋ฐ์ดํฐ๋ฅผ ํฌํจํ๋ 1์ฐจ์ ๋ฐฐ์ด"์
๋๋ค.
๋ ธ๋์ ๋ํ webp ๋์ฝ๋ ํจํค์ง๋ฅผ ์ฐพ๋ ๊ฒ์ ์ ๋ง ๋ฌธ์ ์ ๋๋ค.
์์ฒญ๋! ๊ฐ์ฌ ํด์! TypeScript๋ฅผ ์ํ์ง๋ ๋ชปํ์ง๋ง ๋ฌด์์ ํ ์ ์๋์ง ์์๋ณด๊ฒ ์ต๋๋ค!
๋ฉ์ง!
์ฐธ๊ณ ๋ก ์ ๋ node-vibrant๋ฅผ ๋ฒ์ 3.1.0์ฉ์ผ๋ก ์ฌ๋ฌ ๊ฐ์ ์์ ํจํค์ง๋ก ๋ฆฌํฉํ ๋งํ๊ณ ์์ต๋๋ค. ๋ชจ๋ ์ด๋ฏธ์ง ํด๋์ค๋ ์์ฒด npm ํจํค์ง๋ก ๊ตฌํ๋ฉ๋๋ค.
์ฐธ์กฐ ๊ตฌํ์ ์ํด @vibrant/image-node
๋ฅผ ํ์ธํ์ญ์์ค. ์ฌ์ ํ ์์์ ์ค๋ช
ํ ๊ฒ๊ณผ ๋์ผํฉ๋๋ค. ์ด์ ์ ์ฒด ๋ฆฌํฌ์งํ ๋ฆฌ๋ฅผ ๋ถ๊ธฐํ๋ ๋์ ์ด ํ๋ก์ ํธ์์ ํ๋์ @vibrant/image
์ข
์์ฑ๋ง ํ์ํ๋ค๋ ์ ์ ์ ์ธํ๊ณ . ๋ฐ๋ผ๊ฑด๋ ๊ทธ๊ฒ์ ์ผ์ ๋จ์ํ ํ ๊ฒ์
๋๋ค.
์์ฒญ๋ !
๋๋ ๋ง์ ์ด์ ์ผ๋ก ์ธํด ๊ธฐ๋ณธ์ ์ผ๋ก ๋ชจ๋ ์ด๋ฏธ์ง๋ฅผ webp ํ์์ผ๋ก ํ์ํ๋ ๊ฒ์ผ๋ก ์ด๋ํ๊ธฐ ์์ํ Discord ๋ด์์ ์ด ํจํค์ง๋ฅผ ์ฌ์ฉํ๊ณ ์์ผ๋ฏ๋ก ์ด ๊ธฐ๋ฅ์ ์ ์๊ฒ ํฐ ๋์์ด ๋๊ธฐ ์์ํ์ต๋๋ค. wontfix
๋ ์ด๋ธ์ด ํ์๋์ด ์ ๋ง ๊ฑฑ์ ๋ฉ๋๋ค.
@nitriques "๋ฌด์์ ํ ์ ์๋์ง ๋ณด๊ธฐ"๋ฅผ ์์ง @akfish ๊ฒฐ๊ตญ ์์ ํ ๊ฑด๊ฐ์?
@Favna ๊ธฐ๋ณธ ํจํค์ง/
์ฌ๊ฐ ์๊ฐ์ ์ด ํ๋ก์ ํธ๋ฅผ ์งํ ์ค์ด๋ฉฐ ์ด ๊ธฐ๋ฅ์ ์ฐ์ ์์ ๋ชฉ๋ก์ ์์ต๋๋ค. ๊ทธ๋์ ๋๋ ๊ทธ๊ฒ์ด ๊ณง ๊ณ ์ณ์ง์ง ์์ ๊ฒ ๊ฐ๋ค.
@ํ๋ธ๋
"๋ฌด์์ ํ ์ ์๋์ง ๋ณด๋ ๊ฒ"์ ์์ง ํด๋ณธ ์ ์ด ์์ต๋๊น?
์, ๋ด๊ฐ ๋ณด๋ ๋ชจ๋ ๊ฒ์ ๊ธฐ๋ณธ ์ ๋์จ์ ๋๋ค.
์ข์ ์ ์ ๋ด๊ฐ ํ์ํ๊ธฐ ๋๋ฌธ์ ๊ณง ๋๋ฌ๋ณผ ์๊ฐ์ด ์์ ์ ์๋ค๋ ๊ฒ์ ๋๋ค.
์ ํ์ ํ๋๊ทธ๋ฅผ ํตํด jimp ๋์ sharp ๋ฅผ ์ฌ์ฉํ๋๋ก ํ์ฉํ๋ ๊ฒ์ ๋ํด ์ด๋ป๊ฒ ์๊ฐํ์ญ๋๊น? v0.20 ์คํ๋ ๋๋ถ๋ถ์ ์์คํ
์์ npm install
์ธ์ ์ถ๊ฐ ์ค์น ๋จ๊ณ๊ฐ ํ์ํ์ง ์์ต๋๋ค. ๋ํ webp ๋ฐ svg ์ง์๊ณผ ํจ๊ป ์ ๊ณต๋๋ฉฐ ๊ธฐ๋ณธ ๋ชจ๋์ ๊ธฐ๋ฐ์ผ๋ก ํ๊ธฐ ๋๋ฌธ์ ๋ ๋น ๋ฅธ ์๋ฃจ์
์ ์ฝ์ํฉ๋๋ค.
์คํ ๊ธฐ๋ฐ ImageClass
์ ๋ง๋ค๋ ค๊ณ ํ์ง๋ง resize
/ scaleDown
๋ ๋๊ธฐ์์ด์ด์ผ ํ์ง๋ง ์คํ์ ํฌ๊ธฐ ์กฐ์ ์์
์ ๋น๋๊ธฐ์์ด๋ฏ๋ก ๊ฐ๋จํ์ง ์์ต๋๋ค.
fyi: ๋ค์์ ์คํ๋ฅผ ์ฌ์ฉํ ImageClass ๊ตฌํ์
๋๋ค. ๋ชจ๋ ๊ธฐ๋ณธ ํ์ ์ธ์๋ webp์ svg๋ฅผ ๋ชจ๋ ์ง์ํฉ๋๋ค. ์์ ์ฃผ์์ ์ค๋ช
๋ ํฌ๊ธฐ ์กฐ์ ๋ฌธ์ ๋ก ์ธํด ์ฝ๋๋ load
๋ฉ์๋์์ ์ด๋ฏธ์ง ํฌ๊ธฐ๋ฅผ ์กฐ์ ํ์ฌ node-vibrant์์ ์ค๋ ๋ชจ๋ ํฌ๊ธฐ ์กฐ์ ๋ช
๋ น์ ํจ๊ณผ์ ์ผ๋ก ๋ฌด์ํฉ๋๋ค.
import * as sharp from "sharp";
import {ImageBase, ImageSource} from "@vibrant/image";
class SharpImage extends ImageBase {
private _image: ImageData = undefined as any;
async load(image: ImageSource): Promise<ImageBase> {
if (typeof image === "string" || image instanceof Buffer) {
const {data, info} = await sharp(image)
.resize(200, 200, {fit: "inside", withoutEnlargement: true})
.ensureAlpha()
.raw()
.toBuffer({resolveWithObject: true});
this._image = {
width: info.width,
height: info.height,
data: (data as unknown) as Uint8ClampedArray,
};
return this;
} else {
return Promise.reject(
new Error("Cannot load image from HTMLImageElement in node environment")
);
}
}
clear(): void {}
update(): void {}
getWidth(): number {
return this._image.width;
}
getHeight(): number {
return this._image.height;
}
resize(targetWidth: number, targetHeight: number, ratio: number): void {
// done in the load step, ignoring any maxDimension or quality options
}
getPixelCount(): number {
const {width, height} = this._image;
return width * height;
}
getImageData(): ImageData {
return this._image;
}
remove(): void {}
}
๊ฐ์ฅ ์ ์ฉํ ๋๊ธ
fyi: ๋ค์์ ์คํ๋ฅผ ์ฌ์ฉํ ImageClass ๊ตฌํ์ ๋๋ค. ๋ชจ๋ ๊ธฐ๋ณธ ํ์ ์ธ์๋ webp์ svg๋ฅผ ๋ชจ๋ ์ง์ํฉ๋๋ค. ์์ ์ฃผ์์ ์ค๋ช ๋ ํฌ๊ธฐ ์กฐ์ ๋ฌธ์ ๋ก ์ธํด ์ฝ๋๋
load
๋ฉ์๋์์ ์ด๋ฏธ์ง ํฌ๊ธฐ๋ฅผ ์กฐ์ ํ์ฌ node-vibrant์์ ์ค๋ ๋ชจ๋ ํฌ๊ธฐ ์กฐ์ ๋ช ๋ น์ ํจ๊ณผ์ ์ผ๋ก ๋ฌด์ํฉ๋๋ค.