Galereya — rasm tanlash va serverga yuklash
Muammodan boshlaylik
Profil rasmini o'zgartirish. Foydalanuvchi:
- "Rasmni o'zgartirish" ni bosadi
- Galereyadan tanlaydi yoki darhol suratga oladi
- Rasmni kvadrat qilib kesadi
- Rasm serverga yuklanadi — progress bilan
Yana bir muammo: zamonaviy telefon rasmi 4000×3000 piksel, 5-8 MB. Uni mobil internet orqali yuklash — sekin va foydalanuvchi trafigini yeydi. Profil rasmi uchun esa 400×400 yetarli.
O'rnatish
npx expo install expo-image-picker expo-image-manipulator
"plugins": [
["expo-image-picker", {
"photosPermission": "Profil rasmini tanlash uchun galereyaga kirish kerak.",
"cameraPermission": "Profil rasmini suratga olish uchun kamera kerak."
}]
]
Galereyadan tanlash
import * as ImagePicker from 'expo-image-picker';
async function galereyadanTanla() {
const natija = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ['images'],
allowsEditing: true, // tizimning kesish oynasi
aspect: [1, 1], // kvadrat (Android da)
quality: 0.8,
});
if (natija.canceled) return; // foydalanuvchi bekor qildi
const rasm = natija.assets[0];
// rasm.uri, rasm.width, rasm.height, rasm.fileSize, rasm.mimeType
setRasm(rasm.uri);
}
[!INFO] Zamonaviy Android va iOS da galereyadan tanlash uchun ko'pincha ruxsat kerak emas: tizim o'z "tanlash oynasi" ni ko'rsatadi va ilova faqat tanlangan rasmni oladi, butun galereyani emas. Bu foydalanuvchi maxfiyligi uchun yaxshi.
Kamera orqali
async function suratgaOl() {
const { granted } = await ImagePicker.requestCameraPermissionsAsync();
if (!granted) return Alert.alert('Kamera ruxsati kerak');
const natija = await ImagePicker.launchCameraAsync({ allowsEditing: true, aspect: [1, 1], quality: 0.8 });
if (!natija.canceled) setRasm(natija.assets[0].uri);
}
39-darsdagi CameraView — o'z dizayningizdagi kamera uchun. Oddiy "rasm olish" uchun launchCameraAsync — tizim kamerasi, kamroq kod.
Tanlov oynasi
function rasmManbai() {
Alert.alert('Profil rasmi', undefined, [
{ text: 'Galereyadan tanlash', onPress: galereyadanTanla },
{ text: 'Suratga olish', onPress: suratgaOl },
{ text: 'Bekor qilish', style: 'cancel' },
]);
}
Bir nechta rasm
const natija = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ['images'],
allowsMultipleSelection: true,
selectionLimit: 5,
});
Mahsulot e'loni uchun 5 tagacha rasm.
Kichraytirish — yuklashdan oldin
import { ImageManipulator, SaveFormat } from 'expo-image-manipulator';
async function tayyorla(uri: string) {
const kontekst = ImageManipulator.manipulate(uri);
kontekst.resize({ width: 800 }); // balandlik nisbatda
const rasm = await kontekst.renderAsync();
const natija = await rasm.saveAsync({ compress: 0.7, format: SaveFormat.JPEG });
return natija.uri;
}
| Asl | Kichraytirilgan | |
|---|---|---|
| O'lcham | 4032×3024 | 800×600 |
| Hajm | ~6 MB | ~120 KB |
| 3G da yuklash | ~40 soniya | ~1 soniya |
Profil uchun 400, mahsulot uchun 1200 — maqsadga qarab. JPEG — fotosuratlar uchun; PNG — faqat shaffoflik kerak bo'lsa.
Serverga yuklash
FormData bilan
async function yuklash(uri: string) {
const forma = new FormData();
forma.append('rasm', {
uri,
name: 'avatar.jpg',
type: 'image/jpeg',
} as any);
const token = await tokenlar.olish();
const javob = await fetch(`${BASE_URL}/profil/rasm`, {
method: 'POST',
headers: { Authorization: `Bearer ${token}` }, // ⚠️ Content-Type ni O'ZINGIZ YOZMANG
body: forma,
});
if (!javob.ok) throw new Error('Yuklab bo\'lmadi');
return javob.json();
}
React Native ning FormData si { uri, name, type } ob'ektini qabul qiladi va faylni diskdan o'zi o'qiydi.
[!WARNING]
Content-Type: multipart/form-datani qo'lda yozmang. To'g'ri sarlavhada boundary (qismlar ajratgichi) bo'lishi kerak — unifetcho'zi qo'shadi. Qo'lda yozsangiz — boundary yo'q va server faylni topa olmaydi.
Server tomonida — PHP kursidagi 22-dars ($_FILES, MIME tekshiruv, tasodifiy nom) yoki Node.js da multer.
Progress bilan — expo-file-system
fetch yuklash progressini ko'rsatmaydi. Katta fayllar (video, ko'p rasm) uchun expo-file-system ning yuklash (upload) API sidan foydalaning: u har bir yuklangan qism haqida xabar beradi va progress chizig'ini ko'rsatish imkonini beradi. Aniq funksiya nomlari Expo SDK versiyasiga qarab o'zgarib turadi — o'z versiyangiz hujjatidan tekshiring.
Bulutga to'g'ridan-to'g'ri
Katta ilovalarda rasm serveringiz orqali emas, to'g'ridan-to'g'ri bulut omboriga (S3, Cloudflare R2) yuklanadi:
- Ilova serverdan imzolangan URL so'raydi (
presigned URL, 5 daqiqa amal qiladi) - Rasmni shu URL ga
PUTqiladi - Serverga "yuklandi, kalit: abc.jpg" deydi
Server trafikni o'tkazmaydi va yuklanmaydi.
To'liq misol: profil rasmi
export function ProfilRasmi() {
const [uri, setUri] = useState<string | null>(foydalanuvchi.avatar);
const yangila = useMutation({
mutationFn: async (asl: string) => yuklash(await tayyorla(asl)),
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['profil'] }),
onError: () => Alert.alert('Xato', "Rasmni yuklab bo'lmadi"),
});
async function tanla() {
const n = await ImagePicker.launchImageLibraryAsync({ mediaTypes: ['images'], allowsEditing: true, aspect: [1, 1], quality: 1 });
if (n.canceled) return;
setUri(n.assets[0].uri); // darhol ko'rsatish (optimistik)
yangila.mutate(n.assets[0].uri);
}
return (
<Pressable onPress={tanla} accessibilityLabel="Profil rasmini o'zgartirish">
<Image source={uri ? { uri } : require('@/assets/images/avatar.png')} style={{ width: 100, height: 100, borderRadius: 50 }} />
{yangila.isPending && (
<View style={[StyleSheet.absoluteFill, { borderRadius: 50, backgroundColor: 'rgba(0,0,0,0.4)', justifyContent: 'center' }]}>
<ActivityIndicator color="white" />
</View>
)}
</Pressable>
);
}
Nima uchun shunday?
Nima uchun rasmni serverda emas, telefonda kichraytirish kerak?
Chunki eng qimmat resurs — tarmoq. 6 MB ni yuklash — foydalanuvchi trafigi, vaqti va batareyasi; sekin tarmoqda esa yuklash umuman uzilishi mumkin. Telefon protsessori esa rasmni bir soniyadan kamroq vaqtda kichraytiradi. Server ham 6 MB lik fayllarni qabul qilishi, saqlashi va ishlashi shart emas. Mobil dasturlashning umumiy qoidasi: tarmoq orqali faqat kerakli narsani yuboring.
Xulosa
Eslab qoling:
launchImageLibraryAsync— galereya;launchCameraAsync— tizim kamerasiallowsEditing+aspect— kesish;canceledni tekshiring- Yuklashdan oldin —
expo-image-manipulatorbilan kichraytiring va siqing FormData+{ uri, name, type };Content-Typeni qo'lda yozmang- Katta fayllar — progress bilan; katta ilovalar — imzolangan URL orqali bulutga
- Optimistik ko'rsatish +
useMutation
Keyingi dars
41-dars: Joylashuv va xarita — expo-location, react-native-maps