Przykład wykorzystania ciągów: pseudografika ASCIIFlash Player 9 i nowsze wersje, Adobe AIR 1.0 i nowsze wersje Przykład „Pseudografika ASCII” ilustruje szereg mechanizmów pracy klasą String w języku ActionScript 3.0, a w szczególności:
Termin pseudografika ASCII oznacza tekstową reprezentację obrazu, w której obraz jest rysowany za pomocą znaków należących do czcionki nieproporcjonalnej, takiej jak Courier New. Na poniższej ilustracji przedstawiono przykładową pseudografikę ASCII wygenerowaną przez aplikację: ![]() Wersja obrazu w postaci pseudografiki ASCII jest widoczna po prawej stronie. Aby pobrać pliki tej przykładowej aplikacji, należy przejść na stronę www.adobe.com/go/learn_programmingAS3samples_flash_pl. Pliki aplikacji ASCIIArt znajdują się w folderze Samples/AsciiArt. Aplikacja składa się z następujących plików:
Wyodrębnianie wartości rozdzielonych znakami tabulacjiW omawianym przykładzie zastosowano typową technikę przechowywania danych aplikacji w oddzielnym pliku, niezależnym od samej aplikacji; dzięki temu zmiany danych (np. dodanie nowego obrazu lub zmiana tytułu obrazu) nie wiąże się z koniecznością zrekonstruowania pliku SWF. W tym przypadku metadane obrazów, w tym tytuły, adresy URL właściwych plików z obrazami oraz niektóre wartości potrzebne do manipulowania obrazami są przechowywane w pliku tekstowym (pliku txt/ImageData.txt w projekcie). Oto zawartość tego pliku tekstowego: FILENAME TITLE WHITE_THRESHHOLD BLACK_THRESHHOLD FruitBasket.jpg Pear, apple, orange, and banana d8 10 Banana.jpg A picture of a banana C8 20 Orange.jpg orange FF 20 Apple.jpg picture of an apple 6E 10 Plik zawiera dane rozdzielane znakami tabulacji. Pierwszy wiersz jest wierszem nagłówkowym. Pozostałe wiersze zawierają następujące dane poszczególnych bitmap przeznaczonych do załadowania:
Od razu po uruchomieniu aplikacji klasa AsciiArtBuilder ładuje i analizuje treść pliku tekstowego w celu utworzenia „stosu” obrazów do wyświetlanie. Oto fragment kodu z metody parseImageInfo() w klasie AsciiArtBuilder: var lines:Array = _imageInfoLoader.data.split("\n");
var numLines:uint = lines.length;
for (var i:uint = 1; i < numLines; i++)
{
var imageInfoRaw:String = lines[i];
...
if (imageInfoRaw.length > 0)
{
// Create a new image info record and add it to the array of image info.
var imageInfo:ImageInfo = new ImageInfo();
// Split the current line into values (separated by tab (\t)
// characters) and extract the individual properties:
var imageProperties:Array = imageInfoRaw.split("\t");
imageInfo.fileName = imageProperties[0];
imageInfo.title = normalizeTitle(imageProperties[1]);
imageInfo.whiteThreshold = parseInt(imageProperties[2], 16);
imageInfo.blackThreshold = parseInt(imageProperties[3], 16);
result.push(imageInfo);
}
}
Cała treść pliku tekstowego jest zawarta w jednej instancji klasy String — we właściwości _imageInfoLoader.data. Za pomocą metody split() wywołanej ze znakiem nowego wiersza ("\n") jako parametrem instancja klasy String jest dzielona na wiersze wpisywane do tablicy lines. Elementy tej tablicy odpowiadają poszczególnym wierszom pliku tekstowego. Następnie kod w pętli przetwarza kolejne wiersze (z wyjątkiem pierwszego, bo zawiera on nagłówki, a nie właściwą treść). Wewnątrz pętli ponownie wywoływana jest metoda split(), tym razem w celu podzielenia każdego wiersza na zestaw wartości (obiekt Array o nazwie imageProperties). Parametrem metody split() jest w tym przypadku znak tabulacji ("\t"), ponieważ wartości w każdym wierszu są rozdzielone właśnie znakami tabulacji. Użycie metod klasy String do normalizacji tytułów obrazówJednym z założeń poczynionych przy projektowaniu tej aplikacji było ujednolicenie formatu tytułów obrazów. Pierwsza litera każdego wyrazu w tytule powinna być zapisana wielką literą (z wyłączeniem kilku słów, które w tytułach angielskich nie są nigdy zapisywane wielkimi literami). Ponieważ nie ma pewności, czy plik tekstowy będzie zawierał prawidłowo sformatowane tytuły, aplikacja formatuje je w miarę wyodrębniania z pliku tekstowego. W poprzednim fragmencie kodu, w procesie wyodrębniania wartości metadanych obrazów, występuje poniższy wiersz: imageInfo.title = normalizeTitle(imageProperties[1]); Tytuł obrazu pochodzący z pliku tekstowego jest przetwarzany przez metodę normalizeTitle(), a dopiero potem zapisywany w obiekcie ImageInfo: private function normalizeTitle(title:String):String
{
var words:Array = title.split(" ");
var len:uint = words.length;
for (var i:uint; i < len; i++)
{
words[i] = capitalizeFirstLetter(words[i]);
}
return words.join(" ");
}
W metodzie tej zastosowano metodę split() w celu podzielenia tytułu na poszczególne słowa (rozdzielone spacjami); każde słowo przetwarzane jest przez metodę capitalizeFirstLetter(), a następnie używana jest metoda join() klasy Array w celu ponownego połączenia słów w jeden ciąg znaków. Zgodnie ze swoją nazwą, metoda capitalizeFirstLetter() zamienia pierwszą literę wyrazu na wielką: /**
* Capitalizes the first letter of a single word, unless it's one of
* a set of words that are normally not capitalized in English.
*/
private function capitalizeFirstLetter(word:String):String
{
switch (word)
{
case "and":
case "the":
case "in":
case "an":
case "or":
case "at":
case "of":
case "a":
// Don't do anything to these words.
break;
default:
// For any other word, capitalize the first character.
var firstLetter:String = word.substr(0, 1);
firstLetter = firstLetter.toUpperCase();
var otherLetters:String = word.substring(1);
word = firstLetter + otherLetters;
}
return word;
}
W języku angielskim istnieją słowa, które w tytułach nie są nigdy zapisywane z wielkiej litery: „and,” „the”, „in”, „an”, „or”, „at”, „of”, oraz „a”. (Przyjęto uproszczone reguły). Aby zrealizować tę logikę, zastosowano instrukcję switch, która sprawdza, czy wyraz należy do zbioru słów wykluczonych z zapisu wielką literą. Jeśli należy, to następuje wyjście z instrukcji switch. Jeśli jednak wyraz powinien rozpoczynać się od wielkiej litery, proces zamiany odbywa się w następujących etapach:
Generowanie tekstu pseudografiki ASCIIKlasa BitmapToAsciiConverter zawiera funkcje konwertujące obraz bitmapowy na jego reprezentację tekstową ASCII. Ten proces realizuje metoda parseBitmapData(), której fragment przedstawiono poniżej: var result:String = "";
// Loop through the rows of pixels top to bottom:
for (var y:uint = 0; y < _data.height; y += verticalResolution)
{
// Within each row, loop through pixels left to right:
for (var x:uint = 0; x < _data.width; x += horizontalResolution)
{
...
// Convert the gray value in the 0-255 range to a value
// in the 0-64 range (since that's the number of "shades of
// gray" in the set of available characters):
index = Math.floor(grayVal / 4);
result += palette.charAt(index);
}
result += "\n";
}
return result;
Najpierw definiowana jest instancja klasy String o nazwie result, która posłuży do zbudowania pseudograficznej wersji bitmapy ze znaków ASCII. Następnie analizowane są w pętli poszczególne piksele źródłowego obrazu bitmapowego. Korzystając z kilku technik manipulacji kolorami (których omówienie tutaj pominiemy) program zamienia wartości czerwieni, zieleni i koloru niebieskiego przypisane do danego piksela na jedną wartość w skali szarości (liczbę z przedziału od 0 do 255). Następnie wartość ta jest dzielona przez 4 (tak jak to przedstawiono) w celu przeliczenia jej na skalę 0-63. Wynik zapisywany jest w zmiennej index. (Skala 0-63 odzwierciedla „paletę” 64 znaków ASCII używanych przez aplikację). Paleta znaków jest zdefiniowana jako instancja klasy String w klasie BitmapToAsciiConverter: // The characters are in order from darkest to lightest, so that their
// position (index) in the string corresponds to a relative color value
// (0 = black).
private static const palette:String = "@#$%&8BMW*mwqpdbkhaoQ0OZXYUJCLtfjzxnuvcr[]{}1()|/?Il!i><+_~-;,. ";
Ponieważ zmienna index określa, który znak ASCII w palecie odpowiada wartości bieżącego piksela w bitmapie, możliwe jest pobranie znaku z ciągu palette za pomocą metody charAt(). Następnie znak jest dopisywany do instancji klasy String o nazwie result za pomocą operatora konkatenacji z przypisaniem (+=). Dodatkowo na końcu każdego rzędu pikseli do ciągu result dopisywany jest znak nowego wiersza, co powoduje zawinięcie tekstu i utworzenie nowego wiersza „pikseli” znakowych. |
|