Primeri koda:
File:PythonOnSymbianBookExampleCode CanvasShapes.zip
File:PythonOnSymbianBookExampleCode CanvasText.zip
File:PythonOnSymbianBookExampleCode ImageEditing.zip
File:PythonOnSymbianBookExampleCode PyMPlayer.zip
File:PythonOnSymbianBookExampleCode PySymCamera.zip
File:PythonOnSymbianBookExampleCode RecordVideo.zip
File:PythonOnSymbianBookExampleCode ScreenShot.zip
File:PythonOnSymbianBookExampleCode SoundFiles.zip
File:PythonOnSymbianBookExampleCode TakeMaxresPhoto.zip
File:PythonOnSymbianBookExampleCode TakePhoto.zip
File:PythonOnSymbianBookExampleCode TextToSpeech.zip
File:PythonOnSymbianBookExampleCode UsingViewFinder.zip
Python podržava operacije sa crtanje primitivnih oblika i teksta, fotografisanje, prikazivanje i obradu slika, kao i snimanje i puštanje zvučnih zapisa. Sa porastom mogućnosti mobilnih uređaja u naprednim multimedijalnim operacijama, kreativne mogućnosti su skoro beskrajne.
Ovo poglavlje prikazuje svaku od ovih operacija kroz osnovne primere.
Canvas je kontrola korisničkog interfejsa najnižeg mogućeg nivoa dostupnog u PyS60. Sačinjen je od oblasti na kojoj se može crtati na ekranu. Na toj oblasti se mogu prikazati druge UI komponente, uključujući osnovna crtanja primitivni oblika, teksta, slika itd.
Platno može presresti ključne događaje iz 5-smerne tastature prisutne na većini Symbian uređaja (5-smerna tastatura je zato što možemo signalisati levo, desno, gore, dole i ima centarni 'select' taster). Canvas ima bind() metod koji se može koristiti da se poveže funkcija sa ključnim događajem.
canvas.bind(EKeyUpArrow, your_up_function) |
Neki uređaju, poput onih sa ekranima osetljivim na dodir (touch screen) nemaju fizičke softkey niti 'strelica tastere'. Za ove, možemo koristiti platno da prikažemo virtualni direkcioni pad (podlogu) (ako je aplikacija u full screen modu, direkcioni pad je propraćen sa dva virtualna softkey-a, kao što se vidi na sledećoj slici) (Slika 25). Pad se može omogućiti ili onemogućiti podešavanjem appuifw.app.directional_pad na True ili False, respektivno.
Slika 25 – Virtualni direkcioni pad
Direkcioni pad za normal screen Direkcioni pad za full screen
Aplikacije mogu crtati na Canvas koristeći osnovne 'grafičke primitive' ili oblike. Dostupni oblici uključuju liniju, pravougaonik, poligon, elipsu, luk, odsečak kružnice i tačku. Metode koje se koriste za crtanje oblika i njihovi argumenti imaju generalnu formu method(coordseq[, <options>]).
Naredni primer pokazuje kako nacrtati neke oblike, a rezultujući ekran je prikazan na slici ispod (Slika 26).
import e32, appuifw |
Slika 26 – Nekoliko primitivnih oblika iscrtanih na ekranu
Canvas se takođe može koristiti i za crtanje teksta; ova mogućnost se često koristi za prikaz teksta sa prilagođenim font-om, veličinom ili bojom, na proizvoljnoj poziciji na ekranu. Canvas obezbeđuje text() metod za podešavanje teksta (font i boja) koji će se crtati, i measure_text() za određivanje veličine i položaja koji će se zauzeti nekim zadatim tekstom ako se iscrta zadatim font-om.
Naredni primer pokazuje kako nacrtati tekst 'Symbian' određenim font-om, određene boje i pozicije, a rezultat je prikazan na slici ispod (Slika 27).
import appuifw, e32 |
Slika 27 – Prilagodljiv tekst iscrtan na ekranu
Možemo definisati posebnu funkciju da prosledi redraw callback konstruktoru za Canvas. Ona određuje operacije koje trebaju biti izvršene kada se na platnu treba ponovo crtati (što se događa nakon što bude 'pomračeno' od strane nečeg drugog na ekranu.) Evo dela koda da to pojasni:
... |
Klasa Image, koja je definisana u graphics modulu, se koristi za kreiranje, uređivanje i sačuvavanje (to save) slika. Objekti slika (Image objects) se kreiraju pomoću new() metoda, gde se određuje željena veličina na sledeći način:
import graphics |
Slika se može uređivati na razne načine. Može joj se dodati tekst, na njoj se mogu nacrtati razni oblici i može se transponovati, rotirati i promeniti joj veličinu. Sledeći primer pokazuje kako se sve ove operacije mogu izvesti, a naredna slika prikazuje rezultat (Slika 28):
import graphics, appuifw, e32 |
Slika 28 – Primer uređivanja slike ’Pre’ i ’Posle’
Originalna slika Slika nakon uređivanja
Često je korisno hvatanje screenshot-a naše aplikacije za svrhe promocije, debug-ovanja i sl. Ovo se može raditi iz Python aplikacije koristeći screenshot() funkciju graphics modula.
Funkcija screenshot() vraća objekat slike, koji se može koristiti da se sačuva fotografija u JPEG ili PNG formatu. Po default-u, fotografija se sačuva sinhrono; callback se može specifikovati kao opcioni parametar da bi fajl sačuvali asinhrono.
Sledeći primer prikazuje slikanje i sinhrono čuvanje screenshot-a u JPEG formatu:
import graphics |
PyS60 pruža pristup kameri uređaja preko modula camera i obezbeđuje funkcije za fotografisanje i čuvanje tih fotografija i video snimaka. Viewfinder se može koristiti za prikaz onoga što se fotografiše. Nakon što kamera više nije potrebna, mora se osloboditi da bi je mogle koristiti druge aplikacije.
Jedan od najvažnijih aspekata fotografije i videografije je mogućnost obuhvatiti subjekat po želji. Viewfinder nam omogućuje upravo to, tako što prikazuje sliku koja će se uhvatiti na ekranu uređaja (Slika 29).
Slika 29 – Viewfinder u akciji
Sledeći isečak koda demonstrira kako se upotrebljava viewfinder. Definiše funkciju koja plasira informacije primljene iz kamere u telo aplikacije (koje je instanca od Canvas) i prosleđuje to kao argument start_finder() funkciji. Veličina viewfinder-a se takođe može odrediti prosleđivanjem tuple-a zahtevane širine/visine u pikselima, opcionom argumentu funkcije size.
import camera, appuifw, e32 |
Fotografije se hvataju (fotografišu) sa take_photo() funkcijom. Nakon fotografisanja, možemo je sačuvati baš kao i bilo koju drugu sliku.
Funkcija take_photo() ima mnoštvo (opcionalnih) argumenata pomoću kojih se mogu odrediti razna podešavanja. Puna forma funkcije je take_photo([mode, size, zoom, flash, exposure, white_balance, position]); detaljnije značenje svakog argumenta je opisano u dokumentaciji (http://pys60.garage.maemo.org/doc/s60/module-camera.html).
Sledeća tabela daje kratak opis svakog argumenta (Tabela 13 ):
Tabela 13 – Argumenti ’take_photo()’ funkcije
Argument |
Opis |
Moguće vrednosti |
mode |
Mod prikazivanja slike |
'RGB12', 'RGB16', 'RGB', 'JPEG_Exif', 'JPEG_JFIF'; vraća se od strane image_modes() funkcije. |
size |
Rezolucija slike |
Dvo-elementni tuple vraćen od strane image_sizes()funkcije. |
zoom |
Zum faktor |
Od 0 do vrednosti vraćene od strane max_zoom() funkcije. |
flash |
Podešavanje blica |
'none', 'auto', 'forced', 'fill_in', 'red_eye_reduce'; vraćeno od strane flash_modes() funkcije. |
exposure |
Podešavanje nivoa izloženosti |
'auto', 'night', 'backlight', 'center'; vraćeno od strane exposure_modes() funkcije. |
white_balance |
Temperatura boje pri trenutnoj svetlosti |
'auto', 'daylight', 'cloudy', 'tungsten', 'fluorescent', 'flash'; vraćeno od strane white_balance_modes() funkcije. |
position |
Određivanje koja se kamera koristi (ako uređaj ima više od jedne) |
Od 0 do vrednosti vraćene od strane cameras_available() funkcije minus 1. |
import camera, appuifw, e32 |
Na nekim novijim Symbian uređajima, kako bismo mogli fotografisati sa maksimalnom rezolucijom koju podržava kamera, moramo:
Sledeći primer pokazuje kako fotografisati sa maksimalnom rezolucijom. Kao što je naznačeno u prethodnoj tabeli, funkcija image_sizes() vraća listu mogućih rezolucija fotografija. Pozivajući je sa mode-om kao argumentom, u našem slučaju „JPEG_Exit“, vraća listu svi rezolucija koje su kompatabilne sa tim mode-om. Fotografisati se može odabirom „Take photo“ iz menija Options.
import appuifw, e32 |
Snimanje video zapisa se vrši kroz start_record() funkciju camera modula. Potrebno je pre pozivanja funkcija pokrenuti viewfinder. Sledeći isečak koda koristi tajmer da snimi video zapis od 10 sekundi, nakon kojih se snimanje zaustavlja.
import camera, appuifw, e32 |
Evo primera aplikacije koja može fotografisati i snimati video zapis. Ona ujedinjuje gore pominjano u potpuno funkcionalnu aplikaciju i koristi jezičke (tabs) za prebacivanje između fotografija i video zapisa.
import camera, appuifw, e32, os, graphics, sysinfo |
Analizirajmo sada kod, da vidimo šta radi i kako funkcioniše:
app_lock = e32.Ao_lock() |
Prvo, rukujemo s onim šta se događa kada se aplikacija zatvara. Kreiramo aktivni objektno-bazirani sinhonizacijski servis (app_lock) i definišemo funkciju za pozivanje kada se aplikacija zatvori. Pri zatvaranju, funkcija mora da:
Dodeljujemo funkciju desnom mekom testeru (softkey), da obradi zahtev za izlazak od strane korisnika.
recording = False |
Ovaj flag vodi računa o tome da li se trenutno snima video zapis ili ne. Ovo nam je potrebno kako bismo znali šta da radimo kada se pritisne selekcioni taster u video modu.
def number_of_files(): |
Ovo je funkcija koju koristimo da odredimo broj kojim ćemo imenovati nove fotografije i video snimke. Funkcija jednostavno broji koliko fotografija i video snimaka ima na lokaciji gde čuvamo fotografije i video snimke. Ukoliko se ime fajla na toj lokaciji podudara sa određenim formatom (u ovom slučaju, ako počinje sa „my_photo“/“my_video“ i ima „.jpg“/“.mp4“ ekstenziju), promenljiva brojača se povećava. Vrednost promenljive brojača (number_of_photos ili number_of_videos) se povećava za 1 i dodeljuje imenu povezanog tipa fajla kada se čuva.
def take(): |
Ovo je najvažnija funkcija u čitavom programu. Poziva se kada se selekcioni taster pritisne, i ponaša se različito, u zavisnosti od toga da li je pozvana u 'photocamera' mod ili 'videocamera' mod. U prvom slučaju, izračunava broj fotografija unutar direktorijuma u kom se čuvaju, zatim fotografiše, sačuva je i restart-uje kameru. U drugom slučaju, prvo proverava da li se video zapis trenutno snima. Ukoliko se ne snima, izračunava broj video zapisa u direktorijumu u kojem se čuvaju i počinje snimanje. Ukoliko se video zapis snima, jednostavno zaustavlja snimanje.
def zoom_up(): |
Ove dve funkcije su komplementarne. Koriste se za zoomin i zoomout, respektivno. Pošto je podešavanje zoom-a različitog od nule moguće jedino pri fotografisanju, prvo proveravamo da li je aplikacija u 'photocamera' modu. Ako jeste, proveravamo da li se nivo zoom-a može promeniti u odnosu na trenutni nivo. Ako može, trenutni nivo se modifikuje za pola od maksimalnog nivoa zoom-a. Nakon toga se fotografiše dummy fotografija i kamera se restart-uje kako bi viewfinder displej bio na novom nivou zoom-a.
def handle_tabs(index): |
Ovaj deo koda rukuje sa jezičcima (tabs). Funkcija se poziva kad god korisnik prelazi između dva jezička koje aplikacija koristi (jedan za 'photocamera' mod i drugi za 'videocamera' mod). Ako je izabran jezičak za fotografisanje, svako trenutno snimanje video zapisa se zaustavlja i kamera se restart-uje u fotografski mod. Ukoliko je video jezičak izabran, s obzirom da nema snimanja koje bi se zaustavilo, aplikacija jednostavno prebaci na taj jezičak restart-ujući se u video mod. Zadnji red koda kreira ta dva jezička.
img = graphics.Image.new(sysinfo.display_pixels()) |
Kada prikazujemo viewfinder, visoka brzina pri kojoj se podaci šalju iz kamere ka ekranu može izazvati treperenje. Ovo se rešava primenom koncepta double buffering-a (http://en.wikipedia.org/wiki/Double_buffering). Umesto da prikazujemo podatke viewfinder-a direktno na ekran, prvo ih stavljamo u img i onda prikazujemo to.
def vf(im): |
U prethodnom isečku koda definišemo funkciju koja uzima podatke iz kamere u formi slike i iscrtava to na drugu sliku (prva faza double buffering-a). Onda poziva canvas-ovu redraw callback funkciju, koja stavlja sliku na canvas, te je prikazuje na ekranu (druga faza double buffering-a).
canvas.bind(EKeyUpArrow, zoom_up) |
Sada povezujemo određene tastere sa određenim akcijama. bind() metod Canvas instance veže (binds) funkciju za keycodes. Na primer, kada se pritisne taster up arrow (strelica gore), poziva se funkcija take().
#Definiši callback za snimanje video zapisa |
Povratna funkcija će biti pozvana sa error kodom i informacijama o statusu kao parametrom. Mora biti prisutna kako bi uređaj bio spreman da započne snimanje video zapisa. Lista mogućih stanja je dostupna u PyS60 documentation (http://pys60.garage.maemo.org/doc/s60/module-camera.html
#Zoom je u početnku 0 |
Ovde određujemo da je nivo zoom-a an početnu 0 i blic je onemogućen na početku. Onda definišemo funkciju set_flash(option) koja omogućuje ili onemogućuje blic. Važni redovi ove funkcije su flash = "forced" i flash = "none" (“forced” i “none” su modovi blica) zato što oni uključuju i isključuju blic, zavisno od Boolean vrednosti koja se prosleđuje kao argument.
def photocamera(): |
Ovo je funkcija koja se poziva kada se kamera prebaci u fotografski mod. Podešava trenutni mod u 'photocamera', pokreće viewfinder i sukladno tome podešava meni.
def videocamera(): |
Ova funkcija radi isto što i photocamera(), ali za video mod.
photocamera() |
Jednostavno pokrećemo aplikaciju kamere u fotografskom modu i kažemo skripti da ne završi izvršavanje dok se desni meki taster (softkey) ne pritisne (i onda se poziva quit() funkcija).
Funkcija say() audio modula se može koristiti za izgovor Unicode teksta fonetski (u trenutnom jeziku uređaja). Pomoću ovog postaje trivijalno jednostavno dodati tekst govornim mogućnostima naše aplikacije. Sledeći primer ‘reprodukuje’ tekst ‘Python on Symbian’:
import audio |
Audio zapis se može snimiti i reprodukovati korišćenjem audio modula. Najčešće korišteni metodi zvučnih objekata su:
Podržani formati zvučnih fajlova variraju u zavisnosti od uređaja. Sledeći isečak koda demonstrira kako snimiti zvučni zapis i onda ga reprodukovati.
import appuifw, e32, audio |
Sledeći primer je osnovna verzija aplikacije muzičkog plejera. Njegove osobine uključuju play/pause funkcionalnost, kod za pojačanje i smanjenje glasnoće zvuka, i informacije za prikaz statusa reprodukovanja. Implementacija pause-e i resume-a su vredne pomena, s obzirom da ne postoje standardne metode za njih.
import appuifw, e32, audio, graphics, os, sysinfo |
Pri prvom pogledu na ovaj primer koda, primećujemo da je muzički plejer implementiran kao klasa, a ne kao serija funkcija. Ovaj pristup omogućuje plejeru da bude korišten od strane drugih aplikacija jednostavnim import-ovanje istog kao i bilo koje druge klase iz modula.
def __init__(self, path): #Putanja gde će player tražiti zvučne fajlove self.path = path #Promenljiva koja vodi računa o trenutnom stanju player-a; #None znači da nijedna pesma nije otvorena, False znači da je reprodukovanje pauzirano, a True #znači da se pesma reprodukuje self.playing = None #Ovo ćemo koristiti kada se vraćamo iz pauze, kako bismo znali odakle treba nastaviti reprodukciju self.pickup_time = 0 #Kreiraj sliku veličine ekrana self.img = graphics.Image.new(sysinfo.display_pixels()) #Inicijalizuj Canvas i podesi ga kao telo aplikacije, #i veži (bind) tastere koji kontrolišu opcije reprodukovanja self.canvas = appuifw.Canvas(redraw_callback=self.handle_redraw) self.canvas.bind(EKeyUpArrow, self.volume_up) self.canvas.bind(EKeyDownArrow, self.volume_down) self.canvas.bind(EKeySelect, self.play_pause) appuifw.app.body = self.canvas appuifw.app.menu = [(u"Pick song", self.select_song)] #Inicijalizuj tajmer koji će se koristiti za ažuriranje informacija koje se prikazuju na ekranu self.timer = e32.Ao_timer() |
Ovo je konstruktor. Podaci koji su potrebni odmah nakon pokretanja plejera su definisani ovde. Trenutni zvučni objekat, međutim, je definisan u play_pause() metodu nakon što je zvučni fajl izabran.
#Ova funkcija nalazi sve zvučne fajlove u određenom direktorijumu #i prikazuje ih u listi da bi korisnik mogao da izabere def select_song(self): self.list_of_songs = [] for self.i in os.listdir(self.path): #Proveri da li je ekstenzija od zvučnog fajla, ako jeste, dodaj ime na listu if self.i[-4:] in [".mp3", ".wav", ".wma"]: self.list_of_songs.append(unicode(self.i)) #Pitaj korisnika koji fajl želi reprodukovati, ako ih uopšte ima if len(self.list_of_songs) > 0: try: self.file_name = self.list_of_songs[appuifw.selection_list(self.list_of_songs)] except TypeError: #Desi se kada korisnik poništi selekciju pass else: appuifw.note(u"No appropriate sound files available", 'info') |
Ovu funkciju koristimo za odabir pesme koju želimo reprodukovati. Ona pretražuje direktorijum na određenoj putanji za fajlove čije su ekstenzije zvučnih fajlova i, kada ih nađe, dodaje ih na listu. Lista se onda prikazuje pomoću selekcione liste, korisnik izabere fajl, i onda se utvrđuje ime fajla pesme koja će se reprodukovati.
def volume_up(self): try: self.s.set_volume(self.s.current_volume() + 1) except: pass def volume_down(self): try: self.s.set_volume(self.s.current_volume() - 1) except: pass |
Prethodne dve funkcije rukuju sa promenom glasnoće reprodukcije. One se pozivaju kada se pritisnu tasteri up arrow i down arrow (strelica gore i strelica dole). Glasnoća (volume) se pojačava/stišava za jedan stepen, dok ne dostigne maksimum/0. Izuzeci koji se mogu javiti pri pokušaju da se podesi glasnoća iznad maksimuma ili ispod minimuma ili kada se podešava glasnoća kada nije definisan zvučni objekat (set_volume() metod pripada zvučnom objektu) se rukuju sa try...except izjavama.
def play_pause(self): if self.playing == False: self.s.set_position(self.pickup_time) self.playing = True self.s.play() self.show_info() elif self.playing == True: self.pickup_time = self.s.current_position() self.playing = False self.s.stop() self.timer.cancel() if self.playing == None: try: #Ako se play upotrebi pre odabira pesme, dolazi do greške self.s = audio.Sound.open(self.path + "\\" + self.file_name) appuifw.app.menu = [(u"Stop", self.stop)] self.playing = True self.s.play() self.show_info() except: pass |
Plejer može biti u jednom od tri stanja u svakom trenutku:
Funkcija play_pause() rukuje sa prelazima između ova tri stanja. Kada se pauzira reprodukcija, broju mikrosekundi koje su već reprodukovane se pristupa preko current_position() metoda i taj broj se skladišti u self.pickup.time, i reprodukovanje se zaustavlja. Kako bismo nastavili reprodukovanje, naznačujemo odakle bi fajl trebao započeti reprodukciju koristeći set_position() metod i reprodukcija počinje. Ovaj pristup se koristi zato što nema predefinisanih načina za pauziranje i nastavak reprodukcije.
def stop(self): appuifw.app.menu = [(u"Pick song", self.select_song)] self.s.stop() self.s.close() self.playing = None self.timer.cancel() |
Kao što samo ime sugeriše, ova funkcija se koristi da se zaustavi reprodukcija. Zvučni fajl se zatvori, meni se podesi tako da dopušta korisniku odabir druge pesme, i tajmer koji se koristi za ažuriranje informacija na ekranu se poništava (ažuriranje informacija kada se nijedna pesma reprodukuje bi bilo besmisleno).
def show_info(self): #Izračunaj vrednosti self.min1, self.sec1 = divmod((self.s.current_position() / 1000000), 60) self.min2, self.sec2 = divmod((self.s.duration() / 1000000), 60) #Daj vrednostima standardni format mm:ss if self.min1<10: self.info = u"0" + unicode(self.min1) else: self.info = unicode(self.min1) self.info += u":" if self.sec1<10: self.info += u"0" + unicode(self.sec1) else: self.info += unicode(self.sec1) self.info += u" - " if self.min2<10: self.info += u"0" + unicode(self.min2) else: self.info += unicode(self.min2) self.info += u":" if self.sec2<10: self.info += u"0" + unicode(self.sec2) else: self.info += unicode(self.sec2) #Skloni sliku da se stvari ne bi preklapale self.img.clear() #Proračunaj gde da se prikažu informacije, tako da budu na centru ekrana self.text_size = self.img.measure_text(self.file_name, font='title')[0] self.text_width = self.text_size[2] - self.text_size[0] self.text_height = self.text_size[3] - self.text_size[1] self.text_x = (sysinfo.display_pixels()[0] / 2) - (self.text_width / 2) self.text_y = (sysinfo.display_pixels()[1] / 2) - self.text_height self.img.text((self.text_x, self.text_y), self.file_name, font='title') self.text_size = self.img.measure_text(self.info, font='title')[0] self.text_width = self.text_size[2] - self.text_size[0] self.text_height = self.text_size[3] - self.text_size[1] self.text_x = (sysinfo.display_pixels()[0] / 2) - (self.text_width / 2) self.text_y = (sysinfo.display_pixels()[1] / 2) - self.text_height self.img.text((self.text_x, self.text_y + self.text_height), self.info, font='title') self.handle_redraw(()) #Ažuriraj informacije svake sekunde self.timer.after(1, self.show_info) |
Ovde jednostavno izračunavamo vreme trajanja pesme i koliko je već prošlo tokom reprodukcije i prikazujemo tu informaciju uz ime fajla. Ova funkcija se poziva svake sekunde uz pomoć tajmerovog after() metoda.
Metod measure_text() se koristi da se odredi koliko prostora (u pikselima) će određeni tekst zauzeti ukoliko se ispiše određenim font-om. Vraćeni rezultat sadrži 4-elementni tuple sa koordinatama gornjeg-levog i donjeg-desnog ugla pravougaonika koji bi sadržao tekst. Ovu informaciju koristimo da odredimo gde da iscrtamo tekst kako bi on bio prikazan u sredini ekrana.
def __del__(self): try: self.s.stop() self.s.close() except: pass |
Metod __del__ objekta se poziva kada će taj objekat biti uništen. Ovde zatvaramo bilo koji otvoreni zvučni fajl.