मीडिया थंबनेल जनरेट करना

मीडिया थंबनेल, लोगों को इमेज और वीडियो की झलक तुरंत दिखाता है. इससे ऐप्लिकेशन के इंटरफ़ेस को बेहतर तरीके से दिखाने के साथ-साथ, तेज़ी से ब्राउज़ करने की सुविधा मिलती है आकर्षक और दिलचस्प कॉन्टेंट बनाएं. थंबनेल, फ़ुल साइज़ के मीडिया से छोटे होते हैं. इसलिए, इनसे मेमोरी, स्टोरेज, और बैंडविथ बचती है. साथ ही, मीडिया ब्राउज़ करने की परफ़ॉर्मेंस भी बेहतर होती है.

फ़ाइल टाइप और आपके ऐप्लिकेशन और मीडिया एसेट में फ़ाइल के ऐक्सेस के आधार पर, अलग-अलग तरीकों से थंबनेल बनाए जा सकते हैं.

इमेज लोड करने वाली लाइब्रेरी का इस्तेमाल करके थंबनेल बनाएं

इमेज लोड करने वाली लाइब्रेरी का काम बहुत आसान कर दिया जाता है; वे हैंडल कर सकते हैं लोकल या नेटवर्क से सोर्स मीडिया को फ़ेच करने के लिए लॉजिक के साथ कैश मेमोरी में सेव करना जो 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
)

अगर मुमकिन हो, तो सर्वर साइड पर थंबनेल बनाएं. इमेज लोड करना देखें देखें कि कैसे लिखें और बड़े बिटमैप लोड करके इमेज कैसे लोड करें साथ ही, बड़ी इमेज के साथ काम करने का तरीका भी जानें.

लोकल इमेज फ़ाइल से थंबनेल बनाना

थंबनेल इमेज पाने के लिए, इमेज को डाउनस्केल किया जाता है और विज़ुअल को सुरक्षित रखा जाता है क्वालिटी, मेमोरी के ज़्यादा इस्तेमाल से बचने, और अलग-अलग तरह की इमेज इस्तेमाल करने से रोकना फ़ॉर्मैट करने और Exif डेटा का सही इस्तेमाल करने के लिए किया जा सकता है.

createImageThumbnail तरीका, इन सभी कामों को करता है. हालांकि, इसके लिए ज़रूरी है कि आपके पास इमेज फ़ाइल के पाथ का ऐक्सेस हो.

val bitmap = ThumbnailUtils.createImageThumbnail(File(file_path), Size(640, 480), null)

अगर आपके पास सिर्फ़ Uri है, तो loadThumbnail का इस्तेमाल Android 10 और एपीआई लेवल 29 से शुरू होने वाला Content Solutionsr.

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);

BitmapFactory का इस्तेमाल करके, Android के पुराने वर्शन को टारगेट करने वाले ऐप्लिकेशन के लिए थंबनेल बनाए जा सकते हैं. BitmapFunction.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()

सैंपल साइज़ सेट करने के लिए, BitmapFactory.Options में मौजूद width और height का इस्तेमाल करें:

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)

अगर आपके पास सिर्फ़ कॉन्टेंट के यूआरआई का ऐक्सेस है, तो 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)

Android 9 और उसके बाद के वर्शन (एपीआई लेवल 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
}