Home > Article > Backend Development > How do you convert a bitmap image to ASCII art in C ?
Image to ASCII art conversion in C
Converting a bitmap image to ASCII art involves using mono-spaced fonts and keeping the process simple. There are two main approaches:
Pixel/area intensity based:
This approach treats each pixel or area of pixels as a single dot. It computes the average gray scale intensity of the dot and replaces it with a character of closest intensity.
Character fitting (hybrid):
This approach tries to replace areas (character shaped) with characters of similar intensity and shape. It leads to better results but is slower due to computations.
Detailed Implementation:
Pixel/area intensity based:
Divide the image into gray-scale pixels or rectangular areas (dots). Compute the intensity of each dot. Replace it with a character from a character map (precomputed intensities) with the closest intensity.
A sample character map: " .,:;ox%#@&"
Intensity computation:
<code class="C++">i = p[x+x+x+0]; i += p[x+x+x+1]; i += p[x+x+x+2]; i = (i*l)/768; s += m[l-i];</code>
where:
Character fitting:
Divide the image into rectangular areas with the same aspect ratio as the characters. Divide the character area into zones and compute the intensity of each zone. Find the character in the map with the closest intensity and shape fit.
This approach leads to best, most visually pleasing results when using larger fonts.
Code Example:
<code class="C++">class intensity { public: char c; // Character int il, ir, iu ,id, ic; // Intensity of part: left,right,up,down,center intensity() { c=0; reset(); } void reset() { il=0; ir=0; iu=0; id=0; ic=0; } void compute(DWORD **p,int xs,int ys,int xx,int yy) // p source image, (xs,ys) area size, (xx,yy) area position { int x0 = xs>>2, y0 = ys>>2; int x1 = xs-x0, y1 = ys-y0; int x, y, i; reset(); for (y=0; y<ys; y++) for (x=0; x<xs; x++) { i = (p[yy+y][xx+x] & 255); if (x<=x0) il+=i; if (x>=x1) ir+=i; if (y<=x0) iu+=i; if (y>=x1) id+=i; if ((x>=x0) && (x<=x1) && (y>=y0) && (y<=y1)) ic+=i; } // Normalize i = xs*ys; il = (il << 8)/i; ir = (ir << 8)/i; iu = (iu << 8)/i; id = (id << 8)/i; ic = (ic << 8)/i; } }; AnsiString bmp2txt_big(Graphics::TBitmap *bmp,TFont *font) // Character sized areas { int i, i0, d, d0; int xs, ys, xf, yf, x, xx, y, yy; DWORD **p = NULL,**q = NULL; // Bitmap direct pixel access Graphics::TBitmap *tmp; // Temporary bitmap for single character AnsiString txt = ""; // Output ASCII art text AnsiString eol = "\r\n"; // End of line sequence intensity map[97]; // Character map intensity gfx; // Input image size xs = bmp->Width; ys = bmp->Height; // Output font size xf = font->Size; if (xf<0) xf =- xf; yf = font->Height; if (yf<0) yf =- yf; for (;;) // Loop to simplify the dynamic allocation error handling { // Allocate and initialise buffers tmp = new Graphics::TBitmap; if (tmp==NULL) break; // Allow 32 bit pixel access as DWORD/int pointer tmp->HandleType = bmDIB; bmp->HandleType = bmDIB; tmp->PixelFormat = pf32bit; bmp->PixelFormat = pf32bit; // Copy target font properties to tmp tmp->Canvas->Font->Assign(font); tmp->SetSize(xf, yf); tmp->Canvas->Font ->Color = clBlack; tmp->Canvas->Pen ->Color = clWhite; tmp->Canvas->Brush->Color = clWhite; xf = tmp->Width; yf = tmp->Height; // Direct pixel access to bitmaps p = new DWORD*[ys]; if (p == NULL) break; for (y=0; y<ys; y++) p[y] = (DWORD*)bmp->ScanLine[y]; q = new DWORD*[yf]; if (q == NULL) break; for (y=0; y<yf; y++) q[y] = (DWORD*)tmp->ScanLine[y]; // Create character map for (x=0, d=32; d<128; d++, x++) { map[x].c = char(DWORD(d)); // Clear tmp tmp->Canvas->FillRect(TRect(0, 0, xf, yf)); // Render tested character to tmp tmp->Canvas->TextOutA(0, 0, map[x].c); // Compute intensity map[x].compute(q, xf, yf, 0, 0); } map[x].c = 0; // Loop through the image by zoomed character size step xf -= xf/3; // Characters are usually overlapping by 1/3 xs -= xs % xf; ys -= ys % yf; for (y=0; y<ys; y+=yf, txt += eol) for (x=0; x<xs; x+=xf) { // Compute intensity gfx.compute(p, xf, yf, x, y); // Find the closest match in map[] i0 = 0; d0 = -1; for (i=0; map[i].c; i++) { d = abs(map[i].il-gfx.il) + abs(map[i].ir-gfx.ir) + abs(map[i].iu-gfx.iu) + abs(map[i].id-gfx.id) + abs(map[i].ic-gfx.ic); if ((d0<0)||(d0>d)) { d0=d; i0=i; } } // Add fitted character to output txt += map[i0].c; } break; } // Free buffers if (tmp) delete tmp; if (p ) delete[] p; return txt; }</code>
The above is the detailed content of How do you convert a bitmap image to ASCII art in C ?. For more information, please follow other related articles on the PHP Chinese website!