Click here to Skip to main content
Click here to Skip to main content
Go to top

LINQ to ASCII Art

, 2 Jul 2013
Rate this:
Please Sign up or sign in to vote.
Convert image to ASCII art using LINQ technology.

Introduction

I saw many articles explaining how to generate ASCII Art from image, but I didn't see any article that achieves the same stuff in LINQy style. With that, I 'll explain how to use LINQ technology to compose a couple of functions to achieve our goal.

Background

ASCII Art in a nutshell refers to text-based visual art. So we can create cool arts using ASCII codes from simple things such ^_^ Smile | :) to little advance things such as:

For more information, I advice you to check out this link.

As we know, Language Integrated Query (LINQ) is a powerful technology for composing, querying, transformation different data source, all of that inside your code.

I think of ASCII Art as composing and transforming a couple of functions to generate the beauty stuff.

Using the Code

The LINQ to ASCII Art is very straight forward. In this section, I'll explain every function in detail.

Get Pixels

This main purpose of this function is to get the actual pixels for a specified image, so it accepts a bitmap, iterates through all its pixels horizontally and vertically using the width and the height of that image, and uses the GetPixel function to get a pixel with specific coordinates. Then, the return value is the actual pixels as IEnumerable(Of Color) to make it easy to play with those pixels using LINQ later on. Its code looks like this:

Public Function GetPixels(bmp As Bitmap) As IEnumerable(Of Color)
        Return From x In Enumerable.Range(0, bmp.Width - 1)
               From y In Enumerable.Range(0, bmp.Height - 1)
               Select bmp.GetPixel(y, x)
End Function 

Gray Scale Pixels

This main purpose of this function is to convert the actual pixels to gray scale, so it accepts the bunch of pixels, iterates them and applies the following formula:

Gray Scale = 0.3 * Red + 0.59 * Green + 0.11 * Blue 

For more information about gray scale, please check out this link.

Then the return value is the grayed scale pixels as IEnumerable(Of Color) to make it easy to play with those pixels using LINQ later on. Its code looks like this:

Public Function GrayScalePixles_
(pixels As IEnumerable(Of Color)) As IEnumerable(Of Color)
        Return From p In pixels
               Let g = 0.3 * p.R + 0.59 * p.G + 0.11 * p.B
               Select p = Color.FromArgb(g, g, g)
End Function

Get Characters

This main purpose of this function is to get the character corresponding to the value of gray scale pixel. By the way, I want to thank someone whose name I don't rememberSmile | :) for his experiment to get the underneath characters in the code, but you can use any suitable set. So the idea behind that is check the brightness of the grayed color which is value of anyone of the RGB for that pixel. For example, if the value is 230 means the pixel goes to white, if it's less than 50 means the pixel goes to black, so the idea is simple from lightness to darkness. Then return value is the character (ASCIIs) they should print out, they 're IEnumerable(Of Char) to make it easy to play with those characters using LINQ later on. It's code looks like this:

Public Function GetChars_
(pixels As IEnumerable(Of Color)) As IEnumerable(Of Char)
        Return From p In pixels
        Select If(p.R >= 230, " "c, If(p.R >= 200, _
        "."c, If(p.R >= 180, "*"c, If(p.R >= 160, _
        ":"c, If(p.R >= 130, "o"c, If(p.R >= 100, _
        "&"c, If(p.R >= 70, "8"c, _
        If(p.R >= 50, "#"c, "@"c))))))))

End Function

The last thing is composing them using LINQ as follows:

Dim img As Image = Image.FromFile("Hisham.jpg")
Dim bmp As New Bitmap(img, 150, 150)
Dim parts = GetChars(GrayScalePixles(GetPixels(bmp))).Chunk(bmp.Width _
  - 1).Select(Function(part) String.Join("", part))
Dim data = String.Join(vbCrLf, parts)
File.WriteAllText("test.txt", data)

Last I want to show you that we can go further a little bit and compose them all in a single giant LINQ query as follows:

Dim data = String.Join(vbCrLf, (From x In Enumerable.Range(0, bmp.Width - 1)
     From y In Enumerable.Range(0, bmp.Height - 1)
     Let p = bmp.GetPixel(y, x)
     Let g = 0.3 * p.R + 0.59 * p.G + 0.11 * p.B
     Let v = Color.FromArgb(g, g, g)
     Select If(v.R >= 230, " ", If(v.R >= 200, ".", _
       If(v.R >= 180, "*", If(v.R >= 160, ":", _
       If(v.R >= 130, "o", If(v.R >= 100, "&", _
       If(v.R >= 70, "8", If(v.R >= 50, "#", _
       "@"))))))))).Chunk(bmp.Width - 1).Select(Function(part) _
               String.Join("", part)))

Finally, I want to mention that some of you guys said the last query is expensive and takes much time. Of course I agree with you because there is a lot of processing for many many pixels, anyway we can improve the performance using AsParallel() method, also we can use new async modifier to eliminate the thread blocking.

Points of Interest

Amazingly, we have seen how we can generate ASCII art in LINQy style, which is something beautiful Smile | :) and open mind for many further things such image processing. We saw how we GrayScale an image with simple LINQ query, and we can do more than that, inverting, flipping, ... etc.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Hisham Abdullah Bin Ateya
Web Developer
Yemen Yemen
I'm interest with VB.NET and other Microsoft technologies such as LINQ, WPF, WCF, WF and much more


.:: Wish to become better and better ::.

Comments and Discussions

 
GeneralMy vote of 5 PinmemberMohamed Bin Othman27-Jul-13 14:10 
GeneralMy vote of 5 PinmemberNabil Mosali27-Jul-13 3:37 
GeneralMy vote of 5 PinprofessionalMihai MOGA13-Jul-13 20:50 
GeneralMy vote of 5 PinprofessionalRenju Vinod9-Jul-13 21:20 
GeneralMy vote of 5 Pinprofessionalthanh_bkhn4-Jul-13 23:01 
GeneralMy vote of 4 Pinmembersthotakura1-Jul-13 21:40 
GeneralMy vote of 5 PinmemberIbrahim Hebish1-Jul-13 21:37 
QuestionGetChar PinmemberJames Curran1-Jul-13 5:45 
AnswerRe: GetChar PinmemberHisham Abdullah Bin Ateya1-Jul-13 23:55 
QuestionGreat..! PinmemberArchimedes241-Jul-13 4:09 
GeneralMy vote of 5 PinprofessionalCarlos19071-Jul-13 0:45 
GeneralMy vote of 5 Pinmemberamity200130-Jun-13 20:27 
GeneralMy vote of 5 PinprofessionalPrasad Khandekar30-Jun-13 19:53 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140922.1 | Last Updated 2 Jul 2013
Article Copyright 2013 by Hisham Abdullah Bin Ateya
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid