تتيح الصور المصغّرة للوسائط للمستخدمين معاينة مرئية سريعة للصور والفيديوهات السماح بالتصفح بشكل أسرع مع جعل واجهة التطبيق أكثر وضوحًا جذابة وجذابة. بما أنّ الصور المصغّرة أصغر حجمًا من الوسائط ذات الحجم الكامل، فهي تساعد على توفير الذاكرة ومساحة التخزين ومعدل نقل البيانات مع تحسين أداء الوسائط أداء التصفّح
استنادًا إلى نوع الملف وإمكانية الوصول إلى الملف في تطبيقك ومواد عرض الوسائط، يمكنك إنشاء صور مصغّرة بطرق مختلفة.
إنشاء صورة مصغّرة باستخدام مكتبة لتحميل الصور
تتولّى مكتبات تحميل الصور إنجاز المهام الصعبة نيابةً عنك. يمكنه التعامل مع التخزين المؤقت إلى جانب المنطق لجلب وسائط المصدر من الشبكة المحلية أو الشبكة بناءً على Uri. توضح التعليمة البرمجية التالية استخدام تصلح مكتبة تحميل صور الملف لكل من الصور والفيديوهات، وتعمل على أحد الموارد المحلية أو الشبكة.
// Use Coil to create and display a thumbnail of a video or image with a specific height
// ImageLoader has its own memory and storage cache, and this one is configured to also
// load frames from videos
val videoEnabledLoader = ImageLoader.Builder(context)
.components {
add(VideoFrameDecoder.Factory())
}.build()
// Coil requests images that match the size of the AsyncImage composable, but this allows
// for precise control of the height
val request = ImageRequest.Builder(context)
.data(mediaUri)
.size(Int.MAX_VALUE, THUMBNAIL_HEIGHT)
.build()
AsyncImage(
model = request,
imageLoader = videoEnabledLoader,
modifier = Modifier
.clip(RoundedCornerShape(20)) ,
contentDescription = null
)
إنشاء صور مصغّرة من جهة الخادم، إن أمكن، اطّلِع على مقالة تحميل الصور لمعرفة التفاصيل حول كيفية تحميل الصور باستخدام أداة "الإنشاء"، وعلى مقالة تحميل ملفات بترميز bitmap كبيرة بكفاءة للحصول على إرشادات حول كيفية التعامل مع الصور الكبيرة.
إنشاء صورة مصغّرة من ملف صورة محلي
يتضمن الحصول على صور مصغّرة تقليل الحجم الفعال مع الحفاظ على العناصر المرئية الجودة، وتجنب الاستخدام المفرط للذاكرة، والتعامل مع مجموعة متنوعة من الصور والاستخدام الصحيح لبيانات Exif.
وتنفّذ الطريقة createImageThumbnail
كل هذا، وتوفر لك
الوصول إلى مسار ملف الصورة.
val bitmap = ThumbnailUtils.createImageThumbnail(File(file_path), Size(640, 480), null)
إذا كان لديك Uri
فقط، يمكنك استخدام الطريقة loadThumbnail
في
ContentLearnr بدءًا من Android 10، المستوى 29 من واجهة برمجة التطبيقات
val thumbnail: Bitmap =
applicationContext.contentResolver.loadThumbnail(
content-uri, Size(640, 480), null)
يتضمن ImageDecoder، المتاح بدءًا من Android 9، والمستوى 28 من واجهة برمجة التطبيقات، بعض خيارات قوية لإعادة تشكيل الصورة أثناء فك ترميزها لتجنّب زيادة الذاكرة استخدامها.
class DecodeResampler(val size: Size, val signal: CancellationSignal?) : OnHeaderDecodedListener {
private val size: Size
override fun onHeaderDecoded(decoder: ImageDecoder, info: ImageInfo, source:
// sample down if needed.
val widthSample = info.size.width / size.width
val heightSample = info.size.height / size.height
val sample = min(widthSample, heightSample)
if (sample > 1) {
decoder.setTargetSampleSize(sample)
}
}
}
val resampler = DecoderResampler(size, null)
val source = ImageDecoder.createSource(context.contentResolver, imageUri)
val bitmap = ImageDecoder.decodeBitmap(source, resampler);
ويمكنك استخدام Bitmapfactor لإنشاء صور مصغّرة للتطبيقات التي تستهدف العملاء في مرحلة مبكرة. إصدارات Android يحتوي BitmapFactory.Options على إعداد لفك ترميز حدود الصورة فقط بغرض إعادة أخذ عيّنات منها.
أولاً، يجب فك ترميز حدود الصورة النقطية فقط في BitmapFactory.Options
:
private fun decodeResizedBitmap(context: Context, uri: Uri, size: Size): Bitmap?{
val boundsStream = context.contentResolver.openInputStream(uri)
val options = BitmapFactory.Options()
options.inJustDecodeBounds = true
BitmapFactory.decodeStream(boundsStream, null, options)
boundsStream?.close()
استخدِم width
وheight
من BitmapFactory.Options
لإعداد العيّنة.
الحجم:
if ( options.outHeight != 0 ) {
// we've got bounds
val widthSample = options.outWidth / size.width
val heightSample = options.outHeight / size.height
val sample = min(widthSample, heightSample)
if (sample > 1) {
options.inSampleSize = sample
}
}
فك ترميز مجموعة البث. يتم أخذ عينات من حجم الصورة الناتجة عن طريق قوى أُسس
استنادًا إلى inSampleSize
.
options.inJustDecodeBounds = false
val decodeStream = context.contentResolver.openInputStream(uri)
val bitmap = BitmapFactory.decodeStream(decodeStream, null, options)
decodeStream?.close()
return bitmap
}
إنشاء صورة مصغّرة من ملف فيديو محلي
يتضمن الحصول على صور مصغّرة للفيديو العديد من التحديات نفسها كما في الحصول على صور مصغرة، ولكن حجم الملفات يمكن أن يكون أكبر بكثير لا يكون إطار الفيديو التمثيلي واضحًا دائمًا مثل اختيار أول إطار الفيديو.
تُعد طريقة createVideoThumbnail
خيارًا قويًا إذا كان بإمكانك الوصول إلى
مسار ملف الفيديو.
val bitmap = ThumbnailUtils.createVideoThumbnail(File(file_path), Size(640, 480), null)
إذا كان بإمكانك الوصول إلى محتوى معرف موارد منتظم (Uri) فقط، يمكنك استخدام
MediaMetadataRetriever
تأكَّد أولاً من أنّ الفيديو يحتوي على صورة مصغّرة مضمّنة، واستخدِمها إذا كان ممكن:
private suspend fun getVideoThumbnailFromMediaMetadataRetriever(context: Context, uri: Uri, size: Size): Bitmap? {
val mediaMetadataRetriever = MediaMetadataRetriever()
mediaMetadataRetriever.setDataSource(context, uri)
val thumbnailBytes = mediaMetadataRetriever.embeddedPicture
val resizer = Resizer(size, null)
ImageDecoder.createSource(context.contentResolver, uri)
// use a built-in thumbnail if the media file has it
thumbnailBytes?.let {
return ImageDecoder.decodeBitmap(ImageDecoder.createSource(it));
}
جلب عرض الفيديو وارتفاعه من MediaMetadataRetriever
إلى
حساب عامل القياس:
val width = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH)
?.toFloat() ?: size.width.toFloat()
val height = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT)
?.toFloat() ?: size.height.toFloat()
val widthRatio = size.width.toFloat() / width
val heightRatio = size.height.toFloat() / height
val ratio = max(widthRatio, heightRatio)
في الإصدار 9 من نظام التشغيل Android والإصدارات الأحدث (المستوى 28 من واجهة برمجة التطبيقات)، يمكن أن يعرض MediaMetadataRetriever
إطارًا مكبَّرًا:
if (ratio > 1) {
val requestedWidth = width * ratio
val requestedHeight = height * ratio
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
val frame = mediaMetadataRetriever.getScaledFrameAtTime(
-1, OPTION_PREVIOUS_SYNC,
requestedWidth.toInt(), requestedHeight.toInt())
mediaMetadataRetriever.close()
return frame
}
}
بخلاف ذلك، يمكنك إرجاع الإطار الأول بدون قياس:
// consider scaling this after the fact
val frame = mediaMetadataRetriever.frameAtTime
mediaMetadataRetriever.close()
return frame
}