How Do I store PNG / SVG / JPEG in ReplitDB?

Question:
How do I store PNG / SVG / JPEG files in ReplitDB?

1 Like

You can convert an image to a b64 string.

from base64 import b64decode, b64encode


def encode_image(path):
    with open(path, "rb") as f:
        binary = b64encode(f)
    return binary

def decode_image(b64):
    return b64decode(b64)
2 Likes

Actually, there are MANY ways to store images in ReplitDB. Now, let’s consider the fact that ReplitDB is only a key-value store, so it won’t let you store binary data such as PNG, SVG, or JPEG files within it. As an alternative, you can store image metadata like this:

image_metadata = {
    "file_name": "example.png",
    "file_type": "PNG",
    "file_size": "1024 KB",
}

You can also host images externally using services like Imgur, AWS S3, or any other cloud storage service to upload and host your image files. These services will provide you with URLs that point to the hosted images. Alternatively, you can use this:

image_metadata["image_url"] = "https://example.com/path/to/your/image.png"

Whatever works to be honest, it doesn’t really matter.

2 Likes

@KAlexK I can see it’s getting closer. One problem, though. I’m using Flask and in the HTML, it asks the user for two images so the images aren’t actually stored in the Repl. This means that it does not allow me to use the encode_image() function, because the path of the image isn’t actually in the Repl, rather a image the user imports via a <input type="file"> tag. What is a workaround for this?

1 Like

I know you weren’t talking to me, but you can use this code to achieve what you want. It should work, but I haven’t tested it, so don’t blame me:

from flask import Flask, request, jsonify
from replit import db
import os

app = Flask(__name__)

app.config['UPLOAD_FOLDER'] = 'uploads'
app.config['ALLOWED_EXTENSIONS'] = {'jpg', 'jpeg', 'png', 'gif'}

def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in app.config['ALLOWED_EXTENSIONS']

def save_and_get_url(file):
    if file.filename and allowed_file(file.filename):
        file_path = os.path.join(app.config['UPLOAD_FOLDER'], file.filename)
        file.save(file_path)
        return f"https://{os.getenv('REPL_SLUG')}.{os.getenv('REPL_OWNER')}.repl.co/{file.filename}"
    return None

@app.route('/upload', methods=['POST'])
def upload_file():
    files = request.files
    if 'image1' not in files or 'image2' not in files:
        return "No files provided"

    image_url1 = save_and_get_url(files['image1'])
    image_url2 = save_and_get_url(files['image2'])

    images_list = db.get('images', [])

    images_list.append(image_url1)
    images_list.append(image_url2)

    db['images'] = images_list

    return "Files uploaded and processed successfully"

@app.route('/get_images', methods=['GET'])
def get_images():
    images_list = db.get('images', [])

    return jsonify(images=images_list)

if __name__ == '__main__':
    app.run(debug=True)
2 Likes

I don’t know exactly what the Flask image input returns, so this code converts the Pillow image to b64.

from base64 import b64decode, b64encode
from io import BytesIO
import re
from PIL import Image


def image_to_base64(image: Image):
    output_buffer = BytesIO()
    image.save(output_buffer, format='RGB')
    byte_data = output_buffer.getvalue()
    base64_str = b64encode(byte_data)
    return base64_str

def base64_to_image(base64_str):
    base64_data = re.sub('^data:image/.+;base64,', '', base64_str)
    byte_data = b64decode(base64_data)
    image_data = BytesIO(byte_data)
    img = Image.open(image_data)
    return img

Edit: oh, I didn’t even notice that the answer was already written by @sky

1 Like

@Sky What would this exactly do? Store the image on the Repl? Some how access the actual file even though it isn’t stored in the Repl?


It returns a path. If I import a image named example.png, it will return "example.png".

2 Likes

What do you mean? It is exactly as it appears. It takes the files from the request sent to your Flask route, checks if they are supported, saves the files to the upload folder ./uploads/, then returns the image URL for the uploaded file, and finally saves it in the Replit DB.

Within the repl, correct? Is it temporary storage or permanent?

1 Like

Yeah, unless you delete or clear ./uploads/, the files would be permanent.

What part of this code actually creates and stores the images in the /uploads/ folder?

1 Like

Oh, the function that does this is save_and_get_url().

In save_and_get_url(), does the parameter file accept a file path or a decoded / encoded BASE64 input?

1 Like

In the save_and_get_url() function, the file parameter typically accepts a file object. It doesn’t handle encoded or decoded b64 input by default, but it can be setup to do so if needed.

@Sky How would I set the function up to handle a BASE64 input?

1 Like
from flask import Flask, request, jsonify
from io import BytesIO
from replit import db
import base64
import os

app = Flask(__name__)

app.config['UPLOAD_FOLDER'] = 'uploads'
app.config['ALLOWED_EXTENSIONS'] = {'jpg', 'jpeg', 'png', 'gif'}

def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in app.config['ALLOWED_EXTENSIONS']

def save_and_get_url(file_or_data):
    if isinstance(file_or_data, bytes):
        filename = 'base64_image.png'
        file_data = base64.b64decode(file_or_data)
        file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
        with open(file_path, 'wb') as f:
            f.write(file_data)
        return f"https://{os.getenv('REPL_SLUG')}.{os.getenv('REPL_OWNER')}.repl.co/{filename}"
    elif hasattr(file_or_data, 'filename') and allowed_file(file_or_data.filename):
        file_path = os.path.join(app.config['UPLOAD_FOLDER'], file_or_data.filename)
        file_or_data.save(file_path)
        return f"https://{os.getenv('REPL_SLUG')}.{os.getenv('REPL_OWNER')}.repl.co/{file_or_data.filename}"
    return None

@app.route('/upload', methods=['POST'])
def upload_file():
    files = request.files
    if 'image1' not in files or 'image2' not in files:
        return "No files provided"

    image_url1 = save_and_get_url(files['image1'].read())
    image_url2 = save_and_get_url(files['image2'].read())

    images_list = db.get('images', [])
    images_list.extend([image_url1, image_url2])
    db['images'] = images_list

    return "Files uploaded and processed successfully"

@app.route('/get_images', methods=['GET'])
def get_images():
    images_list = db.get('images', [])
    return jsonify(images=images_list)

if __name__ == '__main__':
    app.run(debug=True)
1 Like

@Sky Problem is, I can’t convert example.png to BASE64 because it is not yet a file so how could I access the code within the uploaded file example.png? I’m not sure how to store it either, because I do not know how to make a File() object.

What do you mean? The code I sent you handles the image byte data, then converts it to b64. Wait, are you trying to send already converted data through it?

I’ll start from the top – the user inputs a image, I need to store it in my repl so I can access it later. The save_and_get_url() function seems to do store the image for me, so that’s great. Only problem is, I don’t have anything to put into save_and_get_url(), so I have no way to use it. I cannot BASE64 encode it because, it is not true file, yet. And there it is again. :confused:
@Sky Any ideas on how I should go about solving this?

Huh, what do you mean? The save_and_get_url() function handles the image data, which in your case should work.