---
metadata:
  - name: generator
    content: Diplodoc Platform v5.70.0
alternate:
  - https://divkit.tech/docs/en/quickstart/resources.md
  - https://divkit.tech/docs/ru/quickstart/resources.md
  - href: https://divkit.tech/docs/en/quickstart/resources.md
    type: text/markdown
    title: Markdown version
  - href: https://divkit.tech/docs/en/llms.txt?revision=r22102947
    rel: describedby
---
> **Documentation Index:** Fetch the complete configuration index at https://divkit.tech/docs/en/llms.txt?revision=r22102947

# Resources: fonts, images, and video

A card only refers to fonts, images, and video, while the app loads and shows them. This page describes what you need to connect on each platform for that. Element properties are described in [Custom fonts](https://divkit.tech/docs/en/concepts/custom-fonts.md), [Images](https://divkit.tech/docs/en/concepts/image.md), and [Video](https://divkit.tech/docs/en/concepts/video.md).

## Fonts {#fonts}

The app maps the font name from the `font_family` parameter to a specific font. To do this, each platform implements a font provider that is passed to DivKit during initialization.

### Android {#fonts-android}

On the Android platform, to use custom fonts, you need to implement the `DivTypefaceProvider` interface.

#### DivTypefaceProvider Implementation

```java
import android.content.Context;
import android.graphics.Typeface;
import androidx.annotation.Nullable;
import com.yandex.div.core.font.DivTypefaceProvider;

public class CustomTypefaceProvider implements DivTypefaceProvider {
    private final Context context;

    // Cache fonts to improve performance
    private Typeface regularTypeface;
    private Typeface mediumTypeface;
    private Typeface lightTypeface;
    private Typeface boldTypeface;

    public CustomTypefaceProvider(Context context) {
        this.context = context;
    }

    @Nullable
    @Override
    public Typeface getRegular() {
        if (regularTypeface == null) {
            regularTypeface = Typeface.createFromAsset(context.getAssets(), "fonts/MyFont-Regular.ttf");
        }
        return regularTypeface;
    }

    @Nullable
    @Override
    public Typeface getMedium() {
        if (mediumTypeface == null) {
            mediumTypeface = Typeface.createFromAsset(context.getAssets(), "fonts/MyFont-Medium.ttf");
        }
        return mediumTypeface;
    }

    @Nullable
    @Override
    public Typeface getLight() {
        if (lightTypeface == null) {
            lightTypeface = Typeface.createFromAsset(context.getAssets(), "fonts/MyFont-Light.ttf");
        }
        return lightTypeface;
    }

    @Nullable
    @Override
    public Typeface getBold() {
        if (boldTypeface == null) {
            boldTypeface = Typeface.createFromAsset(context.getAssets(), "fonts/MyFont-Bold.ttf");
        }
        return boldTypeface;
    }

    // Optional: override the getTypefaceFor method for more precise control
    // over font weight matching
    @Nullable
    @Override
    public Typeface getTypefaceFor(int weight) {
        if (weight >= 0 && weight < 350) {
            return getLight();
        } else if (weight >= 350 && weight < 450) {
            return getRegular();
        } else if (weight >= 450 && weight < 650) {
            return getMedium();
        } else {
            return getBold();
        }
    }
}
```

#### Integration into Application

```java
import com.yandex.div.core.Div2Context;
import com.yandex.div.core.DivConfiguration;
import java.util.Collections;

// When initializing DivKit: activity is your Activity, imageLoader is a DivImageLoader implementation
DivConfiguration configuration = new DivConfiguration.Builder(imageLoader)
    // Default font: for text without font_family and for unknown names
    .typefaceProvider(new CustomTypefaceProvider(activity))
    // Fonts that are selected by the name from font_family
    .additionalTypefaceProviders(
        Collections.singletonMap("MyCustomFont", new CustomTypefaceProvider(activity))
    )
    // other settings
    .build();

Div2Context div2Context = new Div2Context(
    activity,
    configuration
);
```

### iOS {#fonts-ios}

On the iOS platform, to use custom fonts, you need to implement the `DivFontProvider` protocol.

#### Adding Fonts to the Project

1. Add font files (.ttf or .otf) to your project
2. Make sure the fonts are included in the application resources (Bundle Resources)
3. Add font information to Info.plist in the `Fonts provided by application` section:

```xml
<key>UIAppFonts</key>
<array>
    <string>MyFont-Regular.ttf</string>
    <string>MyFont-Medium.ttf</string>
    <string>MyFont-Light.ttf</string>
    <string>MyFont-Bold.ttf</string>
</array>
```

#### DivFontProvider Implementation

```swift
import UIKit
import DivKit
import VGSL

class CustomFontProvider: DivFontProvider {
    func font(family: String, weight: DivFontWeight, size: CGFloat) -> Font {
        // If a specific font family is specified
        if family == "MyCustomFont" {
            let fontName: String
            switch weight {
            case .light:
                fontName = "MyFont-Light"
            case .regular:
                fontName = "MyFont-Regular"
            case .medium:
                fontName = "MyFont-Medium"
            case .bold:
                fontName = "MyFont-Bold"
            }

            if let font = UIFont(name: fontName, size: size) {
                return Font(uiFont: font)
            }
        }

        // Return system font if custom font is not found
        let uiFont: UIFont
        switch weight {
        case .light:
            uiFont = UIFont.systemFont(ofSize: size, weight: .light)
        case .regular:
            uiFont = UIFont.systemFont(ofSize: size, weight: .regular)
        case .medium:
            uiFont = UIFont.systemFont(ofSize: size, weight: .medium)
        case .bold:
            uiFont = UIFont.systemFont(ofSize: size, weight: .bold)
        }

        return Font(uiFont: uiFont)
    }

    // The method for getting a font by numerical weight is already implemented in the protocol extension
}
```

#### Integration into Application

```swift
import DivKit

// When initializing DivKit
let components = DivKitComponents(
    divCustomBlockFactory: nil,
    fontProvider: CustomFontProvider(),
    // other parameters
)
```

### Web {#fonts-web}

On the Web platform, to use custom fonts, you need to:

1. Connect fonts using standard CSS methods (via `@font-face` or external services)
2. Use the `typefaceProvider` parameter when initializing DivKit

#### Connecting Fonts via CSS

The font family in CSS does not have to match the name in JSON.

Don't forget to provide all the styles and weights options that you will need in your markup (in this example, 400, 500, and 700 are added). Another option is to use variable fonts.

```css
@font-face {
  font-family: 'MyCustomFont';
  src: url('fonts/MyFont-Regular.woff2') format('woff2'),
       url('fonts/MyFont-Regular.woff') format('woff');
  font-weight: 400;
  font-style: normal;
}

@font-face {
  font-family: 'MyCustomFont';
  src: url('fonts/MyFont-Medium.woff2') format('woff2'),
       url('fonts/MyFont-Medium.woff') format('woff');
  font-weight: 500;
  font-style: normal;
}

@font-face {
  font-family: 'MyCustomFont';
  src: url('fonts/MyFont-Bold.woff2') format('woff2'),
       url('fonts/MyFont-Bold.woff') format('woff');
  font-weight: 700;
  font-style: normal;
}
```

#### Using typefaceProvider

```javascript
import { render } from '@divkitframework/divkit/client';

render({
    id: 'my-divkit-container',
    target: document.querySelector('#root'),
    json: {
        card: {
            log_id: 'custom_fonts_example',
            states: [{
                state_id: 0,
                div: {
                    type: 'text',
                    font_family: 'MyCustomFont',
                    font_weight_value: 500,
                    text: 'Text with custom font'
                }
            }]
        }
    },
    typefaceProvider: (fontFamily, opts) => {
        // You can implement mapping of font names from JSON to CSS
        if (fontFamily === 'MyCustomFont') {
            return 'MyCustomFont, sans-serif';
        }

        // For the default option, you can return an empty string.
        return '';
    }
});
```

### Recommendations {#fonts-recommendations}

1. **Performance Optimization**: Cache font instances to avoid reloading.
2. **Support for Different Weights**: Implement support for different font weights to ensure design flexibility.
3. **Fallback Options**: Always provide fallback font options in case the custom font fails to load.
4. **Font Preloading**: For the web platform, it is recommended to preload fonts to avoid text flickering when the page loads.
5. **Testing**: Check font rendering on various devices and under different conditions to ensure correct display.

## Images {#images}

Images are loaded by the app: on Android you connect an image loader for that, and on iOS local images are taken from the app bundle.

### iOS {#images-ios}

On iOS, to restrict access to resources, all divkit asset images must start with the 'divkit.' prefix. For example, if you use `"image_url": "divkit-asset://image.png"`, the image must be named `divkit.image.png` in your app's main bundle.

#### Multiple bundle support

iOS supports specifying a specific bundle for loading images using the `bundle` parameter in the URL:

```json
{
  "type": "image",
  "image_url": "divkit-asset://image.png?bundle=com.example.app"
}
```

This feature is useful in modular architectures or when using multiple bundles in an application. On Android, the `bundle` parameter is ignored.

### Android {#images-android}

#### Image loader support

DivKit for Android supports popular image loading libraries:

- **Coil** - modern image loader for Kotlin
- **Glide** - traditional image loader

Both loaders support all image formats and effects, including animated WebP and GIF.

#### Bitmap size limitation {#bitmap-size-limit}

To prevent crashes when loading large images and GIF files, DivKit automatically limits the bitmap size. This feature is enabled by default and helps avoid memory issues on devices.

**How the limitation works:**

- The maximum bitmap size is determined by the maximum screen resolution of the device
- Images exceeding this size are automatically scaled down
- For SVG images, a separate limitation mechanism is applied
- The feature is supported by the `CoilDivImageLoader` and `GlideDivImageLoader` loaders

**Configuring the limitation:**

Bitmap size limitation is enabled by default. If you need to disable this feature (for example, when working with very large images), you can configure it in the image loader implementation:

```kotlin
// Example for CoilDivImageLoader
val imageLoader = CoilDivImageLoader(
    context = context,
    limitImageBitmapSizeEnabled = false // Disable limitation
)
```

{% note warning %}

Disabling bitmap size limitation may lead to application crashes when working with very large images. Use this setting with caution.

{% endnote %}

## Video {#video}

With DivKit, you can use a standard player or your own one. The latter comes in handy, for example, when you want to play videos in a format that's not supported by the standard player.

### Standard player {#video-default}

By default, DivKit uses a standard player for all platforms except Android, where you need to connect the player explicitly.

#### Android

DivKit uses ExoPlayer as a standard player for Android.

Because ExoPlayer initialization is a <q>heavy</q> operation, the player is only connected when you explicitly specify it in the `DivConfiguration` class. If you don't plan to use a video player in your app, don't call the `.divPlayerFactory` method in the `DivConfiguration` class builder.

To work with the standard player, pass `ExoDivPlayerFactory` from the `com.yandex.div.video.m3` package (`div-video-m3` module) to the `DivConfiguration` builder as a `.divPlayerFactory()` method argument.

The `DivConfiguration` class for supporting video will generally look like this:

```translate=no
DivConfiguration.Builder(imageLoader)
    .divPlayerFactory(ExoDivPlayerFactory(context))
    .build()
```

If you don't connect the player in the `DivConfiguration` class, there will be an empty block in place of and the same size as the player when rendering the screen with the `video` element.

#### Other platforms

On iOS and Web, you don't need to connect the standard player: when a `video` element is created, the platform-standard video player is used.

### Custom player support {#video-custom}

Your own video player is connected differently on each platform:

- Android: a factory that implements the `DivPlayerFactory` interface is passed to the `.divPlayerFactory()` method of the `DivConfiguration` builder. The details are given below.
- iOS: a factory that implements the `PlayerFactory` protocol is passed to `DivKitComponents` in the `playerFactory` parameter.
- Web: a player provider is passed to the `render` function in the `videoPlayerProvider` parameter, see [Parameters of the render function](https://divkit.tech/docs/en/quickstart/web.md#render-params).

#### Android {#video-custom-android}

To connect your own video player to DivKit, create a factory that provides a player and a view for it at the request of the DivKit app. The factory must implement the `DivPlayerFactory` interface.

The video player created by the factory must implement the `DivPlayer` interface and thus be a proxy for calls from DivKit. When implementing a custom player, note that JSON object properties (such as `player_settings_payload`) may contain [expressions](https://divkit.tech/docs/en/concepts/expressions.md) that need to be processed using `expressionResolver`.

{% note info %}

When `player_settings_payload` changes while the app is running, DivKit will automatically call the `setSource` method with updated settings. Make sure your custom player correctly handles dynamic playback settings updates.

{% endnote %}

To take one example, here's how `DivPlayer` methods for `ExoPlayer` are implemented in Kotlin.

{% cut "See sample code" %}


```kotlin translate=no
val player: ExoPlayer by lazy {
     ExoPlayer.Builder(context).build()
     }

     override fun play() {
     player.play()
     }

     override fun pause() {
     player.pause()
     }

     override fun seek(toMs: Long) {
     player.seekTo(toMs)
     }

     override fun setSource(sourceVariants: List<DivVideoSource>, config: DivPlayerPlaybackConfig) {
     val mediaSource = sourceVariants.toMediaSource()

     player.setMediaSource(mediaSource)
     player.prepare()
     }

     override fun release() {
     player.release()
     }
```


{% endcut %}

<!-- source: en/_includes/index/troubleshooting.md -->
## Learn more {#troubleshooting}

You can discuss topics of interest in the DivKit user community in Telegram: [https://t.me/divkit_community_en](https://t.me/divkit_community_en).



[DivKit Repository](https://github.com/divkit/divkit)
<!-- endsource: en/_includes/index/troubleshooting.md -->
