5.7. Compunerea imaginilor

Primitivele de desenare din pagina anterioară aplică marcaje geometrice pe o imagine – o linie, un dreptunghi, o bucată de text. Acestea acoperă majoritatea adnotărilor pe care un algoritm trebuie să le facă vizibile, dar nu pe toate. Uneori adnotarea este ea însăși o imagine: un cadru de referință capturat afișat alături de cel curent, o miniatură a unei capturi anterioare afișată într-un colț al previzualizării, un șablon stocat anterior și vizualizat peste un cadru live pentru calibrare. Mecanismul pentru desenarea unei imagini peste alta este o singură metodă – draw_image() – cu suficienți parametri pentru a gestiona poziția, scalarea, paleta de culori și transparența de care are nevoie o compunere reală.

5.7.1. Apelul de bază

În forma sa cea mai simplă, draw_image primește o altă Image și o poziție la care să o deseneze:

reference = image.Image("/sdcard/reference.bmp")
img.draw_image(reference, x=10, y=10)

Destinația este img; sursa este reference; pixelul din colțul stânga-sus al sursei ajunge la (10, 10) din img, iar restul pixelilor sursei urmează spre dreapta și în jos de acolo. Pixelii destinației pe care sursa îi acoperă sunt suprascriși cu pixelii corespunzători ai sursei; pixelii din afara amprentei sursei rămân neatinși.

Dacă sursa se extinde dincolo de marginea destinației, părțile care ies în afară sunt decupate în mod silențios – același comportament îngăduitor pe care set_pixel îl arată pentru pozițiile aflate în afara intervalului. Codul aplicației nu trebuie să limiteze poziția la dimensiunile imaginii în prealabil; poate transmite poziția dorită și poate lăsa metoda să se ocupe de decupare.

5.7.2. Încărcarea unui fișier în linie

draw_image acceptă o cale de fișier în locul argumentului Image și încarcă fișierul înainte de a-l compune:

img.draw_image("/sdcard/reference.bmp", x=10, y=10)

Acest lucru pare o comoditate – o linie în loc de două – și chiar este, dar diferența este mai mult decât sintactică. Construirea unei Image dintr-un fișier alocă un tampon (buffer) pentru a păstra pixelii decodificați, iar acel tampon (buffer) persistă până când colectarea de gunoaie îl eliberează. Transmiterea directă a căii către draw_image permite modulului să decodifice fișierul într-un tampon (buffer) temporar, să compună din el și să elibereze tamponul (buffer) la întoarcerea apelului, fără ca codul aplicației să fie nevoit să păstreze o referință la o Image separată între cadre.

5.7.3. Scalarea

Când sursa și destinația au dimensiuni diferite – o captură de rezoluție mică fiind compusă pe o pânză de rezoluție mai mare, sau o miniatură care trebuie dimensionată la o anumită fracțiune din cadru – doi parametri de scalare se ocupă de redimensionarea sursei pe măsură ce este desenată:

img.draw_image(reference, x=10, y=10, x_scale=2.0, y_scale=2.0)

x_scale și y_scale sunt valori float independente; transmiterea aceleiași valori pentru ambele scalează uniform, iar transmiterea unor valori diferite întinde sau micșorează sursa de-a lungul unei axe. Scalarea are loc la momentul desenării; sursa reference nu este modificată.

O mască de biți cu indicatori de tip hint decide cum interpolează de fapt scalarea între pixeli. image.BILINEAR produce rezultate mai netede cu prețul unui calcul mai mare; image.BICUBIC produce rezultate și mai netede și costă încă și mai mult; valoarea implicită folosește cel-mai-apropiat-vecin, care este cea mai ieftină și alegerea corectă atunci când sursa se află deja la rezoluția în pixeli a destinației. Indicatorii de gestionare a raportului de aspect – SCALE_ASPECT_KEEP, SCALE_ASPECT_EXPAND, SCALE_ASPECT_IGNORE – decid ce trebuie făcut când raportul de aspect al sursei nu se potrivește cu dreptunghiul în care este desenată.

5.7.4. Amestecarea alfa

În mod implicit, draw_image înlocuiește pixelii destinației cu pixelii sursei. Când scopul este o suprapunere translucidă – astfel încât destinația să transpară prin sursă – parametrul alpha controlează modul în care cele două sunt amestecate. alpha=0 afișează doar destinația (fără sursă); alpha=255 este valoarea implicită și afișează doar sursa (înlocuire completă); valorile intermediare le amestecă proporțional pe cele două:

img.draw_image(overlay, x=0, y=0, alpha=128)

Un argument separat alpha_palette este singurul mecanism alfa per-pixel al modulului. Acesta primește o imagine GRAYSCALE ale cărei valori sunt folosite ca alfa la poziția corespunzătoare din sursă – de exemplu, o hartă termică a cărei alfa variază în funcție de intensitatea ei. Valoarea alfa trebuie furnizată ca acel argument separat în tonuri de gri; o imagine sursă care poartă propriul canal alfa (de pildă un PNG cu transparență) nu îl aduce automat.

5.7.5. ROI-ul sursei și paleta

Doi parametri suplimentari completează mecanismul de compunere:

  • roi=(x, y, w, h) restrânge sursa la un sub-dreptunghi al ei însăși, astfel încât numai acel dreptunghi este compus pe destinație. Util pentru decuparea în cadrul aceluiași apel, fără a pregăti un intermediar decupat.

  • color_palette substituie valoarea fiecărui pixel al sursei printr-un tabel de căutare înainte de desenare – același mecanism pe care îl folosesc to_rainbow() și to_ironbow(), expus aici astfel încât o suprapunere să poată fi paletizată pe drumul ei spre destinație fără o etapă de conversie separată.

Ambii se compun cu tot ce mai există în apel: scalarea, alfa, argumentul mask de pe partea destinației și parametrul roi de pe partea destinației care limitează scrierea la un dreptunghi al destinației.