Saida gerada pelo conversorUm topico um pouco esquecido, mas ainda interessante, e a criacao de ASCII art a partir de imagens e fotos.Na epoca em que os consoles de texto eram a mais comum, se nao a unica opcao de interface disponivel para os usuarios de computador, as pessoas se valiam de muita criatividade (e um bocado de trabalho) para criar imagens usando somente os caracteres disponiveis na tabela ASCII. Muita coisa boa foi e ainda e criada com essa ideia, incluindo jogos e animacoes.Depois de assistir a este video, decidi implementar um pequeno conversor ASCII em pascal. O resultado da empreitada pode ser visto na imagem do rei do rock ao lado, que foi criada usando a versao do conversor criada para este artigo.O AlgoritmoPara este conversor vamos usar uma abordagem de conversao pixel a pixel onde cada pixel na imagem vai ser representado por um caractere ASCII. Para tanto, vamos criar uma "paleta" ou uma tabela de equivalencia para cada tom RGB presente na imagem de origem. Alem disto, para manter as coisas simples, vamos gerar somente representacoes em tons de cinza.Assim temos:Converter a imagem de origem para tons de cinza (0..255)Criar uma tabela de equivalencia de cor RGB -> ASCIIRepresentar cada pixel com o caractere de tom mais proximoSimples e rapido. Vamos ao codigo!Convertendo Imagens para Tons de CinzaEsta e a parte mais facil.Para converter um pixel colorido para um tom de cinza, basta calcular a media dos canais RGB:c = (r + g + b) / 3Assumindo que nossa imagem utiliza 32bit por pixel, vamos armazenar o tom calculado no quarto byte, que normalmente e utilizado para guardar o canal alpha. Assim temos:procedure TForm1.ConvertSourceImage;var x, y : integer; pColor : PRGBQuad;begin FreeAndNil(fGrayAlphaImage); fGrayAlphaImage := TBitmap.Create; fGrayAlphaImage.PixelFormat := pf32bit; fGrayAlphaImage.Width := imgOrigem.Picture.Width; fGrayAlphaImage.Height := imgOrigem.Picture.Height; fGrayAlphaImage.Canvas.Draw(0,0, imgOrigem.Picture.Graphic); for y := 0 to fGrayAlphaImage.Height-1 do begin pColor := fGrayAlphaImage.ScanLine[y]; for x:=0 to fGrayAlphaImage.Width-1 do begin pColor^.rgbReserved := ( pColor^.rgbRed + pColor^.rgbGreen + pColor^.rgbBlue) div 3; inc(pColor); end; end;end;Tons de cinza calculados, vamos ao proximo passo, nossos tons (ou shades) ASCII.Equivalencias de intensidade de luzTabela de shadesDe um lado, temos um pixel em um tom de cinza que representa a quantidade de luz existente naquele ponto da imagem (0 = 0% de luz, 255= 100% de luz) do outro, temos um caractere ASCII.Para criar uma equivalencia entre os dois, vamos tratar o caractere como uma imagem em preto e branco e calcular o percentual de pixels pretos em relacao a quantidade de pixels da imagem. Depois de fazer isto para todos os caracteres escolhidos, teremos uma tabela de equivalencia que pode ser visualmente representada pela imagem ao lado.O codigo para esta funcao ficou assim:procedure TForm1.InitShades;var bmp : TBitmap; i, x, y, pixelCount : integer; k: Double; p : PRGBQuad; rct : TRect;begin FillChar(fIntensityByAnsiChar, length(fIntensityByAnsiChar), $FF); FillChar(fAnsiCharByIntensity, length(fAnsiCharByIntensity), AnsiChar(' ')); bmp := TBitmap.Create; bmp.Canvas.Font.Size := 10; bmp.Canvas.Font.Color := clBlack; bmp.Canvas.Font.Name := cbxFont.Text; bmp.PixelFormat := pf32bit; charW := bmp.Canvas.TextWidth('A'); charH := bmp.Canvas.TextHeight('A'); bmp.Height := charH; bmp.Width := charW; pixelCount := charW * charH; bmp.Canvas.Brush.Color := clWhite; for i := 0 to high(fIntensityByAnsiChar) do