St.cache don't cache images

Hi
i am using @st.cache to load an image using PIL module the image is itself around 7.2 MB.
but whenever i click any of the widgets or buttons, the page starts reloading and the image fades away for a while and then comes back, seems like its reloading to the memory again.

Here is my code:

import streamlit as st
from PIL import Image

@st.cache
def load_image(self):
    data = dict()
    data['girl'] = Image.open('static/images/girl.jpg')
    return data

#Sidebar
st.sidebar.title('Authentication')
username = st.sidebar.text_input('username', '')
password = st.sidebar.text_input('password', '')
signin = st.sidebar.button('Sign In')
st.sidebar.markdown('---')
st.sidebar.text('Don\'t have an account?')
signup = st.sidebar.button('Sign Up')

if signin and len(username)>0 and len(password)>0:
    st.sidebar.text('username:{}, password:{}'.format(username, password))

if signup:
    st.sidebar.text('you pressed signup button')

#Main screen
st.markdown("# ***sound wave*** \n---")
st.image(load_image(0)['girl'], use_column_width=True)

st.subheader('Plug into nirvana')
st.markdown("""90% of people love to enjoy music, while they are working!<br>
    are you one of them, we have a curated list of chillout tracks<br>
    that may help you bring out the calmness in you.
    """, unsafe_allow_html=True)

#choices
genre = st.radio("What's your favorite music genre",('Pop', 'Romantic', 'Devotional'))

Hey @imneonizer!

@st.cache does work properly with image data. (I ran your test code to verify there wasn’t anything strange happening with PIL-loaded images.)

However: 7mb is a large image! When Streamlit accesses a cached file, it does some work to make sure the file hasn’t been modified, and the bigger the file, the more work it needs to do. In other words, caching isn’t completely free, and this likely accounts for the slowness you’re seeing.

If you know the image will not change between runs, and you want Streamlit to skip this check, you can use the allow_output_mutation flag in st.cache:

@st.cache(allow_output_mutation=True)
def load_image():
    ...

Some other things to try:

  • Can you reduce the size of the image?
  • Does the image need to be in PIL format? (Are you doing some additional processing on it?) If not, you could instead try st.image('static/images/girl.jpg'). (st.image works with file paths as well.)
1 Like

I noticed this as well.

I’m using a 180kb png logo and it adds roughly 2.5s to the load time no matter if it’s cached or not. Yes, that logo is much higher resolution than it needs to be for the web and I was able to partially solve the problem by simply downscaling it. Still, I expect that this could be a problem for image heavy websites.

@tim How can I cache the image if I use st.image with a file path? Will it use caching in the background automatically?

Hi @pietz!

No, st.image doesn’t do any caching if you use it with a file path. I suggested it to @imneonizer, above, to avoid the double-overhead of loading an image with PIL only to have st.image then convert it to another format for sending to the browser.

We’re working on a change to have Streamlit serve media files - images, video, audio - via HTTP (as opposed to bundling them into protobufs and shipping them over a websocket, which is how they work right now). This should make things faster without any st.cache shenanigans required in Streamlit apps! You can track that issue here.