Image Processing

This comprehensive guide covers all image processing capabilities in GUI Image Studio, from basic transformations to advanced effects and batch operations.

Overview of Image Processing

GUI Image Studio provides powerful image processing capabilities through:

  • Real-time transformations during image loading

  • Non-destructive editing that preserves original images

  • Batch processing for multiple images

  • Framework integration for tkinter and customtkinter

  • High-quality algorithms for professional results

Core Transformation Parameters

All transformations are applied through the get_image() function:

from gui_image_studio import get_image

image = get_image(
    "source_image.jpg",
    framework="tkinter",          # Target GUI framework
    size=(width, height),         # Resize dimensions
    rotate=degrees,               # Rotation angle
    tint_color=(r, g, b),        # Color tint RGB values
    tint_intensity=0.0-1.0,      # Tint strength
    contrast=1.0,                # Contrast adjustment
    saturation=1.0,              # Saturation adjustment
    grayscale=False,             # Convert to grayscale
    transparency=1.0,            # Overall transparency
    theme="default",             # Theme adaptation
    animated=False,              # Handle animated GIFs
    frame_delay=100              # Animation timing
)

Size and Scaling Operations

Resizing and Scaling

Basic Resizing:

# Resize to exact dimensions
image = get_image(
    "photo.jpg",
    framework="tkinter",
    size=(800, 600)
)

# Common sizes for different purposes
thumbnail = get_image("photo.jpg", framework="tkinter", size=(150, 150))
icon = get_image("icon.png", framework="tkinter", size=(32, 32))
banner = get_image("banner.jpg", framework="tkinter", size=(1200, 300))

Aspect Ratio Considerations:

# For maintaining aspect ratio, calculate dimensions
def calculate_size(original_size, target_width=None, target_height=None):
    orig_w, orig_h = original_size

    if target_width and not target_height:
        # Scale by width
        ratio = target_width / orig_w
        return (target_width, int(orig_h * ratio))
    elif target_height and not target_width:
        # Scale by height
        ratio = target_height / orig_h
        return (int(orig_w * ratio), target_height)
    else:
        # Use provided dimensions
        return (target_width, target_height)

# Usage example
new_size = calculate_size((1920, 1080), target_width=800)
image = get_image("photo.jpg", framework="tkinter", size=new_size)

Quality Considerations:

# High-quality resizing for important images
high_quality = get_image(
    "important_photo.jpg",
    framework="customtkinter",
    size=(1024, 768)
)

# Smaller sizes for thumbnails (faster processing)
thumbnail = get_image(
    "photo.jpg",
    framework="tkinter",
    size=(100, 100)
)

Geometric Transformations

Rotation Operations

Basic Rotation:

# Rotate by specific angles
rotated_90 = get_image("image.png", framework="tkinter", rotate=90)
rotated_45 = get_image("image.png", framework="tkinter", rotate=45)
rotated_custom = get_image("image.png", framework="tkinter", rotate=23.5)

Common Rotation Patterns:

# Portrait to landscape
landscape = get_image("portrait.jpg", framework="tkinter", rotate=90)

# Artistic angles
artistic = get_image("photo.jpg", framework="tkinter", rotate=15)

# Correction rotations
corrected = get_image("crooked_photo.jpg", framework="tkinter", rotate=-2.3)

Rotation with Other Transformations:

# Rotate and resize
processed = get_image(
    "image.jpg",
    framework="customtkinter",
    size=(400, 400),
    rotate=45,
    tint_color=(255, 200, 100),
    tint_intensity=0.2
)

Color Adjustments

Tinting and Color Effects

Basic Color Tinting:

# Red tint
red_tinted = get_image(
    "photo.jpg",
    framework="tkinter",
    tint_color=(255, 0, 0),
    tint_intensity=0.3
)

# Blue tint
blue_tinted = get_image(
    "photo.jpg",
    framework="tkinter",
    tint_color=(0, 100, 255),
    tint_intensity=0.4
)

# Warm tone
warm = get_image(
    "photo.jpg",
    framework="tkinter",
    tint_color=(255, 200, 150),
    tint_intensity=0.2
)

Color Intensity Levels:

# Subtle tint (10%)
subtle = get_image(
    "image.jpg",
    framework="tkinter",
    tint_color=(255, 100, 0),
    tint_intensity=0.1
)

# Moderate tint (30%)
moderate = get_image(
    "image.jpg",
    framework="tkinter",
    tint_color=(255, 100, 0),
    tint_intensity=0.3
)

# Strong tint (60%)
strong = get_image(
    "image.jpg",
    framework="tkinter",
    tint_color=(255, 100, 0),
    tint_intensity=0.6
)

Predefined Color Schemes:

# Define common color schemes
COLOR_SCHEMES = {
    'sepia': (210, 180, 140),
    'cool_blue': (100, 150, 255),
    'warm_orange': (255, 180, 100),
    'vintage': (200, 180, 120),
    'cyberpunk': (0, 255, 150),
    'sunset': (255, 150, 80),
    'ocean': (50, 150, 200),
    'forest': (100, 180, 100)
}

# Apply color schemes
sepia_image = get_image(
    "photo.jpg",
    framework="tkinter",
    tint_color=COLOR_SCHEMES['sepia'],
    tint_intensity=0.4
)

Contrast and Saturation

Contrast Adjustments:

# Increase contrast (values > 1.0)
high_contrast = get_image(
    "photo.jpg",
    framework="tkinter",
    contrast=1.5
)

# Decrease contrast (values < 1.0)
low_contrast = get_image(
    "photo.jpg",
    framework="tkinter",
    contrast=0.7
)

# Extreme contrast for artistic effect
dramatic = get_image(
    "photo.jpg",
    framework="tkinter",
    contrast=2.0
)

Saturation Adjustments:

# Boost saturation for vibrant colors
vibrant = get_image(
    "photo.jpg",
    framework="tkinter",
    saturation=1.5
)

# Reduce saturation for muted tones
muted = get_image(
    "photo.jpg",
    framework="tkinter",
    saturation=0.6
)

# Desaturated (almost grayscale)
desaturated = get_image(
    "photo.jpg",
    framework="tkinter",
    saturation=0.2
)

Combined Adjustments:

# Professional photo enhancement
enhanced = get_image(
    "photo.jpg",
    framework="customtkinter",
    contrast=1.2,
    saturation=1.1,
    tint_color=(255, 240, 220),
    tint_intensity=0.1
)

# Vintage film look
vintage = get_image(
    "photo.jpg",
    framework="tkinter",
    contrast=1.3,
    saturation=0.8,
    tint_color=(210, 180, 140),
    tint_intensity=0.3
)

Grayscale and Transparency

Grayscale Conversion

# Convert to grayscale
bw_image = get_image(
    "color_photo.jpg",
    framework="tkinter",
    grayscale=True
)

# Grayscale with contrast boost
dramatic_bw = get_image(
    "photo.jpg",
    framework="tkinter",
    grayscale=True,
    contrast=1.4
)

# Grayscale with tint (sepia effect)
sepia = get_image(
    "photo.jpg",
    framework="tkinter",
    grayscale=True,
    tint_color=(210, 180, 140),
    tint_intensity=0.5
)

Transparency Effects

# Semi-transparent overlay
overlay = get_image(
    "background.jpg",
    framework="customtkinter",
    transparency=0.7
)

# Subtle transparency
subtle_transparent = get_image(
    "image.png",
    framework="tkinter",
    transparency=0.9
)

# Watermark effect
watermark = get_image(
    "logo.png",
    framework="tkinter",
    size=(200, 100),
    transparency=0.3
)

Theme-Aware Processing

Theme Integration

GUI Image Studio supports theme-aware image processing:

# Dark theme optimization
dark_image = get_image(
    "icon.png",
    framework="customtkinter",
    theme="dark",
    size=(64, 64)
)

# Light theme optimization
light_image = get_image(
    "icon.png",
    framework="tkinter",
    theme="light",
    size=(64, 64)
)

# Default theme
default_image = get_image(
    "icon.png",
    framework="tkinter",
    theme="default",
    size=(64, 64)
)

Dynamic Theme Switching:

class ThemeAwareImageLoader:
    def __init__(self, framework="tkinter"):
        self.framework = framework
        self.current_theme = "default"
        self.image_cache = {}

    def set_theme(self, theme):
        self.current_theme = theme
        self.image_cache.clear()  # Clear cache for theme change

    def load_image(self, name, **kwargs):
        cache_key = f"{name}_{self.current_theme}_{kwargs}"

        if cache_key not in self.image_cache:
            self.image_cache[cache_key] = get_image(
                name,
                framework=self.framework,
                theme=self.current_theme,
                **kwargs
            )

        return self.image_cache[cache_key]

# Usage
loader = ThemeAwareImageLoader("customtkinter")

# Load with current theme
icon = loader.load_image("icon.png", size=(32, 32))

# Switch theme and reload
loader.set_theme("dark")
dark_icon = loader.load_image("icon.png", size=(32, 32))

Animated GIF Processing

Working with Animations

# Load animated GIF
animation = get_image(
    "animated.gif",
    framework="tkinter",
    size=(200, 200),
    animated=True,
    frame_delay=100
)

# Extract animation data
frames = animation["animated_frames"]
delay = animation["frame_delay"]
frame_count = len(frames)

Animation Playback:

import tkinter as tk

class AnimationPlayer:
    def __init__(self, root, animation_data):
        self.root = root
        self.frames = animation_data["animated_frames"]
        self.delay = animation_data["frame_delay"]
        self.current_frame = 0
        self.playing = True

        self.label = tk.Label(root)
        self.label.pack()

        self.play_animation()

    def play_animation(self):
        if self.playing and self.frames:
            # Display current frame
            self.label.configure(image=self.frames[self.current_frame])

            # Move to next frame
            self.current_frame = (self.current_frame + 1) % len(self.frames)

            # Schedule next frame
            self.root.after(self.delay, self.play_animation)

    def pause(self):
        self.playing = False

    def resume(self):
        self.playing = True
        self.play_animation()

Animation with Transformations:

# Apply effects to animated GIF
processed_animation = get_image(
    "animated.gif",
    framework="customtkinter",
    size=(150, 150),
    animated=True,
    frame_delay=80,
    tint_color=(255, 100, 100),
    tint_intensity=0.2,
    contrast=1.1
)

Batch Processing Patterns

Processing Multiple Images

Basic Batch Processing:

import os
from gui_image_studio import get_image

def process_image_folder(input_folder, output_folder, **transform_params):
    """Process all images in a folder with given transformations."""

    # Create output folder if it doesn't exist
    os.makedirs(output_folder, exist_ok=True)

    # Supported image extensions
    image_extensions = {'.png', '.jpg', '.jpeg', '.gif', '.bmp', '.tiff'}

    for filename in os.listdir(input_folder):
        name, ext = os.path.splitext(filename)

        if ext.lower() in image_extensions:
            input_path = os.path.join(input_folder, filename)
            output_path = os.path.join(output_folder, f"processed_{filename}")

            try:
                # Process image
                processed = get_image(
                    input_path,
                    framework="tkinter",
                    **transform_params
                )

                print(f"Processed: {filename}")

            except Exception as e:
                print(f"Error processing {filename}: {e}")

# Usage
process_image_folder(
    "input_images/",
    "output_images/",
    size=(800, 600),
    contrast=1.2,
    saturation=1.1
)

Advanced Batch Processing:

class ImageBatchProcessor:
    def __init__(self, framework="tkinter"):
        self.framework = framework
        self.processed_count = 0
        self.error_count = 0
        self.errors = []

    def process_batch(self, image_list, transformations, progress_callback=None):
        """Process a list of images with given transformations."""

        results = []
        total = len(image_list)

        for i, image_path in enumerate(image_list):
            try:
                # Process image
                processed = get_image(
                    image_path,
                    framework=self.framework,
                    **transformations
                )

                results.append({
                    'path': image_path,
                    'image': processed,
                    'status': 'success'
                })

                self.processed_count += 1

            except Exception as e:
                results.append({
                    'path': image_path,
                    'error': str(e),
                    'status': 'error'
                })

                self.error_count += 1
                self.errors.append(f"{image_path}: {e}")

            # Progress callback
            if progress_callback:
                progress_callback(i + 1, total)

        return results

    def get_stats(self):
        return {
            'processed': self.processed_count,
            'errors': self.error_count,
            'error_list': self.errors
        }

# Usage with progress tracking
def progress_callback(current, total):
    percent = (current / total) * 100
    print(f"Progress: {current}/{total} ({percent:.1f}%)")

processor = ImageBatchProcessor("customtkinter")

image_files = ["img1.jpg", "img2.png", "img3.gif"]
transformations = {
    'size': (400, 300),
    'contrast': 1.3,
    'saturation': 1.2,
    'tint_color': (255, 240, 220),
    'tint_intensity': 0.1
}

results = processor.process_batch(
    image_files,
    transformations,
    progress_callback
)

stats = processor.get_stats()
print(f"Processed: {stats['processed']}, Errors: {stats['errors']}")

Quality and Performance Optimization

Image Quality Guidelines

Choosing Appropriate Sizes:

# Size guidelines for different use cases
SIZES = {
    'thumbnail': (150, 150),
    'small_icon': (16, 16),
    'medium_icon': (32, 32),
    'large_icon': (64, 64),
    'button_image': (24, 24),
    'banner': (1200, 300),
    'background': (1920, 1080),
    'mobile_bg': (375, 667),
    'tablet_bg': (768, 1024)
}

# Load appropriate size
thumbnail = get_image("photo.jpg", framework="tkinter", size=SIZES['thumbnail'])

Quality vs Performance Trade-offs:

# High quality for important images
hero_image = get_image(
    "hero.jpg",
    framework="customtkinter",
    size=(1200, 600),
    contrast=1.1,
    saturation=1.05
)

# Lower quality for thumbnails (faster loading)
thumbnail = get_image(
    "photo.jpg",
    framework="tkinter",
    size=(100, 100)
)

Performance Optimization

Caching Strategies:

class OptimizedImageLoader:
    def __init__(self, framework="tkinter", cache_size=100):
        self.framework = framework
        self.cache = {}
        self.cache_size = cache_size
        self.access_order = []

    def get_image(self, name, **kwargs):
        # Create cache key
        cache_key = f"{name}_{hash(str(sorted(kwargs.items())))}"

        if cache_key in self.cache:
            # Move to end (most recently used)
            self.access_order.remove(cache_key)
            self.access_order.append(cache_key)
            return self.cache[cache_key]

        # Load image
        image = get_image(name, framework=self.framework, **kwargs)

        # Add to cache
        self.cache[cache_key] = image
        self.access_order.append(cache_key)

        # Maintain cache size
        while len(self.cache) > self.cache_size:
            oldest = self.access_order.pop(0)
            del self.cache[oldest]

        return image

    def clear_cache(self):
        self.cache.clear()
        self.access_order.clear()

# Usage
loader = OptimizedImageLoader("customtkinter", cache_size=50)

# These will be cached
icon1 = loader.get_image("icon.png", size=(32, 32))
icon2 = loader.get_image("icon.png", size=(32, 32))  # From cache

Memory Management:

import gc

def process_large_batch(image_list, batch_size=10):
    """Process images in smaller batches to manage memory."""

    results = []

    for i in range(0, len(image_list), batch_size):
        batch = image_list[i:i + batch_size]

        # Process batch
        batch_results = []
        for image_path in batch:
            processed = get_image(
                image_path,
                framework="tkinter",
                size=(400, 300)
            )
            batch_results.append(processed)

        results.extend(batch_results)

        # Force garbage collection after each batch
        gc.collect()

        print(f"Processed batch {i//batch_size + 1}")

    return results

Common Processing Recipes

Photo Enhancement

def enhance_photo(image_path, framework="tkinter"):
    """Standard photo enhancement recipe."""
    return get_image(
        image_path,
        framework=framework,
        contrast=1.15,
        saturation=1.1,
        tint_color=(255, 245, 235),
        tint_intensity=0.05
    )

def vintage_effect(image_path, framework="tkinter"):
    """Vintage film effect."""
    return get_image(
        image_path,
        framework=framework,
        contrast=1.3,
        saturation=0.8,
        tint_color=(210, 180, 140),
        tint_intensity=0.4
    )

def dramatic_bw(image_path, framework="tkinter"):
    """Dramatic black and white."""
    return get_image(
        image_path,
        framework=framework,
        grayscale=True,
        contrast=1.5
    )

Icon Processing

def create_icon_set(source_image, framework="tkinter"):
    """Create a set of icons in different sizes."""

    sizes = [16, 24, 32, 48, 64, 128, 256]
    icons = {}

    for size in sizes:
        icons[f"{size}x{size}"] = get_image(
            source_image,
            framework=framework,
            size=(size, size)
        )

    return icons

def create_themed_icons(source_image, framework="customtkinter"):
    """Create icons for different themes."""

    themes = ["default", "light", "dark"]
    icons = {}

    for theme in themes:
        icons[theme] = get_image(
            source_image,
            framework=framework,
            size=(32, 32),
            theme=theme
        )

    return icons

Web Graphics

def optimize_for_web(image_path, max_width=1200):
    """Optimize image for web use."""

    # Calculate appropriate size
    # (In real implementation, you'd get original dimensions first)
    web_size = (max_width, int(max_width * 0.75))  # Assume 4:3 ratio

    return get_image(
        image_path,
        framework="tkinter",
        size=web_size,
        contrast=1.05,
        saturation=1.02
    )

def create_thumbnail_grid(image_list, thumb_size=(150, 150)):
    """Create thumbnails for a grid layout."""

    thumbnails = []

    for image_path in image_list:
        thumb = get_image(
            image_path,
            framework="tkinter",
            size=thumb_size
        )
        thumbnails.append(thumb)

    return thumbnails

Error Handling and Validation

Robust Image Processing

def safe_process_image(image_path, **kwargs):
    """Safely process an image with error handling."""

    try:
        # Validate image path
        if not os.path.exists(image_path):
            raise FileNotFoundError(f"Image not found: {image_path}")

        # Check file size (optional)
        file_size = os.path.getsize(image_path)
        if file_size > 50 * 1024 * 1024:  # 50MB limit
            print(f"Warning: Large file size ({file_size / 1024 / 1024:.1f}MB)")

        # Process image
        result = get_image(image_path, **kwargs)

        return {
            'success': True,
            'image': result,
            'path': image_path
        }

    except FileNotFoundError as e:
        return {
            'success': False,
            'error': 'File not found',
            'message': str(e),
            'path': image_path
        }

    except Exception as e:
        return {
            'success': False,
            'error': 'Processing error',
            'message': str(e),
            'path': image_path
        }

# Usage
result = safe_process_image(
    "photo.jpg",
    framework="tkinter",
    size=(800, 600),
    contrast=1.2
)

if result['success']:
    image = result['image']
    print(f"Successfully processed: {result['path']}")
else:
    print(f"Error: {result['error']} - {result['message']}")

Integration Examples

Complete Application Example

import tkinter as tk
from tkinter import filedialog, messagebox
from gui_image_studio import get_image

class ImageProcessorApp:
    def __init__(self, root):
        self.root = root
        self.root.title("Image Processor")
        self.root.geometry("800x600")

        self.current_image = None
        self.original_path = None

        self.setup_ui()

    def setup_ui(self):
        # Menu
        menubar = tk.Menu(self.root)
        self.root.config(menu=menubar)

        file_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label="File", menu=file_menu)
        file_menu.add_command(label="Open", command=self.open_image)
        file_menu.add_command(label="Save", command=self.save_image)

        # Controls frame
        controls = tk.Frame(self.root)
        controls.pack(side=tk.TOP, fill=tk.X, padx=10, pady=5)

        # Size controls
        tk.Label(controls, text="Size:").grid(row=0, column=0, sticky=tk.W)
        self.size_var = tk.StringVar(value="400x300")
        size_combo = tk.Entry(controls, textvariable=self.size_var, width=10)
        size_combo.grid(row=0, column=1, padx=5)

        # Contrast control
        tk.Label(controls, text="Contrast:").grid(row=0, column=2, sticky=tk.W)
        self.contrast_var = tk.DoubleVar(value=1.0)
        contrast_scale = tk.Scale(
            controls,
            from_=0.5,
            to=2.0,
            resolution=0.1,
            orient=tk.HORIZONTAL,
            variable=self.contrast_var
        )
        contrast_scale.grid(row=0, column=3, padx=5)

        # Process button
        process_btn = tk.Button(
            controls,
            text="Process",
            command=self.process_image
        )
        process_btn.grid(row=0, column=4, padx=10)

        # Image display
        self.image_label = tk.Label(self.root, text="No image loaded")
        self.image_label.pack(expand=True, fill=tk.BOTH, padx=10, pady=10)

    def open_image(self):
        file_path = filedialog.askopenfilename(
            title="Select Image",
            filetypes=[
                ("Image files", "*.png *.jpg *.jpeg *.gif *.bmp"),
                ("All files", "*.*")
            ]
        )

        if file_path:
            self.original_path = file_path
            self.process_image()

    def process_image(self):
        if not self.original_path:
            messagebox.showwarning("Warning", "Please open an image first")
            return

        try:
            # Parse size
            size_str = self.size_var.get()
            width, height = map(int, size_str.split('x'))

            # Process image
            self.current_image = get_image(
                self.original_path,
                framework="tkinter",
                size=(width, height),
                contrast=self.contrast_var.get()
            )

            # Display
            self.image_label.configure(image=self.current_image, text="")

        except Exception as e:
            messagebox.showerror("Error", f"Failed to process image: {e}")

    def save_image(self):
        if not self.current_image:
            messagebox.showwarning("Warning", "No processed image to save")
            return

        file_path = filedialog.asksaveasfilename(
            title="Save Image",
            defaultextension=".png",
            filetypes=[
                ("PNG files", "*.png"),
                ("JPEG files", "*.jpg"),
                ("All files", "*.*")
            ]
        )

        if file_path:
            # Note: In a real implementation, you'd need to save the PIL image
            messagebox.showinfo("Info", f"Image would be saved to: {file_path}")

if __name__ == "__main__":
    root = tk.Tk()
    app = ImageProcessorApp(root)
    root.mainloop()

Next Steps

Now that you understand image processing:

  1. Explore Animation Tools: Animation Tools

  2. Learn Batch Operations: Batch Operations

  3. Try Advanced Examples: Examples

  4. Build Custom Applications: gui_development