analitics

Pages

Sunday, November 24, 2024

Python 3.13.0 : emoji symbols with PIL.

Today I want to use emoji symbols and I wrote this python script:
from PIL import Image, ImageDraw, ImageFont
import os

# Font size and image dimensions
font_size = 88
width = 640
height = 480

# Use Symbola.ttf from current directory
font_path = "Symbola.ttf"

# Create image
img = Image.new('RGB', (width, height), color='white')
draw = ImageDraw.Draw(img)

# Get font
font = ImageFont.truetype(font_path, font_size)

# Emoji matrix
emoji_matrix = [
    ['😀', '😁', '😂', '🤣', '😃'],
    ['😄', '😅', '😆', '😇', '😈'],
    ['😉', '😊', '😋', '😌', '😍'],
    ['😎', '😏', '😐', '😑', '😒']
]

# Calculate spacing
x_spacing = font_size + 10
y_spacing = font_size + 10

# Calculate starting position to center the grid
start_x = (width - (len(emoji_matrix[0]) * x_spacing)) // 2
start_y = (height - (len(emoji_matrix) * y_spacing)) // 2

# Draw emojis
for i, row in enumerate(emoji_matrix):
    for j, emoji in enumerate(row):
        x = start_x + (j * x_spacing)
        y = start_y + (i * y_spacing)
        draw.text((x, y), emoji, font=font, fill='black')

# Save the image
img.save('emoji_art.png')
print("Emoji art has been created successfully! Check emoji_art.png")
The result image named emoji_art.png is this:

Wednesday, November 20, 2024

Python 3.13.0 : generates multiple deformed polygonal shapes .

Today I created this source code in python that generates eight random convex polygons. The idea was to create sprites for a 2D game: snowballs, boulders, or similar objects... Obviously I also used Sonet 3.5 artificial intelligence. You can find the source code on the pagure account in fedora.
#!/usr/bin/env python3
"""
SVG Polygon Generator

This script generates multiple deformed polygonal shapes and saves them as separate SVG files.
Each polygon maintains convex properties while having controlled random deformations.

Features:
    - Generates 8 unique polygonal shapes
    - Controls deformation through radial and angular factors
    - Maintains convex properties
    - Exports each shape to a separate SVG file
    - Uses random colors for visual distinction

Usage:
    python generate_svgs.py

Output:
    Creates 8 SVG files named 'polygon_1.svg' through 'polygon_8.svg'
"""

from lxml import etree
import random
import math
from pathlib import Path


def create_svg_root():
    """Create and return a base SVG root element with standard attributes."""
    root = etree.Element("svg")
    root.set("width", "500")
    root.set("height", "500")
    root.set("xmlns", "http://www.w3.org/2000/svg")
    return root


def calculate_points(center_x: float, center_y: float, radius: float, 
                    num_sides: int, deform_factor: float) -> list:
    """
    Calculate polygon points with controlled deformation.

    Args:
        center_x: X coordinate of polygon center
        center_y: Y coordinate of polygon center
        radius: Base radius of the polygon
        num_sides: Number of polygon sides
        deform_factor: Maximum allowed deformation factor

    Returns:
        List of tuples containing (x, y) coordinates
    """
    points = []
    angle_step = 2 * math.pi / num_sides
    
    for i in range(num_sides):
        angle = i * angle_step
        radial_deform = random.uniform(-deform_factor, deform_factor)
        angular_deform = random.uniform(-deform_factor/2, deform_factor/2)
        
        modified_angle = angle + angular_deform
        modified_radius = radius * (1 + radial_deform)
        
        x = center_x + modified_radius * math.cos(modified_angle)
        y = center_y + modified_radius * math.sin(modified_angle)
        points.append((x, y))
    
    return points


def generate_deformed_shapes():
    """Generate multiple deformed polygons and save them to separate SVG files."""
    # Base parameters
    num_sides = 8
    center_x = 250
    center_y = 250
    base_radius = 150
    max_deformation = 0.15
    output_dir = Path("generated_polygons")
    
    # Create output directory if it doesn't exist
    output_dir.mkdir(exist_ok=True)

    for i in range(8):
        root = create_svg_root()
        points = calculate_points(center_x, center_y, base_radius, 
                                num_sides, max_deformation)
        
        path = etree.SubElement(root, "path")
        path_data = f"M {points[0][0]} {points[0][1]}"
        path_data += "".join(f" L {p[0]} {p[1]}" for p in points[1:])
        path_data += " Z"
        
        path.set("d", path_data)
        path.set("fill", "none")
        path.set("stroke", f"#{random.randint(0, 16777215):06X}")
        path.set("stroke-width", "2")
        path.set("opacity", "0.7")

        # Save individual SVG file
        output_file = output_dir / f"polygon_{i+1}.svg"
        tree = etree.ElementTree(root)
        tree.write(str(output_file), pretty_print=True, 
                  xml_declaration=True, encoding='utf-8')
    
    print(f"Generated {num_sides} polygons in {output_dir}")

if __name__ == "__main__":
    generate_deformed_shapes()

Monday, November 18, 2024

Python 3.13.0 : Tested TinyDB on Fedora 41.

Today I tested the TinyDB python package on Fedora 41 Linux distro:
TinyDB is a lightweight document oriented database optimized for your happiness :) It’s written in pure Python and has no external dependencies. The target are small apps that would be blown away by a SQL-DB or an external database server.
The documentation for this python package can be found on the official website.
The install on Fedora 14 distro can be done with pip tool:
pip install tinydb
This is the source code I tested:
from tinydb import TinyDB, Query
import datetime

# Create a TinyDB instance
db = TinyDB('my_database.json')

# Define a schema for our documents
UserSchema = {
    'name': str,
    'email': str,
    'age': int,
    'created_at': datetime.datetime
}# Insert some sample data
users = [
    {'name': 'John Doe', 'email': 'john@example.com', 'age': 30},
    {'name': 'Jane Smith', 'email': 'jane@example.com', 'age': 25},
    {'name': 'Bob Johnson', 'email': 'bob@example.com', 'age': 35}
]

for user in users:
    db.insert(user)

# Querying all users
print("\nQuerying all users:")
all_users = db.all()
for user in all_users:
    print(f"Name: {user['name']}, Email: {user['email']}, Age: {user['age']}")

# Filtering data
print("\nFidig users older than 28:")
older_than_28 = db.search(Query().age > 28)
for user in older_than_28:
    print(f"Name: {user['name']}, Email: {user['email']}, Age: {user['age']}")

# Updating data
print("\nUpdatig John Doe's age:")
db.update({'age': 31}, Query().name == 'John Doe')

# Deleting data
print("\nDeletig Jane Smith:")
doc_ids = [doc.doc_id for doc in db.search(Query().email == 'jane@example.com')]
if doc_ids:
    db.remove(doc_ids=doc_ids)
else:
    print("No document found with email 'jane@example.com'")

# Adding a new field
print("\nAddig a 'city' field to all users:")
for user in db.all():
    user['city'] = 'New York'
    db.update(user, doc_ids=[doc.doc_id for doc in db.search(Query().name == user['name'])])

# Sorting data
print("\nSorting users by age:")
sorted_users = sorted(db.all(), key=lambda x: x['age'])
for user in sorted_users:
    print(f"Name: {user['name']}, Email: {user['email']}, Age: {user['age']}")

# Getting document count
print("\nTotal number of users:", len(db.all()))

# Closing the database connection
db.close()
This is the result:
$ python test_001.py 

Querying all users:
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: John Doe, Email: john@example.com, Age: 30
Name: Jane Smith, Email: jane@example.com, Age: 25
Name: Bob Johnson, Email: bob@example.com, Age: 35

Fidig users older than 28:
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: John Doe, Email: john@example.com, Age: 30
Name: Bob Johnson, Email: bob@example.com, Age: 35

Updatig John Doe's age:

Deletig Jane Smith:

Addig a 'city' field to all users:

Sorting users by age:
Name: John Doe, Email: john@example.com, Age: 31
Name: John Doe, Email: john@example.com, Age: 31
Name: John Doe, Email: john@example.com, Age: 31
Name: John Doe, Email: john@example.com, Age: 31
Name: John Doe, Email: john@example.com, Age: 31
Name: John Doe, Email: john@example.com, Age: 31
Name: John Doe, Email: john@example.com, Age: 31
Name: John Doe, Email: john@example.com, Age: 31
Name: John Doe, Email: john@example.com, Age: 31
Name: John Doe, Email: john@example.com, Age: 31
Name: John Doe, Email: john@example.com, Age: 31
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: Bob Johnson, Email: bob@example.com, Age: 35
Name: Bob Johnson, Email: bob@example.com, Age: 35

Total number of users: 22

Saturday, November 16, 2024

Python 3.13.0 : Test the gi python package on Fedora distro linux.

The gi (GObject Introspection) Python package is excellent! It provides Python bindings for GObject-based libraries like GTK, GLib, and Secret Service. It enables you to write native GNOME applications in Python and access system services seamlessly.
First, install these Fedora packages:
[mythcat@fedora ~]# dnf5 install python3-gobject libsecret-devel
...
Package "python3-gobject-3.48.2-3.fc41.x86_64" is already installed.
Package "libsecret-devel-0.21.4-3.fc41.x86_64" is already installed.
...
[mythcat@fedora ~]# dnf5 install gnome-shell gnome-keyring libsecret
...
I used this simple python source code to test the gi python package:
import gi

# Specify the version of Gio and Secret we want to use
gi.require_version('Gio', '2.0')
gi.require_version('Secret', '1')

from gi.repository import Gio, Secret, GLib

def check_schema(schema_name):
    try:
        Gio.Settings.new(schema_name)
        print(f"Schema '{schema_name}' is available")
        return True
    except GLib.GError as e:
        print(f"Schema '{schema_name}' is not installed: {str(e)}")
        return False

def store_secret():
    schema = Secret.Schema.new("org.example.Password",
        Secret.SchemaFlags.NONE,
        {
            "username": Secret.SchemaAttributeType.STRING,
        }
    )
    
    Secret.password_store_sync(schema, 
        {"username": "myuser"},
        Secret.COLLECTION_DEFAULT,
        "My secret item",
        "Hello, World!",
        None)
    
    print("Secret stored successfully")

def get_secret():
    schema = Secret.Schema.new("org.example.Password",
        Secret.SchemaFlags.NONE,
        {
            "username": Secret.SchemaAttributeType.STRING,
        }
    )
    
    password = Secret.password_lookup_sync(schema,
        {"username": "myuser"},
        None)
    
    if password is not None:
        print(f"Retrieved secret: {password}")
    else:
        print("No secret found")

if __name__ == "__main__":
    print("Starting secret operations...")
    store_secret()
    get_secret()
    print("Finished secret operations.")
The result is this:
$ python test_001.py 
Starting secret operations...
Secret stored successfully
Retrieved secret: Hello, World!
Finished secret operations.