5.7. Komponowanie obrazów¶
Prymitywy rysowania z poprzedniej strony nanoszą na obraz znaki geometryczne – linię, prostokąt, fragment tekstu. Pokrywa to większość adnotacji, które algorytm musi uwidocznić, ale nie wszystkie. Czasami adnotacja sama jest obrazem: przechwyconą ramką referencyjną wyświetlaną obok bieżącej, miniaturą wcześniejszego ujęcia pokazaną w rogu podglądu albo wcześniej zapisanym szablonem zwizualizowanym na żywej ramce do celów kalibracji. Mechanizmem rysowania jednego obrazu na drugim jest pojedyncza metoda – draw_image() – z wystarczającą liczbą parametrów, aby obsłużyć pozycję, skalowanie, paletę kolorów oraz przezroczystość, których wymaga prawdziwa kompozycja.
5.7.1. Podstawowe wywołanie¶
W najprostszej formie draw_image przyjmuje inny obiekt Image oraz pozycję, w której ma go narysować:
reference = image.Image("/sdcard/reference.bmp")
img.draw_image(reference, x=10, y=10)
Celem jest img; źródłem jest reference; lewy górny piksel źródła trafia w punkt (10, 10) obrazu img, a pozostałe piksele źródła rozmieszczają się od tego miejsca w prawo i w dół. Piksele celu, które źródło zakrywa, zostają nadpisane odpowiadającymi pikselami źródła; piksele poza zasięgiem źródła pozostają nienaruszone.
Jeśli źródło wykracza poza krawędź celu, części, które wypadają poza obszar, są po cichu przycinane – to samo wyrozumiałe zachowanie, jakie set_pixel wykazuje wobec pozycji spoza zakresu. Kod aplikacji nie musi z góry ograniczać pozycji do wymiarów obrazu; może przekazać żądaną pozycję i pozostawić przycinanie metodzie.
5.7.2. Wczytywanie pliku w jednym wierszu¶
draw_image przyjmuje ścieżkę pliku w miejsce argumentu Image i wczytuje plik przed jego skomponowaniem:
img.draw_image("/sdcard/reference.bmp", x=10, y=10)
Wygląda to na udogodnienie – jeden wiersz zamiast dwóch – i tak jest, ale różnica wykracza poza składnię. Utworzenie obiektu Image z pliku alokuje bufor na zdekodowane piksele, a ten bufor istnieje aż do momentu, gdy odśmiecanie pamięci go zwolni. Przekazanie ścieżki bezpośrednio do draw_image pozwala modułowi zdekodować plik do bufora roboczego, skomponować z niego obraz i zwolnić bufor po zakończeniu wywołania, bez konieczności utrzymywania przez kod aplikacji odwołania do osobnego obiektu Image między ramkami.
5.7.3. Skalowanie¶
Gdy źródło i cel mają różne rozmiary – ujęcie o niskiej rozdzielczości komponowane na płótnie o wyższej rozdzielczości albo miniatura, której rozmiar musi stanowić określoną część ramki – dwa parametry skali odpowiadają za zmianę rozmiaru źródła podczas rysowania:
img.draw_image(reference, x=10, y=10, x_scale=2.0, y_scale=2.0)
x_scale i y_scale to niezależne liczby zmiennoprzecinkowe; przekazanie obu o tej samej wartości skaluje równomiernie, a przekazanie różnych wartości rozciąga lub zwęża źródło wzdłuż jednej osi. Skalowanie odbywa się w czasie rysowania; samo źródło reference nie jest modyfikowane.
Maska bitowa flag hint decyduje o tym, jak skalowanie faktycznie interpoluje między pikselami. image.BILINEAR daje gładsze wyniki kosztem większej liczby obliczeń; image.BICUBIC daje jeszcze gładsze wyniki i kosztuje jeszcze więcej; domyślnie używana jest metoda najbliższego sąsiada, która jest najtańsza i właściwa wtedy, gdy źródło ma już rozdzielczość pikselową celu. Flagi obsługi proporcji – SCALE_ASPECT_KEEP, SCALE_ASPECT_EXPAND, SCALE_ASPECT_IGNORE – decydują o tym, co zrobić, gdy proporcje źródła nie pasują do prostokąta, w którym jest rysowane.
5.7.4. Mieszanie alfa¶
Domyślnie draw_image zastępuje piksele celu pikselami źródła. Gdy celem jest półprzezroczysta nakładka – tak aby cel prześwitywał przez źródło – parametr alpha steruje sposobem ich zmieszania. alpha=0 pokazuje wyłącznie cel (brak źródła); alpha=255 jest wartością domyślną i pokazuje wyłącznie źródło (pełne zastąpienie); wartości pośrednie mieszają oba proporcjonalnie:
img.draw_image(overlay, x=0, y=0, alpha=128)
Osobny argument alpha_palette to jedyny w module mechanizm alfa na poziomie pojedynczego piksela. Przyjmuje obraz GRAYSCALE, którego wartości są używane jako alfa w odpowiadającej pozycji w źródle – na przykład mapa cieplna, której alfa zmienia się wraz z jej intensywnością. Alfa musi być dostarczona jako ten osobny argument w skali szarości; obraz źródłowy zawierający własny kanał alfa (np. PNG z przezroczystością) nie przenosi go automatycznie.
5.7.5. Źródłowy ROI i paleta¶
Dwa kolejne parametry dopełniają mechanizm kompozycji:
roi=(x, y, w, h)ogranicza źródło do jego własnego podprostokąta, tak że tylko ten prostokąt zostaje skomponowany na celu. Przydatne do przycinania w obrębie tego samego wywołania, bez przygotowywania przyciętego obrazu pośredniego.color_palettezastępuje wartość każdego piksela źródła przez tablicę przeglądową przed rysowaniem – to ten sam mechanizm, którego używająto_rainbow()ito_ironbow(), udostępniony tutaj, aby nakładka mogła zostać poddana paletyzacji w drodze na cel, bez osobnego przebiegu konwersji.
Oba komponują się ze wszystkim pozostałym w wywołaniu: ze skalowaniem, alfą, argumentem mask po stronie celu oraz parametrem roi po stronie celu, który ogranicza zapis do prostokąta celu.