56 lines
1.9 KiB
JavaScript
56 lines
1.9 KiB
JavaScript
|
|
// 프로필 아바타 유틸 — 표시 우선순위(커스텀 > 구글 > 이니셜)와 업로드용 다운스케일.
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 표시할 아바타 이미지 소스를 고른다.
|
||
|
|
* 우선순위: 사용자 지정(profileImage) > 구글 아바타(googlePicture) > null(이니셜 폴백)
|
||
|
|
*/
|
||
|
|
export function avatarSrc(user) {
|
||
|
|
if (!user) return null
|
||
|
|
return user.profileImage || user.googlePicture || null
|
||
|
|
}
|
||
|
|
|
||
|
|
/** 이름/아이디에서 이니셜(첫 글자) 한 글자 — 이미지 없을 때 폴백 */
|
||
|
|
export function avatarInitial(user) {
|
||
|
|
const s = (user?.name || user?.loginId || '').trim()
|
||
|
|
return s ? s[0].toUpperCase() : '?'
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 업로드용으로 이미지 파일을 정사각형으로 크롭·축소해 JPEG data URL 로 변환한다.
|
||
|
|
* (서버/로컬 저장 용량을 작게 — 기본 192px)
|
||
|
|
*/
|
||
|
|
export function fileToAvatarDataUrl(file, size = 192, quality = 0.85) {
|
||
|
|
return new Promise((resolve, reject) => {
|
||
|
|
if (!file || !file.type?.startsWith('image/')) {
|
||
|
|
reject(new Error('이미지 파일이 아닙니다.'))
|
||
|
|
return
|
||
|
|
}
|
||
|
|
const url = URL.createObjectURL(file)
|
||
|
|
const img = new Image()
|
||
|
|
img.onload = () => {
|
||
|
|
try {
|
||
|
|
const canvas = document.createElement('canvas')
|
||
|
|
canvas.width = size
|
||
|
|
canvas.height = size
|
||
|
|
const ctx = canvas.getContext('2d')
|
||
|
|
// 중앙 정사각형 크롭(cover)
|
||
|
|
const min = Math.min(img.width, img.height)
|
||
|
|
const sx = (img.width - min) / 2
|
||
|
|
const sy = (img.height - min) / 2
|
||
|
|
ctx.drawImage(img, sx, sy, min, min, 0, 0, size, size)
|
||
|
|
const dataUrl = canvas.toDataURL('image/jpeg', quality)
|
||
|
|
URL.revokeObjectURL(url)
|
||
|
|
resolve(dataUrl)
|
||
|
|
} catch (e) {
|
||
|
|
URL.revokeObjectURL(url)
|
||
|
|
reject(e)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
img.onerror = () => {
|
||
|
|
URL.revokeObjectURL(url)
|
||
|
|
reject(new Error('이미지를 읽지 못했습니다.'))
|
||
|
|
}
|
||
|
|
img.src = url
|
||
|
|
})
|
||
|
|
}
|