Image in Markdown

Hi everyone
For some reason, I have to use the image in markdown instead of st.image. However, it didn’t work. Do you know how can I do?

a = """Some text

![Cool Image](images/DWAFig22.png)

Some more text"""

st.markdown(a)
2 Likes

Hey @Berk_Demir,

Hard to say with just this snippet, do you have a link to a GitHub repo and can you screenshot the error you get when you try to use st.image()? (also please add the image code you use)

Happy Streamlit-ing!
Marisa

1 Like

I am sorry, I think I wasn’t clear. I want to use markdown to show my image. not the st.image. The snippet I have sent you is a markdown text which is later on shwon in Streamlit as st.markdown(a). But, image does not appear.

1 Like

It is shown as a broken link and the link is: http://localhost:4444/images/DWAFig22.png

1 Like

Hello again. I have tried with online images and it works. However, images on my computer during localhost application does not work.

https://share.streamlit.io/akrolsmir/streamlit-snippet/main?snippet_id=3biYhJQ4

1 Like

So you are trying to use markdown to display an image on your app that is stored in your local computer? Why do you want to use markdown instead of the st.image function?

What does your directory structure look like?

Based on the path you supply you have a /images/ folder in your current working directory and in that folder there should be a DWAFig22.png

can you screenshot the error you get?

1 Like

if i want to display a markdown file in streamlit, and the markdown file incloud local images , than the images can not display in streamlit web page.

Hi @Berk_Demir, @lt8cn ,

Images in st.markdown can only be loaded when served by a β€œserver”. This is an example of the trick I use when displaying my README.md files in Streamlit apps, which relies on the code being in GitHub, i.e. the β€œserver”. (The example is from https://github.com/asehmi/fastapi-wrapper-apiness.)

Change the list of images and the base URL for your GitHub repo. And it assumes markdown image statements appear in their own line in your .md file.

    if st.sidebar.checkbox('Readme', False):
        st.markdown('---')
        '''
        ### Readme :smile:
        '''
        with open('./README.md', 'r', encoding='utf-8') as f:
            readme_lines = f.readlines()
            readme_buffer = []
            images = [
                'images/fastapi_wrapper_demo.gif',
                'images/full_screenshot.png',
                'images/fastapi_wrapper_st_demo.gif',
                'images/fastapi_wrapper_installation.gif',
                'images/json_data.png',
                'images/html_table.png',
                'images/pbi_report_m_lang.png',
                'images/pbi_report.png',
                'images/apiness.png',
                'images/fastapi_testimonial.png'
            ]
            for line in readme_lines:
                readme_buffer.append(line)
                for image in images:
                    if image in line:
                        st.markdown(' '.join(readme_buffer[:-1]))
                        st.image(f'https://raw.githubusercontent.com/asehmi/fastapi-wrapper-apiness/main/{image}')
                        readme_buffer.clear()
            st.markdown(' '.join(readme_buffer))

(This code is from the line beginning here)

HTH,
Arvindra

5 Likes

Bumping this thread because the use case is important. I have tons of markdown files that contain in-line image links to local files. I do not want to have to either a) break them up with st.image links or b) implement something as complicated as the above (although it is as usual cool work by @asehmi). There should be a better way.

2 Likes

Hi @fredzannarbor,

Thanks for bumping this thread up. I’ve created a Streamlit app that shows 2 ways to display images:

  1. Using st.image
  2. Using st.markdown

Demo app is available here https://dataprofessor-st-demo-image-markdown-streamlit-app-layled.streamlitapp.com/

Code is available on GitHub here GitHub - dataprofessor/st-demo-image-markdown

Code for implementing these is shown below:

  1. Using st.image
from PIL import Image
img = Image.open('streamlit-logo-secondary-colormark-darktext.png')
st.image(img)
  1. Using st.markdown

# img_to_bytes and img_to_html inspired from https://pmbaumgartner.github.io/streamlitopedia/sizing-and-images.html
import base64
from pathlib import Path
from utilities import load_bootstrap

load_bootstrap()

def img_to_bytes(img_path):
    img_bytes = Path(img_path).read_bytes()
    encoded = base64.b64encode(img_bytes).decode()
    return encoded
def img_to_html(img_path):
    img_html = "<img src='data:image/png;base64,{}' class='img-fluid'>".format(
      img_to_bytes(img_path)
    )
    return img_html

st.markdown(img_to_html('streamlit-logo-secondary-colormark-darktext.png'), unsafe_allow_html=True)
9 Likes

Thanks! This is pretty helpful, but doesn’t quite solve my use case. I have many long markdown files like this:

asdsafd
asdfasdfas
asdfsaf
image with local links
sfasdfadf
asdfasdf
sdfsafd
image with local links
asfasfdaf
asdfasf

It is not practical for me to break all these files into chunks and insert st.markdown(img_to_html) commands in between the chunks. I could write something to look for local links and chunk before and after, but that sounds potentially error-prone.

Maybe this is utopian, but I think Streamlit ought to be able to read a markdown file with standard markdown components like images and do its best to render the whole thing. If it comes across a link to a local image, it should see if it can reach the image and display it; if it can’t, it can emit some sort of warning or place a small β€œno luck” image.

1 Like

Aha, I see what you mean. You want to be able to read in several images from markdown files.

What we want to achieve here is a unique use case that may require some creative solutions.

I’ve implemented something similar in the 30 Days of Streamlit app.

Conceptual explanation of the 30 Days app

Instead of storing text and image URL inside a single long markdown file, I’ve split it into: markdown and CSV file.

The markdown file contains only the text while the CSV file contains the image file name and figure caption text.

Practically, the user selects from a select box one of 30 possible options (Days 1-30) and a for loop is implemented to display one of 30 possible markdown/CSV files. f-strings is then used to append the selected day into the relative URL so that the appropriate markdown and images are displayed.

Directory tree of the 30 Days app

Markdown files are found inside the content/ directory while CSV files are located in content/figures.

The actual images are located at content/images

πŸ“¦ 
β”œβ”€ .streamlit
β”‚  └─ config.toml
β”œβ”€ 3AF34648-C61D-47CE-9E56-C496C5A7C240.jpeg
β”œβ”€ LICENSE
β”œβ”€ README.md
β”œβ”€ content
β”‚  β”œβ”€ Day1.md
β”‚  β”œβ”€ Day10.md
β”‚  β”œβ”€ Day11.md
β”‚  β”œβ”€ Day12.md
β”‚  β”œβ”€ Day13.md
β”‚  β”œβ”€ Day14.md
β”‚  β”œβ”€ Day15.md
β”‚  β”œβ”€ Day16.md
β”‚  β”œβ”€ Day17.md
β”‚  β”œβ”€ Day18.md
β”‚  β”œβ”€ Day19.md
β”‚  β”œβ”€ Day2.md
β”‚  β”œβ”€ Day20.md
β”‚  β”œβ”€ Day21.md
β”‚  β”œβ”€ Day22.md
β”‚  β”œβ”€ Day23.md
β”‚  β”œβ”€ Day24.md
β”‚  β”œβ”€ Day25.md
β”‚  β”œβ”€ Day26.md
β”‚  β”œβ”€ Day27.md
β”‚  β”œβ”€ Day28.md
β”‚  β”œβ”€ Day29.md
β”‚  β”œβ”€ Day3.md
β”‚  β”œβ”€ Day30.md
β”‚  β”œβ”€ Day4.md
β”‚  β”œβ”€ Day5.md
β”‚  β”œβ”€ Day6.md
β”‚  β”œβ”€ Day7.md
β”‚  β”œβ”€ Day8.md
β”‚  β”œβ”€ Day9.md
β”‚  β”œβ”€ figures
β”‚  β”‚  β”œβ”€ Day1.csv
β”‚  β”‚  β”œβ”€ Day20.csv
β”‚  β”‚  └─ Day6.csv
β”‚  └─ images
β”‚     β”œβ”€ 0CEEBB8C-29FB-4B85-9932-CEF642777A8A.jpeg
β”‚     β”œβ”€ 2C9104F7-CF84-4DAF-9004-52BB4644CF28.png
β”‚     β”œβ”€ 77EC58A5-25FD-4477-A74E-421333312514.jpeg
β”‚     β”œβ”€ 7A7B0072-71ED-42BD-B985-B0D35CF03A1F.jpeg
β”‚     β”œβ”€ 8032B4CC-A9BD-4B4F-8DFB-EBE7326886DE.jpeg
β”‚     β”œβ”€ 8085E82C-304F-48EE-8AD6-3F941E31860B.jpeg
β”‚     β”œβ”€ 8ED4483A-58C6-4F76-BE59-C8CC6DCDB95E.jpeg
β”‚     β”œβ”€ F8DCC7EB-D497-426D-904F-6941E2C4B750.jpeg
β”‚     └─ readme.md
β”œβ”€ requirements.txt
β”œβ”€ streamlit-logo-secondary-colormark-darktext.png
└─ streamlit_app.py

Β©generated by Project Tree Generator

Displaying Images

Of particular note is that not all 30 Days will contain images because there are only 3 Days (Days 1, 6 and 20) that contain images and thus there are 3 CSV files (containing the image file name and figure caption as mentioned above).

For example, Day 1 contains both text and images (from markdown and CSV files, respectively). Images are appended after markdown text as shown below:

Contents of CSV file:

img,figure,caption
2C9104F7-CF84-4DAF-9004-52BB4644CF28.png, Figure 1, Streamlit demo app is launched via "streamlit hello"

Code for implementing the display of Text and Images

An excerpt of the code in streamlit_app.py file is shown below:


# Display content
for i in days_list:
    if selected_day == i:
        st.markdown(f'# πŸ—“οΈ {i}')
        j = i.replace(' ', '')
        with open(f'content/{j}.md', 'r') as f:
            st.markdown(f.read())
        if os.path.isfile(f'content/figures/{j}.csv') == True:
            st.markdown('---')
            st.markdown('### Figures')
            df = pd.read_csv(f'content/figures/{j}.csv', engine='python')
            for i in range(len(df)):
                st.image(f'content/images/{df.img[i]}')
                st.info(f'{df.figure[i]}: {df.caption[i]}')

The GitHub repo for 30 Days app is available here: GitHub - streamlit/30days: #30DaysOfStreamlit is a 30-day social challenge for you to build and deploy Streamlit apps.

Hope this helps :slight_smile:

bumping this because its a bug, I believe github pages uses jeckyl to do the rendering if that helps. Streamlit has quickly become a platform of choice for when I want to do quick prototyping and this would help me quickly build cool stuff :slight_smile:

Great example!
I modified a bit your functions and implemented a replacement of markdown images:

import os
import re
import base64
from pathlib import Path

import streamlit as st

def markdown_images(markdown):
    # example image markdown:
    # ![Test image](images/test.png "Alternate text")
    images = re.findall(r'(!\[(?P<image_title>[^\]]+)\]\((?P<image_path>[^\)"\s]+)\s*([^\)]*)\))', markdown)
    return images


def img_to_bytes(img_path):
    img_bytes = Path(img_path).read_bytes()
    encoded = base64.b64encode(img_bytes).decode()
    return encoded


def img_to_html(img_path, img_alt):
    img_format = img_path.split(".")[-1]
    img_html = f'<img src="data:image/{img_format.lower()};base64,{img_to_bytes(img_path)}" alt="{img_alt}" style="max-width: 100%;">'

    return img_html


def markdown_insert_images(markdown):
    images = markdown_images(markdown)

    for image in images:
        image_markdown = image[0]
        image_alt = image[1]
        image_path = image[2]
        if os.path.exists(image_path):
            markdown = markdown.replace(image_markdown, img_to_html(image_path, image_alt))
    return markdown

with open("README.md", "r") as readme_file:
    readme = readme_file.read()

readme = markdown_insert_images(readme)

with st.container():
    st.markdown(readme, unsafe_allow_html=True)
3 Likes

Thanks a lot,it’s working,Awesome job

This doesn’t work with private repos. Is there any other way?

I think there are loads of different usecases why to use the st.markdown.
But for me, all I wanted was to round the edges of my images…

I managed with this:

import streamlit as st
from PIL import Image, ImageDraw

def round_corners(image, radius):
    width, height = image.size
    mask = Image.new("L", (width, height), 0)
    draw = ImageDraw.Draw(mask)
    draw.rounded_rectangle((0, 0, width, height), radius, fill=255)
    result = Image.new("RGBA", (width, height))
    result.paste(image, (0, 0), mask)
    return result

# Load your image
image = Image.open("images/your_image.jpg")

# Set the corner radius for rounding
corner_radius = 20  # Adjust the radius as needed

# Round the corners of the image
rounded_image = round_corners(image, corner_radius)

# Display the rounded image using Streamlit
st.image(rounded_image, caption="Rounded Image", use_column_width=None)

P.S This unfortunately does not work with .gif files. Does anyone have a better solution?

Cheers
Fred

I guess you can use markdown and CSS for that.

1 Like

I have problem displaying in st.markdown as well (display local image file). and It’s fix with using this comment. Confirm & Thank you.

1 Like

Glad to hear that it is helpful and working.