ASCII művészet Java-ban

ASCII Art 1Átte­kint­jük a ka­rak­ter­a­la­pú raj­zo­lás le­he­tő­sé­ge­it Java 2D gra­fi­ká­val, illetve a ka­rak­ter­fü­zé­rek kép­ként va­ló ke­ze­lé­sé­nek újabb le­he­tő­sé­ge­it is.

Az ASCII művészet jelentése és kezdete

Az ábécék betűiből/szövegeiből kialakított ábrák egyidősek lehetnek az írásbeliséggel. A technológiától függetlenül a karakterekből kialakított kép megjeleníthető: papír és penna vagy írógép, illetve számítógép és nyomtató vagy monitor segítségével.
Az ASCII művészet (ASCII art) tágabb értelemben a szövegalapú vizuális művészetre vonatkozik. Szűkebb értelemben véve a számítógépes grafika részterületének tekinthető. Az ASCII művészet számítógépet használ nyomtatható standard ASCII kompatibilis karakterekből álló képek készítéséhez és megjelenítéséhez. A képeken a képi elemek a nyomtatható karakterek, amelyek a pointilizmushoz hasonló optikai effektust mutatnak.
A művészeti ág indulása arra vezethető vissza, hogy a korai nyomtatókkal nem lehetett grafikát nyomtatni, a monitorokon nem lehetett grafikát megjeleníteni. Cégek, programok bannerjeinek, logóinak készítésére pedig akkor is volt igény. Ezek mellett például prezentációkhoz, kapcsolási rajzokhoz is használták az ASCII művészetet, valamint természetesen a korai e-mailekben is. A grafikus kártyák megjelenése előtti időkben pedig a videójátékok „grafikája” is ezzel a technikával készült.
Most nézzünk meg néhány lehetőséget saját programmal való képkészítésre.

ASCII képek rajzolása programozási alapismeretek tanulásakor

Saját programmal már az alapok tanulásakor készíthetők ASCII képek a vezérlő szerkezetek megismerése kapcsán. Az alábbi képek bemutatják a lehetőségeket.

ASCII Art 2

További sok-sok kép található az alábbi weboldalakon:

A 2D grafikával való szövegrajzoláshoz használható BufferedImage osztály

A BufferedImage osztály a java.awt.image csomag része. Az Image osztály utódja. Hozzáférhető képadat-puffert tartalmaz, colorModel-ből és képadatok raster-éből áll. A raster sampleModel-jében a sávok számának és típusainak illeszkedniük kell a színt és átlátszó (alpha) komponenseket megadó colorModel által megkívánt számhoz és típusokhoz. A BufferedImage típusú objektumnak van bal felső koordinátája (0, 0), ezért a létrehozásához használt raster-nek kell legyen minX=0 és minY=0 értéke. A BufferedImage osztály a raster fetch és set metódusaira, valamint a colorModel színmódosítási módszereire támaszkodik.

Szöveg képként megjelenítése karakterekkel a konzolon

A kép méretét beállítjuk. A Graphics2D osztály drawString() metódusával String-et képként jeleníthetünk meg. Bár elég „munkás”, de Java-ban gyakran BufferedImage példány létrehozásával oldjuk ezt meg, és a Graphics példányt attól kérjük el. A Graphics2D osztály karakterfüzérek rajzolásakor egyszerű mátrixszerű technikát használ. A String-et kirajzoló mátrixrészek nullától különböző értéket kapnak. A megjelenítendő terület értékét egyszerű adatként, például int-ként kell megadnunk, nem RGB színértékekkel. Ehhez a képtípust int-módba állítottuk: BufferedImage.TYPE_INT_RGB. Az ASCII képek alapötlete az, hogy a képmátrix nem nulla indexeihez hozzárendelt értékeket a kívánt művészi karakterrel helyettesítjük. A nulla értékű mátrixindexeknek szóközt adunk. A nulla integer-módban -16777216-tal egyenlő. Ezután a Java 2D grafika haladó renderelő beállításainak használatához kasztoljuk a Graphics objektumot Graphics2D példánnyá. Majd beállítjuk a kívánt renderelési paramétereket, végül meghívjuk a drawString() metódust egy karakterlánccal.

Íme az elkészült szöveg/képernyőkép:

ASCII Art 3

A karakterek cserélgetésével a pozitív képből könnyen kaphatunk inverz/negatív képet is. A generált/renderelt képet fájlban is tárolhatjuk, például a javax.imageio.ImageIO osztállyal és adott a lehetőség a kép méretének megadására, a rajta megjelenő szöveg betűtípusának beállítására, háttérszín és szövegszín alkalmazására is.

A Java BufferedImage osztály néhány lehetőségének áttekintése után jó szórakozást kívánunk az ASCII képek létrehozásához, a lehetőségek további tanulmányozásához. Aki nem programból szeretne karakterekből/szövegekből felépülő képeket készíteni, használhat online alkalmazásokat is, például az Image to HTML/ASCII-t.

A bejegyzéshez tartozó teljes forráskódot ILIAS e-learning tananyagban tesszük elérhetővé tanfolyamaink résztvevői számára.

A feladat a Java SE szoftverfejlesztő tanfolyam szakmai moduljának 21-24. óra: Objektumorientált programozás, 2. rész alkalmához kötődik.

Telefonos billentyűzettel kódolunk/dekódolunk

Telephone-keypadNem­rég egy be­tű­ket és szá­mo­kat tar­tal­ma­zó kó­dolt szö­ve­get kap­tam azzal a ké­rés­sel, hogy pró­bál­jam meg­fej­te­ni. A tit­ko­sí­tott szö­ve­get a kö­vet­ke­ző for­má­tum­ban kap­tam: 88.222.666.333.444.888.33.333. Azt is le­he­tett ró­la tud­ni, hogy a meg­fej­tés csak az an­gol á­bé­cé be­tű­it és szá­mo­kat tar­tal­maz­hat. Ilyen és ehhez ha­son­ló kó­dok meg­fej­té­se­it az Ingress ne­vű AR (augmented reality) já­ték­ban le­het fel­hasz­nál­ni (Android és iOS plat­for­mon is el­ér­he­tő), ahol a já­ték fej­lesz­tői min­dig va­la­mi­lyen egy­sze­rűbb kó­do­lás­sal juttat­ják el a já­té­ko­sok egy cso­port­ja szá­má­ra a kó­do­kat, ami­ért a já­ték­ban extra fel­sze­re­lés­hez le­het jut­ni. Az elő­ző for­du­lók­ban már ta­lál­koz­tam Base64 és Morse-kódolás­sal is, így gya­ní­tot­tam, hogy a mos­ta­ni felad­vány meg­fej­té­se sem le­het ne­héz fela­dat. Úgy gon­dol­tam, hogy a szá­mok kö­zötti pon­tok egy-egy ka­rak­ter el­vá­lasz­tá­sát je­lent­he­tik, míg a szám­je­gyek da­rab­szá­ma is hor­doz­hat hasz­nos in­for­má­ci­ót, nem csak az ér­té­kük. In­for­ma­ti­kus lé­vén rög­tön az ASCII táb­la ju­tott eszem­be, de bár­hogy pró­bál­tam va­la­mi­lyen le­ké­pe­ző függ­vényt al­kot­ni, nem si­ke­rült a szá­mo­kat le­szű­kí­te­ni a be­tűk és szá­mok tar­to­má­nyá­ra. A vég­ső megol­dást egy csa­pat­tár­sam se­gí­tett meg­ta­lál­ni, aki a jobb ol­da­lon lát­ha­tó ké­pet küld­te el ne­kem.

Például kódoljuk a SZOFTVERFEJLESZTES szöveget és ezt kapjuk: 7777.9999.666.333.8.888.33.777.333.33.5.555.33.7777.9999.8.33.7777, amit dekódolva természetesen visszakapjuk az eredeti szöveget. Hogyan működik mindez?

Tegyük fel, hogy a kódolás és dekódolás során csak az angol ábécé nagybetűit és a szóközt fogjuk használni. Hasznos néhány konstans deklarációja: a nyomógombok feliratai szövegként ( TABLE1) és tömbben ( TABLE2), szeparátorok nélküli ábécé ( TABLE3) a kódolás elvégzéséhez, valamint a dekódoláshoz szükséges szöveg ( TABLE4):

A kódolás (titkosítás) lépései

A kódolás elvégzését ellenőrzésnek kell megelőznie, hiszen a paraméterként átvett szöveg ( text) nem kódolható ha üres ( isEmpty()) vagy érvénytelen karaktert tartalmaz (olyat, ami nem szerepel a telefon nyomógombjain: ékezetes vagy írásjel). Bármilyen probléma esetén a kódoló metódus kivételt dob. A kódolás során a szöveget automatikusan nagybetűsként értelmezzük.
A kódolás során minden karakter (pl.: E) esetén ki kell választani, hogy a TABLE2 tömb melyik elemében szerepel (pl.: j=3, a nyomógomb felirata DEF) és a j-edik elemben tárolt szöveg hányadik pozícióján található (pl.: index=1). Tehát tudjuk, hogy a C karakter kódja 33, azaz ehhez a 3-as gombot kétszer ( index+1) kell lenyomni. A Java nyelvben tömbök indexelése és a szövegben lévő karakterek pozíciója is nulla bázisú sorszámmal történik. A karakterek 1-4 (változó) hosszú kódjai közé pont kerül ( coded).

A dekódolás (visszafejtés) lépései

A dekódolás elvégzését is ellenőrzésnek kell megelőznie, hiszen a paraméterként átvett szöveg ( text) nem dekódolható ha üres ( isEmpty()) vagy érvénytelen karaktert tartalmaz (olyat, ami nem feleltethető meg a telefon nyomógombjain található karakterek egyikének). Bármilyen probléma esetén a dekódoló metódus is kivételt dob.
A dekódolás során minden karakter kódja (pl.: 33) esetén szükség van annak hosszára ( length=2) és első karakterére számként ( index=3). Ezek alapján tudjuk, hogy a TABLE2 tömb index-edik ( DEF) elemének length-1-edik eleme a dekódolt karakter ( E). A dekódoló metódus nem tesz szeparátort a dekódolt karakterek ( decoded) összefűzése során. A változó hosszúságú kódolt szöveg elemeiből egykarakteres dekódolt szövegdarabok keletkeznek.

Az ellenőrzés lépései

A logikai értékkel visszatérő ellenőrző függvény ( isValidText()) feladata eldönteni, hogy a kódolás/dekódolás során használandó szöveg ( text) minden karaktere feldolgozható, azaz a folyamat során értelmezhető (másképpen: a validCharacters szöveg tartalmazza). Optimális esetben a text hossza megegyezik a benne lévő feldolgozható/értelmezhető karakterek számával (végighalad a ciklus a text-en), egyébként leáll a ciklus az első problémás karakternél.

A bejegyzéshez tartozó teljes forráskódot ILIAS e-learning tananyagban tesszük elérhetővé tanfolyamaink résztvevői számára.

Ez a feladat a Java SE szoftverfejlesztő tanfolyam szakmai moduljának 21-24. óra: Objektumorientált programozás, 2. rész alkalmához, valamint minden tanfolyamunk orientáló moduljának 1-4. óra: Programozási tételek alkalmához kapcsolódik.