Files
2026-05-07 17:22:56 +09:00

478 lines
16 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
__version__ = "1.0.0"
# --- package ---
# --- color ---
import webcolors
# --- image ---
from pathlib import Path
from PIL import Image, ImageSequence
import cv2
import numpy as np
from io import BytesIO
# --- base64 ---
import base64
# --- common ---
import os
from datetime import datetime
import shutil
import time
import inspect
def hex_to_rgb(hex_code):
"""Convert a hex code to RGB values."""
hex_code = hex_code.lstrip('#')
return tuple(int(hex_code[i:i+2], 16) for i in (0, 2, 4))
def rgb_to_hex(rgb_values):
"""Convert RGB values to a hex code."""
r, g, b = rgb_values
hex_code = "{:02x}{:02x}{:02x}".format(r, g, b)
return hex_code
def get_color_name(rgb_values):
"""Return the name of the closest matching color."""
min_colors = {}
for key, name in webcolors.CSS3_HEX_TO_NAMES.items():
r_c, g_c, b_c = hex_to_rgb(key)
rd = (r_c - rgb_values[0]) ** 2
gd = (g_c - rgb_values[1]) ** 2
bd = (b_c - rgb_values[2]) ** 2
min_colors[(rd + gd + bd)] = name
return min_colors[min(min_colors.keys())]
def image_resize(import_path, import_raw_path, export_path, img, resize_target, resize_resolution):
image_ext = os.path.splitext(img)[1].split('.')[1]
move_date = datetime.now().strftime('%y%m%d%H%M%S')
img_new_nm = '{}_{}{}'.format('import', move_date, f'.{image_ext}')
shutil.move(img, f"{import_path}{img_new_nm}")
image = cv2.imread(f'{import_path}{img_new_nm}')
img_width = image.shape[1]
img_height = image.shape[0]
if resize_target == 'W':
resize_height = int(img_height * (resize_resolution / img_width))
dim = (resize_resolution, resize_height)
elif resize_target == 'H':
resize_width = int(img_width * (resize_resolution / img_height))
dim = (resize_width, resize_resolution)
resized_img = cv2.resize(image, dim, interpolation=cv2.INTER_AREA)
cv2.imwrite(f"{export_path}export_{move_date}.{image_ext}", resized_img)
move_date = datetime.now().strftime('%y%m%d%H%M%S')
img_new_nm = '{}_{}{}'.format('import', move_date, f'.{image_ext}')
shutil.move(f'{import_path}{img_new_nm}', f"{import_raw_path}{img_new_nm}")
time.sleep(1)
return 'Success Image Resize'
def distribute_serveral_png(import_path, import_raw_path, export_path, img):
image_ext = os.path.splitext(img)[1].split('.')[1]
if image_ext == 'png':
move_date = datetime.now().strftime('%y%m%d%H%M%S')
img_new_nm = '{}_{}{}'.format('import', move_date, f'.{image_ext}')
shutil.move(img, f"{import_path}{img_new_nm}")
pc_sizes = [16, 24, 32, 48, 64,
72, 80, 96, 128, 256]
and_sizes = [36, 48, 72, 96, 144]
ios_sizes = [20, 29, 40, 40, 48,
50, 55, 57, 58, 60,
60, 72, 76, 80, 87,
88, 100, 114, 120, 144,
152, 167, 172, 180, 196,
1024]
android_names = ['launcher_ldpi',
'launcher_mdpi',
'launcher_hdpi',
'launcher_xhdpi',
'launcher_xxhdpi']
ios_names = ['icon-20',
'icon-29',
'icon-20@2x',
'icon-40',
'icon-24@2x',
'icon-50',
'icon-27.5@2x',
'icon',
'icon-29@2x',
'icon-20@3x',
'icon-60',
'icon-72',
'icon-76',
'icon-40@2x',
'icon-83.5@2x',
'icon-44@2x',
'icon-50@2x',
'icon@2x',
'icon-60@2x',
'icon-72@2x',
'icon-76@2x',
'icon-29@3x',
'icon-86@2x',
'icon-60@3x',
'icon-98@2x',
'icon-1024']
pc_icon_sizes = [(x, x) for x in pc_sizes]
and_icon_sizes = [(x, x) for x in and_sizes]
ios_icon_sizes = [(x, x) for x in ios_sizes]
image = Image.open(f'{import_path}{img_new_nm}')
for size in pc_icon_sizes:
exp_img_new_nm = f"{export_path}export_{move_date}_{str(size[0])}.{image_ext}"
new_image = image.resize(size)
new_image.save(exp_img_new_nm)
new_logo_ico_filename = f"{export_path}export_{move_date}_main.ico"
new_logo_ico = image.resize(size)
new_logo_ico.save(new_logo_ico_filename, format="ICO", quality=100)
for num, label in zip(and_icon_sizes, android_names):
exp_img_new_nm = f"{export_path}export_{move_date}_{label}.{image_ext}"
new_image = image.resize(num)
new_image.save(exp_img_new_nm)
for num, label in zip(ios_icon_sizes, ios_names):
exp_img_new_nm = f"{export_path}export_{move_date}_{label}.{image_ext}"
new_image = image.resize(num)
new_image.save(exp_img_new_nm)
time.sleep(1)
shutil.move(f'{import_path}{img_new_nm}', f"{import_raw_path}{img_new_nm}")
return 'Success Image to Icon'
else:
return 'Only Convert .PNG'
def bake_one_big_png_to_ico(import_path, import_raw_path, export_path, img):
"""Converts one big PNG into one ICO file.
args:
sourcefile (str): Pathname of a PNG file.
targetfile (str): Pathname of the resulting ICO file.
sizes (list of int): Requested sizes of the resulting
icon file, defaults to [16, 32, 48].
Use this function if you have one big, square PNG file
and dont care about fine-tuning individual icon sizes.
Example::
sourcefile = "Path/to/high_resolution_logo_512x512.png"
targetfile = "Path/to/logo.ico"
sizes = [16, 24, 32, 48, 256]
bake_one_big_png_to_ico(sourcefile, targetfile, sizes)
"""
# if sizes is None:
# sizes = [16, 24, 32, 48, 256, 512]
# icon_sizes = [(x, x) for x in sizes]
# Image.open(sourcefile).save(targetfile, icon_sizes=icon_sizes)
image_ext = os.path.splitext(img)[1].split('.')[1]
if image_ext == 'png':
move_date = datetime.now().strftime('%y%m%d%H%M%S')
img_new_nm = '{}_{}{}'.format('import', move_date, f'.{image_ext}')
shutil.move(img, f"{import_path}{img_new_nm}")
sizes = [16, 24, 32, 48, 64, 72, 80, 96, 128, 256]
icon_sizes = [(x, x) for x in sizes]
print(icon_sizes)
# img_new_nm = '{}_{}{}'.format('import', move_date, f'.{image_ext}')
Image.open(f'{import_path}{img_new_nm}').save(f"{export_path}export_{move_date}.ico", icon_sizes=icon_sizes)
# shutil.move(f'{import_path}{img_new_nm}', f"{import_raw_path}{img_new_nm}")
time.sleep(1)
return 'Success Image to Icon'
else:
return 'Only Convert .PNG'
def bake_several_pngs_to_ico(sourcefiles, targetfile):
"""Converts several PNG files into one ICO file.
args:
sourcefiles (list of str): A list of pathnames of PNG files.
targetfile (str): Pathname of the resulting ICO file.
Use this function if you want to have fine-grained control over
the resulting icon file, providing each possible icon resolution
individually.
Example::
sourcefiles = [
"Path/to/logo_16x16.png",
"Path/to/logo_32x32.png",
"Path/to/logo_48x48.png"
]
targetfile = "Path/to/logo.ico"
bake_several_pngs_to_ico(sourcefiles, targetfile)
"""
# Write the global header
number_of_sources = len(sourcefiles)
data = bytes((0, 0, 1, 0, number_of_sources, 0))
offset = 6 + number_of_sources * 16
# Write the header entries for each individual image
for sourcefile in sourcefiles:
img = Image.open(sourcefile)
data += bytes((img.width, img.height, 0, 0, 1, 0, 32, 0, ))
bytesize = Path(sourcefile).stat().st_size
data += bytesize.to_bytes(4, byteorder="little")
data += offset.to_bytes(4, byteorder="little")
offset += bytesize
# Write the individual image data
for sourcefile in sourcefiles:
data += Path(sourcefile).read_bytes()
# Save the icon file
Path(targetfile).write_bytes(data)
# def image_to_icon(import_path, import_raw_path, export_path, img, resize_resolution):
# image_ext = os.path.splitext(img)[1].split('.')[1]
#
# if image_ext == 'png':
# move_date = datetime.now().strftime('%y%m%d%H%M%S')
#
# img_new_nm = '{}_{}{}'.format('import', move_date, f'.{image_ext}')
#
# shutil.move(img, f"{import_path}{img_new_nm}")
#
# image = cv2.imread(f'{import_path}{img_new_nm}')
#
# resized_img = cv2.resize(image, (resize_resolution, resize_resolution))
#
# cv2.imwrite(f"{export_path}export_{image_ext}_{move_date}.ico", resized_img, [cv2.IMWRITE_PNG_COMPRESSION, 9])
#
# move_date = datetime.now().strftime('%y%m%d%H%M%S')
#
# img_new_nm = '{}_{}{}'.format('import', move_date, f'.{image_ext}')
#
# shutil.move(f'{import_path}{img_new_nm}', f"{import_raw_path}{img_new_nm}")
#
# time.sleep(1)
#
# return 'Success Image to Icon'
#
# else:
# return 'Only Convert .PNG'
def image_to_extension(import_path, import_raw_path, export_path, img, extension):
image_ext = os.path.splitext(img)[1].split('.')[1]
move_date = datetime.now().strftime('%y%m%d%H%M%S')
img_new_nm = '{}_{}{}'.format('import', move_date, f'.{image_ext}')
shutil.move(img, f"{import_path}{img_new_nm}")
if image_ext == 'gif':
# Load the GIF into a PIL Image object
image = Image.open(f"{import_path}{img_new_nm}")
if extension == 'png':
# Split the GIF into individual frames
frames = []
for frame in ImageSequence.Iterator(image):
frames.append(frame.copy())
# Save each frame as an individual image file
for i, frame in enumerate(frames):
move_date = datetime.now().strftime('%y%m%d%H%M%S')
frame.save(f"{export_path}export_{move_date}_{i}.{extension}", format=extension)
else:
image = image.convert("RGB")
image.save(f"{export_path}export_{move_date}.{extension}")
elif image_ext == 'png':
# Load the GIF into a PIL Image object
image = Image.open(f"{import_path}{img_new_nm}")
background = Image.new('RGB', image.size, (255, 255, 255))
background.paste(image, mask=image)
background.save(f"{export_path}export_{move_date}.{extension}")
else:
image = cv2.imread(f'{import_path}{img_new_nm}')
cv2.imwrite(f"{export_path}export_{move_date}.{extension}", image)
shutil.move(f'{import_path}{img_new_nm}', f"{import_raw_path}{img_new_nm}")
time.sleep(1)
return 'Success Image Extension'
def base64_to_image(import_raw_path, export_path, base64_str, txt_file, file):
try:
# ImageFile.LOAD_TRUNCATED_IMAGES = True
# Remove the "data:image/png;base64," prefix from the string
base64_string = base64_str.split(',')[1]
# Determine the length of the input string
length = len(base64_string)
# Add padding characters if necessary
if length % 4 != 0:
base64_string += '=' * (4 - length % 4)
# Decode the base64-encoded string into bytes
image_bytes = base64.b64decode(base64_string)
image = Image.open(BytesIO(image_bytes))
image_ext = base64_str.split('/')[1].split(';')[0]
move_date = datetime.now().strftime('%y%m%d%H%M%S')
if image_ext == 'gif':
if image.mode == "RGBA":
# If the image has an alpha channel, convert it to RGB mode
image = image.convert("RGB")
# Get the duration of each frame in the animation
frame_durations = []
frames = []
for frame in ImageSequence.Iterator(image):
frame_durations.append(frame.info.get("duration", 100)) # default duration is 100ms
frames.append(frame.copy())
# Calculate the speed of the animation
average_duration = sum(frame_durations) / len(frame_durations)
# if not average_duration == 0.0:
if average_duration != 0:
speed = 1 / (average_duration / 1000) # speed in frames per second
else:
speed = 0
frames[0].save(f"{export_path}export_{move_date}.{image_ext}", format="GIF", save_all=True, append_images=frames[1:], duration=speed, loop=0)
# Check if the image is a PNG with transparency
elif image_ext == "png":
# Convert the image to RGB mode to remove the alpha channel
image = image.convert("RGBA")
# Save the image to file
image.save(f"{export_path}export_{move_date}.{image_ext}")
else:
# Convert the bytes to a numpy array
image_array = np.frombuffer(image_bytes, dtype=np.uint8)
# Decode the numpy array into an OpenCV image
image = cv2.imdecode(image_array, cv2.IMREAD_UNCHANGED)
# Save the image to a file
cv2.imwrite(f"{export_path}export_{move_date}.{image_ext}", image)
file.close()
image_ext = os.path.splitext(txt_file)[1].split('.')[1]
img_new_nm = '{}_{}{}'.format('import', move_date, f'.{image_ext}')
shutil.move(txt_file, f"{import_raw_path}{img_new_nm}")
time.sleep(1)
return 'Success Image Convert'
except Exception as e:
return e
def image_to_base64(import_path, import_raw_path, export_path, img):
image_ext = os.path.splitext(img)[1].split('.')[1]
move_date = datetime.now().strftime('%y%m%d%H%M%S')
img_new_nm = '{}_{}{}'.format('import', move_date, f'.{image_ext}')
shutil.move(img, f"{import_path}{img_new_nm}")
if image_ext == 'gif':
image_pil = Image.open(f"{import_path}{img_new_nm}")
# Convert the image to a sequence of frames
frames = []
try:
while True:
frames.append(image_pil.copy())
image_pil.seek(len(frames)) # skip to the next frame
except EOFError:
pass # end of sequence
# Encode the frames as GIF bytes
with BytesIO() as output:
frames[0].save(output, format='GIF', save_all=True, append_images=frames[1:])
image_bytes = output.getvalue()
elif image_ext == 'png':
image = Image.open(f'{import_path}{img_new_nm}')
if image.mode != 'RGBA':
image = image.convert('RGBA')
buffer = BytesIO()
image.save(buffer, format='PNG')
# Encode the image data as a base64 string
image_bytes = buffer.getvalue()
else:
# Load the image file
image = cv2.imread(f'{import_path}{img_new_nm}')
# Convert the image to bytes
success, image_bytes = cv2.imencode(f'.{image_ext}', image)
image_bytes = image_bytes.tobytes()
# Encode the bytes as a base64 string
base64_str = base64.b64encode(image_bytes).decode()
# Create the base64-encoded image string
base64_str_dec = f"data:image/{image_ext};base64," + base64_str
shutil.move(f'{import_path}{img_new_nm}', f"{import_raw_path}{img_new_nm}")
time.sleep(1)
# Print the base64-encoded image string
return base64_str_dec, 'Success Base64 Convert', f"{export_path}export_{move_date}"