LINUX.ORG.RU

[C] сделать надпись на рисунке

 


0

0

Как при помощи С выполнить такую непростую операцию? Можно, конечно, самому сделать простенькие растровые шрифты и, поочередно вычисляя координаты каждой буквы, изменять значения яркости нужных пикселей картинки. Но должен же быть более простой способ? Как, например, это делается в ImageMagic? В исходниках ковыряюсь, но уж очень там много всего...

☆☆☆☆☆

Ответ на: комментарий от Sylvia

в libgd кажется были функции

Спасибо, сейчас посмотрю.

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от lester

cairo...

Что-то я не нашел, как при помощи этих функций добавить текст к хранящемуся в буфере памяти изображению.

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Eddy_Em

> Что-то я не нашел, как при помощи этих функций добавить текст к хранящемуся в буфере памяти изображению.

cairo_image_surface_create_for_data

lester ★★★★
()

Я бы воспользовался Cairo и GdkPixbuf:

1) с помощью GdkPixbuf грузите картинку

2) создаете по данным картинки cairo surface

3) с помощью cairo рисуете текст на созданном surface; если нужна хитрая отрисовка текста, то стоит использовать Pango

4) с помощью GdkPixbuf сохраняете

dmitry_vk ★★★
()
Ответ на: комментарий от Sylvia

Спасибо!

Работает! И, главное, требует совсем немного кода:

...
char *s = "Hello.";
gdImageString(im, gdFontGetLarge(),
	im->sx / 2 - (strlen(s) * gdFontGetLarge()->w / 2),
	im->sy / 2 - gdFontGetLarge()->h / 2,
	s, white);
...
(использовал этотмануал).

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от lester

и дает худший результат ;)

Для вывода на видео сообщения «нет сигнала» красивые шрифты не нужны :)

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Eddy_Em

проще тогда сохранить этот текст в виде монохромной картинки( можно прямо в текст программы запихнуть как массив ) и наложить ее на исходную, делается это двумя циклами и не требует сторонних библиотек

lester ★★★★
()
Ответ на: комментарий от lester

Не хочется руками рисовать текст, да и возможно, придется еще кое-какие информационные сообщения (например, критические ошибки) на экран выводить, т.к. изменение текста в div'е сообщений менее заметно.

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Eddy_Em

Не хочется руками рисовать текст

Gimp - он еще и в .c сможет сохранить

да и возможно, придется еще кое-какие информационные сообщения (например, критические ошибки) на экран выводить

тогда сразу надо брать на заметку, что gdImageString пригоден только для английской локали, а еще можно просто выдрать эту функцию + «шрифты», т.к. она из себя представляет те же два цикла:

  for (py = y; (py < (y + f->h)); py++)
    {
      for (px = x; (px < (x + f->w)); px++)
	{
	  if (f->data[fline + cy * f->w + cx])
	    {
	      gdImageSetPixel (im, px, py, color);
	    }
	  cx++;
	}
      cx = 0;
      cy++;
    }

и тащить из-за нее libgd+libpng+zlib+libjpeg+libfreetype и т.д. нет смысла

lester ★★★★
()
Ответ на: комментарий от Legioner

> freetype-ом можно.

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

lester ★★★★
()
Ответ на: комментарий от lester

В принципе, конечно, оно и так, но не хочется ковыряться в куче кода и писать еще лишние несколько сот строк. А так у меня получается вот что:

#include <gd.h>
#include <gdfontl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
	gdImagePtr im;
	FILE *jpegout;
	int red, green, brect[8], x, y, ctr, levels[256];
	double sz = 40.;
	char *fc = "monotype";
	char *err, *f = "Some words";
	gdFTUseFontConfig(1);
	jpegout = fopen("test.jpg", "w");
	im = gdImageCreateTrueColor(800, 600);
	for(x=0; x<256; x++)
		levels[x] = gdImageColorResolve(im, x, x, x);
	red = gdImageColorResolve(im, 255, 0, 0);
	green = gdImageColorResolve(im, 0, 255, 0);
	for(ctr = 1; ctr < 1000; ctr++){
	for(x=0; x<800; x++)
		for(y=0; y<600; y++)
			im->tpixels[y][x] = levels[rand()%256];
	gdImageLine(im, 0, 0, 63, 63, red);

/*
   0	lower left corner, X position
   1	lower left corner, Y position
   2	lower right corner, X position
   3	lower right corner, Y position
   4	upper right corner, X position
   5	upper right corner, Y position
   6	upper left corner, X position
   7	upper left corner, Y position

*/
	err = gdImageStringFT(NULL,brect,0,fc,sz,0.,0,0,f);
	if (err) {fprintf(stderr,err); return 1;}
	x = brect[2]-brect[6] + 6;
	y = brect[3]-brect[7] + 6;
	if(x > 400 || y > 50){
		double max = (x/400. > y/500.) ? (x/400.) : (y/50.);
		sz /= max;
	}
	x = 200;
	y = 500;
	gdImageStringFT(im,brect,green,fc,sz,0.0,x,y,f);
	}
	gdImageJpeg(im, jpegout, 50);
	fclose(jpegout);
	gdImageDestroy(im);
}
gcc 22.c -lgd && time ./a.out 
Command exited with non-zero status 240
18.34user 0.01system 0:18.48elapsed 99%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (0major+1199minor)pagefaults 0swaps
Для копирования из восьмибитного рисунка придется заполнять цветовые карты. Но т.к. выдача видео производится с небольшой скоростью (максимум 5 кадров в секунду), думаю, тормозов от использования libgd не будет (сейчас одна картинка обрабатывается около 19мс).

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Eddy_Em

> думаю, тормозов от использования libgd не будет

на личном опыте libgd таки очень тормознутая( в сравнении с аналогами ес-но ), но в вашем случае часто создавать изображения не надо( к тому же можно один раз создать и запомнить ) - так что это не проблема

lester ★★★★
()
Ответ на: комментарий от lester

gdImageString пригоден только для английской локали

Кстати, да - КОИ8 и в gdImageStringFT не работает. Так что надо будет либо заранее заполнить массивы сообщений в дурацком юникоде, либо писать на английском.

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Eddy_Em

> Кстати, да - КОИ8 и в gdImageStringFT не работает. Так что надо будет либо заранее заполнить массивы сообщений в дурацком юникоде

да - там UTF8 вроде надо, но на самом деле UTF8(16/32) это хорошо и правильно, а у gdImageStringFT есть другие косяки - вроде левых кернингов( т.к. написан вывод текста через одно место )

lester ★★★★
()
Ответ на: комментарий от lester

в вашем случае часто создавать изображения не надо( к тому же можно один раз создать и запомнить )

Можно, конечно, заранее создать нужные сообщения в виде gdImage, а потом копировать информацию из них поверх моих изображений. Но не думаю, что это ускорит процесс: копировать картинку из mmap-буфера v4l2 в локальный буфер все равно придется (иначе есть шанс получить мусор, или испортить изображение основной программе-обработчику); сжимать итоговое изображение в jpeg тоже необходимо, чтобы отправить в mjpeg-потоке. Прикидку размеров шрифта можно выкинуть, т.к. размер кадра фиксирован - надо только подобрать оптимальный кегль шрифта.

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от lester

у gdImageStringFT есть другие косяки - вроде левых кернингов( т.к. написан вывод текста через одно место ) Тестовое сообщение писалось нормально. А разница в скорости между gdImageStringFT и gdImageString - всего две миллисекунды в пользу второго.

Eddy_Em ☆☆☆☆☆
() автор топика
Ответ на: комментарий от Eddy_Em

> Тестовое сообщение писалось нормально.

оно не на всех шрифтах лажает, точнее левый пиксель туда/сюда - бывает почти всегда, а на некоторых шрифтах доходит до того, что расстояния становятся совсем левыми

А разница в скорости между gdImageStringFT и gdImageString - всего две миллисекунды в пользу второго.


а если слов будет в 1000 раз больше( это не к вашему примеру, а вообще ) - получится по сути огромная задержка как для обычного вывода текста

lester ★★★★
()
Ответ на: комментарий от lester

а если слов будет в 1000 раз больше( это не к вашему примеру, а вообще ) - получится по сути огромная задержка как для обычного вывода текста

Да у меня и так интерфейс перегружен: раз в секунду отправляется xmlhttprequest для вывода сообщений о текущем состоянии оборудования; при активации пользователем какой-нибудь кнопочки или т.п. посылается запрос на изменение выбранного параметра; в это время на сервере непрерывно крутится управляющий CGI, получающий видео с фреймграббера и обрабатывающий его, а также нить этого CGI, контролирующая приводы по RS-232. При запросе клиентом видео запускается еще одна копия этого CGI, которая из mmap-нутой памяти выдирает картинки, рисует на них значки/текст и отправляет клиенту.

Ну а текст поверх видео я хочу писать хотя бы в случае пропадания видеосигнала, чтобы информировать, что обработка не производится.

Eddy_Em ☆☆☆☆☆
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.