Today, I worked with art artificial intelligence, to create tool for my game development.
I used python and PyQt6 and this tool help me to remove border, resize, split, rename and save images as PNG file type for Godot game engine.



Is a blog about python programming language. You can see my work with python programming language, tutorials and news.
from krita import *
from PyQt5.QtWidgets import QAction, QMessageBox
import os
class ExportGodotPNG(Extension):
def __init__(self, parent):
super().__init__(parent)
def setup(self):
pass
def export_png(self):
# Get the active document
doc = Krita.instance().activeDocument()
if not doc:
QMessageBox.warning(None, "Error", "No document open! Please open a document and try again.")
return
# Create an InfoObject for PNG export
info = InfoObject()
info.setProperty("alpha", True) # Keep alpha channel for transparency
info.setProperty("compression", 0) # No compression for maximum quality
info.setProperty("interlaced", False) # Disable interlacing
info.setProperty("forceSRGB", True) # Force sRGB for Godot compatibility
# Build the output file path
if doc.fileName():
base_path = os.path.splitext(doc.fileName())[0]
else:
base_path = os.path.join(os.path.expanduser("~"), "export_godot")
output_file = base_path + "_godot.png"
# Export the document as PNG
try:
doc.exportImage(output_file, info)
# Show success message with brief usage info
QMessageBox.information(None, "Success",
f"Successfully exported as PNG for Godot: {output_file}\n\n"
"This PNG has no compression, alpha channel support, and sRGB for Godot compatibility. "
"To use in Godot, import the PNG and adjust texture settings as needed."
)
except Exception as e:
QMessageBox.critical(None, "Error", f"Export failed: {str(e)}")
def createActions(self, window):
# Create only the export action in Tools > Scripts
action_export = window.createAction("export_godot_png", "Export Godot PNG", "tools/scripts")
action_export.triggered.connect(self.export_png)
# Register the plugin
Krita.instance().addExtension(ExportGodotPNG(Krita.instance()))
bl_info = {
"name": "Append Materials from Folder",
"author": "Grok",
"version": (1, 2),
"blender": (3, 0, 0),
"location": "View3D > Sidebar > Append Materials",
"description": "Select a folder and append all materials from .blend files recursively",
"category": "Import-Export",
}
import bpy
import os
from bpy.types import Operator, Panel, PropertyGroup
from bpy.props import StringProperty, PointerProperty
class AppendMaterialsProperties(PropertyGroup):
folder_path: StringProperty(
name="Folder Path",
description="Path to the folder containing .blend files",
default="",
maxlen=1024,
subtype='DIR_PATH'
)
class APPEND_OT_materials_from_folder(Operator):
bl_idname = "append.materials_from_folder"
bl_label = "Append Materials from Folder"
bl_options = {'REGISTER', 'UNDO'}
bl_description = "Append all materials from .blend files in the selected folder and subfolders"
def execute(self, context):
props = context.scene.append_materials_props
folder_path = props.folder_path
# Normalize path to avoid issues with slashes
folder_path = os.path.normpath(bpy.path.abspath(folder_path))
if not folder_path or not os.path.isdir(folder_path):
self.report({'ERROR'}, f"Invalid or no folder selected: {folder_path}")
return {'CANCELLED'}
self.report({'INFO'}, f"Scanning folder: {folder_path}")
blend_files_found = 0
materials_appended = 0
errors = []
# Walk recursively through the folder
for root, dirs, files in os.walk(folder_path):
self.report({'INFO'}, f"Checking folder: {root}")
for file in files:
if file.lower().endswith('.blend'):
blend_files_found += 1
blend_path = os.path.join(root, file)
self.report({'INFO'}, f"Found .blend file: {blend_path}")
try:
# Open the .blend file to inspect materials
with bpy.data.libraries.load(blend_path, link=False) as (data_from, data_to):
if data_from.materials:
data_to.materials = data_from.materials
materials_appended += len(data_from.materials)
self.report({'INFO'}, f"Appended {len(data_from.materials)} materials from: {blend_path}")
else:
self.report({'WARNING'}, f"No materials found in: {blend_path}")
except Exception as e:
errors.append(f"Failed to process {blend_path}: {str(e)}")
self.report({'WARNING'}, f"Error in {blend_path}: {str(e)}")
# Final report
if blend_files_found == 0:
self.report({'WARNING'}, f"No .blend files found in {folder_path} or its subfolders!")
else:
self.report({'INFO'}, f"Found {blend_files_found} .blend files, appended {materials_appended} materials.")
if errors:
self.report({'WARNING'}, f"Encountered {len(errors)} errors: {'; '.join(errors)}")
return {'FINISHED'}
class VIEW3D_PT_append_materials(Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_category = "Append Materials"
bl_label = "Append Materials from Folder"
def draw(self, context):
layout = self.layout
props = context.scene.append_materials_props
layout.prop(props, "folder_path")
layout.operator("append.materials_from_folder", text="Append Materials")
def register():
bpy.utils.register_class(AppendMaterialsProperties)
bpy.utils.register_class(APPEND_OT_materials_from_folder)
bpy.utils.register_class(VIEW3D_PT_append_materials)
bpy.types.Scene.append_materials_props = PointerProperty(type=AppendMaterialsProperties)
def unregister():
bpy.utils.unregister_class(VIEW3D_PT_append_materials)
bpy.utils.unregister_class(APPEND_OT_materials_from_folder)
bpy.utils.unregister_class(AppendMaterialsProperties)
del bpy.types.Scene.append_materials_props
if __name__ == "__main__":
register()
import subprocess
import sys
import os
import shutil
import importlib.util
import re
import concurrent.futures
from typing import List, Tuple, Set
class ModuleManager:
def __init__(self):
self.modules: Set[str] = set()
self.pip_path = self._get_pip_path()
def _get_pip_path(self) -> str:
possible_path = os.path.join(sys.exec_prefix, "Scripts", "pip.exe")
return shutil.which("pip") or (possible_path if os.path.exists(possible_path) else None)
def extract_imports_from_file(self, file_path: str) -> List[Tuple[str, str]]:
imports = []
try:
with open(file_path, 'r', encoding='utf-8') as file:
for line in file:
# Detect 'import module'
import_match = re.match(r'^\s*import\s+([a-zA-Z0-9_]+)(\s+as\s+.*)?$', line)
if import_match:
module = import_match.group(1)
imports.append((module, line.strip()))
continue
# Detect 'from module import ...'
from_match = re.match(r'^\s*from\s+([a-zA-Z0-9_]+)\s+import\s+.*$', line)
if from_match:
module = from_match.group(1)
imports.append((module, line.strip()))
except FileNotFoundError:
print(f"❌ Fișierul {file_path} nu a fost găsit.")
except Exception as e:
print(f"❌ Eroare la citirea fișierului {file_path}: {e}")
return imports
def scan_directory_for_py_files(self, directory: str = '.') -> List[str]:
py_files = []
for root, _, files in os.walk(directory):
for file in files:
if file.endswith('.py'):
py_files.append(os.path.join(root, file))
return py_files
def collect_unique_modules(self, directory: str = '.') -> None:
py_files = self.scan_directory_for_py_files(directory)
all_imports = []
with concurrent.futures.ThreadPoolExecutor() as executor:
future_to_file = {executor.submit(self.extract_imports_from_file, file_path): file_path for file_path in py_files}
for future in concurrent.futures.as_completed(future_to_file):
imports = future.result()
all_imports.extend(imports)
for module, _ in all_imports:
self.modules.add(module)
def is_module_installed(self, module: str) -> bool:
return importlib.util.find_spec(module) is not None
def run_pip_install(self, module: str) -> bool:
if not self.pip_path:
print(f"❌ Nu am găsit pip pentru {module}.")
return False
try:
subprocess.check_call([self.pip_path, "install", module])
print(f"✅ Pachetul {module} a fost instalat cu succes.")
return True
except subprocess.CalledProcessError as e:
print(f"❌ Eroare la instalarea pachetului {module}: {e}")
return False
def check_and_install_modules(self) -> None:
def process_module(module):
print(f"\n🔎 Verific dacă {module} este instalat...")
if self.is_module_installed(module):
print(f"✅ {module} este deja instalat.")
else:
print(f"📦 Instalez {module}...")
self.run_pip_install(module)
# Re-verifică după instalare
if self.is_module_installed(module):
print(f"✅ {module} funcționează acum.")
else:
print(f"❌ {module} nu funcționează după instalare.")
with concurrent.futures.ThreadPoolExecutor() as executor:
executor.map(process_module, self.modules)
def main():
print("🔍 Verific pip...")
manager = ModuleManager()
if manager.pip_path:
print(f"✅ Pip este disponibil la: {manager.pip_path}")
else:
print("⚠️ Pip nu este disponibil.")
return
directory = sys.argv[1] if len(sys.argv) > 1 else '.'
print(f"\n📜 Scanez directorul {directory} pentru fișiere .py...")
manager.collect_unique_modules(directory)
if not manager.modules:
print("⚠️ Nu s-au găsit module în importuri.")
return
print(f"\nModule unice detectate: {', '.join(manager.modules)}")
manager.check_and_install_modules()
if __name__ == "__main__":
main()