Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Конвертируем картинку в ANSI

Anna | 24.06.2014 | нет комментариев

Не знаю, насколько это будет кому-то увлекательно, но на днях решил поиграться и сделать следующее:Дано: Картинка (скажем, BMP) 640 на 400, шрифт 8 на 16

Нужно: Перевести ее в ANSI псевдографику в стандартном режиме 80 на 25 символов, символы и фон могут иметь всякий цвет (true color).

image


Тут стоит оговориться, что «тру» EGA текстовый режим с 16 цветами нам не подойдет, так как получится слишком уродливо из-за низкого разрешения и большого размера символов. 2-й довод: задача не стоИт максимально приблизить картинку ее символьному представлению, так как тогда дозволено было бы сокращать шрифт, увеличивать разрешение и т.д. Задача — сделать именно такой фильтр, тот, что описан выше.

Для чего я тут это публикую: мне показалось, что начинающим программистам было бы пригодно попрактиковаться в понимании алгорифма, следственно я подметил данный материал, как туториал.

Для реализации нам потребуется какая-нибудь библиотека для работы с графикой, умеющая getpixel и putpixel, то есть считать цвет пикселя с экрана и нарисовать пиксель заданным цветом на экран. Я пользуюсь старенькой, но проверенной библиотекой Allegro (www.allegro.cc), которая легка в обращении, а также разрешает трудиться в различных ОС (даже в MSDOS!).

Но хватит слов, пора к делу.

const int size_x=640;
const int size_y=400;
const int ascii_x=80;
const int ascii_y=25;

Устанавливаем константы, отвечающие за размер картинки и размер ее текстового представления.

for(int cx=0;cx<ascii_x;cx  )
	for(int cy=0;cy<ascii_y;cy  ){
		int fullr=0;
		int fullg=0;
		int fullb=0;
		int pixels=0;

//find background color
		for(int i=0;i<size_x/ascii_x;i  )
		for(int j=0;j<size_y/ascii_y;j  ){
			int col=getpixel(pic,i cx*size_x/ascii_x,j cy*size_y/ascii_y);
			int r=getr(col);
			int g=getg(col);
			int b=getb(col);
			fullr =r;fullg =g;fullb =b;
			pixels  ;
		}
		fullr/=pixels;fullg/=pixels;fullb/=pixels;

Начинаем стержневой цикл, в котором ступенчато находим всякий символ из 80 на 25 матрицы. Дальнейший цикл — по всякому пикселю той области картинки, которая соответствует на экране данному символу из этой матрицы. Как легко сообразить, область эта составляет 640/80=8 на 400/25=16 пикселей. Тут благотворно припомнить, что это как раз равно размеру нашего шрифта.

В этом втором цикле наша задача — обнаружить средний цвет, тот, что мы установим в качестве цвета фона нашего ANSI символа. Сделать это дюже легко: раскладываем цвет на R, G, B компоненты и вычисляем среднее по всякой из них.

//find ascii and its color
		int rms=100000000;

		for(int curch=1;curch<256;curch  ){ //loop over ASCII table
			int charr=0;
			int charg=0;
			int charb=0;

//find char color
			pixels=0; //number of pixels for char
			for(i=0;i<size_x/ascii_x;i  )
			for(int j=0;j<size_y/ascii_y;j  ){
				int col=getpixel(pic,i cx*size_x/ascii_x,j cy*size_y/ascii_y);
				int r=getr(col);
				int g=getg(col);
				int b=getb(col);

				int colch=getpixel(font,i (curch%32)*8,j (curch/32)*16);
				int rc=getr(colch);
				int gc=getg(colch);
				int bc=getb(colch);
				if(rc!=0&&gc!=0&&bc!=0){ //get actual char pixels only
					charr =r;
					charg =g;
					charb =b;
					pixels  ;
				}
			}
			if(pixels!=0){
				charr/=pixels;charg/=pixels;charb/=pixels;
			}

Дальше теснее больше увлекательно. Нам доводится вставить еще один цикл — по всякому символу из ASCII таблицы (каждого их 256). Я беру их из черно-белой картинки с шрифтом, то есть теоретически, там могут быть всякие изображения 8 на 16 в качестве символа. Стоит подметить, что в этом месте дозволено ограничиться только какой-то одной областью символов (скажем, кириллицей), что

В приведенном выше куске кода мы находим цвет символа. Для этого мы считаем сумму как выше, но с небольшим изменением: пиксели берутся по маске, которой является нынешний символ из шрифта. Таким образом, 2-й «средний цвет» соответствует только пикселям, которыми будет нарисован сам символ.

Стоит также подметить, что число таких пикселей может быть равно нулю (скажем, символ 32 — пробел). С этим нужно быть внимательнее.

//find rms
			int currms=0;
			for(i=0;i<size_x/ascii_x;i  )
			for(int j=0;j<size_y/ascii_y;j  ){
				int col=getpixel(pic,i cx*size_x/ascii_x,j cy*size_y/ascii_y);
				int r=getr(col);
				int g=getg(col);
				int b=getb(col);
				int rr=0,gg=0,bb=0;

				int colch=getpixel(font,i (curch%32)*8,j (curch/32)*16);
				int rc=getr(colch);
				int gc=getg(colch);
				int bc=getb(colch);
				if(rc!=0&&gc!=0&&bc!=0){ //char pixel
					rr=charr;
					gg=charg;
					bb=charb;
				}
				else{ //back pixel
					rr=fullr;
					gg=fullg;
					bb=fullb;
				}
				currms =sqrt((r-rr)*(r-rr) (g-gg)*(g-gg) (b-bb)*(b-bb));
			}

			if(currms<rms){ //find minimal rms
				findr=charr;
				findg=charg;
				findb=charb;

				findch=curch;
				rms=currms;
				if(DEBUG)printf("!!!%d %dn",currms, curch);
			}
			else
				if(DEBUG)printf("%d %dn",currms, curch);

		} //find char

Ну и, наконец, пришли к самой соли. В этом куске кода мы еще раз проходимся по пикселям заданной области картинки и считаем RMS (среднеквадратичное отклонение) всех 3 компонент цвета от цвета фона либо символа (в зависимости от того, находится ли данный пиксель на фоне либо на символе). Суммарный RMS и будет являться критерием того, насколько данный символ отлично соответствует данной области картинки.

Дальше следует итог на экран (в 2-х режимах — с фоном и без (пример)), но на нем мы останавливаться не будем, так как там всё самоочевидно.

image

Программу и начальный код дозволено скачать тут: dimouse.ru/data/ansiconv.rar (130 Kb).

Как насчет нарисовать это дело в текстовом режиме? Как вы можете увидеть, программа создает файл с итогами (помимо нового bmp) — ascii. Там для всякого символа хранится его значение в ASCII таблице, его цвет и цвет его фона. Я для текстового режима пользуюсь pdcurses.sourceforge.net/ (пишите в комментариях, если знаете что-то отменнее!), но эта библиотека, хоть и является враппером над SDL (во каждом случае, виндовая версия — верно), не может показывать цвета огромнее 16: тяжелое достояние древности. Как вы, вероятно, помните, PDCurses берет свое предисловие от известной Interactive Fiction игры Curses. Но один товарищ написал усовершенствование этой библиотеки и выложил тут: www.projectpluto.com/win32a.htm

К сожалению, в ней невозможно применять bitmap шрифт, только системные (но дозволено предпочесть всякий), что несколько портит ощущение. Но задачу также дозволено считать исполненной.

Программу для чтения ascii дозволено скачать тут: dimouse.ru/data/ascii.rar (70 Kb).

 

Источник: programmingmaster.ru

 

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB