ΠΡΡΠΎΠΊΠΎΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΡΠΉ ΠΊΠΎΠΌΠΏΡΠ΅ΡΡΠΎΡ ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΠΉ, Π½Π°ΠΏΠΈΡΠ°Π½Π½ΡΠΉ Π½Π° Rust ΠΈ ΡΠΊΠΎΠΌΠΏΠΈΠ»ΠΈΡΠΎΠ²Π°Π½Π½ΡΠΉ Π² WebAssembly Π΄Π»Ρ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΡ Π² Π±ΡΠ°ΡΠ·Π΅ΡΠ΅.
- π ΠΡΡΠΎΠΊΠ°Ρ ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΡ - Π½Π°ΠΏΠΈΡΠ°Π½ Π½Π° Rust ΠΈ ΡΠΊΠΎΠΌΠΏΠΈΠ»ΠΈΡΠΎΠ²Π°Π½ Π² WASM
- ποΈ ΠΠ°ΡΡΡΠ°ΠΈΠ²Π°Π΅ΠΌΠΎΠ΅ ΠΊΠ°ΡΠ΅ΡΡΠ²ΠΎ - ΠΎΡ 1% Π΄ΠΎ 100% ΠΊΠ°ΡΠ΅ΡΡΠ²Π° ΡΠΆΠ°ΡΠΈΡ
- π¦ ΠΠ°ΠΊΡΠΈΠΌΠ°Π»ΡΠ½ΠΎΠ΅ ΡΠΆΠ°ΡΠΈΠ΅ - Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΎΠ΅ ΡΠΌΠ΅Π½ΡΡΠ΅Π½ΠΈΠ΅ ΡΠ°Π·ΠΌΠ΅ΡΠ° ΠΈ ΠΊΠ°ΡΠ΅ΡΡΠ²Π°
- π ΠΠΎΠ΄Π΄Π΅ΡΠΆΠΊΠ° Π±ΡΠ°ΡΠ·Π΅ΡΠΎΠ² - ΡΠ°Π±ΠΎΡΠ°Π΅Ρ Π²ΠΎ Π²ΡΠ΅Ρ ΡΠΎΠ²ΡΠ΅ΠΌΠ΅Π½Π½ΡΡ Π±ΡΠ°ΡΠ·Π΅ΡΠ°Ρ
- π± ΠΠΎΠ΄Π΄Π΅ΡΠΆΠΊΠ° ΡΠΎΡΠΌΠ°ΡΠΎΠ² - JPEG, PNG, WebP, GIF, BMP ΠΈ Π΄ΡΡΠ³ΠΈΠ΅
- π§ ΠΡΠΎΡΡΠΎΠΉ API - ΡΠ΄ΠΎΠ±Π½ΡΠΉ JavaScript ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡ
- π― Π‘ΠΎΡ ΡΠ°Π½Π΅Π½ΠΈΠ΅ ΡΠΎΡΠΌΠ°ΡΠ° - ΡΠ°ΠΉΠ» ΠΎΡΡΠ°Π΅ΡΡΡ Π² ΠΈΡΡ ΠΎΠ΄Π½ΠΎΠΌ ΡΠΎΡΠΌΠ°ΡΠ΅ ΠΏΠΎΡΠ»Π΅ ΡΠΆΠ°ΡΠΈΡ
curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh# ΠΠ»ΠΎΠ½ΠΈΡΡΠΉΡΠ΅ ΡΠ΅ΠΏΠΎΠ·ΠΈΡΠΎΡΠΈΠΉ
git clone <repository-url>
cd image-compressor
# Π‘ΠΎΠ±Π΅ΡΠΈΡΠ΅ WASM ΠΌΠΎΠ΄ΡΠ»Ρ
./build.shΠΠ»ΠΈ Π²ΡΡΡΠ½ΡΡ:
wasm-pack build --target web --out-dir pkg --devimport ImageCompressor from './js/image-compressor.js';
// ΠΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΡ
const compressor = new ImageCompressor();
await compressor.init('./pkg/image_compressor.js');
// Π‘ΠΆΠ°ΡΠΈΠ΅ ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΡ Ρ ΠΊΠ°ΡΠ΅ΡΡΠ²ΠΎΠΌ 80%
const compressedData = await compressor.compressImage(file, 80);
// ΠΠ°ΠΊΡΠΈΠΌΠ°Π»ΡΠ½ΠΎΠ΅ ΡΠΆΠ°ΡΠΈΠ΅
const maxCompressedData = await compressor.compressImageMax(file);
// Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ Blob Π΄Π»Ρ ΡΠΊΠ°ΡΠΈΠ²Π°Π½ΠΈΡ
const blob = compressor.createBlob(compressedData);
const url = compressor.createObjectURL(blob);// ΠΠ°Π³ΡΡΠ·ΠΊΠ° ΡΠ°ΠΉΠ»Π° ΡΠ΅ΡΠ΅Π· input
const fileInput = document.getElementById('fileInput');
const file = fileInput.files[0];
// Π‘ΠΆΠ°ΡΠΈΠ΅
const compressedData = await compressor.compressImage(file, 70);
// Π‘ΠΊΠ°ΡΠΈΠ²Π°Π½ΠΈΠ΅ ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΠ°
const blob = compressor.createBlob(compressedData);
const downloadUrl = compressor.createObjectURL(blob);
const a = document.createElement('a');
a.href = downloadUrl;
a.download = 'compressed-image.jpg';
a.click();
// ΠΡΠ²ΠΎΠ±ΠΎΠΆΠ΄Π΅Π½ΠΈΠ΅ ΠΏΠ°ΠΌΡΡΠΈ
compressor.revokeObjectURL(downloadUrl);const info = await compressor.getImageInfo(file);
console.log(`Π Π°Π·ΠΌΠ΅Ρ: ${info.width}x${info.height}`);
console.log(`Π Π°Π·ΠΌΠ΅Ρ ΡΠ°ΠΉΠ»Π°: ${info.size_bytes} Π±Π°ΠΉΡ`);const compressor = new ImageCompressor();ΠΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·ΠΈΡΡΠ΅Ρ WASM ΠΌΠΎΠ΄ΡΠ»Ρ.
ΠΠ°ΡΠ°ΠΌΠ΅ΡΡΡ:
wasmPath(string) - ΠΏΡΡΡ ΠΊ ΡΠΊΠΎΠΌΠΏΠΈΠ»ΠΈΡΠΎΠ²Π°Π½Π½ΠΎΠΌΡ WASM ΠΌΠΎΠ΄ΡΠ»Ρ
ΠΠΎΠ·Π²ΡΠ°ΡΠ°Π΅Ρ: Promise
Π‘ΠΆΠΈΠΌΠ°Π΅Ρ ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΠ΅ Ρ Π·Π°Π΄Π°Π½Π½ΡΠΌ ΠΊΠ°ΡΠ΅ΡΡΠ²ΠΎΠΌ, ΡΠΎΡ ΡΠ°Π½ΡΡ ΠΈΡΡ ΠΎΠ΄Π½ΡΠΉ ΡΠΎΡΠΌΠ°Ρ.
ΠΠ°ΡΠ°ΠΌΠ΅ΡΡΡ:
imageInput(File|Uint8Array) - ΡΠ°ΠΉΠ» ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΡ ΠΈΠ»ΠΈ ΠΌΠ°ΡΡΠΈΠ² Π±Π°ΠΉΡΠΎΠ²quality(number) - ΠΊΠ°ΡΠ΅ΡΡΠ²ΠΎ ΡΠΆΠ°ΡΠΈΡ ΠΎΡ 1 Π΄ΠΎ 100
ΠΠΎΠ·Π²ΡΠ°ΡΠ°Π΅Ρ: Promise - ΡΠΆΠ°ΡΡΠ΅ Π΄Π°Π½Π½ΡΠ΅ ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΡ Π² ΠΈΡΡ ΠΎΠ΄Π½ΠΎΠΌ ΡΠΎΡΠΌΠ°ΡΠ΅
ΠΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°Π΅ΠΌΡΠ΅ ΡΠΎΡΠΌΠ°ΡΡ:
- JPEG β JPEG (Ρ Π½Π°ΡΡΡΠ°ΠΈΠ²Π°Π΅ΠΌΡΠΌ ΠΊΠ°ΡΠ΅ΡΡΠ²ΠΎΠΌ)
- PNG β PNG (Ρ ΠΌΠ°ΠΊΡΠΈΠΌΠ°Π»ΡΠ½ΡΠΌ ΡΠΆΠ°ΡΠΈΠ΅ΠΌ)
- WebP β JPEG (ΠΊΠΎΠ½Π²Π΅ΡΡΠ°ΡΠΈΡ Ρ Π½Π°ΡΡΡΠ°ΠΈΠ²Π°Π΅ΠΌΡΠΌ ΠΊΠ°ΡΠ΅ΡΡΠ²ΠΎΠΌ)
- GIF/BMP β PNG (ΠΊΠΎΠ½Π²Π΅ΡΡΠ°ΡΠΈΡ)
Π‘ΠΆΠΈΠΌΠ°Π΅Ρ ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΠ΅ Ρ ΠΌΠ°ΠΊΡΠΈΠΌΠ°Π»ΡΠ½ΡΠΌ ΡΠΆΠ°ΡΠΈΠ΅ΠΌ, ΡΠΌΠ΅Π½ΡΡΠ°Ρ ΡΠ°Π·ΠΌΠ΅Ρ ΠΈ ΠΊΠ°ΡΠ΅ΡΡΠ²ΠΎ.
ΠΠ°ΡΠ°ΠΌΠ΅ΡΡΡ:
imageInput(File|Uint8Array) - ΡΠ°ΠΉΠ» ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΡ ΠΈΠ»ΠΈ ΠΌΠ°ΡΡΠΈΠ² Π±Π°ΠΉΡΠΎΠ²
ΠΠΎΠ·Π²ΡΠ°ΡΠ°Π΅Ρ: Promise - ΠΌΠ°ΠΊΡΠΈΠΌΠ°Π»ΡΠ½ΠΎ ΡΠΆΠ°ΡΡΠ΅ Π΄Π°Π½Π½ΡΠ΅
ΠΡΠΎΠ±Π΅Π½Π½ΠΎΡΡΠΈ:
- Π£ΠΌΠ΅Π½ΡΡΠ°Π΅Ρ ΡΠ°Π·ΠΌΠ΅Ρ ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΡ Π² 2 ΡΠ°Π·Π°
- ΠΡΠΏΠΎΠ»ΡΠ·ΡΠ΅Ρ ΠΌΠΈΠ½ΠΈΠΌΠ°Π»ΡΠ½ΠΎΠ΅ ΠΊΠ°ΡΠ΅ΡΡΠ²ΠΎ Π΄Π»Ρ JPEG
- Π‘ΠΎΡ ΡΠ°Π½ΡΠ΅Ρ ΡΠΎΡΠΌΠ°Ρ PNG Π±Π΅Π· ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ
ΠΠΎΠ»ΡΡΠ°Π΅Ρ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΡ ΠΎΠ± ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΠΈ.
ΠΠ°ΡΠ°ΠΌΠ΅ΡΡΡ:
imageInput(File|Uint8Array) - ΡΠ°ΠΉΠ» ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΡ ΠΈΠ»ΠΈ ΠΌΠ°ΡΡΠΈΠ² Π±Π°ΠΉΡΠΎΠ²
ΠΠΎΠ·Π²ΡΠ°ΡΠ°Π΅Ρ: Promise - ΠΎΠ±ΡΠ΅ΠΊΡ Ρ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΠ΅ΠΉ:
{
width: number,
height: number,
format: string,
size_bytes: number
}Π‘ΠΎΠ·Π΄Π°Π΅Ρ Blob ΠΈΠ· Uint8Array.
ΠΠ°ΡΠ°ΠΌΠ΅ΡΡΡ:
data(Uint8Array) - Π΄Π°Π½Π½ΡΠ΅ ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΡmimeType(string) - MIME ΡΠΈΠΏ (ΠΏΠΎ ΡΠΌΠΎΠ»ΡΠ°Π½ΠΈΡ 'image/jpeg')
ΠΠΎΠ·Π²ΡΠ°ΡΠ°Π΅Ρ: Blob
Π‘ΠΎΠ·Π΄Π°Π΅Ρ URL Π΄Π»Ρ Blob.
ΠΠ°ΡΠ°ΠΌΠ΅ΡΡΡ:
blob(Blob) - Blob ΠΎΠ±ΡΠ΅ΠΊΡ
ΠΠΎΠ·Π²ΡΠ°ΡΠ°Π΅Ρ: string - URL
ΠΡΠ²ΠΎΠ±ΠΎΠΆΠ΄Π°Π΅Ρ URL ΠΎΠ±ΡΠ΅ΠΊΡ.
ΠΠ°ΡΠ°ΠΌΠ΅ΡΡΡ:
url(string) - URL Π΄Π»Ρ ΠΎΡΠ²ΠΎΠ±ΠΎΠΆΠ΄Π΅Π½ΠΈΡ
<!DOCTYPE html>
<html>
<head>
<title>Image Compressor Example</title>
</head>
<body>
<input type="file" id="fileInput" accept="image/*">
<button onclick="compress()">Π‘ΠΆΠ°ΡΡ</button>
<img id="result" style="display:none;">
<script type="module">
import ImageCompressor from './js/image-compressor.js';
let compressor;
async function init() {
compressor = new ImageCompressor();
await compressor.init('./pkg/image_compressor.js');
}
window.compress = async function() {
const file = document.getElementById('fileInput').files[0];
if (!file) return;
const compressedData = await compressor.compressImage(file, 60);
const blob = compressor.createBlob(compressedData);
const url = compressor.createObjectURL(blob);
const img = document.getElementById('result');
img.src = url;
img.style.display = 'block';
};
init();
</script>
</body>
</html>async function compressMultiple(files, quality) {
const results = [];
for (const file of files) {
try {
const compressedData = await compressor.compressImage(file, quality);
const blob = compressor.createBlob(compressedData);
results.push({
original: file,
compressed: blob,
compressionRatio: (1 - compressedData.length / file.size) * 100
});
} catch (error) {
console.error(`ΠΡΠΈΠ±ΠΊΠ° ΡΠΆΠ°ΡΠΈΡ ${file.name}:`, error);
}
}
return results;
}image-compressor/
βββ src/
β βββ lib.rs # ΠΡΠ½ΠΎΠ²Π½ΠΎΠΉ Rust ΠΊΠΎΠ΄
βββ js/
β βββ image-compressor.js # JavaScript ΠΎΠ±Π΅ΡΡΠΊΠ°
βββ example/
β βββ index.html # ΠΠ΅ΠΌΠΎ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅
βββ pkg/ # Π‘ΠΊΠΎΠΌΠΏΠΈΠ»ΠΈΡΠΎΠ²Π°Π½Π½ΡΠ΅ WASM ΡΠ°ΠΉΠ»Ρ
βββ Cargo.toml # Rust Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡΠΈ
βββ build.sh # Π‘ΠΊΡΠΈΠΏΡ ΡΠ±ΠΎΡΠΊΠΈ
βββ README.md # ΠΠΎΠΊΡΠΌΠ΅Π½ΡΠ°ΡΠΈΡ
ΠΡΠ½ΠΎΠ²Π½ΠΎΠΉ ΠΊΠΎΠ΄ Π½Π°Ρ
ΠΎΠ΄ΠΈΡΡΡ Π² src/lib.rs:
ImageCompressor- ΠΎΡΠ½ΠΎΠ²Π½ΠΎΠΉ ΠΊΠ»Π°ΡΡ Π΄Π»Ρ ΡΠΆΠ°ΡΠΈΡcompress_image_quick- Π±ΡΡΡΡΠ°Ρ ΡΡΠ½ΠΊΡΠΈΡ ΡΠΆΠ°ΡΠΈΡcompress_image_max_quick- ΠΌΠ°ΠΊΡΠΈΠΌΠ°Π»ΡΠ½ΠΎΠ΅ ΡΠΆΠ°ΡΠΈΠ΅get_image_info- ΠΏΠΎΠ»ΡΡΠ΅Π½ΠΈΠ΅ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΠΈ ΠΎΠ± ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΠΈ
wasm-bindgen- Π΄Π»Ρ Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΈΡ Ρ JavaScriptimage- Π΄Π»Ρ ΡΠ°Π±ΠΎΡΡ Ρ ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΡΠΌΠΈserde- Π΄Π»Ρ ΡΠ΅ΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΠΈ Π΄Π°Π½Π½ΡΡ
wasm-pack build --target web --out-dir pkg --devwasm-pack build --target web --out-dir pkg --release- Π‘ΠΊΠΎΡΠΎΡΡΡ ΡΠΆΠ°ΡΠΈΡ: ~10-50ms Π΄Π»Ρ ΠΈΠ·ΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΠΉ Π΄ΠΎ 5MB
- Π‘ΠΆΠ°ΡΠΈΠ΅: 60-90% ΡΠΌΠ΅Π½ΡΡΠ΅Π½ΠΈΠ΅ ΡΠ°Π·ΠΌΠ΅ΡΠ° ΠΏΡΠΈ ΠΊΠ°ΡΠ΅ΡΡΠ²Π΅ 80%
- ΠΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°Π΅ΠΌΡΠ΅ ΡΠΎΡΠΌΠ°ΡΡ: JPEG, PNG, WebP, BMP, GIF
- ΠΠ°ΠΊΡΠΈΠΌΠ°Π»ΡΠ½ΡΠΉ ΡΠ°Π·ΠΌΠ΅Ρ: ΠΎΠ³ΡΠ°Π½ΠΈΡΠ΅Π½ ΠΏΠ°ΠΌΡΡΡΡ Π±ΡΠ°ΡΠ·Π΅ΡΠ°
ΠΠΊΠ»ΡΡΠΈΡΠ΅ Π»ΠΎΠ³ΠΈ Π² ΠΊΠΎΠ½ΡΠΎΠ»ΠΈ Π±ΡΠ°ΡΠ·Π΅ΡΠ° Π΄Π»Ρ ΠΎΡΠ»Π°Π΄ΠΊΠΈ:
// ΠΠΊΠ»ΡΡΠΈΡΡ ΠΏΠΎΠ΄ΡΠΎΠ±Π½ΡΠ΅ Π»ΠΎΠ³ΠΈ
localStorage.setItem('debug', 'image-compressor');MIT License - ΡΠΌ. ΡΠ°ΠΉΠ» LICENSE Π΄Π»Ρ Π΄Π΅ΡΠ°Π»Π΅ΠΉ.
- Π€ΠΎΡΠΊΠ½ΠΈΡΠ΅ ΡΠ΅ΠΏΠΎΠ·ΠΈΡΠΎΡΠΈΠΉ
- Π‘ΠΎΠ·Π΄Π°ΠΉΡΠ΅ Π²Π΅ΡΠΊΡ Π΄Π»Ρ Π½ΠΎΠ²ΠΎΠΉ ΡΡΠ½ΠΊΡΠΈΠΈ
- ΠΠ½Π΅ΡΠΈΡΠ΅ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΡ
- ΠΠΎΠ±Π°Π²ΡΡΠ΅ ΡΠ΅ΡΡΡ
- Π‘ΠΎΠ·Π΄Π°ΠΉΡΠ΅ Pull Request
ΠΡΠ»ΠΈ Ρ Π²Π°Ρ Π΅ΡΡΡ Π²ΠΎΠΏΡΠΎΡΡ ΠΈΠ»ΠΈ ΠΏΡΠΎΠ±Π»Π΅ΠΌΡ:
- ΠΡΠΎΠ²Π΅ΡΡΡΠ΅ Issues
- Π‘ΠΎΠ·Π΄Π°ΠΉΡΠ΅ Π½ΠΎΠ²ΡΠΉ Issue Ρ ΠΏΠΎΠ΄ΡΠΎΠ±Π½ΡΠΌ ΠΎΠΏΠΈΡΠ°Π½ΠΈΠ΅ΠΌ
- ΠΡΠΈΠ»ΠΎΠΆΠΈΡΠ΅ ΠΏΡΠΈΠΌΠ΅Ρ ΠΊΠΎΠ΄Π° ΠΈ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΡ ΠΎ Π±ΡΠ°ΡΠ·Π΅ΡΠ΅
Π‘Π΄Π΅Π»Π°Π½ΠΎ Ρ β€οΈ Π½Π° Rust ΠΈ WebAssembly