Tutorial: Working with large blocks of text

Share on Facebook0Share on Google+0Tweet about this on TwitterShare on LinkedIn0

Some people attempt to create large scrolling blocks of text in Corona only to find that it doesn’t work. The reason for this lies at Corona’s graphics core which is based on OpenGL. This means that almost everything on screen is a graphic… even text.

In native apps, text is just an object on the screen, but in OpenGL, everything must be an image “texture.” Thus, to make text appear on screen, Corona takes the string value that you pass to display.newText() and it tells the operating system’s font engine to generate an image using the font metrics that you provide. Then, a Corona display object (image texture) is returned and rendered on screen.

Why can this be a problem with very large blocks of text? Well in this case, you may encounter the device’s maxTextureSize limit. In OpenGL, the maximum texture size is defined as the greatest pixel limit — horizontal or vertical — that a rendered image can fit in. This includes large blocks of text, as noted, since they are rendered into image textures by Corona. For some older devices, this limit is as small as 1024 pixels in either direction, meaning that if you attempt to display a larger texture on these devices, OpenGL will be unable to render it properly.

Fortunately, most modern devices have a minimum texture size limit of 2048 pixels, and for your convenience, Corona provides this information via the following system.getInfo() call:

Regarding Text

Even with a typical texture size limit of 2048 pixels, when creating large blocks of text via a multi-line display.newText() call, it’s easy to exceed the the limit. This may result in a solid white block where you expect the text to be. So how do you work around this issue? Simple — avoid creating extremely large blocks of text, and instead create smaller blocks (textures) and place them on the screen.

Understanding end-of-line encodings

Back in early computer history, there were two competing standards for defining the character sets used by computers: ASCII and EBCDIC. Similar to how BluRay won the battle against HD-DVD, ASCII ended up winning over EBCDIC. Now, almost everything, including OS X, Windows, Android, and iOS, are ASCII-based.

ASCII includes the 26 capital letters, 26 lowercase letters, numbers, and various symbol characters in a single byte of data. In addition to the visible characters that you know, ASCII includes a series of control characters. In fact, the first 31 characters are control characters. These control characters can be used to control text positioning on the screen and their heritage goes back to old manual typewriters. Some of these include:

  • CTRL-G — bell (character #7)
  • CTRL-H — backspace (character #8)
  • CTRL-I — tab (character #9)
  • CTRL-J — line feed (character #10)
  • CTRL-M — carriage return (character #13)

For those of us old enough to remember manual typewriters, a carriage return would return the typing head to the left side of the page. By itself, this would not advance the paper to the next line, so if you started typing after a carriage return, you’d overwrite the previous line. Thus, a second action called a line feed was needed to advance the paper a line.

Computers tried to mimic this system, however different operating systems approached it slightly differently. Microsoft DOS (and now Windows) opted for a 2-character end of line sequence, mimicking the typewriter. That is, each line ended with a CTRL-M, CTRL-J sequence. Unix, however, being the “minimalist” OS, used a line feed (CTRL-J) to indicate the end of line.

Today, Android, OS X, and iOS are all based on Unix, so the more universal standard is to use a single CTRL-J line feed to mark the end of line. Windows, however, still uses the CTRL-M + CTRL-J combination. To add to the confusion, there are different ways that people reference these strings. For instance:

  • CTRL-M = ^M = \r
  • CTRL-J = ^J = \n

When you see the carrot (^) it means Control (CTRL). When you see a backslash (\) it indicates an escape character, so in this case, \r is return and \n is newline.

Multi-line strings

Because the operating systems for our mobile devices are Unix-based, the escape versions are more commonly used. You may have seen examples of multi-line strings in Corona code such as:

Specifying multiple lines in this manner will be treated as separate visual lines of text in Corona, assuming you define the width parameter in the display.newText() call (this tells Corona to render the text as a multi-line block instead of rendering it as one long line).

Alternatively, you can use Lua’s multi-line text quotes to achieve the same thing:

In this case, you don’t need to specify the newline marker like in the first version.

Breaking up long text

Because it usually doesn’t take much text to create a rendered text image that exceeds 2048 pixels, you can loop over large strings of text and, as mentioned above, break it into smaller blocks which can be rendered properly by OpenGL and remain below the max texture size limit.

When doing so, one option is to split apart long blocks using our natural language concept of paragraphs. In this case, you’ll generally only need to deal with the Unix newline. For this tutorial, let’s use some text generated by http://www.lipsum.com/. These 5 paragraphs of text will be inserted into a widget.newScrollView(), so remember to include the widget library:

Let’s inspect this code in detail:

  • The paragraphs table is meant to hold the different display.newText() objects for each paragraph (the separated blocks). The paragraph and tmpString variables hold, respectively, the current paragraph text and a copy of the string with the current paragraph removed. You’ll be modifying tmpString so leave the original source string alone.
  • Next we construct the scroll view widget. In this case, it occupies the whole screen and it has 8000 pixels of total scrollable height. The variable yOffset is used to position each paragraph, one after the next, with a value of 10 (pixels) to provide a little space before each new paragraph.
  • Using the “new” table-based options format for display.newText(), we define the width of the text block, the font, fontSize, and the text alignment. We begin with text as an empty string, but we’ll fill it in shortly.
  • The main work happens in the repeat until loop. Since we want to perform this process at least once, for multiple paragraphs, a repeat loop makes more sense than a while loop. This loop will run until either tmpString is nil or the length of the tmpString is 0. This is an important check which will be covered in more detail below.
  • Inside the loop, we use string.match() to search the string for a newline characters (\n). This cryptic looking search string basically tells Lua to capture the string in two parts: any number of characters that are not a newline ([^\n*]) up until the first newline that we encounter (\n). Then, the rest of the string is captured into the second variable. These get returned as paragraph and tmpString.
  • With the variable paragraph now holding a single paragraph of text, we change the options table’s .text member to hold the paragraph that we want to generate, then we create the display object using display.newText( options ). By using #paragraphs+1 as the loop index, it will create a new table entry at the end of the paragraphs table. Afterwards, we just reference the last entry in this table by using #paragraphs as the index.
  • Next, we position the text. To keep things simple, we change the anchor point for each text block to the top and left of the display object (0,0), then we position the x coordinate at 10 to provide some left padding. We set the y coordinate to yOffset, which for the first pass is also 10. The scroll view defaults to a white background, so we additionally change the text color to black (or any color of your choice) and, finally, we insert the paragraph into the scroll view.
  • On the following line, we increment yOffset by the height of the previous paragraph created. This will let you position the next block of text immediately below the previous one, providing the illusion that it’s one long block of text with a slight space between each paragraph.


In Lua, strings inside double quotes ("") can exist only on one line of physical code. It can be quite long, but it’s still one physical line so you’ll have to use \n to identify where the lines break. Alternatively, if you use the ([[ ]]) method of declaring a string, your text can be on multiple lines of code with an implied \n at the end of each line. Because of this, there’s a subtle difference in handling how string.match() fills out tmpString on the last iteration through. The double test of “is tmpString == nil or is it out of characters?” handles this condition, so both declaration styles will work.


Hopefully this tutorial has shown you how to construct long text blocks in Corona with just a little extra effort to work around the limits of maxTextureSize.

Share on Facebook0Share on Google+0Tweet about this on TwitterShare on LinkedIn0
Rob Miracle

Rob Miracle creates mobile apps for his own enjoyment and the amusement of others. He serves the Corona Community in the forums, on the blog, and at local events.

This entry has 9 replies

  1. Kerem says:

    Rob, thank you very much for this tutorial. Very timely.

    For some reason the string.match did not work well with my data. I used a slightly less refined way of getting the same result. Sharing below. Not sure why string.match is not working well but this approach is. Will poke around some more to understand this better.

    Also note I’m looking for “\r\n” to avoid one extra line inserted in between my paragraphs. In other words, when I looked for \n to define paragraphs I ended up with extra lines in between my actual paragraphs. Changing from “\n” to “\r\n” helped solve that problem.

    local b, e = string.find(tmpString, “\r\n”)
    if b then
    print(b .. ” ” .. e)
    paragraph = string.sub(tmpString, 1, b-1)
    tmpString = string.sub(tmpString, e+1)
    paragraph = tmpString
    tmpString = “”
    print(yOffset .. ” ” .. paragraph)
    options.text = paragraph
    paragraphs[#paragraphs+1] = display.newText( options )
    paragraphs[#paragraphs].anchorX = 0
    paragraphs[#paragraphs].anchorY = 0
    paragraphs[#paragraphs].x = 10
    paragraphs[#paragraphs].y = yOffset
    paragraphs[#paragraphs]:setFillColor( 0 )
    scrollView:insert( paragraphs[#paragraphs] )
    yOffset = yOffset + paragraphs[#paragraphs].height
    print( #paragraphs, paragraph )

    until tmpString == nil or string.len( tmpString ) == 0

  2. Kerem says:

    Continuing discussion on forum thread to allow better code formatting… See at


  3. In the past I’ve just written a webpage to a temporary file and loaded it in a webview. That provides a neat way of handling large blocks of text, and adds more advanced support for styling. Webviews do flash unappealing grey when loading an image, at least with backgrounds turned of, and handling touch events on them is tricky to say the least (but not impossible using some JavaScript and a URLRequest listener).

  4. Nicholas says:

    Hi Rob!

    When i run my scrollView in my simulator, it shows all the text. I’m able to scroll all the way down to the end of the whole block of text.

    However when i build it on my iPhone, it get cuts off and alignment has gone haywire.

    Is the above the solution?

    • Rob Miracle says:

      Hi Nicolas. We would have to see your code, config.lua, etc. to know what’s going on. This would best be asked and answered in the forums. The comments here are not very good for posting code and doing diagnostics.


  5. Aru_aak says:

    What is the best way to display running text using Corona SDK? I want to display a number that would add to itself based on some calculation. I used the enterframe event to display the text on top and all I see is that there is a white block. If I remove the adding logic and just display a plain text, it works. Can you please help?

    • Rob Miracle says:

      This is a question best asked in the forums. We are going to need to see your code and code doesn’t format well in blog comments. Please ask there.


  6. Bivek says:

    Can we have some text with different color? Like highlighting a certain verb?

    Thank you

    • Rob Miracle says:

      To do this with display.newText() you would have to generate the text up to the word you want to color in you default color, generate the colored text as it’s own object, then draw the rest of the text.