I have come up with Python code which does output Base64 images as files, but none of the files are valid nor can be viewed with any image viewer as it gives an "Unknown format error". Can someone point me into the the right direction what is not right with this code:
import mysql.connector
import base64
import binascii
# base64 decoding function
def decode_base64(data, image_type):
if data is None:
return None
missing_padding = 4 - len(data) % 4
if missing_padding:
data = b'=' * missing_padding
try:
return base64.b64decode(data)
except binascii.Error as e:
print(f"Invalid image for id {id} image type: {image_type}, Invalid Padding")
return base64.b64decode(data)
# Connect to the MySQL server
cnx = mysql.connector.connect(user='myuser', password='my_password',
host='127.0.0.1',
database='cms')
# Create a cursor
cursor = cnx.cursor()
# Execute the SELECT statement
cursor.execute("SELECT id, icon, icon_large FROM games")
# Iterate through the results
for (id, icon, icon_large) in cursor:
image_type = 'icon'
try:
# Decode the base64-encoded images
icon_data = decode_base64(icon, 'icon')
icon_large_data = decode_base64(icon_large, 'icon_large')
# Write the images to files if the data is not None
if icon_data is not None:
with open("icon_{}.png".format(id), "wb") as f:
f.write(icon_data)
except binascii.Error as e:
print(f"Invalid image for id {id} image type: {image_type}")
image_type = 'icon_large'
try:
if icon_large_data is not None:
with open("icon_large_{}.png".format(id), "wb") as f:
f.write(icon_large_data)
except binascii.Error as e:
print(f"Invalid image for id {id} image type: {image_type}")
# Close the cursor and connection
cursor.close()
cnx.close()
Base64 code is actually producing images and are fine, some could be having padding issues, but are still working on the browser, thus I expect them to be converted to file images no problem too.
CodePudding user response:
Your images are JPEGs, so saving them with .png
extensions is going to confuse your viewer.
The start of a JPEG looks roughly like this in hex:
00000000: ffd8 ffe0 0010 4a46 4946 0001 0100 0001 ......JFIF......
00000010: 0001 0000 ffe2 0218 4943 435f 5052 4f46 ........ICC_PROF
Note: I can see JFIF
in your hex printout - that's how I know your images are JPEGs.
The start of a PNG looks roughly like this:
00000000: 8950 4e47 0d0a 1a0a 0000 000d 4948 4452 .PNG........IHDR
00000010: 0000 01f4 0000 01f4 0802 0000 0044 b448 .............D.H
If you are on Windows and don't have proper tools available, you can use the online hex viewer at hexedit.
CodePudding user response:
When @jps has asked to post part of Base64 image code and I took a look at it I soon realized what is wrong with it. Base64 is basically a text while my output from DB was binary. Binary and in BLOB type of the column itself. This has hinted me that this is not a Base64 image but an actual binary image data. SO I found a solution myself by rewriting my code to export images from binary storage in MySQL. Here is the code (and the above code is for Base64 encoded images if they are stored on MySQL):
import mysql.connector
from PIL import Image
import io
import base64
from PIL.Image import UnidentifiedImageError
# Connect to the database
cnx = mysql.connector.connect(user='myuser', password='mypassword', host='127.0.0.1', database='cms')
cursor = cnx.cursor()
# Retrieve the all ids from the games table
cursor.execute('SELECT id FROM games')
ids = cursor.fetchall()
# query
query = 'SELECT icon, icon_large FROM games WHERE id = %s'
#create a text file to save ids with no data.
with open("no_data_ids.txt", "w") as f:
# Iterate through all the ids
for id in ids:
cursor.execute(query, (id[0],))
icon_data, icon_large_data = cursor.fetchone()
if icon_data:
# Create an io.BytesIO object from the binary data
image_file = io.BytesIO(icon_data)
# Reset the file pointer to the beginning
image_file.seek(0)
# Open the image using the Image.open() method
image = Image.open(image_file)
#Save the image using the detected file format
image.save(f'icon_{id[0]}.{image.format.lower()}')
if icon_large_data:
# Create an io.BytesIO object from the binary data
image_file = io.BytesIO(icon_large_data)
# Reset the file pointer to the beginning
image_file.seek(0)
# Open the image using the Image.open() method
image = Image.open(image_file)
#Save the image using the detected file format
image.save(f'icon_large_{id[0]}.{image.format.lower()}')
if not icon_data and not icon_large_data:
# write id to no_data_ids.txt
f.write(str(id[0]) "\n")
# close cursor and connection
cursor.close()
cnx.close()
f.close()