> ## Documentation Index
> This page is part of the Image and Video APIs product. Fetch the complete documentation index for Image and Video APIs at: https://cloudinary.com/documentation/llms-image-and-video-apis.txt?referrer=docpage and then use it to discover all relevant pages before exploring further.
> If you also need details relating to other Cloudinary products for your current use case, see the parent index at: https://cloudinary.com/documentation/llms.txt?referrer=docpage

# Text, contrast, and color



Ensuring text and visual elements are readable and distinguishable is central to visual accessibility. This page covers caption styling, text overlays, contrast and brightness adjustments, color replacement for light and dark themes, customizable text overlay parameters, and OCR text extraction.

> **See also:**:
>
> * [Color accessibility](accessible_media_visual_audio_clarity#assist_people_with_color_blind_conditions): Simulate and assist color blind conditions, analyze color accessibility, and replace colors for light and dark themes.

> * [Audio controls and mixing](accessible_media_visual_audio_clarity_audio): Adjust audio volume programmatically, use Video Player volume controls, and mix audio tracks to meet WCAG requirements.

## Customizable caption styling

Captions and subtitles must meet specific contrast requirements to be accessible to people with visual impairments. The WCAG guidelines specify minimum contrast ratios between text and background colors to ensure readability.

### Understanding contrast ratios

A **contrast ratio** measures the difference in brightness between text and its background, expressed as a ratio like 4.5:1 or 7:1. The higher the number, the more contrast there is.

**WCAG Requirements:**

- **Level AA (minimum)**: 4.5:1 contrast ratio for normal text
- **Level AAA (enhanced)**: 7:1 contrast ratio for normal text  
- **Large text** (18pt+ or 14pt+ bold): Lower ratios of 3:1 (AA) or 4.5:1 (AAA)

### How to measure contrast ratios

You can measure contrast ratios using online tools such as [WebAIM Contrast Checker](https://webaim.org/resources/contrastchecker/).

**How it works:**

1. **Pick your colors**: Select the text color and background color
2. **Get the ratio**: The tool calculates the mathematical contrast ratio
3. **Check compliance**: See if it meets WCAG AA (4.5:1) or AAA (7:1) standards

**Example measurements:**

* Black text (#000000) on white background (#FFFFFF) = **21:1** (excellent)
* White text (#FFFFFF) on blue background (#0066CC) = **5.74:1** (passes AA)
* Light gray text (#CCCCCC) on white background (#FFFFFF) = **1.61:1** (fails - too low)

### Implementing accessible caption styling

The Cloudinary Video Player allows you to customize caption appearance to meet contrast requirements. The recommended approach is to use the built-in `theme` options which provide predefined backgrounds and styling.

The built-in themes are described in this table:

| Theme | Description | Best for |
|-------|------------|----------|
| `default` | None | High contrast videos only |
| `videojs-default` | High contrast theme with a dark background and white text | General accessibility |
| `yellow-outlined` | Yellow text with a dark outline for visibility | Videos with varied backgrounds |
| `player-colors` | Uses the video player's custom color scheme for the text and background | Brand consistency + accessibility |
| `3d` | Text with a 3D shadow effect | Stylistic preference |

The example at the top of this section uses the `videojs-default` theme. Note that you can also override elements of the theme, for example, by setting the font size.  Here's the Video Player configuration:

```js
const highContrastPlayer = cloudinary.videoPlayer('high-contrast-player', {
  cloudName: 'demo'
});

highContrastPlayer.source('outdoors', {
  textTracks: { 
    captions: { 
      label: 'English (Captions)',
      default: true,
      url: 'https://res.cloudinary.com/demo/raw/upload/outdoors.vtt'
    },
    options: {
      box: {
        x: '10%',
        y: '300%',
        width: '80%',
        height: '20%'
      },
      theme: 'videojs-default',
      fontSize: '16px',
      fontFace: 'Arial, sans-serif'
    }
  }
});
```

To set custom colors for the font and background you can use the `player-colors` theme. This theme uses the colors that you configure when customizing your Video Player. 

```js
  colors: {
    base: '#000000',    // Black background for controls
    text: '#ffffff',    // White text for controls and captions
    accent: '#0066cc'   // Blue accent color - also controls the background for captions
  }
```

```js
const customColorsPlayer = cloudinary.videoPlayer('custom-colors-player', {
  cloudName: 'demo',
  colors: {
    base: '#000000',    // Black background for controls
    text: '#ffffff',    // White text
    accent: '#0066cc'   // Blue accent color - also controls the background for captions
  }
});

customColorsPlayer.source('outdoors', {
  textTracks: { 
    captions: { 
      label: 'English (Captions)',
      default: true,
      url: 'https://res.cloudinary.com/demo/raw/upload/outdoors.vtt'
    },
    options: {
      box: {
        x: '10%',
        y: '300%',
        width: '80%',
        height: '20%'
      },
      theme: 'player-colors',
      fontSize: '16px',
      fontFace: 'Arial, sans-serif'
    }
  }
});
```

> **READING**:
>
> * Docs: [Customizable caption styling](video_player_customization#visual_customization)

## Text overlays on images and videos

Before creating text overlays embedded in images or videos, consider whether the text could instead be placed in your HTML and visually positioned over the media using CSS. HTML text is inherently more accessible because it can be announced by screen readers, restyled by users, translated automatically, and scales with user preferences—all without requiring additional accessibility techniques.

When you do need embedded text overlays in images and videos, it's crucial to ensure sufficient contrast between the text and background for readability. People with visual impairments or those viewing content in bright environments need clear, high-contrast text. Adding background colors or effects to text overlays helps meet WCAG contrast requirements and improves accessibility for everyone.

### Text overlays on images with background

Without proper [contrast](#understanding_contrast_ratios), text overlays can be difficult or impossible to read. Here's how to add accessible text overlays with background colors:

Poor contrast - hard to read

High contrast - accessible

The accessible version uses a semi transparent black background (`b_rgb:00000080`) behind white text (`co_white`) to achieve maximum contrast:

![Image with accessible text overlay](https://res.cloudinary.com/demo/image/upload/l_text:Arial_300:%20Accessible%20Text%20,co_white,b_rgb:00000080/fl_layer_apply,g_center,y_200/docs/white-church-europe-sea.jpg "with_image:false")

```nodejs
cloudinary.image("docs/white-church-europe-sea.jpg", {transformation: [
  {overlay: {font_family: "Arial", font_size: 300, text: "%20Accessible%20Text%20"}, color: "white", background: "#00000080"},
  {flags: "layer_apply", gravity: "center", y: 200}
  ]})
```

```react
import { source } from "@cloudinary/url-gen/actions/overlay";
import { text } from "@cloudinary/url-gen/qualifiers/source";
import { Position } from "@cloudinary/url-gen/qualifiers/position";
import { TextStyle } from "@cloudinary/url-gen/qualifiers/textStyle";
import { compass } from "@cloudinary/url-gen/qualifiers/gravity";

new CloudinaryImage("docs/white-church-europe-sea.jpg").overlay(
  source(
    text(" Accessible Text ", new TextStyle("Arial", 300))
      .textColor("white")
      .backgroundColor("#00000080")
  ).position(
    new Position()
      .gravity(compass("center"))
      .offsetY(200)
  )
);
```

```vue
import { source } from "@cloudinary/url-gen/actions/overlay";
import { text } from "@cloudinary/url-gen/qualifiers/source";
import { Position } from "@cloudinary/url-gen/qualifiers/position";
import { TextStyle } from "@cloudinary/url-gen/qualifiers/textStyle";
import { compass } from "@cloudinary/url-gen/qualifiers/gravity";

new CloudinaryImage("docs/white-church-europe-sea.jpg").overlay(
  source(
    text(" Accessible Text ", new TextStyle("Arial", 300))
      .textColor("white")
      .backgroundColor("#00000080")
  ).position(
    new Position()
      .gravity(compass("center"))
      .offsetY(200)
  )
);
```

```angular
import { source } from "@cloudinary/url-gen/actions/overlay";
import { text } from "@cloudinary/url-gen/qualifiers/source";
import { Position } from "@cloudinary/url-gen/qualifiers/position";
import { TextStyle } from "@cloudinary/url-gen/qualifiers/textStyle";
import { compass } from "@cloudinary/url-gen/qualifiers/gravity";

new CloudinaryImage("docs/white-church-europe-sea.jpg").overlay(
  source(
    text(" Accessible Text ", new TextStyle("Arial", 300))
      .textColor("white")
      .backgroundColor("#00000080")
  ).position(
    new Position()
      .gravity(compass("center"))
      .offsetY(200)
  )
);
```

```js
import { source } from "@cloudinary/url-gen/actions/overlay";
import { text } from "@cloudinary/url-gen/qualifiers/source";
import { Position } from "@cloudinary/url-gen/qualifiers/position";
import { TextStyle } from "@cloudinary/url-gen/qualifiers/textStyle";
import { compass } from "@cloudinary/url-gen/qualifiers/gravity";

new CloudinaryImage("docs/white-church-europe-sea.jpg").overlay(
  source(
    text(" Accessible Text ", new TextStyle("Arial", 300))
      .textColor("white")
      .backgroundColor("#00000080")
  ).position(
    new Position()
      .gravity(compass("center"))
      .offsetY(200)
  )
);
```

```python
CloudinaryImage("docs/white-church-europe-sea.jpg").image(transformation=[
  {'overlay': {'font_family': "Arial", 'font_size': 300, 'text': "%20Accessible%20Text%20"}, 'color': "white", 'background': "#00000080"},
  {'flags': "layer_apply", 'gravity': "center", 'y': 200}
  ])
```

```php
use Cloudinary\Transformation\Overlay;
use Cloudinary\Transformation\Source;
use Cloudinary\Transformation\Position;
use Cloudinary\Transformation\TextStyle;
use Cloudinary\Transformation\Color;
use Cloudinary\Transformation\Gravity;
use Cloudinary\Transformation\Compass;

(new ImageTag('docs/white-church-europe-sea.jpg'))
	->overlay(Overlay::source(
	Source::text(" Accessible Text ",(new TextStyle("Arial",300)))
	->textColor(Color::WHITE)
	->backgroundColor(Color::rgb("00000080"))
	)
	->position((new Position())
	->gravity(
	Gravity::compass(
	Compass::center()))
->offsetY(200))
	);
```

```java
cloudinary.url().transformation(new Transformation()
  .overlay(new TextLayer().fontFamily("Arial").fontSize(300).text("%20Accessible%20Text%20")).color("white").background("#00000080").chain()
  .flags("layer_apply").gravity("center").y(200)).imageTag("docs/white-church-europe-sea.jpg");
```

```ruby
cl_image_tag("docs/white-church-europe-sea.jpg", transformation: [
  {overlay: {font_family: "Arial", font_size: 300, text: "%20Accessible%20Text%20"}, color: "white", background: "#00000080"},
  {flags: "layer_apply", gravity: "center", y: 200}
  ])
```

```csharp
cloudinary.Api.UrlImgUp.Transform(new Transformation()
  .Overlay(new TextLayer().FontFamily("Arial").FontSize(300).Text("%20Accessible%20Text%20")).Color("white").Background("#00000080").Chain()
  .Flags("layer_apply").Gravity("center").Y(200)).BuildImageTag("docs/white-church-europe-sea.jpg")
```

```dart
cloudinary.image('docs/white-church-europe-sea.jpg').transformation(Transformation()
	.addTransformation("l_text:Arial_300: Accessible Text ,co_white,b_rgb:00000080/fl_layer_apply,g_center,y_200"));
```

```swift
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation()
  .setOverlay("text:Arial_300:%20Accessible%20Text%20").setColor("white").setBackground("#00000080").chain()
  .setFlags("layer_apply").setGravity("center").setY(200)).generate("docs/white-church-europe-sea.jpg")!, cloudinary: cloudinary)
```

```android
MediaManager.get().url().transformation(new Transformation()
  .overlay(new TextLayer().fontFamily("Arial").fontSize(300).text("%20Accessible%20Text%20")).color("white").background("#00000080").chain()
  .flags("layer_apply").gravity("center").y(200)).generate("docs/white-church-europe-sea.jpg");
```

```flutter
cloudinary.image('docs/white-church-europe-sea.jpg').transformation(Transformation()
	.addTransformation("l_text:Arial_300: Accessible Text ,co_white,b_rgb:00000080/fl_layer_apply,g_center,y_200"));
```

```kotlin
cloudinary.image {
	publicId("docs/white-church-europe-sea.jpg")
	 overlay(Overlay.source(
	Source.text(" Accessible Text ",TextStyle("Arial",300)) {
	 textColor(Color.WHITE)
	 backgroundColor(Color.rgb("00000080"))
	 }) {
	 position(Position() {
	 gravity(
	Gravity.compass(
	Compass.center()))
 offsetY(200) })
	 }) 
}.generate()
```

```jquery
$.cloudinary.image("docs/white-church-europe-sea.jpg", {transformation: [
  {overlay: new cloudinary.TextLayer().fontFamily("Arial").fontSize(300).text("%20Accessible%20Text%20"), color: "white", background: "#00000080"},
  {flags: "layer_apply", gravity: "center", y: 200}
  ]})
```

```react_native
import { source } from "@cloudinary/url-gen/actions/overlay";
import { text } from "@cloudinary/url-gen/qualifiers/source";
import { Position } from "@cloudinary/url-gen/qualifiers/position";
import { TextStyle } from "@cloudinary/url-gen/qualifiers/textStyle";
import { compass } from "@cloudinary/url-gen/qualifiers/gravity";

new CloudinaryImage("docs/white-church-europe-sea.jpg").overlay(
  source(
    text(" Accessible Text ", new TextStyle("Arial", 300))
      .textColor("white")
      .backgroundColor("#00000080")
  ).position(
    new Position()
      .gravity(compass("center"))
      .offsetY(200)
  )
);
```

### Text overlays on videos with background

Video text overlays face additional challenges as backgrounds change throughout the video. Consistent background colors ensure text remains readable regardless of the video content. This video uses white text (`co_white`) on a semi-transparent blue background (`b_rgb:0000cc90`) to create an overlay that remains visible throughout the video.

> **READING**:
>
> * Docs: [Text overlays on images](image_text_layers#text_layer_options)

> * Docs: [Text overlays on videos](video_text_layers#text_layer_options)

## Adjust contrast on images and videos

Proper contrast, brightness, and saturation adjustments are essential for making images and videos accessible to people with visual impairments, low vision, or those viewing content in challenging lighting conditions. These adjustments can help ensure content remains visible and legible across different viewing environments and for users with varying visual needs.

### Contrast adjustments for images

Contrast adjustments can dramatically improve the readability and accessibility of images. Here are examples showing how different contrast levels affect image visibility:

Low contrast(-80)

Original(0)

High contrast(+80)

Use the [contrast effect](transformation_reference#e_contrast) with a value between -100 and 100:

![Image with high contrast](https://res.cloudinary.com/demo/image/upload/e_contrast:80/docs/apartment-kitchen.jpg "with_image:false")

```nodejs
cloudinary.image("docs/apartment-kitchen.jpg", {effect: "contrast:80"})
```

```react
import { contrast } from "@cloudinary/url-gen/actions/adjust";

new CloudinaryImage("docs/apartment-kitchen.jpg").adjust(contrast().level(80));
```

```vue
import { contrast } from "@cloudinary/url-gen/actions/adjust";

new CloudinaryImage("docs/apartment-kitchen.jpg").adjust(contrast().level(80));
```

```angular
import { contrast } from "@cloudinary/url-gen/actions/adjust";

new CloudinaryImage("docs/apartment-kitchen.jpg").adjust(contrast().level(80));
```

```js
import { contrast } from "@cloudinary/url-gen/actions/adjust";

new CloudinaryImage("docs/apartment-kitchen.jpg").adjust(contrast().level(80));
```

```python
CloudinaryImage("docs/apartment-kitchen.jpg").image(effect="contrast:80")
```

```php
use Cloudinary\Transformation\Adjust;

(new ImageTag('docs/apartment-kitchen.jpg'))
	->adjust(Adjust::contrast()->level(80));
```

```java
cloudinary.url().transformation(new Transformation().effect("contrast:80")).imageTag("docs/apartment-kitchen.jpg");
```

```ruby
cl_image_tag("docs/apartment-kitchen.jpg", effect: "contrast:80")
```

```csharp
cloudinary.Api.UrlImgUp.Transform(new Transformation().Effect("contrast:80")).BuildImageTag("docs/apartment-kitchen.jpg")
```

```dart
cloudinary.image('docs/apartment-kitchen.jpg').transformation(Transformation()
	.adjust(Adjust.contrast().level(80)));
```

```swift
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation().setEffect("contrast:80")).generate("docs/apartment-kitchen.jpg")!, cloudinary: cloudinary)
```

```android
MediaManager.get().url().transformation(new Transformation().effect("contrast:80")).generate("docs/apartment-kitchen.jpg");
```

```flutter
cloudinary.image('docs/apartment-kitchen.jpg').transformation(Transformation()
	.adjust(Adjust.contrast().level(80)));
```

```kotlin
cloudinary.image {
	publicId("docs/apartment-kitchen.jpg")
	 adjust(Adjust.contrast() { level(80) }) 
}.generate()
```

```jquery
$.cloudinary.image("docs/apartment-kitchen.jpg", {effect: "contrast:80"})
```

```react_native
import { contrast } from "@cloudinary/url-gen/actions/adjust";

new CloudinaryImage("docs/apartment-kitchen.jpg").adjust(contrast().level(80));
```

### Interactive contrast, brightness, and saturation demo

In addition to contrast, you can also alter [brightness](transformation_reference#e_brightness) and [saturation](transformation_reference#e_saturation) to help improve image visibility. 

Use the controls below to see how contrast, brightness, and saturation adjustments affect image accessibility in real-time. Notice how the transformation URL changes as you adjust the settings:

  
    Contrast: 0
    
  
  
  
    Brightness: 0
    
  
  
  
    Saturation: 0
    
  
  
  Reset to Original

  Current transformation URL:
  https://res.cloudinary.com/demo/image/upload/c_scale,w_500/f_auto/q_auto/docs/groceryshop.jpg

### Video visual adjustments

Video content can also benefit from contrast, brightness, and saturation adjustments. These are especially important for users with visual impairments who may struggle with low-contrast video content.

This video uses enhanced contrast (`e_contrast:50`), increased brightness (`e_brightness:10`) and saturation (`e_saturation:20`) to improve visibility and accessibility.

![Video with contrast adjustments](https://res.cloudinary.com/demo/video/upload/e_contrast:50/e_brightness:10/e_saturation:20/docs/grocery-store.mp4 "thumb:c_scale,w_500")

```nodejs
cloudinary.video("docs/grocery-store", {transformation: [
  {effect: "contrast:50"},
  {effect: "brightness:10"},
  {effect: "saturation:20"}
  ]})
```

```react
import { contrast, brightness, saturation } from "@cloudinary/url-gen/actions/adjust";

new CloudinaryVideo("docs/grocery-store.mp4")
  .adjust(contrast().level(50))
  .adjust(brightness().level(10))
  .adjust(saturation().level(20));
```

```vue
import { contrast, brightness, saturation } from "@cloudinary/url-gen/actions/adjust";

new CloudinaryVideo("docs/grocery-store.mp4")
  .adjust(contrast().level(50))
  .adjust(brightness().level(10))
  .adjust(saturation().level(20));
```

```angular
import { contrast, brightness, saturation } from "@cloudinary/url-gen/actions/adjust";

new CloudinaryVideo("docs/grocery-store.mp4")
  .adjust(contrast().level(50))
  .adjust(brightness().level(10))
  .adjust(saturation().level(20));
```

```js
import { contrast, brightness, saturation } from "@cloudinary/url-gen/actions/adjust";

new CloudinaryVideo("docs/grocery-store.mp4")
  .adjust(contrast().level(50))
  .adjust(brightness().level(10))
  .adjust(saturation().level(20));
```

```python
CloudinaryVideo("docs/grocery-store").video(transformation=[
  {'effect': "contrast:50"},
  {'effect': "brightness:10"},
  {'effect': "saturation:20"}
  ])
```

```php
use Cloudinary\Transformation\Adjust;

(new VideoTag('docs/grocery-store.mp4'))
	->adjust(Adjust::contrast()->level(50))
	->adjust(Adjust::brightness()->level(10))
	->adjust(Adjust::saturation()->level(20));
```

```java
cloudinary.url().transformation(new Transformation()
  .effect("contrast:50").chain()
  .effect("brightness:10").chain()
  .effect("saturation:20")).videoTag("docs/grocery-store");
```

```ruby
cl_video_tag("docs/grocery-store", transformation: [
  {effect: "contrast:50"},
  {effect: "brightness:10"},
  {effect: "saturation:20"}
  ])
```

```csharp
cloudinary.Api.UrlVideoUp.Transform(new Transformation()
  .Effect("contrast:50").Chain()
  .Effect("brightness:10").Chain()
  .Effect("saturation:20")).BuildVideoTag("docs/grocery-store")
```

```dart
cloudinary.video('docs/grocery-store.mp4').transformation(Transformation()
	.adjust(Adjust.contrast().level(50))
	.adjust(Adjust.brightness().level(10))
	.adjust(Adjust.saturation().level(20)));
```

```swift
cloudinary.createUrl().setResourceType("video").setTransformation(CLDTransformation()
  .setEffect("contrast:50").chain()
  .setEffect("brightness:10").chain()
  .setEffect("saturation:20")).generate("docs/grocery-store.mp4")
```

```android
MediaManager.get().url().transformation(new Transformation()
  .effect("contrast:50").chain()
  .effect("brightness:10").chain()
  .effect("saturation:20")).resourceType("video").generate("docs/grocery-store.mp4");
```

```flutter
cloudinary.video('docs/grocery-store.mp4').transformation(Transformation()
	.adjust(Adjust.contrast().level(50))
	.adjust(Adjust.brightness().level(10))
	.adjust(Adjust.saturation().level(20)));
```

```kotlin
cloudinary.video {
	publicId("docs/grocery-store.mp4")
	 adjust(Adjust.contrast() { level(50) })
	 adjust(Adjust.brightness() { level(10) })
	 adjust(Adjust.saturation() { level(20) }) 
}.generate()
```

```jquery
$.cloudinary.video("docs/grocery-store", {transformation: [
  {effect: "contrast:50"},
  {effect: "brightness:10"},
  {effect: "saturation:20"}
  ]})
```

```react_native
import { contrast, brightness, saturation } from "@cloudinary/url-gen/actions/adjust";

new CloudinaryVideo("docs/grocery-store.mp4")
  .adjust(contrast().level(50))
  .adjust(brightness().level(10))
  .adjust(saturation().level(20));
```

> **READING**:
>
> * Docs: [The contrast effect](transformation_reference#e_contrast)

> * Docs: [The brightness effect](transformation_reference#e_brightness) 

> * Docs: [The saturation effect](transformation_reference#e_saturation)

## Customize text overlays in images

Customizable text overlays are essential for accessibility because they allow you to adapt text presentation to meet diverse user needs. Users with visual impairments, dyslexia, or reading difficulties often benefit from specific font styles, sizes, and spacing adjustments. By providing flexibility in text overlay styling, you ensure your content remains accessible across different abilities and preferences.

The WCAG guidelines emphasize that text should be customizable to support users who need larger fonts, different font families, or modified spacing for better readability. Cloudinary's text overlay system provides extensive customization options that help you meet these accessibility requirements while maintaining visual appeal.

![Standard text](https://res.cloudinary.com/demo/image/upload/l_text:Arial_150:Standard%20Text,co_black/fl_layer_apply,g_center/docs/white-texture.jpg "thumb:c_scale,w_300")

```nodejs
cloudinary.image("docs/white-texture.jpg", {transformation: [
  {overlay: {font_family: "Arial", font_size: 150, text: "Standard%20Text"}, color: "black"},
  {flags: "layer_apply", gravity: "center"}
  ]})
```

```react
import { source } from "@cloudinary/url-gen/actions/overlay";
import { text } from "@cloudinary/url-gen/qualifiers/source";
import { Position } from "@cloudinary/url-gen/qualifiers/position";
import { TextStyle } from "@cloudinary/url-gen/qualifiers/textStyle";
import { compass } from "@cloudinary/url-gen/qualifiers/gravity";

new CloudinaryImage("docs/white-texture.jpg").overlay(
  source(
    text("Standard Text", new TextStyle("Arial", 150)).textColor("black")
  ).position(new Position().gravity(compass("center")))
);
```

```vue
import { source } from "@cloudinary/url-gen/actions/overlay";
import { text } from "@cloudinary/url-gen/qualifiers/source";
import { Position } from "@cloudinary/url-gen/qualifiers/position";
import { TextStyle } from "@cloudinary/url-gen/qualifiers/textStyle";
import { compass } from "@cloudinary/url-gen/qualifiers/gravity";

new CloudinaryImage("docs/white-texture.jpg").overlay(
  source(
    text("Standard Text", new TextStyle("Arial", 150)).textColor("black")
  ).position(new Position().gravity(compass("center")))
);
```

```angular
import { source } from "@cloudinary/url-gen/actions/overlay";
import { text } from "@cloudinary/url-gen/qualifiers/source";
import { Position } from "@cloudinary/url-gen/qualifiers/position";
import { TextStyle } from "@cloudinary/url-gen/qualifiers/textStyle";
import { compass } from "@cloudinary/url-gen/qualifiers/gravity";

new CloudinaryImage("docs/white-texture.jpg").overlay(
  source(
    text("Standard Text", new TextStyle("Arial", 150)).textColor("black")
  ).position(new Position().gravity(compass("center")))
);
```

```js
import { source } from "@cloudinary/url-gen/actions/overlay";
import { text } from "@cloudinary/url-gen/qualifiers/source";
import { Position } from "@cloudinary/url-gen/qualifiers/position";
import { TextStyle } from "@cloudinary/url-gen/qualifiers/textStyle";
import { compass } from "@cloudinary/url-gen/qualifiers/gravity";

new CloudinaryImage("docs/white-texture.jpg").overlay(
  source(
    text("Standard Text", new TextStyle("Arial", 150)).textColor("black")
  ).position(new Position().gravity(compass("center")))
);
```

```python
CloudinaryImage("docs/white-texture.jpg").image(transformation=[
  {'overlay': {'font_family': "Arial", 'font_size': 150, 'text': "Standard%20Text"}, 'color': "black"},
  {'flags': "layer_apply", 'gravity': "center"}
  ])
```

```php
use Cloudinary\Transformation\Overlay;
use Cloudinary\Transformation\Source;
use Cloudinary\Transformation\Position;
use Cloudinary\Transformation\TextStyle;
use Cloudinary\Transformation\Gravity;
use Cloudinary\Transformation\Compass;

(new ImageTag('docs/white-texture.jpg'))
	->overlay(Overlay::source(
	Source::text("Standard Text",(new TextStyle("Arial",150)))
	->textColor(Color::BLACK)
	)
	->position((new Position())
	->gravity(
	Gravity::compass(
	Compass::center()))
	)
	);
```

```java
cloudinary.url().transformation(new Transformation()
  .overlay(new TextLayer().fontFamily("Arial").fontSize(150).text("Standard%20Text")).color("black").chain()
  .flags("layer_apply").gravity("center")).imageTag("docs/white-texture.jpg");
```

```ruby
cl_image_tag("docs/white-texture.jpg", transformation: [
  {overlay: {font_family: "Arial", font_size: 150, text: "Standard%20Text"}, color: "black"},
  {flags: "layer_apply", gravity: "center"}
  ])
```

```csharp
cloudinary.Api.UrlImgUp.Transform(new Transformation()
  .Overlay(new TextLayer().FontFamily("Arial").FontSize(150).Text("Standard%20Text")).Color("black").Chain()
  .Flags("layer_apply").Gravity("center")).BuildImageTag("docs/white-texture.jpg")
```

```dart
cloudinary.image('docs/white-texture.jpg').transformation(Transformation()
	.addTransformation("l_text:Arial_150:Standard Text,co_black/fl_layer_apply,g_center"));
```

```swift
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation()
  .setOverlay("text:Arial_150:Standard%20Text").setColor("black").chain()
  .setFlags("layer_apply").setGravity("center")).generate("docs/white-texture.jpg")!, cloudinary: cloudinary)
```

```android
MediaManager.get().url().transformation(new Transformation()
  .overlay(new TextLayer().fontFamily("Arial").fontSize(150).text("Standard%20Text")).color("black").chain()
  .flags("layer_apply").gravity("center")).generate("docs/white-texture.jpg");
```

```flutter
cloudinary.image('docs/white-texture.jpg').transformation(Transformation()
	.addTransformation("l_text:Arial_150:Standard Text,co_black/fl_layer_apply,g_center"));
```

```kotlin
cloudinary.image {
	publicId("docs/white-texture.jpg")
	 overlay(Overlay.source(
	Source.text("Standard Text",TextStyle("Arial",150)) {
	 textColor(Color.BLACK)
	 }) {
	 position(Position() {
	 gravity(
	Gravity.compass(
	Compass.center()))
	 })
	 }) 
}.generate()
```

```jquery
$.cloudinary.image("docs/white-texture.jpg", {transformation: [
  {overlay: new cloudinary.TextLayer().fontFamily("Arial").fontSize(150).text("Standard%20Text"), color: "black"},
  {flags: "layer_apply", gravity: "center"}
  ]})
```

```react_native
import { source } from "@cloudinary/url-gen/actions/overlay";
import { text } from "@cloudinary/url-gen/qualifiers/source";
import { Position } from "@cloudinary/url-gen/qualifiers/position";
import { TextStyle } from "@cloudinary/url-gen/qualifiers/textStyle";
import { compass } from "@cloudinary/url-gen/qualifiers/gravity";

new CloudinaryImage("docs/white-texture.jpg").overlay(
  source(
    text("Standard Text", new TextStyle("Arial", 150)).textColor("black")
  ).position(new Position().gravity(compass("center")))
);
```

![Large bold (low vision)](https://res.cloudinary.com/demo/image/upload/l_text:Arial_200_bold:Large%20Bold%20Text,co_black/fl_layer_apply,g_center/docs/white-texture.jpg "thumb:c_scale,w_300")

```nodejs
cloudinary.image("docs/white-texture.jpg", {transformation: [
  {overlay: {font_family: "Arial", font_size: 200, font_weight: "bold", text: "Large%20Bold%20Text"}, color: "black"},
  {flags: "layer_apply", gravity: "center"}
  ]})
```

```react
import { source } from "@cloudinary/url-gen/actions/overlay";
import { text } from "@cloudinary/url-gen/qualifiers/source";
import { Position } from "@cloudinary/url-gen/qualifiers/position";
import { TextStyle } from "@cloudinary/url-gen/qualifiers/textStyle";
import { compass } from "@cloudinary/url-gen/qualifiers/gravity";

new CloudinaryImage("docs/white-texture.jpg").overlay(
  source(
    text(
      "Large Bold Text",
      new TextStyle("Arial", 200).fontWeight("bold")
    ).textColor("black")
  ).position(new Position().gravity(compass("center")))
);
```

```vue
import { source } from "@cloudinary/url-gen/actions/overlay";
import { text } from "@cloudinary/url-gen/qualifiers/source";
import { Position } from "@cloudinary/url-gen/qualifiers/position";
import { TextStyle } from "@cloudinary/url-gen/qualifiers/textStyle";
import { compass } from "@cloudinary/url-gen/qualifiers/gravity";

new CloudinaryImage("docs/white-texture.jpg").overlay(
  source(
    text(
      "Large Bold Text",
      new TextStyle("Arial", 200).fontWeight("bold")
    ).textColor("black")
  ).position(new Position().gravity(compass("center")))
);
```

```angular
import { source } from "@cloudinary/url-gen/actions/overlay";
import { text } from "@cloudinary/url-gen/qualifiers/source";
import { Position } from "@cloudinary/url-gen/qualifiers/position";
import { TextStyle } from "@cloudinary/url-gen/qualifiers/textStyle";
import { compass } from "@cloudinary/url-gen/qualifiers/gravity";

new CloudinaryImage("docs/white-texture.jpg").overlay(
  source(
    text(
      "Large Bold Text",
      new TextStyle("Arial", 200).fontWeight("bold")
    ).textColor("black")
  ).position(new Position().gravity(compass("center")))
);
```

```js
import { source } from "@cloudinary/url-gen/actions/overlay";
import { text } from "@cloudinary/url-gen/qualifiers/source";
import { Position } from "@cloudinary/url-gen/qualifiers/position";
import { TextStyle } from "@cloudinary/url-gen/qualifiers/textStyle";
import { compass } from "@cloudinary/url-gen/qualifiers/gravity";

new CloudinaryImage("docs/white-texture.jpg").overlay(
  source(
    text(
      "Large Bold Text",
      new TextStyle("Arial", 200).fontWeight("bold")
    ).textColor("black")
  ).position(new Position().gravity(compass("center")))
);
```

```python
CloudinaryImage("docs/white-texture.jpg").image(transformation=[
  {'overlay': {'font_family': "Arial", 'font_size': 200, 'font_weight': "bold", 'text': "Large%20Bold%20Text"}, 'color': "black"},
  {'flags': "layer_apply", 'gravity': "center"}
  ])
```

```php
use Cloudinary\Transformation\Overlay;
use Cloudinary\Transformation\Source;
use Cloudinary\Transformation\Position;
use Cloudinary\Transformation\TextStyle;
use Cloudinary\Transformation\FontWeight;
use Cloudinary\Transformation\Gravity;
use Cloudinary\Transformation\Compass;

(new ImageTag('docs/white-texture.jpg'))
	->overlay(Overlay::source(
	Source::text("Large Bold Text",(new TextStyle("Arial",200))
	->fontWeight(
	FontWeight::bold())
	)
	->textColor(Color::BLACK)
	)
	->position((new Position())
	->gravity(
	Gravity::compass(
	Compass::center()))
	)
	);
```

```java
cloudinary.url().transformation(new Transformation()
  .overlay(new TextLayer().fontFamily("Arial").fontSize(200).fontWeight("bold").text("Large%20Bold%20Text")).color("black").chain()
  .flags("layer_apply").gravity("center")).imageTag("docs/white-texture.jpg");
```

```ruby
cl_image_tag("docs/white-texture.jpg", transformation: [
  {overlay: {font_family: "Arial", font_size: 200, font_weight: "bold", text: "Large%20Bold%20Text"}, color: "black"},
  {flags: "layer_apply", gravity: "center"}
  ])
```

```csharp
cloudinary.Api.UrlImgUp.Transform(new Transformation()
  .Overlay(new TextLayer().FontFamily("Arial").FontSize(200).FontWeight("bold").Text("Large%20Bold%20Text")).Color("black").Chain()
  .Flags("layer_apply").Gravity("center")).BuildImageTag("docs/white-texture.jpg")
```

```dart
cloudinary.image('docs/white-texture.jpg').transformation(Transformation()
	.addTransformation("l_text:Arial_200_bold:Large Bold Text,co_black/fl_layer_apply,g_center"));
```

```swift
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation()
  .setOverlay("text:Arial_200_bold:Large%20Bold%20Text").setColor("black").chain()
  .setFlags("layer_apply").setGravity("center")).generate("docs/white-texture.jpg")!, cloudinary: cloudinary)
```

```android
MediaManager.get().url().transformation(new Transformation()
  .overlay(new TextLayer().fontFamily("Arial").fontSize(200).fontWeight("bold").text("Large%20Bold%20Text")).color("black").chain()
  .flags("layer_apply").gravity("center")).generate("docs/white-texture.jpg");
```

```flutter
cloudinary.image('docs/white-texture.jpg').transformation(Transformation()
	.addTransformation("l_text:Arial_200_bold:Large Bold Text,co_black/fl_layer_apply,g_center"));
```

```kotlin
cloudinary.image {
	publicId("docs/white-texture.jpg")
	 overlay(Overlay.source(
	Source.text("Large Bold Text",TextStyle("Arial",200) {
	 fontWeight(
	FontWeight.bold())
	 }) {
	 textColor(Color.BLACK)
	 }) {
	 position(Position() {
	 gravity(
	Gravity.compass(
	Compass.center()))
	 })
	 }) 
}.generate()
```

```jquery
$.cloudinary.image("docs/white-texture.jpg", {transformation: [
  {overlay: new cloudinary.TextLayer().fontFamily("Arial").fontSize(200).fontWeight("bold").text("Large%20Bold%20Text"), color: "black"},
  {flags: "layer_apply", gravity: "center"}
  ]})
```

```react_native
import { source } from "@cloudinary/url-gen/actions/overlay";
import { text } from "@cloudinary/url-gen/qualifiers/source";
import { Position } from "@cloudinary/url-gen/qualifiers/position";
import { TextStyle } from "@cloudinary/url-gen/qualifiers/textStyle";
import { compass } from "@cloudinary/url-gen/qualifiers/gravity";

new CloudinaryImage("docs/white-texture.jpg").overlay(
  source(
    text(
      "Large Bold Text",
      new TextStyle("Arial", 200).fontWeight("bold")
    ).textColor("black")
  ).position(new Position().gravity(compass("center")))
);
```

![Letter spacing (dyslexia)](https://res.cloudinary.com/demo/image/upload/l_text:Arial_150_letter_spacing_35:Spaced%20Text,co_black/fl_layer_apply,g_center/docs/white-texture.jpg "thumb:c_scale,w_300")

```nodejs
cloudinary.image("docs/white-texture.jpg", {transformation: [
  {overlay: {font_family: "Arial", font_size: 150, letter_spacing: 35, text: "Spaced%20Text"}, color: "black"},
  {flags: "layer_apply", gravity: "center"}
  ]})
```

```react
import { source } from "@cloudinary/url-gen/actions/overlay";
import { text } from "@cloudinary/url-gen/qualifiers/source";
import { Position } from "@cloudinary/url-gen/qualifiers/position";
import { TextStyle } from "@cloudinary/url-gen/qualifiers/textStyle";
import { compass } from "@cloudinary/url-gen/qualifiers/gravity";

new CloudinaryImage("docs/white-texture.jpg").overlay(
  source(
    text(
      "Spaced Text",
      new TextStyle("Arial", 150).letterSpacing(35)
    ).textColor("black")
  ).position(new Position().gravity(compass("center")))
);
```

```vue
import { source } from "@cloudinary/url-gen/actions/overlay";
import { text } from "@cloudinary/url-gen/qualifiers/source";
import { Position } from "@cloudinary/url-gen/qualifiers/position";
import { TextStyle } from "@cloudinary/url-gen/qualifiers/textStyle";
import { compass } from "@cloudinary/url-gen/qualifiers/gravity";

new CloudinaryImage("docs/white-texture.jpg").overlay(
  source(
    text(
      "Spaced Text",
      new TextStyle("Arial", 150).letterSpacing(35)
    ).textColor("black")
  ).position(new Position().gravity(compass("center")))
);
```

```angular
import { source } from "@cloudinary/url-gen/actions/overlay";
import { text } from "@cloudinary/url-gen/qualifiers/source";
import { Position } from "@cloudinary/url-gen/qualifiers/position";
import { TextStyle } from "@cloudinary/url-gen/qualifiers/textStyle";
import { compass } from "@cloudinary/url-gen/qualifiers/gravity";

new CloudinaryImage("docs/white-texture.jpg").overlay(
  source(
    text(
      "Spaced Text",
      new TextStyle("Arial", 150).letterSpacing(35)
    ).textColor("black")
  ).position(new Position().gravity(compass("center")))
);
```

```js
import { source } from "@cloudinary/url-gen/actions/overlay";
import { text } from "@cloudinary/url-gen/qualifiers/source";
import { Position } from "@cloudinary/url-gen/qualifiers/position";
import { TextStyle } from "@cloudinary/url-gen/qualifiers/textStyle";
import { compass } from "@cloudinary/url-gen/qualifiers/gravity";

new CloudinaryImage("docs/white-texture.jpg").overlay(
  source(
    text(
      "Spaced Text",
      new TextStyle("Arial", 150).letterSpacing(35)
    ).textColor("black")
  ).position(new Position().gravity(compass("center")))
);
```

```python
CloudinaryImage("docs/white-texture.jpg").image(transformation=[
  {'overlay': {'font_family': "Arial", 'font_size': 150, 'letter_spacing': 35, 'text': "Spaced%20Text"}, 'color': "black"},
  {'flags': "layer_apply", 'gravity': "center"}
  ])
```

```php
use Cloudinary\Transformation\Overlay;
use Cloudinary\Transformation\Source;
use Cloudinary\Transformation\Position;
use Cloudinary\Transformation\TextStyle;
use Cloudinary\Transformation\Gravity;
use Cloudinary\Transformation\Compass;

(new ImageTag('docs/white-texture.jpg'))
	->overlay(Overlay::source(
	Source::text("Spaced Text",(new TextStyle("Arial",150))->letterSpacing(35))
	->textColor(Color::BLACK)
	)
	->position((new Position())
	->gravity(
	Gravity::compass(
	Compass::center()))
	)
	);
```

```java
cloudinary.url().transformation(new Transformation()
  .overlay(new TextLayer().fontFamily("Arial").fontSize(150).letterSpacing(35).text("Spaced%20Text")).color("black").chain()
  .flags("layer_apply").gravity("center")).imageTag("docs/white-texture.jpg");
```

```ruby
cl_image_tag("docs/white-texture.jpg", transformation: [
  {overlay: {font_family: "Arial", font_size: 150, letter_spacing: 35, text: "Spaced%20Text"}, color: "black"},
  {flags: "layer_apply", gravity: "center"}
  ])
```

```csharp
cloudinary.Api.UrlImgUp.Transform(new Transformation()
  .Overlay(new TextLayer().FontFamily("Arial").FontSize(150).LetterSpacing(35).Text("Spaced%20Text")).Color("black").Chain()
  .Flags("layer_apply").Gravity("center")).BuildImageTag("docs/white-texture.jpg")
```

```dart
cloudinary.image('docs/white-texture.jpg').transformation(Transformation()
	.addTransformation("l_text:Arial_150_letter_spacing_35:Spaced Text,co_black/fl_layer_apply,g_center"));
```

```swift
imageView.cldSetImage(cloudinary.createUrl().setTransformation(CLDTransformation()
  .setOverlay("text:Arial_150_letter_spacing_35:Spaced%20Text").setColor("black").chain()
  .setFlags("layer_apply").setGravity("center")).generate("docs/white-texture.jpg")!, cloudinary: cloudinary)
```

```android
MediaManager.get().url().transformation(new Transformation()
  .overlay(new TextLayer().fontFamily("Arial").fontSize(150).letterSpacing(35).text("Spaced%20Text")).color("black").chain()
  .flags("layer_apply").gravity("center")).generate("docs/white-texture.jpg");
```

```flutter
cloudinary.image('docs/white-texture.jpg').transformation(Transformation()
	.addTransformation("l_text:Arial_150_letter_spacing_35:Spaced Text,co_black/fl_layer_apply,g_center"));
```

```kotlin
cloudinary.image {
	publicId("docs/white-texture.jpg")
	 overlay(Overlay.source(
	Source.text("Spaced Text",TextStyle("Arial",150) { letterSpacing(35) }) {
	 textColor(Color.BLACK)
	 }) {
	 position(Position() {
	 gravity(
	Gravity.compass(
	Compass.center()))
	 })
	 }) 
}.generate()
```

```jquery
$.cloudinary.image("docs/white-texture.jpg", {transformation: [
  {overlay: new cloudinary.TextLayer().fontFamily("Arial").fontSize(150).letterSpacing(35).text("Spaced%20Text"), color: "black"},
  {flags: "layer_apply", gravity: "center"}
  ]})
```

```react_native
import { source } from "@cloudinary/url-gen/actions/overlay";
import { text } from "@cloudinary/url-gen/qualifiers/source";
import { Position } from "@cloudinary/url-gen/qualifiers/position";
import { TextStyle } from "@cloudinary/url-gen/qualifiers/textStyle";
import { compass } from "@cloudinary/url-gen/qualifiers/gravity";

new CloudinaryImage("docs/white-texture.jpg").overlay(
  source(
    text(
      "Spaced Text",
      new TextStyle("Arial", 150).letterSpacing(35)
    ).textColor("black")
  ).position(new Position().gravity(compass("center")))
);
```

### Understanding text overlay parameters

Cloudinary's [text overlay transformation](transformation_reference#l_text) (`l_text`) supports numerous styling parameters that can be combined to create accessible and visually appealing text:

**Core Parameters (Required):**

* **Font**: Any universally available font or custom font (e.g., `Arial`, `Helvetica`, `Times`)
* **Size**: Text size in pixels (e.g., `50`, `100`)

**Styling Parameters (Optional):**

* **Weight**: Font thickness (`normal`, `bold`, `thin`, `light`)
* **Style**: Font appearance (`normal`, `italic`)
* **Decoration**: Text decoration (`normal`, `underline`, `strikethrough`)
* **Alignment**: Text positioning (`left`, `center`, `right`, `justify`)
* **Stroke**: Text outline (`none`, `stroke`)
* **Letter spacing**: Space between characters (`letter_spacing_<value>`)
* **Line spacing**: Space between lines (`line_spacing_<value>`)

**Visual Enhancement Parameters:**

* **Color**: Text color (`co_<color>`)
* **Background**: Background color (`b_<color>`)
* **Border**: Outline styling (`bo_<border>`)

> **TIP**:
>
> :title=Best practices for accessible text overlays

> * **Font Size**: Use sizes of at least 16px for body text, larger for headers. Users with low vision may need even larger text.

> * **Font Choice**: Sans-serif fonts like Arial and Helvetica are often easier to read, especially for users with dyslexia.

> * **Letter Spacing**: Additional spacing between letters can improve readability for users with dyslexia or visual processing difficulties.

> * **Color Contrast**: Ensure sufficient contrast between text and background colors (minimum 4.5:1 ratio for normal text).

> * **Background**: Use solid background colors behind text when overlaying on complex images to ensure readability.

> * **Font Weight**: Bold text can improve readability, but avoid fonts that are too thin (like `light` or `thin` weights) for important content.

### Interactive text overlay customization demo

Use the controls below to experiment with different text styling parameters and see how they affect accessibility and readability. Notice how the transformation URL updates as you adjust the settings:

  
    
    
      Text Content:
              
    
    
          
        Font Family:
        
          Arial
          Helvetica
          Times
          Courier
          Verdana
          Roboto
          Open Sans
        
      
    
          
        Font Size: 50px
        
      
    
    
      Font Weight:
      
        Normal
        Bold
        Thin
        Light
      
    
    
    
      Font Style:
      
        Normal
        Italic
      
    
    
    
      Decoration:
      
        Normal
        Underline
        Strikethrough
      
    
    
    
      Letter Spacing: 0px
      
    
    
    
      Alignment:
      
        Left
        Center
        Right
        Justify
      
    
    
    
      Text Color:
      
        Black
        White
        Red
        Blue
        Green
        Purple
      
    
    
    
      Background:
      
        None
        White
        Black
        Yellow
        Light Blue
        Light Gray
      
    
    
  
  
  Reset to Defaults

  Current transformation URL:
  https://res.cloudinary.com/demo/image/upload/c_fit,l_text:Arial_50:Sample%20Text,co_black,w_1800/fl_layer_apply,g_center/c_scale,w_600/f_auto/q_auto/docs/white-texture.jpg

### Video text overlays

The same customization principles apply to video text overlays. Here's an example of accessible text styling on video content:

![Video with customized text overlay](https://res.cloudinary.com/demo/video/upload/l_text:Arial_60_bold:Accessible%20Video%20Text,co_white,b_rgb:000000cc/fl_layer_apply,g_north,y_50/docs/grocery-store.mp4 "thumb:c_scale,w_500")

```nodejs
cloudinary.video("docs/grocery-store", {transformation: [
  {overlay: {font_family: "Arial", font_size: 60, font_weight: "bold", text: "Accessible%20Video%20Text"}, color: "white", background: "#000000cc"},
  {flags: "layer_apply", gravity: "north", y: 50}
  ]})
```

```react
import { source } from "@cloudinary/url-gen/actions/overlay";
import { text } from "@cloudinary/url-gen/qualifiers/source";
import { Position } from "@cloudinary/url-gen/qualifiers/position";
import { TextStyle } from "@cloudinary/url-gen/qualifiers/textStyle";
import { compass } from "@cloudinary/url-gen/qualifiers/gravity";

new CloudinaryVideo("docs/grocery-store.mp4").overlay(
  source(
    text("Accessible Video Text", new TextStyle("Arial", 60).fontWeight("bold"))
      .textColor("white")
      .backgroundColor("#000000cc")
  ).position(
    new Position()
      .gravity(compass("north"))
      .offsetY(50)
  )
);
```

```vue
import { source } from "@cloudinary/url-gen/actions/overlay";
import { text } from "@cloudinary/url-gen/qualifiers/source";
import { Position } from "@cloudinary/url-gen/qualifiers/position";
import { TextStyle } from "@cloudinary/url-gen/qualifiers/textStyle";
import { compass } from "@cloudinary/url-gen/qualifiers/gravity";

new CloudinaryVideo("docs/grocery-store.mp4").overlay(
  source(
    text("Accessible Video Text", new TextStyle("Arial", 60).fontWeight("bold"))
      .textColor("white")
      .backgroundColor("#000000cc")
  ).position(
    new Position()
      .gravity(compass("north"))
      .offsetY(50)
  )
);
```

```angular
import { source } from "@cloudinary/url-gen/actions/overlay";
import { text } from "@cloudinary/url-gen/qualifiers/source";
import { Position } from "@cloudinary/url-gen/qualifiers/position";
import { TextStyle } from "@cloudinary/url-gen/qualifiers/textStyle";
import { compass } from "@cloudinary/url-gen/qualifiers/gravity";

new CloudinaryVideo("docs/grocery-store.mp4").overlay(
  source(
    text("Accessible Video Text", new TextStyle("Arial", 60).fontWeight("bold"))
      .textColor("white")
      .backgroundColor("#000000cc")
  ).position(
    new Position()
      .gravity(compass("north"))
      .offsetY(50)
  )
);
```

```js
import { source } from "@cloudinary/url-gen/actions/overlay";
import { text } from "@cloudinary/url-gen/qualifiers/source";
import { Position } from "@cloudinary/url-gen/qualifiers/position";
import { TextStyle } from "@cloudinary/url-gen/qualifiers/textStyle";
import { compass } from "@cloudinary/url-gen/qualifiers/gravity";

new CloudinaryVideo("docs/grocery-store.mp4").overlay(
  source(
    text("Accessible Video Text", new TextStyle("Arial", 60).fontWeight("bold"))
      .textColor("white")
      .backgroundColor("#000000cc")
  ).position(
    new Position()
      .gravity(compass("north"))
      .offsetY(50)
  )
);
```

```python
CloudinaryVideo("docs/grocery-store").video(transformation=[
  {'overlay': {'font_family': "Arial", 'font_size': 60, 'font_weight': "bold", 'text': "Accessible%20Video%20Text"}, 'color': "white", 'background': "#000000cc"},
  {'flags': "layer_apply", 'gravity': "north", 'y': 50}
  ])
```

```php
use Cloudinary\Transformation\Overlay;
use Cloudinary\Transformation\Source;
use Cloudinary\Transformation\Position;
use Cloudinary\Transformation\TextStyle;
use Cloudinary\Transformation\Color;
use Cloudinary\Transformation\FontWeight;
use Cloudinary\Transformation\Gravity;
use Cloudinary\Transformation\Compass;

(new VideoTag('docs/grocery-store.mp4'))
	->overlay(Overlay::source(
	Source::text("Accessible Video Text",(new TextStyle("Arial",60))
	->fontWeight(
	FontWeight::bold())
	)
	->textColor(Color::WHITE)
	->backgroundColor(Color::rgb("000000cc"))
	)
	->position((new Position())
	->gravity(
	Gravity::compass(
	Compass::north()))
->offsetY(50))
	);
```

```java
cloudinary.url().transformation(new Transformation()
  .overlay(new TextLayer().fontFamily("Arial").fontSize(60).fontWeight("bold").text("Accessible%20Video%20Text")).color("white").background("#000000cc").chain()
  .flags("layer_apply").gravity("north").y(50)).videoTag("docs/grocery-store");
```

```ruby
cl_video_tag("docs/grocery-store", transformation: [
  {overlay: {font_family: "Arial", font_size: 60, font_weight: "bold", text: "Accessible%20Video%20Text"}, color: "white", background: "#000000cc"},
  {flags: "layer_apply", gravity: "north", y: 50}
  ])
```

```csharp
cloudinary.Api.UrlVideoUp.Transform(new Transformation()
  .Overlay(new TextLayer().FontFamily("Arial").FontSize(60).FontWeight("bold").Text("Accessible%20Video%20Text")).Color("white").Background("#000000cc").Chain()
  .Flags("layer_apply").Gravity("north").Y(50)).BuildVideoTag("docs/grocery-store")
```

```dart
cloudinary.video('docs/grocery-store.mp4').transformation(Transformation()
	.addTransformation("l_text:Arial_60_bold:Accessible Video Text,co_white,b_rgb:000000cc/fl_layer_apply,g_north,y_50"));
```

```swift
cloudinary.createUrl().setResourceType("video").setTransformation(CLDTransformation()
  .setOverlay("text:Arial_60_bold:Accessible%20Video%20Text").setColor("white").setBackground("#000000cc").chain()
  .setFlags("layer_apply").setGravity("north").setY(50)).generate("docs/grocery-store.mp4")
```

```android
MediaManager.get().url().transformation(new Transformation()
  .overlay(new TextLayer().fontFamily("Arial").fontSize(60).fontWeight("bold").text("Accessible%20Video%20Text")).color("white").background("#000000cc").chain()
  .flags("layer_apply").gravity("north").y(50)).resourceType("video").generate("docs/grocery-store.mp4");
```

```flutter
cloudinary.video('docs/grocery-store.mp4').transformation(Transformation()
	.addTransformation("l_text:Arial_60_bold:Accessible Video Text,co_white,b_rgb:000000cc/fl_layer_apply,g_north,y_50"));
```

```kotlin
cloudinary.video {
	publicId("docs/grocery-store.mp4")
	 overlay(Overlay.source(
	Source.text("Accessible Video Text",TextStyle("Arial",60) {
	 fontWeight(
	FontWeight.bold())
	 }) {
	 textColor(Color.WHITE)
	 backgroundColor(Color.rgb("000000cc"))
	 }) {
	 position(Position() {
	 gravity(
	Gravity.compass(
	Compass.north()))
 offsetY(50) })
	 }) 
}.generate()
```

```jquery
$.cloudinary.video("docs/grocery-store", {transformation: [
  {overlay: new cloudinary.TextLayer().fontFamily("Arial").fontSize(60).fontWeight("bold").text("Accessible%20Video%20Text"), color: "white", background: "#000000cc"},
  {flags: "layer_apply", gravity: "north", y: 50}
  ]})
```

```react_native
import { source } from "@cloudinary/url-gen/actions/overlay";
import { text } from "@cloudinary/url-gen/qualifiers/source";
import { Position } from "@cloudinary/url-gen/qualifiers/position";
import { TextStyle } from "@cloudinary/url-gen/qualifiers/textStyle";
import { compass } from "@cloudinary/url-gen/qualifiers/gravity";

new CloudinaryVideo("docs/grocery-store.mp4").overlay(
  source(
    text("Accessible Video Text", new TextStyle("Arial", 60).fontWeight("bold"))
      .textColor("white")
      .backgroundColor("#000000cc")
  ).position(
    new Position()
      .gravity(compass("north"))
      .offsetY(50)
  )
);
```

This example uses large, bold white text (`Arial_60_bold`) with a semi-transparent black background (`b_rgb:000000cc`) to ensure high contrast and readability across the entire video.

> **READING**:
>
> * Docs: [Text overlays on images](image_text_layers#text_layer_options)

> * Docs: [Text overlays on videos](video_text_layers#text_layer_options)

> * Docs: [Create images from text](create_images_from_text)

## OCR text detection and extraction

For images containing text content, Optical Character Recognition (OCR) technology can extract that text and make it accessible to screen readers and other assistive technologies. This is particularly important for images of documents, signs, menus, handwritten notes, or any visual content where text is embedded within the image rather than provided as separate HTML text.

Cloudinary's [OCR Text Detection and Extraction add-on](ocr_text_detection_and_extraction_addon) can automatically extract text from images during upload, making the content available for accessibility purposes.

Here's an example showing an Italian restaurant menu and the text that Cloudinary's OCR add-on automatically extracted from it:

  Extracted Text Content (Available to Screen Readers):
  
    MENU 1
    INSALATA VERDE
    PIZZA CAPRESE
    18.50
    
    MENU 2
    BRUSCHETTA DELLA CASA
    INSALATA DI POLLO
    19.50
    
    MENU 3
    BRUSCHETTA DELLA CASA
    CANNELLONI DI CARNE
    AL FORNO 21.50
  

  This text content was automatically extracted using OCR and can be read by screen readers, making the Italian menu accessible to users with visual impairments. Note that the OCR detected the language as Italian (locale: "it") and extracted all menu items with their prices.

To extract text from an image:

1. **Subscribe to the OCR add-on**: Enable the [OCR Text Detection and Extraction add-on](ocr_text_detection_and_extraction_addon) in your Cloudinary account.

2. **Extract text during upload**: When uploading images that contain text, use the `ocr` parameter to extract the text content:

    ```multi
    |ruby
    Cloudinary::Uploader.upload("menu-827750_1920.jpg", 
      public_id: "docs/restaurant_menu",
      ocr: "adv_ocr")

    |php_2
    $cloudinary->uploadApi()->upload("menu-827750_1920.jpg", 
      ["public_id" => "docs/restaurant_menu", "ocr" => "adv_ocr"]);

    |python
    cloudinary.uploader.upload("menu-827750_1920.jpg",
      public_id = "docs/restaurant_menu",
      ocr = "adv_ocr")

    |nodejs
    cloudinary.v2.uploader
    .upload("menu-827750_1920.jpg", 
      { public_id: "docs/restaurant_menu", ocr: "adv_ocr" })
    .then(result=>console.log(result)); 

    |java
    cloudinary.uploader().upload("menu-827750_1920.jpg", 
      ObjectUtils.asMap("public_id", "docs/restaurant_menu", "ocr", "adv_ocr"));

    |csharp
    var uploadParams = new ImageUploadParams()
    {
      File = new FileDescription(@"menu-827750_1920.jpg"),
      PublicId = "docs/restaurant_menu",
      Ocr = "adv_ocr"
    };
    var uploadResult = cloudinary.Upload(uploadParams); 

    |cli
    cld uploader upload "menu-827750_1920.jpg" public_id="docs/restaurant_menu" ocr="adv_ocr"
    ```

3. **Use extracted text for accessibility**: The OCR results are returned in the upload response and can be used to provide accessible alternatives:

    ```json
    {
      "public_id": "docs/restaurant_menu",
      "version": 1750668169,
      "info": {
        "ocr": {
          "adv_ocr": {
            "status": "complete",
            "data": [
              {
                "textAnnotations": [
                  {
                    "locale": "it",
                    "description": "MENU 1\nINSALATA VERDE\nPIZZA CAPRESE\n18.50\nMENU 2\nBRUSCHETTA DELLA CASA\nINSALATA DI POLLO\n19.50\nMENU 3\nBRUSCHETTA DELLA CASA\nCANNELLONI DI CARNE\nAL FORNO 21.50"
                  }
                ]
              }
            ]
          }
        }
      }
    }
   ```

    Here's an example in React using the Italian restaurant menu response:

    ```react
    import React from 'react';

    const RestaurantMenuWithOCR = ({ uploadResult }) => {
      // Extract OCR data from the upload response
      const ocrData = uploadResult?.info?.ocr?.adv_ocr;
      const extractedText = ocrData?.data?.[0]?.textAnnotations?.[0]?.description || '';
      
      return (
        <div>
          <img 
            src={uploadResult.secure_url} 
            alt={`${extractedText.replace(/\n/g, ' ')}`}
          />
        </div>
      );
    };

    export default RestaurantMenuWithOCR;
    ```

> **NOTES**:
>
> * You can invoke the OCR Text Detection and Extraction add-on for images already in your product environment using the Admin API [update](admin_api#update_details_of_an_existing_resource) method. 

> * You can retrieve the response at a later date using the Admin API [resource](admin_api#get_details_of_a_single_resource_by_asset_id) method.

> * Consider using [contextual or structured metadata](accessible_media_images#managing_text_alternatives) to store the text.

> **READING**:
>
> * Docs: [OCR text detection and extraction add-on](ocr_text_detection_and_extraction_addon)

.select-wrapper {
    position: relative;
    width: 200px;
    margin-bottom: 20px;
}
.custom-select {
    position: relative;
    width: 100%;
}
.select-selected {
    background-color: var(--dropdown-menu-bg-color);
    padding: 10px 35px 10px 10px;
    font-size: 16px;
    border: 1px solid #ccc;
    border-radius: 4px;
    cursor: pointer;
}
.select-selected::after {
    content: '\25BC';
    position: absolute;
    top: 50%;
    right: 10px;
    transform: translateY(-50%);
    pointer-events: none;
}
.select-items {
    position: absolute;
    background-color: var(--dropdown-menu-bg-color);
    top: 100%;
    left: 0;
    right: 0;
    z-index: 99;
    border: 1px solid #ccc;
    border-top: none;
    border-radius: 0 0 4px 4px;
    max-height: 300px;
    overflow-y: auto;
    display: none;
}
.select-item {
    padding: 10px;
    cursor: pointer;
}
.select-item:hover {
    background-color: var(--dropdown-background-active-color);
}
.language-icon {
    width: 20px;
    height: 20px;
    margin-right: 8px;
    vertical-align: middle;
}
select {
    appearance: none;
    -webkit-appearance: none;
    width: 100%;
    padding: 10px 35px 10px 10px;
    font-size: 16px;
    border: 1px solid #ccc;
    border-radius: 4px;
    background-color: var(--dropdown-menu-bg-color);
    cursor: pointer;
}
.select-wrapper::after {
    content: '\25BC';
    position: absolute;
    top: 50%;
    right: 10px;
    transform: translateY(-50%);
    pointer-events: none;
}

/*
.custom-select {
    position: relative;
    width: 200px;
}
.select-selected {
    background-color: #fff;
    border: 1px solid #ccc;
    padding: 8px;
    cursor: pointer;
    border-radius: 4px;
    display: flex;
    align-items: center;
}
.select-selected:after {
    content: "\25BC";
    position: absolute;
    top: 50%;
    right: 10px;
    transform: translateY(-50%);
}
.select-items {
    position: absolute;
    background-color: #fff;
    top: 100%;
    left: 0;
    right: 0;
    z-index: 99;
    border: 1px solid #ccc;
    border-top: none;
    border-radius: 0 0 4px 4px;
}
.select-hide {
    display: none;
}
.select-items div {
    padding: 8px;
    cursor: pointer;
    display: flex;
    align-items: center;
}
.select-items div:hover {
    background-color: #f1f1f1;
}
.language-icon {
    width: 20px;
    height: 20px;
    margin-right: 8px;
}
*/

.select-css-pocs {
	display: block;
	font-size: 16px;
	font-family: sans-serif;
	font-weight: 700;
	color: #3448c5;
	line-height: 1.3;
	padding: .6em 1.4em .5em .8em;
	width: 100%;
	max-width: 100%; /* useful when width is set to anything other than 100% */
	box-sizing: border-box;
	margin: 0;
	border: 1px solid #aaa;
	box-shadow: 0 1px 0 1px rgba(0,0,0,.04);
	border-radius: .5em;
	-moz-appearance: none;
	-webkit-appearance: none;
	appearance: none;
	background-color: #fff;
	/* note: bg image below uses 2 urls. The first is an svg data uri for the arrow icon, and the second is the gradient. 
		for the icon, if you want to change the color, be sure to use `%23` instead of `#`, since it's a url. You can also swap in a different svg icon or an external image reference

	*/

	background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22292.4%22%20height%3D%22292.4%22%3E%3Cpath%20fill%3D%22%233448c5%22%20d%3D%22M287%2069.4a17.6%2017.6%200%200%200-13-5.4H18.4c-5%200-9.3%201.8-12.9%205.4A17.6%2017.6%200%200%200%200%2082.2c0%205%201.8%209.3%205.4%2012.9l128%20127.9c3.6%203.6%207.8%205.4%2012.8%205.4s9.2-1.8%2012.8-5.4L287%2095c3.5-3.5%205.4-7.8%205.4-12.8%200-5-1.9-9.2-5.5-12.8z%22%2F%3E%3C%2Fsvg%3E');

	background-repeat: no-repeat, repeat;

	/* arrow icon position (1em from the right, 50% vertical) , then gradient position*/
	background-position: right .7em top 50%, 0 0;
	/* icon size, then gradient */
	background-size: .65em auto, 100%;
}

/* CSS for demos */

.select-css {
	display: block;
	font-size: 16px;
	font-family: sans-serif;
	font-weight: 700;
	color: #FF5050;
	line-height: 1.3;
	padding: .6em 1.4em .5em .8em;
	width: 100%;
	max-width: 100%; /* useful when width is set to anything other than 100% */
	box-sizing: border-box;
	margin: 0;
	border: 1px solid #aaa;
	box-shadow: 0 1px 0 1px rgba(0,0,0,.04);
	border-radius: .5em;
	-moz-appearance: none;
	-webkit-appearance: none;
	appearance: none;
	background-color: #fff;
	/* note: bg image below uses 2 urls. The first is an svg data uri for the arrow icon, and the second is the gradient. 
		for the icon, if you want to change the color, be sure to use `%23` instead of `#`, since it's a url. You can also swap in a different svg icon or an external image reference

	*/

	background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22292.4%22%20height%3D%22292.4%22%3E%3Cpath%20fill%3D%22%23FF5050%22%20d%3D%22M287%2069.4a17.6%2017.6%200%200%200-13-5.4H18.4c-5%200-9.3%201.8-12.9%205.4A17.6%2017.6%200%200%200%200%2082.2c0%205%201.8%209.3%205.4%2012.9l128%20127.9c3.6%203.6%207.8%205.4%2012.8%205.4s9.2-1.8%2012.8-5.4L287%2095c3.5-3.5%205.4-7.8%205.4-12.8%200-5-1.9-9.2-5.5-12.8z%22%2F%3E%3C%2Fsvg%3E');

	background-repeat: no-repeat, repeat;

	/* arrow icon position (1em from the right, 50% vertical) , then gradient position*/
	background-position: right .7em top 50%, 0 0;
	/* icon size, then gradient */
	background-size: .65em auto, 100%;
}
/* Hide arrow icon in IE browsers */
.select-css::-ms-expand {
	display: none;
}
/* Hover style */
.select-css:hover {
	border-color: #888;
}
/* Focus style */
.select-css:focus {
	border-color: #FF5050;
	/* It'd be nice to use -webkit-focus-ring-color here but it doesn't work on box-shadow */
	box-shadow: 0 0 1px 3px rgba(255, 80, 80, .7);
	box-shadow: 0 0 0 3px -moz-mac-focusring;
	color: #FF5050; 
	outline: none;
}

/* Set options to normal weight */
.select-css option {
	font-weight:normal;
}

/* Support for rtl text, explicit support for Arabic and Hebrew */
*[dir="rtl"] .select-css, :root:lang(ar) .select-css, :root:lang(iw) .select-css {
	background-position: left .7em top 50%, 0 0;
	padding: .6em .8em .5em 1.4em;
}

/* Disabled styles */
.select-css:disabled, .select-css[aria-disabled=true] {
	color: graytext;
	background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22292.4%22%20height%3D%22292.4%22%3E%3Cpath%20fill%3D%22graytext%22%20d%3D%22M287%2069.4a17.6%2017.6%200%200%200-13-5.4H18.4c-5%200-9.3%201.8-12.9%205.4A17.6%2017.6%200%200%200%200%2082.2c0%205%201.8%209.3%205.4%2012.9l128%20127.9c3.6%203.6%207.8%205.4%2012.8%205.4s9.2-1.8%2012.8-5.4L287%2095c3.5-3.5%205.4-7.8%205.4-12.8%200-5-1.9-9.2-5.5-12.8z%22%2F%3E%3C%2Fsvg%3E'),
	  linear-gradient(to bottom, #ffffff 0%,#e5e5e5 100%);
}

.select-css:disabled:hover, .select-css[aria-disabled=true] {
	border-color: #aaa;

}

table{
    table-layout: fixed;
}

.time_warn{
  color: #FF0000;
  font-size:12px;
}

.instructions{
font-family: Tahoma;
text-align: center;
padding-left: 10%;
padding-right: 10%;
  color: #0c163b;
}

.instructions-large{
  font-family: Tahoma;
  text-align: center;
  font-size:20px;
  padding-left: 10%;
  padding-right: 10%;
  color: #0c163b;
  }

.selectcontainer {
   color: #FF5050;
   font-weight: bold;
   font-size:90%;
}

.selectcontainer-padleft {
  color: #FF5050;
  font-weight: bold;
  font-size:90%;
  padding-left: 15%;
}

.size_value{
  color: #FF5050;
  font-weight: bold;
}

.thumb-img {
  border: solid 6px #aaa;
  border-radius: 6px;
  opacity: 0.5;
}

.thumb-img:hover {
  border: solid 6px #FF8383;
  border-radius: 6px;
  cursor: pointer;
  opacity: 1;
}

.thumb-img.active {
  border: solid 6px #FF5050;
  border-radius: 6px;
  opacity: 1;
}

.art-img, .photo-img  {
  border: solid 6px #aaa;
  border-radius: 6px;
  opacity: 0.5;
}

.art-img:hover,  .photo-img:hover{
  border: solid 6px #f5956c;
  border-radius: 6px;
  cursor: pointer;
  opacity: 1;
}

.art-img.active, .photo-img.active {
  border: solid 6px #FF5050;
  border-radius: 6px;
  opacity: 1;
}

.select_label{
   color: #3448C5;
   font-weight: bold;
}

.select_label1{
  color: #0c163b;
  font-weight: bold;
  font-size: 12px;
}

.select_label2{
  color: #0c163b;
  font-weight: normal;
}

.env_select_label{
   color: #3448C5;
   font-weight: bold;
   padding-left: 15%;
}

.sliders{
  display: inline;
}

.slider_value{
   color: #FF5050;
   font-weight: bold;
}

.slider_label{
   color: #3448C5;
   font-weight: bold;
  padding-left: 15%;
}

.step_number {
        background:  black;
        color:  white;
        width: 24px;
        height: 24px;
        display: inline-block;
        text-align: center;
        line-height: 24px;
        border-radius: 100px;
}

.slidecontainer {
  width: 85%; /* Width of the outside container */
  text-align: center;
float: right;
padding-right: 15%;
}

/* The slider itself */

/* Mouse-over effects */
.slider:hover {
  opacity: 1; /* Fully shown on mouse-over */
}

.slider {
  -webkit-appearance: none;
  width: 100%;
  height: 15px;
  border-radius: 5px;  
  background: #3448C5;
  outline: none;
  opacity: 0.7;
  -webkit-transition: .2s;
  transition: opacity .2s;
}

.slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 25px;
  height: 25px;
  border-radius: 50%; 
  background: #FF5050;
  cursor: pointer;
}

.slider::-moz-range-thumb {
  width: 25px;
  height: 25px;
  border-radius: 50%;
  background: #FF5050;
  cursor: pointer;
}

.cloudinary-button {
  display: inline-block;
  padding: 15px 25px;
  font-size: 18px;
  cursor: pointer;
  text-align: center;
  text-decoration: none;
  outline: none;
  color: #fff;
  background-color: #FF5050;
  border: none;
  border-radius: 15px;
  box-shadow: 0 9px #999;
}

.cloudinary-button:hover {
  background-color: #ff0303;
  cursor: pointer;
}

.cloudinary-button:active {
  background-color: #ff0303;
  box-shadow: 0 5px #666;
  transform: translateY(4px);
}

.fix {
 display: block;
}

.loader {
  position: static;
  margin: auto;
  border: 16px solid #5A616A; 
  border-top: 16px solid #3448C5; 
  border-radius: 50%;
  width: 120px;
  height: 120px;
  animation: spin 2s linear infinite;
} 

@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}

.current-img {
	padding:8px 16px;
}

.demo-btn {
	border: 0px;
	background-color:#FF5050;
	border-radius:30px;
	display:inline-block;
	cursor:pointer;
	color:#ffffff;
	font-size:14px;
	font-weight:600;;
	padding:10px 16px;
	text-decoration:none;
	
}
.demo-btn:hover {
	background-color:#ff0303;
}

a.demo-btn:link, a.demo-btn:visited, a.demo-btn:hover, a.demo-btn:active {
	color: #ffffff;
	text-decoration:none;
}

.demo-btn:active {
	position:relative;
	top:1px;
}

span.mystep {
  background: #FF5050;
  border-radius: 0.8em;
  -moz-border-radius: 0.8em;
  -webkit-border-radius: 0.8em;
  color: #ffffff;
  display: inline-block;
  font-weight: bold;
  line-height: 1.6em;
  margin-right: 5px;
  text-align: center;
  width: 1.6em;
}

.coordinates {
  text-align: center;
  color: #0c163b;
}

.tr_all {
  display:inline-block;
  vertical-align:top;
  margin-left: 3em;
  margin-bottom: 1em;
  text-align: left;
}

.tl_all {
  display:inline-block;
  vertical-align:top;
  margin-right: 3em;
  margin-bottom: 1em;
  text-align: right;
}

.br_all {
  display:inline-block;
  vertical-align:top;
  margin-left: 3em;
  margin-bottom: 1em;
  text-align: left;
}

.bl_all {
  display:inline-block;
  vertical-align:top;
  margin-right: 3em;
  margin-bottom: 1em;
  text-align: right;
}

.options {
  font-size: 18px;
  font-weight: bold;
  color: #0c163b;
}

.coordinate-value {
  color: #FF5050;
  font-weight: bold; 
  text-align: right;  
}

/* Accessible Media Demo Styles */

/* Dark theme support for audio description demo */
[data-theme="dark"] .audio-description-demo {
  border-color: var(--dark-border) !important;
  background: var(--dark-bg) !important;
  color: var(--dark-text) !important;
}

[data-theme="dark"] .audio-description-demo h4 {
  color: var(--dark-border) !important;
}

/* Video player demo styles */
#wordHighlight {
  height: 400px;
  padding-top: unset;
}
#wordHighlight > div.vjs-poster > picture > img {
  object-fit: contain;
}

#wordHighlight > div.vjs-poster > picture {
  background: var(--main-content-color);
}
#wordHighlight.video-js {
  background-color: var(--main-content-color);
}

/* Dark theme support for colorblind demo */
[data-theme="dark"] .colorblind-demo {
  background-color: #2d3748 !important;
  border-color: #4a5568 !important;
  color: #e2e8f0 !important;
}

[data-theme="dark"] .colorblind-demo label {
  color: #e2e8f0 !important;
}

[data-theme="dark"] .colorblind-demo select {
  background-color: #4a5568 !important;
  color: #e2e8f0 !important;
  border: 1px solid #718096 !important;
}

[data-theme="dark"] .url-display {
  background-color: #2c5282 !important;
  border: 1px solid #3182ce !important;
}

[data-theme="dark"] .url-display h4 {
  color: #63b3ed !important;
}

[data-theme="dark"] .url-display code {
  color: #e2e8f0 !important;
}

[data-theme="dark"] .tips-section {
  background-color: #744210 !important;
  border: 1px solid #975a16 !important;
}

[data-theme="dark"] .tips-section h4 {
  color: #fbb041 !important;
}

[data-theme="dark"] .tips-section,
[data-theme="dark"] .tips-section ul,
[data-theme="dark"] .tips-section li {
  color: #faf089 !important;
}

/* Dark theme support for text overlay demo */
[data-theme="dark"] .text-overlay-demo label,
[data-theme="dark"] .text-overlay-demo input,
[data-theme="dark"] .text-overlay-demo select {
  --text-color: #e2e8f0;
  --input-bg: #2d3748;
}

/* Dark theme support for OCR text content */
[data-theme="dark"] .ocr-text-content {
  background: var(--dark-bg) !important;
  color: var(--dark-text) !important;
}

/* Dark theme support for audio mixing demo */
[data-theme="dark"] .db-status-container {
  background: var(--dark-bg) !important;
  color: var(--dark-text) !important;
}

/* Dark theme support for motion demo */
[data-theme="dark"] .motion-demo-container {
  border-color: var(--dark-border) !important;
  background: var(--dark-bg) !important;
  color: var(--dark-text) !important;
}

/* Dark theme support for gallery demo container */
[data-theme="dark"] #accessible-gallery-demo {
  background: #2d3748 !important;
  border-color: #4a90e2 !important;
}

[data-theme="dark"] #accessible-gallery-demo h4 {
  color: #4a90e2 !important;
}

[data-theme="dark"] #accessible-gallery-demo p {
  color: #e2e8f0 !important;
}

/* Dark theme support for keyboard controls */
[data-theme="dark"] .keyboard-controls-container {
  border-color: var(--dark-border) !important;
  background: var(--dark-bg) !important;
  color: var(--dark-text) !important;
}

[data-theme="dark"] .keyboard-controls-container h4 {
  color: var(--dark-border) !important;
}

[data-theme="dark"] .keyboard-key {
  background: var(--dark-kbd-bg) !important;
  color: var(--dark-kbd-text) !important;
  border-color: #718096 !important;
}

/* Dark theme support for video player demo */
[data-theme="dark"] .video-player-demo {
  border-color: var(--dark-border) !important;
  background: var(--dark-bg) !important;
  color: var(--dark-text) !important;
}

[data-theme="dark"] .video-player-demo h4 {
  color: var(--dark-border) !important;
}

[data-theme="dark"] .video-demo-features {
  color: var(--dark-subtext) !important;
}

/* Dark theme support for upload widget demo */
[data-theme="dark"] .upload-widget-demo {
  border-color: var(--dark-border) !important;
  background: var(--dark-bg) !important;
  color: var(--dark-text) !important;
}

[data-theme="dark"] .upload-widget-demo h4 {
  color: var(--dark-border) !important;
}

[data-theme="dark"] .upload-widget-demo > div:last-child {
  color: var(--dark-subtext) !important;
}

/* Text Layer Demo Styles */
.text-layer-demo-container {
  --light-border: #0066cc;
  --light-bg: #f8f9fa;
  --light-text: #333;
  --light-input-bg: #fff;
  --light-url-bg: #f8fafc;
  --light-url-border: #e2e8f0;
  --dark-border: #4a90e2;
  --dark-bg: #2d3748;
  --dark-text: #e2e8f0;
  --dark-input-bg: #1a202c;
  --dark-url-bg: #1e293b;
  --dark-url-border: #334155;
  
  border: 2px solid var(--light-border);
  border-radius: 8px;
  padding: 20px;
  background: var(--light-bg);
  color: var(--light-text);
}

.text-layer-demo-container h4 {
  margin-top: 0;
  color: var(--light-border);
}

.text-layer-demo-container .demo-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 30px;
  margin-bottom: 20px;
}

.text-layer-demo-container .controls-section {
  text-align: left;
}

.text-layer-demo-container .control-group {
  margin-bottom: 15px;
}

.text-layer-demo-container .control-group label {
  display: block;
  font-weight: bold;
  margin-bottom: 5px;
}

.text-layer-demo-container .checkbox-label {
  display: flex;
  align-items: center;
  cursor: pointer;
  font-weight: normal;
}

.text-layer-demo-container .demo-checkbox {
  margin-right: 8px;
  cursor: pointer;
  width: 18px;
  height: 18px;
}

.text-layer-demo-container .checkbox-label code {
  background: rgba(0, 0, 0, 0.05);
  padding: 2px 6px;
  border-radius: 3px;
  font-size: 0.9em;
}

.text-layer-demo-container .control-hint {
  font-size: 12px;
  color: #666;
  margin-top: 4px;
  font-style: italic;
}

.text-layer-demo-container .text-input {
  width: 100%;
  padding: 8px;
  border: 1px solid #ccc;
  border-radius: 4px;
  background: var(--light-input-bg);
  color: var(--light-text);
  box-sizing: border-box;
}

.text-layer-demo-container .demo-select {
  width: 100%;
  padding: 8px;
  border: 1px solid #ccc;
  border-radius: 4px;
  background: var(--light-input-bg);
  color: var(--light-text);
}

.text-layer-demo-container .text-input:focus,
.text-layer-demo-container .demo-select:focus {
  outline: 2px solid #3448c5;
  outline-offset: 2px;
}

.text-layer-demo-container .preview-section {
  text-align: center;
}

.text-layer-demo-container .preview-label {
  margin-bottom: 10px;
  font-weight: bold;
}

.text-layer-demo-container .preview-image {
  max-width: 100%;
  height: auto;
  border-radius: 8px;
  border: 2px solid #ccc;
}

.text-layer-demo-container .preview-video {
  max-width: 100%;
  height: auto;
  border-radius: 8px;
  border: 2px solid #ccc;
}

.text-layer-demo-container .transformation-url-box {
  margin-top: 20px;
  padding: 15px;
  border: 2px solid var(--light-border);
  border-radius: 5px;
  font-family: monospace;
  font-size: 12px;
  word-break: break-all;
  text-align: left;
  background: var(--light-url-bg);
}

.text-layer-demo-container .transformation-url-box strong {
  display: block;
  margin-bottom: 8px;
  font-family: sans-serif;
  color: var(--light-text);
}

.text-layer-demo-container #transformation-url-link {
  color: var(--light-border);
  text-decoration: none;
  display: block;
  transition: opacity 0.2s ease;
}

.text-layer-demo-container #transformation-url-link:hover {
  opacity: 0.8;
  text-decoration: underline;
}

.text-layer-demo-container #transformation-url-display {
  color: inherit;
}

/* Dark theme support for text layer demo */
[data-theme="dark"] .text-layer-demo-container {
  border-color: var(--dark-border) !important;
  background: var(--dark-bg) !important;
  color: var(--dark-text) !important;
}

[data-theme="dark"] .text-layer-demo-container h4 {
  color: var(--dark-border) !important;
}

[data-theme="dark"] .text-layer-demo-container .text-input,
[data-theme="dark"] .text-layer-demo-container .demo-select {
  background: var(--dark-input-bg) !important;
  color: var(--dark-text) !important;
  border-color: #4a5568 !important;
}

[data-theme="dark"] .text-layer-demo-container .transformation-url-box {
  background: var(--dark-url-bg) !important;
  border-color: var(--dark-border) !important;
}

[data-theme="dark"] .text-layer-demo-container .transformation-url-box strong {
  color: var(--dark-text) !important;
}

[data-theme="dark"] .text-layer-demo-container #transformation-url-link {
  color: var(--dark-border) !important;
}

[data-theme="dark"] .text-layer-demo-container .preview-image {
  border-color: #4a5568 !important;
}

[data-theme="dark"] .text-layer-demo-container .preview-video {
  border-color: #4a5568 !important;
}

[data-theme="dark"] .text-layer-demo-container .checkbox-label code {
  background: rgba(255, 255, 255, 0.1) !important;
}

[data-theme="dark"] .text-layer-demo-container .control-hint {
  color: #a0aec0 !important;
}

/* X-Cld-Error Inspector Tool Styles */
.x-cld-error-inspector {
  max-width: 800px;
  margin: 20px 0;
  padding: 20px;
  border: 1px solid var(--inspector-border, #ddd);
  border-radius: 8px;
  background-color: var(--inspector-bg, #f9f9f9);
  color: var(--inspector-text, #333);
}

.x-cld-error-inspector .input-wrapper {
  margin-bottom: 15px;
}

.x-cld-error-inspector label {
  display: block;
  margin-bottom: 8px;
  font-weight: bold;
  color: var(--inspector-text, #333);
}

.x-cld-error-inspector input[type="text"] {
  width: 100%;
  padding: 10px;
  border: 1px solid var(--inspector-input-border, #ccc);
  border-radius: 4px;
  font-family: monospace;
  font-size: 14px;
  background-color: var(--inspector-input-bg, #fff);
  color: var(--inspector-text, #333);
  box-sizing: border-box;
}

.x-cld-error-inspector button.x-cld-inspect-btn {
  padding: 10px 25px;
  line-height: 1.4;
  background-color: var(--button-background-color);
  font-family: "Inter", Helvetica, Arial, sans-serif;
  color: var(--sign-up-button-color);
  font-weight: 600;
  font-size: 14px;
  text-transform: uppercase;
  border: none;
  border-radius: 20px;
  cursor: pointer;
  transition: filter 0.2s ease;
}

.x-cld-error-inspector button.x-cld-inspect-btn:hover {
  filter: brightness(85%);
}

.x-cld-error-inspector #result-container {
  margin-top: 20px;
}

.x-cld-error-inspector #loading {
  color: var(--inspector-loading, #666);
}

.x-cld-error-inspector .result-success {
  padding: 15px;
  background-color: var(--result-warning-bg, #fff3cd);
  border: 1px solid var(--result-warning-border, #ffc107);
  border-radius: 4px;
  margin-top: 10px;
  color: var(--inspector-text, #333);
}

.x-cld-error-inspector .result-error {
  padding: 15px;
  background-color: var(--result-error-bg, #f8d7da);
  border: 1px solid var(--result-error-border, #dc3545);
  border-radius: 4px;
  margin-top: 10px;
  color: var(--inspector-text, #333);
}

.x-cld-error-inspector .result-ok {
  padding: 15px;
  background-color: var(--result-success-bg, #d4edda);
  border: 1px solid var(--result-success-border, #28a745);
  border-radius: 4px;
  margin-top: 10px;
  color: var(--inspector-text, #333);
}

.x-cld-error-inspector .header-info {
  margin-top: 10px;
  padding: 10px;
  background-color: var(--header-info-bg, #e9ecef);
  border-radius: 4px;
  font-family: monospace;
  font-size: 13px;
  color: var(--inspector-text, #333);
}

.x-cld-error-inspector .header-label {
  font-weight: bold;
  color: var(--inspector-label, #495057);
}

/* Support for explicit dark theme class */
[data-theme="dark"] .x-cld-error-inspector {
  --inspector-border: #4a5568;
  --inspector-bg: #2d3748;
  --inspector-text: #e2e8f0;
  --inspector-input-border: #4a5568;
  --inspector-input-bg: #1a202c;
  --inspector-loading: #a0aec0;
  --inspector-label: #cbd5e0;
  --header-info-bg: #1a202c;
  --result-warning-bg: #744210;
  --result-warning-border: #d69e2e;
  --result-error-bg: #742a2a;
  --result-error-border: #fc8181;
  --result-success-bg: #22543d;
  --result-success-border: #48bb78;
}

/* Image Enhancement Demo Styles */

#image-enhancement-demo {
  max-width: 1200px;
  margin: 20px auto;
  padding: 20px;
  border: 1px solid var(--inspector-border, #ddd);
  border-radius: 8px;
  background-color: var(--inspector-bg, #f9f9f9);
}

#image-enhancement-demo h4 {
  color: var(--inspector-text, #333);
  margin-top: 0;
}

#image-thumbs {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  margin-bottom: 30px;
  gap: 10px;
}

.thumb-container {
  text-align: center;
  margin: 10px;
}

.thumb-img {
  cursor: pointer;
  max-width: 150px;
  height: 100px;
  object-fit: cover;
}

.thumb-label {
  font-size: 12px;
  margin-top: 5px;
  color: var(--inspector-text, #333);
}

.demo-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
  margin-bottom: 30px;
}

.image-section {
  margin-bottom: 20px;
}

.image-label-wrapper {
  margin-bottom: 10px;
}

.comparison-label {
  color: var(--inspector-text, #333);
}

.comparison-image {
  max-width: 100%;
  height: auto;
  border-radius: 4px;
  display: block;
  cursor: pointer;
}

.comparison-image.original {
  border: 2px solid var(--inspector-border, #ddd);
}

.comparison-image.enhanced {
  border: 2px solid #3448c5;
}

.enhancement-option-wrapper {
  margin-bottom: 15px;
}

.enhancement-option-label {
  display: flex;
  align-items: flex-start;
  cursor: pointer;
  padding: 12px;
  border-radius: 6px;
  border: 2px solid transparent;
  transition: all 0.2s ease;
  background: var(--inspector-input-bg, #fff);
  color: var(--inspector-text, #333);
}

.enhancement-option-label:hover {
  background: var(--dropdown-background-active-color, #f0f0f0);
}

.enhancement-option-label.selected {
  background: var(--inspector-input-bg, #fff);
  border-color: #3448c5;
}

.enhancement-option-label input[type="radio"] {
  margin-right: 10px;
  margin-top: 4px;
}

.enhancement-option-name {
  font-weight: bold;
  margin-bottom: 4px;
}

.enhancement-option-description {
  font-size: 13px;
  opacity: 0.8;
}

#transformation-url {
  margin-top: 20px;
  padding: 20px;
  background-color: #f8fafc;
  border-radius: 8px;
  border: 1px solid #e2e8f0;
}

.url-link {
  text-decoration: none;
}

.url-code {
  background: #f1f5f9;
  padding: 8px 12px;
  border-radius: 6px;
  font-size: 13px;
  font-family: 'Monaco', 'Menlo', 'Courier New', monospace;
  color: #0f172a;
  word-break: break-all;
  cursor: pointer;
  display: block;
  border: 1px solid #e2e8f0;
  transition: all 0.2s ease;
}

.url-code:hover {
  background: #e2e8f0;
  border-color: #cbd5e1;
}

#transformation-url > div {
  margin-bottom: 12px;
}

#transformation-url > div:last-child {
  margin-bottom: 0;
}

#transformation-url strong {
  color: #64748b;
  display: block;
  margin-bottom: 6px;
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  font-weight: 600;
}

.thumb-label {
  color: var(--inspector-text, #333);
}

.comparison-label {
  color: var(--inspector-text, #333);
}

/* Dark theme support for Image Enhancement Demo */
[data-theme="dark"] #image-enhancement-demo {
  background-color: #2d3748 !important;
  border-color: #4a5568 !important;
  color: #e2e8f0 !important;
}

[data-theme="dark"] #image-enhancement-demo h4 {
  color: #e2e8f0 !important;
}

[data-theme="dark"] .comparison-image.original {
  border-color: #4a5568;
}

[data-theme="dark"] #transformation-url {
  background-color: #1e293b !important;
  border: 1px solid #334155 !important;
}

[data-theme="dark"] #transformation-url strong {
  color: #94a3b8 !important;
}

[data-theme="dark"] .url-code {
  background: #1e293b;
  color: #94a3b8;
  border-color: #334155;
}

[data-theme="dark"] .url-code:hover {
  background: #334155;
  border-color: #475569;
}

[data-theme="dark"] .enhancement-option-label {
  background: #1a202c;
  color: #e2e8f0;
}

[data-theme="dark"] .enhancement-option-label:hover {
  background: #2d3748;
}

[data-theme="dark"] .enhancement-option-label.selected {
  background: #2d3748;
  border-color: #4a90e2 !important;
}

[data-theme="dark"] .thumb-label {
  color: #e2e8f0 !important;
}

[data-theme="dark"] .comparison-label {
  color: #e2e8f0 !important;
}

