이미지 포맷 변환기 - PNG, JPG, WebP, AVIF 변환 온라인
PNG, JPG, WebP, AVIF 이미지 포맷을 브라우저에서 변환하세요. 일괄 변환, 품질 조절, 파일 크기 비교 — 서버 업로드 없이 100% 클라이언트 처리.
자주 묻는 질문
이미지 포맷 변환기란 무엇이며 왜 필요한가요?
이미지 포맷 변환기는 이미지를 한 파일 형식에서 다른 형식으로 변환합니다(예: PNG에서 WebP, JPG에서 AVIF). 이는 웹 개발에 필수적인데, WebP와 AVIF 같은 최신 포맷이 기존 PNG와 JPEG보다 파일 크기가 훨씬 작아 페이지 로드 시간 단축, 대역폭 비용 절감, Core Web Vitals 점수 향상을 가져오기 때문입니다. 일반적인 2MB PNG 이미지를 WebP로 변환하면 시각적 품질 손실 없이 500KB 이하로 줄일 수 있습니다.
이 이미지 포맷 변환기는 어떻게 사용하나요?
1. 업로드 영역에 이미지를 드래그 앤 드롭하세요(또는 클릭하여 파일 탐색). 2. 출력 포맷을 선택하세요(PNG, JPG, WebP 또는 AVIF). 3. 손실 압축 포맷의 품질 슬라이더를 조정하세요(기본값 80%). 4. 개별 이미지는 '변환'을, 일괄 처리는 '모두 변환'을 클릭하세요. 5. 변환 전/후 파일 크기 비교를 확인하세요. 6. 개별 이미지를 다운로드하거나 '모두 다운로드'로 ZIP 파일을 받으세요.
이미지 데이터는 안전한가요? 이미지가 서버에 업로드되나요?
이미지는 100% 안전하며 브라우저를 벗어나지 않습니다. 모든 포맷 변환은 HTML5 Canvas API를 사용하여 클라이언트 측에서 수행됩니다. 어떤 이미지 데이터도 서버로 전송되지 않으므로 완전한 프라이버시가 보장됩니다. 페이지가 로드된 후에는 오프라인에서도 사용할 수 있습니다.
PNG, JPG, WebP, AVIF의 차이점은 무엇인가요?
PNG는 투명도를 지원하는 무손실 포맷으로 그래픽과 아이콘에 적합하지만 파일 크기가 큽니다. JPG/JPEG는 투명도가 없는 손실 포맷으로 사진에 적합하며 좋은 압축률을 제공합니다. WebP는 손실 및 무손실 압축과 투명도를 모두 지원하는 최신 포맷으로, 일반적으로 JPEG보다 25-35% 작으며 95% 이상의 브라우저에서 지원됩니다. AVIF는 가장 새로운 포맷으로 최고의 압축률(WebP보다 20-50% 작음)과 투명도를 지원하지만, 브라우저 지원은 아직 확대 중입니다.
변환된 파일이 원본보다 더 큰 이유는 무엇인가요?
이는 고압축 포맷에서 비효율적인 포맷으로 변환할 때(예: WebP에서 PNG) 또는 원본이 이미 잘 최적화되어 있을 때 발생할 수 있습니다. Canvas API의 PNG 출력은 항상 무손실이므로 손실 압축 대안보다 클 수 있습니다. 최적의 크기 대비 품질 비율을 위해 WebP 또는 AVIF를 80% 품질 설정으로 사용해 보세요.
이 도구는 모든 브라우저에서 AVIF를 지원하나요?
Canvas API를 통한 AVIF 인코딩은 현재 Chrome 96+ 및 Edge 96+에서 지원됩니다. Firefox와 Safari는 제한적인 AVIF 인코딩을 지원합니다. 이 도구는 브라우저의 기능을 자동으로 감지하여 AVIF가 지원되지 않으면 해당 옵션을 비활성화하고 명확한 메시지를 표시합니다.
JPG로 변환하면 투명도는 어떻게 되나요?
JPEG는 투명도를 지원하지 않습니다. 투명한 PNG 또는 WebP 이미지를 JPG로 변환하면 투명한 영역이 배경색(기본값: 흰색)으로 채워집니다. 출력 포맷으로 JPG를 선택하면 나타나는 색상 선택기를 사용하여 사용자 정의 배경색을 선택할 수 있습니다.
여러 이미지를 한 번에 변환할 수 있나요?
네, 일괄 변환은 최대 20개의 이미지를 동시에 지원합니다. 모든 이미지가 동일한 대상 포맷과 동일한 품질 설정으로 변환됩니다. 변환 후 '모두 다운로드(ZIP)'를 사용하면 변환된 모든 이미지를 하나의 ZIP 파일로 다운로드할 수 있습니다.
코드 예제
// Client-side image format conversion using Canvas API
async function convertImageFormat(file, outputFormat, quality = 0.8) {
return new Promise((resolve, reject) => {
const img = new Image();
const url = URL.createObjectURL(file);
img.onload = () => {
URL.revokeObjectURL(url);
const canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
const ctx = canvas.getContext('2d');
// Fill background for JPEG (no transparency support)
if (outputFormat === 'image/jpeg') {
ctx.fillStyle = '#ffffff';
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
ctx.drawImage(img, 0, 0);
canvas.toBlob(
(blob) => {
if (!blob) {
reject(new Error('Conversion failed'));
return;
}
resolve({
blob,
originalSize: file.size,
convertedSize: blob.size,
inputFormat: file.type,
outputFormat: outputFormat,
sizeDiff: Math.round(((blob.size - file.size) / file.size) * 100),
});
},
outputFormat,
outputFormat === 'image/png' ? undefined : quality
);
};
img.onerror = () => {
URL.revokeObjectURL(url);
reject(new Error('Failed to load image'));
};
img.src = url;
});
}
// Check AVIF support
async function checkAvifSupport() {
const canvas = document.createElement('canvas');
canvas.width = 1;
canvas.height = 1;
return new Promise((resolve) => {
canvas.toBlob(
(blob) => resolve(blob?.type === 'image/avif'),
'image/avif',
0.5
);
});
}
// Batch conversion
async function convertBatch(files, outputFormat, quality = 0.8) {
const results = [];
for (const file of files) {
try {
const result = await convertImageFormat(file, outputFormat, quality);
results.push({ filename: file.name, ...result });
} catch (error) {
results.push({ filename: file.name, error: error.message });
}
}
return results;
}
// Usage
const input = document.querySelector('input[type="file"]');
input.addEventListener('change', async (e) => {
const files = Array.from(e.target.files);
const results = await convertBatch(files, 'image/webp', 0.8);
results.forEach((result) => {
if (result.error) {
console.error(`${result.filename}: ${result.error}`);
} else {
console.log(
`${result.filename}: ${result.inputFormat} -> ${result.outputFormat}, ` +
`${result.originalSize} -> ${result.convertedSize} (${result.sizeDiff}%)`
);
}
});
});