Objavljeno: 30.10.2012 | Avtor: Matevž Pesek | Monitor Oktober 2012 | Teme: foto

Delo s fotoaparatom

Kaj vse vsebuje moj telefon? Za del vaše mobilne naprave je na voljo aplikacija, ki omogoča interakcijo ali prikaz in uporabo zbranih podatkov naprave. Veliko takšnih izdelkov smo včasih poznali kot samostojne elektronske naprave, v zadnjih letih pa le redko koga vidimo poslušati mp3 predvajalnik ali slikati s fotoaparatom. Pa je res za vsako enoto aplikacija, kakršno si želimo?

Delo s fotoaparatom

Telefon je postal zmes nekdaj samostojnih naprav. Slednje so še vedno na voljo, a v nahrbtniku zasedajo veliko prostora. Včasih smo se vozili okoli z Garminom, slikali z Nikonom in poslušali Walkman. Igre, kakršno smo tudi mi skupaj z vami implementirali v preteklih člankih, smo igrali na priljubljeni konzoli Gameboy ali vsaj kateremu izmed klonov prenosnih ali TV klonov. Vsaka od teh naprav je v svoji reinkarnaciji ponujala dodatne zmožnosti glede na tehnologijo, ki je bila na voljo. S prihodom pametnih telefonov pa je del teh funkcionalnosti prevzel mobitel. Še vedno so slike boljše s samostojnim fotoaparatom, tudi naprave GPS ponavadi bolje sprejemajo signal satelitov kot mobilni telefon. Tudi poslušanje predvajalnikov mp3 je bilo svoj čas bolj blagodejno za ušesa glede na sposobnosti mobitelov. A kaj, ko imamo slednjega vedno v žepu. Ko pride priložnost, slikamo. Ko nam je dolgčas, poslušamo glasbo. Če se izgubimo, poženemo aplikacijo Google Maps. Ko nam je dolgčas, pa seveda igramo ... Space invaders.

Nekatere izmed aplikacij, ki uporabljajo različne dodatke mobilne naprave

Navsezadnje je danes že običajno, če za brskanje po spletu uporabljamo tablico ali mobitel, povezan prek brezžične naprave ali povezave UMTS. Lahko tudi naša aplikacija izrablja vse dodatke? V nadaljevanju bomo spoznali, da je izraba zmožnosti mobilne naprave v operacijskem sistemu Android standardizirana in nadvse enostavna. Sistematično zastavljen model zmožnosti strojne opreme omogoča enostaven dostop do zunanjih enot. Ker je strojno opremo znotraj aplikacije moč izkoristiti tudi na načine, ki niso v dobro uporabniku, je poleg modela strojne opreme sestavljen seznam dovoljenj za uporabo slednje. Ne nazadnje dovoljenja obvarujejo uporabnika pred nepotrebnim razsutjem aplikacije, ki bi za delovanje potrebovala del strojne opreme, ki ni na voljo. Tako Android v primerjavi s sistemom, ki je s strojnega vidika zaprt, omogoča nenehno nadgradnjo strojne opreme z minimalnim dodatnim vložkom pri razvoju aplikacije.

Dovoljenja

Glavni namen sistema dovoljenj v Androidu je onemogočanje povzročitve kakršnekoli škode z vidika izrabe zmožnosti mobilnega telefona s strani aplikacije brez uporabnikovega izrecnega dovoljenja. Ne glede na to, da Google preverja, ali naše aplikacije vsebujejo škodljivo kodo, še preden so objavljene v spletni prodajalni Google Play, je čisto mogoče, da se v aplikaciji skriva več kot v samem opisu na spletnih straneh. Pred nameščanjem aplikacije v mobilno napravo je zato uporabnik vsakič seznanjen z vsemi dovoljenji, ki jih aplikacija zahteva od uporabnika. Ob morebitnem nestrinjanju (Facebook na primer v zadnjih različicah zahteva dostop do naših smsov) uporabnik prekliče začetek nameščanja aplikacije. Glede na širok spekter aplikacij, ki služijo podobnim aktivnostim, je skoraj zagotovo takšna, ki je bila napisana z dobro namero in ne zahteva preveč dovoljenj.

Zgled predstavitve seznama dovoljenj, ki jih aplikacija zahteva od uporabnika.

Z istim namenom preprečevanja zavajanja uporabnika je bil uveden sistem podpisovanja paketov APK, ki jih uporabnik naloži iz spleta. Brez podpisovanja bi lahko zlonamerno pretentali uporabnika v uporabo škodljive aplikacije z enostavnim kopiranjem imena in ikone druge, neškodljive aplikacije. Obenem mora razvijalec poskrbeti za ustrezna dovoljenja, ki pa se lahko sproti spreminjajo ob posodobitvah. To na eni strani omogoča prožnost razvoja pri podjetjih, na drugi strani pa ravno te spremembe delno omejujejo samodejne posodobitve in nadgradnje aplikacij. V operacijskem sistemu Android lahko omogočimo avtomatsko posodobitev, ki se izvede, ko je na voljo novejša različica nameščene aplikacije v trgovini Google Play. Kadar posodobitev nimamo omogočenih, o slednji v vrstico z obvestili prejmemo novo obvestilo o možni posodobitvi. Če se dovoljenja aplikacije spremenijo, sistem Android tudi ob vključenih avtomatskih posodobitvah slednjih ne dovoljuje. Tak ukrep je potreben, da bi se izognili škodljivim aplikacijam, ki so v prvi fazi v spletni trgovini predstavljene na primer kot igre, ob novi različici pa se z dovoljenji za prebiranje smsov, stikov in lokacije uporabnika preobrazijo v sistem za vohunjenje.

Programsko kodo, predstavljeno v tem članku, lahko skupaj s preteklimi članki in projekti najdete na android.monitor.si.

Določanje dovoljenj pri izgradnji aplikacije

V programskem okolju Eclipse lahko določimo dovoljenja aplikacije s spreminjanjem datoteke AndroidManifest.xml. Na podzavihku "permissions" lahko izberemo ustrezno dovoljenje, ki ga želimo dodati aplikaciji. Glede na količino dovoljenj na voljo nam je v pomoč spletna dokumentacija Android za razvijalce. Pri posameznih razredih (kot na primer kamera mobilnega telefona) je v uvodu dokumentacije opisan zgled dela XML manifest datoteke na naslednji način:

<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />

Dovoljenju sledi tudi opis zmožnosti, ki jih bo aplikacija uporabila, saj s tem definiramo minimalne zahtevane pogoje, ki jim mora strojna oprema zadoščati, da je aplikacija združljiva z mobilno napravo. Slednje omogoča dobro prečiščevanje iskanih rezultatov in se izogne kupu težav, ki bi ga povzročilo nameščanje takšne aplikacije v telefon, ki ne zadošča potrebam. Takšne aplikacije bi najverjetneje povzročale vrsto napak in prisilnih zaustavitev izvajanja. Marsikateri bralec je s takšnimi zmožnostmi sistema že seznanjen, saj uporablja napravo, ki jo poganja NVidiin procesor Tegra. Določene androidne igre so napisane posebej za to platformo in niso združljive z drugimi telefoni. Na to nas trgovina Google Play opozori pred poskusom nameščanja aplikacije.

Zgled opozorila pri nameščanju igre, ki je namenjena zgolj procesorjem Tegra.

Dovoljenja, povezana z dostopom do mobilne ali brezžične povezave, si bomo ogledali v prihodnjem članku. Slednja so posredno povezana tudi z določanjem lokacije uporabnika, saj Android omogoča razmeroma natančno lokacijo mobilne naprave ob pomoči brezžičnega modula. Takšno določanje je uporabno predvsem v mestih med visokimi zgradbami, kjer je signal GPS šibak in zaradi odbojev precej nenatančen.

V nadaljevanju si bomo podrobneje ogledali dostop do vgrajene kamere, vzpostavitev dovoljenj za njeno uporabo in po zgledu mnogih drugih napisali aplikacijo, ki bo sliko iz kamere malce "umetniško" priredila.

Izdelava aplikacije

Za cilj si bomo izbrali implementacijo enostavne kamere s preprostimi filtri v slogu umetnika Andyja Warhola. Sprva bomo aplikaciji nastavili ustrezna dovoljenja, dodali pogled, ki bo omogočal takojšnje spremljanje slike na zaslonu mobilne naprave. Implementirali bomo osnovno aplikacijo za fotografiranje in z malo spremembe osnovnih barvnih komponent slike - rdeče, zelene in modre - izdelali sliko, ki se bo po umetniškem vtisu zlahka kosala z najbolj umetniškimi filtri tipa Instagram (http://instagram.com/) in podobnimi. Ogrodje aplikacije je mogoče pridobiti v spletu (android.monitor.si) in nadgraditi s poljubnimi filtri. Aplikacija bo slike shranila v poprej nastavljeno datoteko v mobilni napravi. V prihodnjem članku bomo dodali enostavno storitev za nalaganje slik v spletni strežnik, od koder jih bomo lahko delili s prijatelji in preostalim svetom.

V programskem okolju Eclipse bomo ustvarili projekt CameraFilter skupaj z aktivnostjo CameraFilterActivity. Tisti, ki še niste spremljali serije člankov o razvoju za Android, lahko natančnejša navodila o vzpostavitvi okolja najdete v februarski številki naše revije ali na zgoraj omenjenem spletnem naslovu. Poleg same aktivnosti bomo potrebovali še en razred Predogled, ki bo razširjal vgrajeni razred View. Osnovnemu pogledu bomo dodali gumb za slikanje, ki bo imel dve funkciji. Ob pritisku na gumb se bo sprožila metoda za zajem slike, v primeru dolgega pritiska pa bomo simulirali "polpritisk" gumba na klasičnem fotoaparatu - sprožili bomo izostritev fotoaparata.

Razred CameraFilterActivity

Najprej si oglejmo, kako pridobimo sliko iz fotoaparata?????

Osnovnemu pogledu bomo dodali tudi gumb za slikanje in nanj obesili poslušalca. Poslušalec naj lovi dva tipa dogodkov: pritisk na gumb naj izvede zajem slike, daljši pritisk pa naj sliko izostri.

button = (Button) findViewById(R.id.clickButton);
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
camera.takePicture(null, rawCallback, null, jpegCallback);
}
});

Na kratko razložimo metodo takePicture(). Metoda za vsakega od parametrov sprejme ime druge metode, ki jo bo izvedla po uspešnem koncu. Ker je zajem slike neposredno vezan na strojno opremo, ki ni vedno stabilna, bi bilo nesmiselno zajemati sliko v glavni niti aktivnosti, v kateri smo. Ob onemogočenem zajemu - ko npr. kamero uporablja druga aplikacija, ko kamera ne deluje ali če je ni - bi grafični vmesnik zmrznil. Ker je klic asinhron - se ne izvaja nujno neposredno za klicem metode v kontekstu preostale programske kode - ne moremo ugotoviti, kdaj bo do zajema slike dejansko prišlo, lahko pa ugotovimo, da je do zajema prišlo, ko se kliče povratna metoda (angl. callback method). S povratnimi metodami lahko določimo, kaj bomo izvedli ob uspešno zajeti sliki. Oglejmo si tri pomembnejše parametre.

Prvi vsebuje ime razreda, katerega metoda se izvede ob zajemu slike. Takšno metodo lahko uporabimo za zvočno animacijo zaslonke fotoaparata ali za obvestilo uporabniku, da je prišlo do zajema. Metoda drugega parametra vrača nestisnjeno sliko RAW, zajeto ob pomoči fotoaparata. Takšna metoda je nadvse uporabna predvsem v našem primeru, ko bomo filter naivno implementirali v obliki sprehoda po slikovnih pikah in spremenili vrednosti. Seveda se naprednejši filtri implementirajo drugače in se predvsem izvajajo hitreje. Poglavitni problem te metode je sama slika. Nekatere naprave takšne slike zajemajo, druge, med drugim tudi uporabljena naprava Asus Transformer Prime, pa tega ne dovoljujejo. Problem je verjetno v rezervaciji tako velikega prostora znotraj pomnilniškega prostora same aplikacije, ki je sistemsko omejen na 16 megabajtov, kar je razmeroma malo glede na velikost nestisnjene slike, zajete z novejšimi napravami s kamerami z možnostjo zajema slik z 8 ali več milijoni slikovnih pik. Podobni problemi, odvisni od same naprave, se pojavljajo pri vračanju slike v metodo, zapisano v tretjem parametru. Slednja naj bi dobila sliko, ki je že obdelana in ustrezno pomanjšana glede na zahtevane parametre kamere, določene s pomočjo metode get/setParameters(). Vse naprave pa podpirajo vračanje stisnjene slike JPEG, ki jo lahko pridobimo prek imena metode, zapisanega kot četrti parameter. Slednjo metodo bomo tudi implementirali. Tisti med vami, ki lahko bitno sliko pridobite v metodi onPictureTaken() razreda rawCallback, lahko izpustite pretvarjanje stisnjene slike v bitno.

Izgradnja filtra

Pri izgradnji povratne metode jpegCallback() bomo uporabili anonimni razred. To načelo smo že večkrat uporabili v preteklih člankih, predvsem pri poslušalcih elementov na zaslonu in časovnikih. Razredu tipa PictureCallback() moramo implementirati metodo onPictureTaken().

PictureCallback jpegCallback = new PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
...
}};

Bitno sliko bomo ustvarili iz polja bajtov s pomočjo razreda BitmapFactory. Slednji v eni izmed različic metode decodeByteArray(), ki jo bomo uporabili tudi mi, kot zadnji parameter sprejema instanco razreda Options. Iz polja bajtov, v katerem je shranjena stisnjena slika JPEG, bomo pridobili bitno sliko, ki jo je moč spreminjati. Sliko bomo zaradi hitrosti, ki se z implementacijo filtra občutno zniža, tudi pomanjšali na šestnajstino velikosti.

Options o = new Options();
o.inMutable = true;
o.inSampleSize = 4;
Bitmap bmp = BitmapFactory.decodeByteArray(data, 0, data.length, o);

S sprehodom po višini in širini slike bomo ob pomoči metode getPixel() dobili trenutno vrednost slikovne pike. Slednjo bomo razdelili na komponente rdeče, zelene in modre barve ter alfa kanala in glede na povprečno sivinsko vrednost slike določili novo barvo. Nova barva bo določena z enostavno pragovno funkcijo, ki bo interval sivinske vrednosti posamezne slikovne pike med 0 in 255 razdelila na tri območja. Črno bomo obarvali območje vrednosti na intervalu med 0 in 79, sivo (kasneje pa še rdeče, zeleno in modro) bomo obarvali območje vrednosti na intervalu med 80 in 159, belo pa bomo obarvali območje vrednosti nad vrednostjo 160.

int width = bmp.getWidth();
int height = bmp.getHeight();

for(int i = 0; i < width; i++) {
for(int j = 0; j < height; j++) {
int pixel = bmp.getPixel(i, j);
int red = (pixel " 16) & 0xFF;
int green = (pixel " 8) & 0xFF;
int blue = pixel & 0xFF;
int grayvalue = red + green + blue;
grayvalue /= 3;
if(grayvalue >= 160)
bmp.setPixel(i, j, Color.WHITE);
else if(grayvalue >= 80)
bmp.setPixel(i, j, Color.GRAY);
else
bmp.setPixel(i, j, Color.BLACK);
}
}

Na mestu je opomba, da predstavlja klic metode getPixel() velik presežek porabe procesorskega časa. Na mestu je preprostejša rešitev dela s poljem, kjer slikovne pike naslavljamo neposredno in se izognemo klicu metode. Pri pridobivanju posameznih barvnih komponent slikovnih pik smo uporabili logične operatorje """ in "&". Prvi operator služi zamiku bitov znotraj podatkovnega tipa int v desno, drugi pa kot rezultat vrne izračun logičnega operatorja IN (angl. and) med biti prvega in drugega operanda. Alfa kanala oz. prosojnostne komponente posamezne slikovne pike ne uporabljamo in je zaradi tega ne izločamo iz posamezne vrednosti slikovne pike. Posamezna slikovna pika je sestavljena iz štirih zaporedij osmih bitov (skupno 32 bitov, kolikor lahko hrani primitivni tip int) v sosledju kanal alfa, rdeča, zelena in modra komponenta. Ko število, ki ga predstavlja slikovna pika, na primer zamaknemo za 16 bitov na desno, dobimo v najbolj desnih osmih bitih zapis rdeče barve. Logični operator IN skupaj s številom 0xFF dobesedno izniči prvih 24 bitov in ohrani vrednosti zadnjih 8 bitov. Rezultat je vrednost posamezne barvne komponente.

Sliko bomo zapisali kar v datoteko slika.jpg v mapi DCIM internega pomnilnika, v kateri se ponavadi shranjujejo slike, zajete s kamero naprave.

OutputStream outputStream = new FileOutputStream("/sdcard/DCIM/slika.jpg");
bmp.compress(Bitmap.CompressFormat.JPEG, 50, outStream);
outStream.close();

Metoda compress() omogoča določanje kakovosti zapisane slike. V našem primeru bomo določili srednjo stopnjo stiskanja (vrednost 50), saj se intenzivnost stiskanja opisuje med 0 in 100. Prav tako smo uporabili format JPEG, druge formate pa lahko preizkusite sami. Ob izbiri brezizgubnih formatov (slika ne "pokvari" posameznih slikovnih pik) se bo vrednost intenzivnosti stiskanja ignorirala.

Rezultat štirih enobarvnih različic slike implementiranega filtra

Deluje!

Preprosto smo predstavili uporabo kamere, dodali enostaven filter, ki je iz slike naredil pravo moderno umetnost, in sliko shranili v interni pomnilniški prostor naprave. Predogled slike, ki si ga želimo pri zajemu slike, smo zaradi količine programskih vrstic izpustili, slednje si lahko ogledate na spletni strani http://android.monitor.si, kjer je projekt za okolje Eclipse iz članka tega meseca. S preostalimi zmožnostmi kamere lahko skupaj s predogledom med slikanjem enostavno implementiramo vse funkcionalnosti aplikacije Fotoaparat, ki je v vsaki androidni napravi. V prihodnjem članku bomo aplikacijo razširili s spletno storitvijo, na katero bomo prek brezžične ali mobilne povezave nalagali slike in si tako ogledali še druge zmožnosti strojne opreme. Skupaj z drugimi zunanjimi enotami bomo v prihodnje sliki dodali lokacijo GPS in jo poslali v spletno storitev, prek katere bomo sliko enostavno delili s prijatelji v družabnih omrežjih. Dodali bomo še druge enostavne filtre, v paketu SDK pa najdete tudi druge zglede rabe kamere in filtrov na slikah. Vzpodbujeni ste, da aplikacijo dopolnite z naprednejšimi filtri in jo delite z nami na spletni strani.

Naroči se na redna tedenska ali mesečna obvestila o novih prispevkih na naši spletni strani!

Komentirajo lahko le prijavljeni uporabniki

 
  • Polja označena z * je potrebno obvezno izpolniti
  • Pošlji