Crop rectangular images into a circle?

Summary

I currently have an image of 200x300 size that I would like to output.
Ex: https://s3.amazonaws.com/ballotpedia-api4/files/thumbs/200/300/Michael-Tannousis.jpg

Is there a way to make the image output in a circle?
Ex: https://w7.pngwing.com/pngs/142/1021/png-transparent-cat-computer-icons-user-profile-avatar-profile-mammal-animals-cat-like-mammal-thumbnail.png

I have hundreds of images, so is there a way to do this in streamlit?

The normal output I have right now:

with innercol1:
  if official["profile_pic"] == "N/A":
      st.image("https://upload.wikimedia.org/wikipedia/commons/thumb/a/ac/No_image_available.svg/1024px-No_image_available.svg.png")
  else:
      st.image(official["profile_pic"], use_column_width="auto")

Not sure what you’re doing exactly but you should be able to handle it through the CSS properties;

  1. If you output your images into a dive element, give it a class name, then just inject some CSS into the code and it should be alright.

  2. If you can’t output it in a div element with a class name, just output it as it is now, go to your browser dev console and inspect the image element, take the class name and now you can affect it inside your streamlit CSS.

example:

    <div class="circle-image">
        <img src="image.jpg" alt="My Rectangular Image">
    </div>
st.markdown("""
        <style>
          .circle-image {
              width: 200px;
              height: 200px;
              border-radius: 50%;
              overflow: hidden;
              box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
          }
          
          .circle-image img {
              width: 100%;
              height: 100%;
              object-fit: cover;
          }
        </style>
        """, unsafe_allow_html=True)

Hi, thanks for responding, I’m not too familiar with CSS, can you help explain what I should do with the code blocks?

In the code block in my question, I am looping through a dictionary, and if there is a profile_pic link available (official['profile_pic']), I output the picture as follows. The issue I have is that the current picture from the link is rectangular and 200x300 pixels. I hope I was able to explain what I was doing.

Here is a snippet of what I have:
Screenshot 2023-08-17 190211

Here is a snippet of what I am aiming for.
image

Thanks!

@cjimmy
Here’s a video demo for how to do it:

And this is the code to test things out.

st.markdown("""
  <style>
    // this is for all img elements in the Streamlit div class nesting a img
    .css-1v0mbdj > img{
      border-radius: 50%;
    }
  </style>
""", unsafe_allow_html=True)
st.markdown("""
  <style>
    // this is a specific element selector (the second shin chan image)
    div.css-ocqkz7:nth-child(6) > div:nth-child(1) > div:nth-child(1) > div:nth-child(1) > div:nth-child(1) > div:nth-child(1) > div:nth-child(2) > div:nth-child(1) > img:nth-child(1) {
            border-radius: 50%;
    }
  </style>
""", unsafe_allow_html=True)

Use one or the other,

NOTE: There are ways in CSS to select elements either in odds or pairs, if you have a long list of images and want to select/highlight…etc always the second one in a div for example you can do so, check nth-child properties.

1 Like

Thank you @IndigoWizard, also, I love the crayon shin-chan cartoon, the image you used!

Also, I’m sorry to ask another question, but how do I make it a perfect circle when the image isn’t a perfect square before? It becomes an oval when the order radius is set. I tried setting the height and width but that didn’t work. Thank you in advance again.
image

@cjimmy

Through user input

You can request end users to only upload square pictures (it’s usally better to let the end user deal with the picture and align with the apps requirement rather than the dev having to deal with bad input and solve it caase by case)

Through python

You can write a script in your code that crops the pictures. Take a look at the PIL (pillow) python library.
You can check my repo forinspiration; a simple thumbnail generator, takes an image, crops it according to specified requierements using pillow library (PIL)

IndigoWizard/YT-Thumbnail-Gen - crop image using PIL

Through CSS

This being said, there’s a way to do it in CSS of course which is cropping the picture based on a specific shape, here a circle.

Theory concept:

You have a div that has a nested img element, you give the hosting div a circle shape (it’s transparent so it helps to add a backgroudn color while you work to see things clearly), now everything that is in the div will show through the shape of the dive (think of it as a home window, if it’s circle you can see only a circle surface of the house from the outside).

CSS Code Solution

As per my previous answer, the Streamlit div name class that host the nested img element is css-1v0mbdj ebxwdo61, you can use just css-1v0mbdj in this case since it doesn’t have a variant.
Make it circular shape while considering the width value according to your image size (200x300) and the height should be the same (it’s a circle duh)

st.markdown("""
  <style>

    /*the main div*/
    .css-1v0mbdj {
        width: 200px; /*max value according to image width, can be smaller but not larger*/
        height: 200px;
        position: relative;
        overflow: hidden;
        border-radius: 50%;
    }
    
    /*the img elements in the main div class*/
    .css-1v0mbdj > img{
        display: inline;
        margin: 0 auto;
        margin-top: -35%; /*Tweak this one according to your need*/
    }
  
  </style>
""", unsafe_allow_html=True)

Here’s a demo:

IMPORTANT NOTE:

It give you the right result but it will still depend on the images you’re using as you can see in the video; if it’s a close-up image the cropped result will have the face in it, if it’s an image where the person’s head is close to the top-end of the image it’ll look half cropped… etc. Best thing is to make sure the head is not too close to the top-end of the image and all images are more or less the same, no close-ups vs profile.

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.