Contents

Jak stworzyć kolaż obrazów w Pythonie?

Kolaż to piękny sposób na zaprezentowanie wspomnień i wyświetlenie zestawów zdjęć. Twórcy kolaży online mogą mieć obawy dotyczące bezpieczeństwa, a aplikacje offline mogą kosztować pieniądze i nie mieć wymaganych funkcji.

Można złagodzić obawy i zachować absolutną władzę, konstruując własny kreator kolaży obrazów. Jak zatem skonstruować takie narzędzie?

Moduł Tkinter i PIL

Aby stworzyć graficzny interfejs użytkownika dla aplikacji do tworzenia kolaży obrazów, konieczne jest wykorzystanie zarówno biblioteki Tkinter, jak i Python Imaging Library (PIL). Pierwsza z nich umożliwia tworzenie aplikacji desktopowych poprzez dostarczanie różnych elementów wizualnych lub “widżetów”, które usprawniają proces projektowania graficznych interfejsów użytkownika (GUI).

Biblioteka Pillow, pochodna dobrze znanej biblioteki Python Imaging Library (PIL), oferuje szereg funkcji manipulacji obrazem, które ułatwiają zadania takie jak edycja, generowanie i zapisywanie różnych typów wizualnych plików multimedialnych.

Instalację Tkinter i Pillow można zainicjować, otwierając interfejs wiersza poleceń i wykonując następujące polecenie:

 pip install tk pillow 

GUI Setup and Image Manipulation

Kod źródłowy tego projektu można znaleźć w dedykowanym repozytorium GitHub, które służy jako cyfrowe repozytorium wszystkich plików i dokumentacji z nim związanej.

Aby rozpocząć, konieczne jest zaimportowanie niezbędnych modułów. Następnie utworzymy nową klasę o nazwie ImageCollageApp , która będzie służyć jako główny obiekt aplikacji. Początkowy krok obejmuje ustawienie tytułu i wymiarów okna. Następnie wygenerujemy płótno za pomocą metody tk.Canvas() i skonfigurujemy jego element nadrzędny, szerokość, wysokość i kolor tła.

 import tkinter as tk
from tkinter import filedialog, simpledialog, messagebox
from PIL import Image, ImageTk

class ImageCollageApp:
    def __init__(self, root):
        self.root = root
        self.root.title("Image Collage Maker")
        self.images = []
        self.image_refs = []
        self.collage_size = (600, 500)

        self.collage_canvas = tk.Canvas(
            self.root,
            width=self.collage_size[0],
            height=self.collage_size[1],
            bg="white",
        )

        self.collage_canvas.pack()

Upewnij się, że użytkownik przyznał uprawnienia do wprowadzania plików przed utworzeniem obiektu FileReader do odczytu plików graficznych z urządzenia.

Zainicjowanie struktury danych o nazwie “image\_positions” do przechowywania wizualnego pozycjonowania elementów multimedialnych w graficznym interfejsie użytkownika. Wdrożenie trzech oddzielnych procedur obsługi zdarzeń w celu uwzględnienia działań związanych z wybieraniem, przenoszeniem i zwalnianiem wspomnianych elementów multimedialnych.

         self.btn_add_image = tk.Button(
            self.root,
            text="Add Image",
            command=self.add_images,
            font=("Arial", 12, "bold"),
        )

        self.btn_add_image.pack(pady=10)

        self.btn_create_collage = tk.Button(
            self.root,
            text="Create Collage",
            command=self.create_collage,
            font=("Arial", 12, "bold"),
        )

        self.btn_create_collage.pack(pady=5)
        self.drag_data = {"x": 0, "y": 0, "item": None}
        self.image_positions = []
        self.collage_canvas.bind("<ButtonPress-1>", self.on_press)
        self.collage_canvas.bind("<B1-Motion>", self.on_drag)
        self.collage_canvas.bind("<ButtonRelease-1>", self.on_release) 

Aby zaimplementować funkcjonalność opisaną w dostarczonym fragmencie kodu, musimy najpierw zdefiniować metodę o nazwie “on\_press”. Metoda ta jest uruchamiana, gdy użytkownik kliknie myszą podczas rysowania na płótnie.Celem tej metody jest pobranie najbliższego obiektu canvas do punktu, w którym użytkownik kliknął myszką i zapisanie go w słowniku “drag\_data”. Dodatkowo będziemy przechowywać współrzędne X i Y kliknięcia myszą, abyśmy mogli później obliczyć, jak daleko użytkownik przesunął mysz podczas przeciągania.

     def on_press(self, event):
        self.drag_data["item"] = self.collage_canvas.find_closest(event.x, event.y)[0]
        self.drag_data["x"] = event.x
        self.drag_data["y"] = event.y 

Aby zaimplementować funkcjonalność opisaną w podanym fragmencie kodu, konieczne jest zdefiniowanie metody o nazwie “on\_drag”, która będzie uruchamiana, gdy użytkownik poruszy myszą, przytrzymując lewy przycisk. Metoda ta obliczy poziomą i pionową odległość przebytą przez kursor podczas operacji przeciągania przy użyciu zmiennych “dx” i “dy”. Na podstawie tych wartości można następnie zaktualizować pozycję obrazu, modyfikując atrybuty “x” i “y” obiektu “image” w widżecie “self.canvas”. Co więcej, nowe współrzędne obrazu powinny być przechowywane w słowniku “drag\_data” powiązanym z bieżącą instancją klasy, co pozwala na ich zachowanie w wielu klatkach.

     def on_drag(self, event):
        delta_x = event.x - self.drag_data["x"]
        delta_y = event.y - self.drag_data["y"]
        self.collage_canvas.move(self.drag_data["item"], delta_x, delta_y)
        self.drag_data["x"] = event.x
        self.drag_data["y"] = event.y 

Aby wyczyścić wszelkie pozostałe odniesienia do wcześniej przeciągniętego obrazu i ponownie obliczyć położenie wszystkich elementów wizualnych na kanwie w odpowiedzi na zdarzenie zwolnienia, można zaimplementować metodę “on\_release”, która rozwiązuje te problemy. W szczególności metoda ta powinna wyczyścić odniesienie do obrazu, któremu towarzyszył kursor użytkownika podczas operacji przeciągania, jednocześnie wywołując funkcję “update\_image\_positions” w celu zmiany układu wszystkich wyświetlanych obrazów po zaprzestaniu interakcji użytkownika.

     def on_release(self, event):
        self.drag_data["item"] = None
        self.drag_data["x"] = 0
        self.drag_data["y"] = 0
        self.update_image_positions() 

W elegancki sposób określimy funkcję zatytułowaną “update\_image\_positions”, która pociąga za sobą wymazanie zawartości tablicy “image\_positions” i iterację przez każdy składnik płótna. Podczas tego procesu dla każdego komponentu zidentyfikujemy jego dane pozycyjne i dołączymy je do wspomnianej tablicy.

     def update_image_positions(self):
        self.image_positions.clear()

        for item in self.collage_canvas.find_all():
            x, y = self.collage_canvas.coords(item)
            self.image_positions.append((x, y)) 

Jasne! Oto przykładowa implementacja w Pythonie przy użyciu Tkinter i biblioteki Pillow:pythonimport tkinter as tkfrom tkinter import filedialogimport osfrom PIL import Imagedef add_images():# create a new windowwindow = tk.Toplevel(root)# ask user how many images they want to uploadnum_images = tk.Entry(window)num_images.pack()num_entries = tk.Label(window, text=“Wprowadź liczbę obrazów:")num_entries.pack()# pobierz wartość z pola wpisunum_values = num_images.get()if num_values.isdigit() and int(

Wykorzystaj funkcję resize_image do przeskalowania bieżącego obrazu w pamięci, tworząc nowy obraz zgodny z Tkinter PhotoImage .Następnie dołącz to zaktualizowane odniesienie do listy image_refs przed aktualizacją płótna za pomocą metody update_canvas .

     def add_images(self):
        num_images = simpledialog.askinteger(
            "Number of Images", "Enter the number of images:"
        )

        if num_images is not None:
            file_paths = filedialog.askopenfilenames(
                filetypes=[("Image files", "*.png;*.jpg;*.jpeg;*.gif")]
            )

            if file_paths:
                for i in range(min(num_images, len(file_paths))):
                    file_path = file_paths[i]
                    image = Image.open(file_path)
                    resized_image = self.resize_image(image)
                    self.images.append(resized_image)
                    self.image_refs.append(ImageTk.PhotoImage(resized_image))

                self.update_canvas() 

Oto przykładowa implementacja metody resize_image w Pythonie:pythondef resize_image(self, image):# Get the current dimensions of the imageimg_width, img_height = image.size# Calculate the aspect ratio of the imageaspect_ratio = img_height / img_width# Check if the aspect ratio is greater than 1 (i.e., orientacja portretowa)if aspect_ratio > 1:# Ustaw nową szerokość na połowę szerokości kolażunew_width = self.collage_width / 2# Oblicz odpowiednią nową wysokość, zachowując współczynnik proporcjiew_height = int((

Jeśli współczynnik proporcji kolażu jest mniejszy niż jeden, zmniejszymy o połowę zarówno jego wysokość, jak i szerokość, obliczając odpowiednie wymiary na podstawie oryginalnego rozmiaru kolażu. Następnie możemy użyć funkcji Pillow’s resize , aby wygenerować powiększoną wersję kolażu z tymi dostosowanymi wymiarami, zachowując jego proporcje.

     def resize_image(self, image):
        img_width, img_height = image.size
        aspect_ratio = img_width / img_height

        if aspect_ratio > 1:
            new_width = self.collage_size[0] // 2
            new_height = int(new_width / aspect_ratio)
        else:
            new_height = self.collage_size[1] // 2
            new_width = int(new_height * aspect_ratio)

        return image.resize((new_width, new_height)) 

Zdefiniuj metodę o nazwie “update\_canvas” z następującymi krokami:1. Wyczyść wszystkie elementy na płótnie, usuwając odpowiednie klikalne linki powiązane z każdym elementem z poprzedniego układu obrazów.2. Przedstaw użytkownikowi możliwość wprowadzenia żądanej liczby wierszy i kolumn za pomocą okna dialogowego pliku. Podane wymiary powinny być zgodne ze specyfikacjami podanymi wcześniej w tym dokumencie.3. Określ całkowitą liczbę wymaganych kolumn na podstawie liczby wierszy wprowadzonych przez użytkownika. W naszym przykładzie założymy, że na każdy wiersz przypada sześć kolumn. Oblicz odpowiednio szerokość i wysokość kolażu. Oznacza to, że jeśli użytkownik wybierze cztery wiersze, szerokość będzie dwukrotnie większa od szerokości jednej kolumny (6) plus margines przestrzeni między nimi. Consequently

     def update_canvas(self):
        self.collage_canvas.delete("all")
        rows = simpledialog.askinteger("Number of Rows", "Enter the number of rows:")

        cols = simpledialog.askinteger(
            "Number of Columns", "Enter the number of columns:"
        )

        collage_width = self.collage_size[0] * cols // 2
        collage_height = self.collage_size[1] * rows // 2
        self.collage_canvas.config(width=collage_width, height=collage_height)
        self.image_positions.clear()
        x_offset, y_offset = 0, 0 

Iterate through each item in the image_refs list, creating a visual representation of it on the canvas by utilizing the provided offset. Umieść lewy górny róg obrazu w wyznaczonych współrzędnych, ustawiając jego punkt zakotwiczenia w północno-zachodnim rogu. Dodatkowo dołącz odpowiednie współrzędne do listy image_positions w celu dalszego odniesienia.

Aby skutecznie rozmieścić kolejny obraz w siatce, konieczne jest zaktualizowanie zmiennej x_offset poprzez dodanie połowy kolażu

         for i, image_ref in enumerate(self.image_refs):
            self.collage_canvas.create_image(
                x_offset, y_offset, anchor=tk.NW, image=image_ref
            )

            self.image_positions.append((x_offset, y_offset))
            x_offset \\+= self.collage_size[0] // 2

            if (i \\+ 1) % cols == 0:
                x_offset = 0
                y_offset \\+= self.collage_size[1] // 2 

Tworzenie kolażu i zapisywanie go

Aby wygenerować atrakcyjną wizualną reprezentację różnych zasobów cyfrowych, opracujemy funkcję znaną jako create_collage . Algorytm ten najpierw sprawdzi, czy w kompozycji znajdują się jakiekolwiek elementy multimedialne. W przypadku ich braku wyświetli komunikat ostrzegawczy. Następnie ta technika określi wymiary elektronicznego montażu, uzyskując jego szerokość i wysokość. Następnie skonstruuje nowy pusty obiekt Pillow Image, który posiada nieskazitelnie białe tło. Następnie funkcja iteruje po katalogu plików i umieszcza je dokładnie na płótnie we wcześniej określonych współrzędnych, korzystając z potężnej biblioteki PIL Pythona do wydajnego manipulowania danymi obrazu.

Wykorzystaj wstępnie ustawioną przeglądarkę obrazów, aby wyświetlić cyfrowy kolaż, zapisując go najpierw, wykorzystując jego wbudowane możliwości dla optymalnej wizualizacji.

     def create_collage(self):
        if len(self.images) == 0:
            messagebox.showwarning("Warning", "Please add images first!")
            return

        collage_width = self.collage_canvas.winfo_width()
        collage_height = self.collage_canvas.winfo_height()
        background = Image.new("RGB", (collage_width, collage_height), "white")

        for idx, image in enumerate(self.images):
            x_offset, y_offset = self.image_positions[idx]
            x_offset, y_offset = int(x_offset), int(y_offset)

            paste_box = (
                x_offset,
                y_offset,
                x_offset \\+ image.width,
                y_offset \\+ image.height,
            )

            background.paste(image, paste_box)

        background.save("collage_with_white_background.jpg")
        background.show() 

Wykorzystanie możliwości biblioteki Tkinter poprzez utworzenie nowej instancji aplikacji ImageCollage, która jest wyposażona w niezbędne atrybuty i metody wymagane do generowania wizualnych kolaży na podstawie danych wprowadzonych przez użytkownika. Po utworzeniu należy zainicjować wykonanie pętli zdarzeń Tkinter przy użyciu metody mainloop(). Polecenie to nakazuje interpreterowi Pythona ciągłe monitorowanie i przetwarzanie wszelkich zdarzeń występujących w oknie, skutecznie utrzymując jego stan do momentu ręcznego zamknięcia przez użytkownika końcowego.

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

Testowanie różnych funkcji programu Image Collage Maker

Po uruchomieniu aplikacji wyświetlany jest interfejs zawierający dwie opcje - “Dodaj obraz” i “Utwórz kolaż”. Po kliknięciu opcji “Dodaj obraz” pojawi się wyskakujące okienko z zapytaniem o całkowitą liczbę zdjęć, które użytkownik chce umieścić w kolażu. Po wprowadzeniu “5” jako żądanej liczby obrazów i wybraniu ich z podanej listy, pojawi się kolejne okno dialogowe z prośbą o podanie informacji dotyczących zarówno liczby poziomych wierszy, jak i pionowych kolumn, które powinny zostać wykorzystane przy tworzeniu kolażu.

/pl/images/start-screen-of-image-collage-application.jpg

Po wstawieniu dwóch rzędów i trzech kolumn elementów wizualnych w wyznaczonej przestrzeni granicznej, graficzny interfejs użytkownika układa je systematycznie jako tablicę lub konfigurację matrycy, tworząc spójny wyświetlacz, który podkreśla położenie i kolejność każdego elementu.

/pl/images/image-collage-default-preview-for-5-images-in-2-rows-3-columns.jpg

Podgląd umożliwia manipulowanie obrazami poprzez zmianę ich położenia zgodnie z własnymi preferencjami. Po kliknięciu przycisku “Utwórz kolaż” oprogramowanie zapisze wynikowy obraz.

/pl/images/dragging-images-to-desired-positions-within-canvas.jpg

Po sprawdzeniu wizualnej reprezentacji wygenerowanego kolażu widać, że aplikacja osiągnęła zamierzony cel w odniesieniu do złożenia spójnej i atrakcyjnej wizualnie kolekcji obrazów.

/pl/images/desired-collage-image.jpg

Ulepszenie funkcjonalności kreatora kolaży obrazów

Zamiast wykorzystywać strukturę opartą na tabeli, można zaoferować użytkownikom wybór predefiniowanych szablonów do wyboru. Dodatkowo można włączyć funkcje umożliwiające zmianę odcienia tła, wpisywanie treści pisemnych, stosowanie ulepszeń obrazu i integrację elementów dekoracyjnych pochodzących ze źródeł internetowych.

Włączając te funkcje, należy umożliwić prostą metodę modyfikowania złożonego obrazu poprzez zapewnienie opcji cofania lub przerysowywania operacji. Ponadto należy umożliwić użytkownikom dostosowanie kadrowania, zmiany rozmiaru i orientacji poszczególnych obrazów zgodnie z ich preferencjami. Dodatkowo zawiera funkcję umożliwiającą zapisanie końcowego wyniku w wybranym formacie pliku.