Today, I was sorting out the articles to be read in Pocket and saw this article "Creating ASCII art in functional Swift", which explains how to use Swift to convert images into ASCII characters. The specific principle is explained in detail in the article, so I will not repeat it here, but the "in functional Swift" in the title made me very interested. I wanted to know where the functionality is reflected, so I downloaded the swift-ascii-art source code to find out. Pixel The image is composed of pixels, which are implemented by the Pixel struct in the code. Each pixel is allocated 4 bytes, which (2^8 = 256) are used to store the RBGA value. createPixelMatrix You can create a width * height pixel matrix using the static method createPixelMatrix:
intensityFromPixelPointer The intensityFromPixelPointer method calculates and returns the brightness value of a pixel. The code is as follows:
The calculateIntensity method obtains the intensity of a pixel based on Y'UV encoding:
YUV is a color encoding method, where Y represents brightness, UV represents color difference, and U and V are the two components that make up color. Its advantage is that it can use the characteristics of the human eye to reduce the storage capacity required for digital color images. The Y we get from this formula is the value of brightness. Offset There is actually only one value stored in Pixel: offset. The matrix created by Pixel.createPixelMatrix looks like this:
It does not store the relevant data of each pixel as you might imagine, but is more like a conversion tool that calculates the grayscale value of PixelPointer. AsciiArtist AsciiArtist encapsulates some methods for generating character paintings. createAsciiArt The createAsciiArt method is used to create character art:
The CFDataGetBytePtr function returns the pointer to the byte array of the image. Each element in the array is a byte, that is, an integer from 0 to 255. Every 4 bytes form a pixel, corresponding to the RGBA value. intensityMatrixFromPixelPointer intensityMatrixFromPixelPointer This method generates the corresponding brightness value matrix through PixelPointer:
First, an empty two-dimensional array is created through the Pixel.createPixelMatrix method to store values. Then two maps are nested to traverse all the elements in it and convert pixels into intensity values. symbolMatrixFromIntensityMatrix The symbolMatrixFromIntensityMatrix function converts an array of brightness values into an array of glyphs:
Map + reduce successfully implements string accumulation. Each reduce operation uses the symbolFromIntensity method to obtain the character corresponding to the brightness value. The symbolFromIntensity method is as follows:
Pass intensity, make sure the value is between 0 and 1, convert it to the corresponding character through AsciiPalette, and output sumbol. AsciiPalette AsciiPalette is a tool used to convert numerical values into characters, just like a palette in a character painting, generating characters based on different colors. loadSymbols loadSymbols loads all symbols:
As you can see, the character range we selected is 32 ~ 126 characters. The next step is to sort these characters by brightness through the symbolsSortedByIntensityForAsciiCodes method. For example, the & symbol definitely represents an area darker than ., so how is it compared? Please see the sorting method. symbolsSortedByIntensityForAsciiCodes The symbolsSortedByIntensityForAsciiCodes method implements string generation and sorting:
Among them, the sortByIntensity sorting method is as follows:
summary After a brief review of the project, I can vaguely feel some functional style, which is mainly reflected in the following aspects: The application of functions such as map reduce is just right, and can easily handle the conversion and concatenation of arrays. Data processing is performed through input and output, such as the sortByIntensity method and the symbolFromIntensity method. There are few states and attributes, but more direct function conversions. Function logic does not depend on external variables, but only on the parameters passed in. The code feels simple and light. Through this simple example, we can verify what we have learned from the functional features. It feels great! |
<<: Why is it difficult for domestic apps to dominate overseas markets?
>>: How to Become a Great JavaScript Programmer
Recently, a netizen of People's Daily Online ...
Talking about foods that cannot be eaten on an em...
Doctor, doctor, oh no! I saw online that Every 10...
What is a fecal microbiota transplant? Fecal micr...
In Fuhai County in Altay Prefecture in northern X...
Recently, French scientists isolated a new type o...
This article is a review of my recent practice. T...
Author: Sun Xiaobiao On March 2, Science Advances...
By 2016, signs of a reshuffle in the domestic mob...
To create a sense of fashion, exquisite small ite...
Have you ever had this experience when you had a ...
"We, BYD, have the pricing power in the 100,...
We once predicted that SSD would replace HDD and ...
In the past few years, I probably contributed nea...