Читаем *.bmp напрямую в ТабДок двоичными данными

12.04.17

Интеграция - Файловый обмен (TXT, XML, DBF), FTP

После полученного интереса к публикации http://infostart.ru/public/601635/ о одном из способов формирования изображений в 1С я решил продолжить изучать другие возможности "рисования" в 1С. Естественно, самым простым форматом после svg будет старый добрый растр в bmp. Но когда приступил к написанию - понял, что формировать картинку с "0", наверное, будет нечестно по отношению к читателю, и для начала нужно разобрать, что такое bmp как формат, как его читать и, главное, показать примеры работы с новыми механизмами платформы.

Скачать файл

ВНИМАНИЕ: Файлы из Базы знаний - это исходный код разработки. Это примеры решения задач, шаблоны, заготовки, "строительные материалы" для учетной системы. Файлы ориентированы на специалистов 1С, которые могут разобраться в коде и оптимизировать программу для запуска в базе данных. Гарантии работоспособности нет. Возврата нет. Технической поддержки нет.

Наименование По подписке [?] Купить один файл
Обработка чтения bmp в ТабДок
.epf 9,02Kb
12
12 Скачать (1 SM) Купить за 1 850 руб.

Обработка, прикрепленная к статье, опять написана в стол и не имеет практического применения, но имея ее, конфигуратор и клавишу F10, думаю, понять, как там все устроено в bmp, гораздо легче. Потому помимо выкладок кода прикреплю и ее, хотя слепить такую же, скопировав код ниже - не составит проблем.

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

Неинтересный поворот картинки:

Картинка = Новый Картинка("C:\My Documents\My Pictures\home.bmp");
ОбработчикКартинок = Новый ОбработкаКартинок;

Картинка_90 = ОбработчикКартинок.Повернуть(Картинка, 90);

Вопросы преобразования в 1С тоже более или менее решены:

Картинка.Преобразовать(ФорматКартинки.PNG);

В общем, решено было хотя бы просто считать картинку как набор двоичных данных и вывести ее на некую канву. Канвой послужил ТабДок :)) размер ячеек которого необходимо "зажать" до приемлемого размера пикселя и задать цвет фона ячейки, соответсвующий битмапу. 

Описание формата bmp подробно расписано на вики: https://ru.wikipedia.org/wiki/BMP мы будем читать, полагая, что на вход нам подали файл версии №3. Декодер на все возможные версии занял бы много кода, да и не имеет практического смысла. Исходя из описания формата получилась следующая процедура чтения:

&НаКлиенте
Функция ДекодироватьИВывести(ПутьКФайлу)
		
	ПотокИсходный          = ФайловыеПотоки.ОткрытьДляЧтения(ПутьКФайлу);
	ЧтениеДанных           = Новый ЧтениеДанных(ПотокИсходный);
	//читаем 14 байт соответствующих структуре описания файла
	Буфер_BITMAPFILEHEADER		   = ЧтениеДанных.ПрочитатьВБуферДвоичныхДанных(14);
	//для bitmap допустима сигнатура 424D или 4D42
	Сигнатура 			   = Буфер_BITMAPFILEHEADER.ПрочитатьЦелое16(0);
	
	Если Сигнатура <> 19778 И Сигнатура <> 16973 Тогда
		Возврат "Выбранный файл не является файлом формата bitmap";
	КонецЕсли;
	
	РазмерФайлБайт = Буфер_BITMAPFILEHEADER.ПрочитатьЦелое32(2);
	ПоложениеМассиваПикселей = Буфер_BITMAPFILEHEADER.ПрочитатьЦелое32(10);
	
	//т.к. читаем не все сразу (в образовательных целях)следующей итерацией просто считаем 
	//один байт, это будет адрес 0E. в нем содержится информация 
	//о размере следующей структуры - BITMAPINFO
	
	Длина_BITMAPINFO = ЧтениеДанных.ПрочитатьЦелое32();
	
	//пока мы работаем только с 3й версией файла, 
	//для него длина структуры BITMAPINFO заявлена
	//длинной в 40 байт
	Если Длина_BITMAPINFO <> 40 Тогда
		Возврат "Выбранный файл является файлом bitmap неподходящей версии. Для чтения доступна только вер. 3.";
	КонецЕсли;
	
	//читаем BITMAPINFO
	//вычитаем из длины структуры 4 байта т.к. выше мы их уже считали 
	//для определения длины
	Буфер_BITMAPINFO = ЧтениеДанных.ПрочитатьВБуферДвоичныхДанных(Длина_BITMAPINFO - 4);
	
	//расшифровка структуры 3й версии
	//12	04	4	biWidth Ширина растра в пикселях. Указывается целым числом со знаком. Ноль и отрицательные не документированы.
	//16	08	4	biHeight Целое число со знаком, содержащее два параметра: высота растра в пикселях (абсолютное значение числа) и порядок следования строк в двумерных массивах (знак числа). Нулевое значение не документировано.
	//1A	0C	2	biPlanes В BMP допустимо только значение 1. Это поле используется в значках и курсорах Windows.
	//1C	0E	2	biBitCount Количество бит на пиксель (список поддерживаемых смотрите в отдельном разделе ниже).
	//1E	10	4	biCompression Указывает на способ хранения пикселей (см. в разделе ниже).
	//22	14	4	biSizeImage Размер пиксельных данных в байтах. Может быть обнулено если хранение осуществляется двумерным массивом.
	//26	18	4	biXPelsPerMeter Количество пикселей на метр по горизонтали и вертикали (см. раздел «Разрешение изображения» данной статьи).
	//2A	1C	4	biYPelsPerMeter
	//2E	20	4	biClrUsed Размер таблицы цветов в ячейках.
	//32	24	4	biClrImportant Количество ячеек от начала таблицы цветов до последней используемой (включая её саму).
	
	//мы ведь ЧтениеДанных продолжили считывать в новый буфер
	//адресация теперь в пределах этого буфера (или другими словами - в пределах структуры BITMAPINFO)
	ШиринаРастра = Буфер_BITMAPINFO.ПрочитатьЦелое32(0);
	ВысотаРастра = Буфер_BITMAPINFO.ПрочитатьЦелое32(4);
	Уровень = Буфер_BITMAPINFO.ПрочитатьЦелое16(8);
	БитНаПиксель = Буфер_BITMAPINFO.ПрочитатьЦелое16(10);
	Компрессия = Буфер_BITMAPINFO.ПрочитатьЦелое32(12);
	БайтПикселей = Буфер_BITMAPINFO.ПрочитатьЦелое32(16);
	ПикселейНаМетрГоризонт = Буфер_BITMAPINFO.ПрочитатьЦелое32(20);
	ПикселейНаМетрВертикаль = Буфер_BITMAPINFO.ПрочитатьЦелое32(24);
	РазмерТаблицыЦветов = Буфер_BITMAPINFO.ПрочитатьЦелое32(28);
	ЯчеекТаблицыЦветов = Буфер_BITMAPINFO.ПрочитатьЦелое32(32);
		
	//выведем подробное описание считанного
	стрПредставление = "Размер файла: %1 байт
	|Сигнатура: %2
	|Положение массива пикселей: %3
	|Длина структуры BITMAPINFO: %4 байт
	|Ширина растра: %5 px
	|Высота растра: %6 px
	|Уровень: %7
	|Бит на пиксель: %8 px
	|Компрессия: %9
	|Размер пикселей: %A байт
	|Пикселей на метр по горизонтали: %B px
	|Пикселей на метр по вертикали: %C  px
	|Размер таблицы цветов: %D байт
	|Ячеек в таблице цветов: %F ";
	
	ОписаниеФайла = ПодставитьПараметрыВСтроку(стрПредставление, РазмерФайлБайт, Сигнатура, ПоложениеМассиваПикселей,
											   Длина_BITMAPINFO, ШиринаРастра, ВысотаРастра, Уровень, БитНаПиксель,
											   Компрессия, БайтПикселей, ПикселейНаМетрГоризонт, ПикселейНаМетрВертикаль,
											   РазмерТаблицыЦветов, ЯчеекТаблицыЦветов);
											   
	//между структурами файла и массивом самих пикселей может быть 
	//не задействованный промежуток
	//высчитаем его исходя из длины структур
	ЧтениеДанных.Пропустить(ПоложениеМассиваПикселей - (14 + Длина_BITMAPINFO));
	//теперь читаем поток до конца
	БуферПикселей = ЧтениеДанных.ПрочитатьВБуферДвоичныхДанных();
	ВывестиПотокНаКанвуТабДок(БуферПикселей, ШиринаРастра, ВысотаРастра, БитНаПиксель);
		
	ЧтениеДанных.Закрыть();
		
КонецФункции

Процедуру вывода результата в ТабДок тоже приведу... Дело в том, что в bmp при количестве пикселей по горизонтали, не кратному 4 байтам, строка пикселей дополняется нулями. При выводе это надо учитывать, иначе изображение съедет по диагонали:

вот она:

&НаКлиенте
Функция ВывестиПотокНаКанвуТабДок(БуферПикселей, ШиринаКанвы, ВысотаКанвы, БитНаПиксель)
		
	//рассчитаем длину строки в байт, т.к. для bmp
	//строки не кратные четрым байтам заполняются
	//не используемыми значениями - их нужно отсечь
	
	ДействительныхБайт = ШиринаКанвы * 3;
	
	ДлинаСтрокиБайт = Цел((ШиринаКанвы * 3) / 4)  * 4;
	ДлинаСтрокиБайт = ?(ДлинаСтрокиБайт < ДействительныхБайт, ДлинаСтрокиБайт + 4, ДлинаСтрокиБайт);
	БайтНаДополнениеСтроки = ДлинаСтрокиБайт - (ШиринаКанвы * 3);
	
	КурсорПикселя = -1;                     
	КоординатаПикселя_R = ВысотаКанвы;
	Пока КоординатаПикселя_R > 0 Цикл
			
		Для КоординатаПикселя_C = 1 По ШиринаКанвы Цикл
									
			ИмяПикселя = "R" + Формат(КоординатаПикселя_R, "ЧН=; ЧГ=") + "C" + Формат(КоординатаПикселя_C, "ЧН=; ЧГ=");
			Пиксель = Канва.Область(ИмяПикселя);
			Пиксель.ШиринаКолонки = 0.3;
			Пиксель.ВысотаСтроки = 1;
			
			КурсорПикселя = КурсорПикселя +1;
			ЦветB = БуферПикселей[КурсорПикселя];
			
			КурсорПикселя = КурсорПикселя +1;
			ЦветG = БуферПикселей[КурсорПикселя];
			
			КурсорПикселя = КурсорПикселя +1;
			ЦветR = БуферПикселей[КурсорПикселя];
			
			Пиксель.ЦветФона = Новый Цвет(ЦветR, ЦветG, ЦветB);		
			
			//смещаем курсор на размер пустых байт
			Если КоординатаПикселя_C % ШиринаКанвы = 0 Тогда
				КурсорПикселя = КурсорПикселя + БайтНаДополнениеСтроки;
			КонецЕсли;

		КонецЦикла;
		
		КоординатаПикселя_R = КоординатаПикселя_R - 1;
		
	КонецЦикла;

КонецФункции

В следующий раз нарисуем битмап, думаю, это опять будет картинка штрихкод EAN-13. Но когда дойдут руки до новой поделки - пока не знаю(

PS. Не давайте обработке большие файлы либо файлы с большим количеством цветов в палитре. Все-таки табличный документ не есть канва, и он плотно подвисает в попытках отрисовать сколько-нибудь серьезную картинку... 200х200 максимум и желательно минимум цветов при этом)) 

PSS. Тестовые картинки с лого Infostart - изображения Infostart - на всякий случай)

См. также

SALE! 10%

Перенос данных 1C Файловый обмен (TXT, XML, DBF), FTP Системный администратор Программист Платформа 1С v8.3 1С:Розница 2 1С:Управление нашей фирмой 1.6 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х 1С:Управление нашей фирмой 3.0 1С:Розница 3.0 Россия Платные (руб)

Правила в универсальном формате обмена для ERP 2.5, КА 2.5, УТ 11.5, БП 3.0, Розница, УНФ, для последних версий конфигураций. Ссылки на другие конфигурации в описании публикации. Правила совместимы со всеми другими версиями конфигураций новыми и старыми, поддерживающими обмен и синхронизацию в формате EnterpriseData. Не требуется синхронного обновления правил после обновления другой конфигурации, участвующей в обмене. Типовой обмен через планы обмена кнопкой Синхронизация вручную или автоматически по расписанию, или вручную обработкой.

27660 руб.

12.06.2017    143921    830    297    

431

SALE! 10%

Перенос данных 1C Файловый обмен (TXT, XML, DBF), FTP Системный администратор Программист Платформа 1С v8.3 Оперативный учет 1С:Управление торговлей 10 Россия Управленческий учет Платные (руб)

Перенос данных из 1С:Управление торговлей 10.3 в 1С:Управление торговлей 11.5 с помощью правил обмена. Переносятся остатки, документы (обороты за период), справочная информация. Правила проверены на конфигурациях УТ 10.3 (10.3.88.x) и УТ 11.5 (11.5.20.x), также подходят для релиза 11.5 (11.5.19.x).

35000 31500 руб.

23.07.2020    54166    239    73    

194

SALE! 10%

Перенос данных 1C Файловый обмен (TXT, XML, DBF), FTP Программист Платформа 1С v8.3 1С:ERP Управление предприятием 2 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х Россия Платные (руб)

Перенос данных из ERP в БП 3 | из КА 2 в БП 3 | из УТ 11 в БП 3 | из ЕРП в БП 3 | Сэкономьте время - используйте готовое решение для перехода! | Перенос разработан в формате КД 2 (правила конвертации данных) | Переносятся все возможные виды документов, начальных остатков и нормативно-справочная информация| Можно опционально выгружать каждую пару "номенклатура+характеристика" как отдельную номенклатуру | Есть выгрузка настроек счетов учета и зарплатных данных из ERP / КА 2 | Можно проверить на вашем сервере перед покупкой

55778 50200 руб.

15.04.2019    73121    190    152    

127

SALE! 10%

Перенос данных 1C Файловый обмен (TXT, XML, DBF), FTP Программист Платформа 1С v8.3 1С:ERP Управление предприятием 2 1С:Комплексная автоматизация 2.х 1С:Зарплата и Управление Персоналом 3.x Россия Бухгалтерский учет Управленческий учет Платные (руб)

Перенос данных из ERP в ЗУП 3 | из КА 2 в ЗУП | Готовые правила конвертации данных (КД 2) для переноса остатков, документов с движениями и справочной информации 3 | Есть перенос начальной задолженности по зарплате и начальной штатной расстановки на выбранную дату | Обороты за прошлые годы (данные для расчета среднего) переносятся свернуто в документ "Перенос данных" | Есть фильтр по организациям | Документы за текущий период переносятся сразу с движениями, поэтому не потребуется делать перерасчеты | Перенос можно проверить перед покупкой, обращайтесь!

53111 47800 руб.

03.12.2020    37586    101    68    

97

SALE! 10%

Перенос данных 1C Файловый обмен (TXT, XML, DBF), FTP Системный администратор Программист Платформа 1С v8.3 1С:Управление производственным предприятием 1С:Бухгалтерия 3.0 Россия Бухгалтерский учет Управленческий учет Платные (руб)

Перенос данных из 1С:Управление производственным предприятием 1.3 в 1С:Бухгалтерия предприятия 3.0 с помощью правил обмена. Переносятся остатки, документы (обороты за период), справочная информация. Правила проверены на конфигурациях УПП 1.3 (1.3.240.x) и БП 3.0 (3.0.169.x). Правила подходят для версии ПРОФ и КОРП.

35000 31500 руб.

15.12.2021    25157    175    51    

133

SALE! 10%

Перенос данных 1C Файловый обмен (TXT, XML, DBF), FTP Системный администратор Программист Платформа 1С v8.3 1С:Комплексная автоматизация 1.х 1С:Управление производственным предприятием 1С:Бухгалтерия 3.0 Россия Бухгалтерский учет Платные (руб)

Перенос данных из 1С:Управление производственным предприятием 1.3 в 1С:Бухгалтерия предприятия 3.0 с помощью правил обмена | Можно выполнить переход с УПП на БП 3 или запускать выгрузку данных за выбранный период времени | Переносятся документы, начальные остатки и вся справочная информация | Есть фильтр по организации и множество других параметров выгрузки | Поддерживается несколько сценариев работы: как первичный полный перенос, так и перенос только новых документов | Перенос данных возможен в "1С: Бухгалтерия 3.0" версии ПРОФ, КОРП или базовую | Переход с "1С: УПП1.3" / "1С:КА 1.1" на "1С:БП3.0" с помощью правил конвертации будет максимально комфортным! | Можно бесплатно проверить перенос на вашем сервере!

48278 43450 руб.

25.02.2015    172336    308    259    

385

SALE! 10%

Перенос данных 1C Файловый обмен (TXT, XML, DBF), FTP Программист Платформа 1С v8.3 1С:Управление производственным предприятием 1С:ERP Управление предприятием 2 Бухгалтерский учет Управленческий учет Платные (руб)

Перенос данных из 1С:Управление производственным предприятием 1.3 в 1С:ERP Управление предприятием 2.5 и 1С:Комплексную автоматизацию 2.5 с помощью правил обмена. Переносятся остатки, документы (обороты за период), справочная информация. Правила проверены на конфигурациях УПП 1.3 (1.3.240.x), ERP 2.5 (2.5.20.x), КА 2.5 (2.5.20.x), также подходят для релиза ERP 2.5 (2.5.19.x), КА 2.5 (2.5.19.x).

35000 31500 руб.

24.06.2020    64323    79    27    

89

SALE! 10%

Перенос данных 1C Взаиморасчеты Оптовая торговля Логистика, склад и ТМЦ Файловый обмен (TXT, XML, DBF), FTP Системный администратор Программист Платформа 1С v8.3 1С:Управление торговлей 10 1С:ERP Управление предприятием 2 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х Россия Управленческий учет Платные (руб)

Можно проверить до покупки, оставьте заявку! Воспользовались более 268 компаний! Перенос данных из УТ 10.3 в УТ 11 | из УТ 10.3 в КА 2 | из УТ 10.3 в ERP. Предлагаем качественное и проверенное временем решение для перехода с УТ 10.3. Можно перенести начальные остатки, нормативно-справочную информацию и все возможные документы. При выгрузке можно установить отбор по периоду, организациям и складам. При выходе новых релизов конфигураций 1C оперативно выпускаем обновление переноса данных.

55778 50200 руб.

24.04.2015    196264    155    244    

284
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. Brawler 459 20.04.17 08:27 Сейчас в теме
1С "любит" нас.
Класс "ОбработкаКартинок" вообще детский... две операции, поворот и обрезка лишнего...
Ни размера изображения не узнать, ни этот самый размер изменить...
Ну и хоть какой нить доступ к аналогу канвы не помешал бы.
Интересно, что их останавливает...
2. premierex 206 20.04.17 09:56 Сейчас в теме
(1) Наверное, не хочет 1С превращать платформу в аналог Photoshop'а )
user774630; +1 Ответить
4. Brawler 459 20.04.17 11:39 Сейчас в теме
(2) да ей до фотошопа рости как до края галактики...
3. v3rter 20.04.17 10:44 Сейчас в теме
Из внешних утилит мне больше всего понравился портированный с линукса консольный ImageMagick https://ru.wikipedia.org/wiki/ImageMagick
правда несколько проблемный из-за совпадения имени основной утилиты convert.exe с одноименной консольной командой windows, то есть или переименовывать или запускать с полным путем
5. Mr.Rm 23.06.17 11:13 Сейчас в теме
Похоже, вот тут опечатка:
|Ячеек в таблице цветов: %F "

Должно быть:
|Ячеек в таблице цветов: %E "
6. Mopo3 334 29.06.17 10:19 Сейчас в теме
Небольшая оптимизация кода. А то на больших размерах тормозит...

Вместо:
Пиксель.ШиринаКолонки = 0.3;
Пиксель.ВысотаСтроки = 1;

которые выполняются в цикле лучше сделать перед циклом:
Канва = Новый ТабличныйДокумент;
всяОбласть = Канва.Область(1,1,ВысотаКанвы,ШиринаКанвы);
всяОбласть.ШиринаКолонки = 0.3;
всяОбласть.ВысотаСтроки = 1;
всяОбласть.АвтоВысотаСтроки = Ложь;

Ускорение процентов на 25.


Также лучше вместо:
ИмяПикселя = "R" + Формат(КоординатаПикселя_R, "ЧН=; ЧГ=") + "C" + Формат(КоординатаПикселя_C, "ЧН=; ЧГ=");
Пиксель = Канва.Область(ИмяПикселя);

сделать:
Пиксель = Канва.Область(КоординатаПикселя_R,КоординатаПикселя_C,КоординатаПикселя_R,КоординатаПикселя_C);

Ускорение еще процентов на 10.



И еще интересное наблюдение, может кому пригодится...
Понадобилось мне вывести объект ГеографическаяСхема в ТабДок. Как раз воспользовался алгоритмом Автора. Но, выявилась проблема. При выполгении ГеографическаяСхема.ПолучитьКартинку() картинка получается с параметром БитНаПиксель = 32. А данный алгоритм корректно отображает картинку только если у нее БитНаПиксель = 24. Соответственно для обработки картинки из ГеоСхемы я применил следующий алгоритм:
_картинкаСхемы = ГеографическаяСхема.ПолучитьКартинку(100,100,ФорматКартинки.BMP);

ОбработкаКартинок = Новый ОбработкаКартинок;
_картинкаСхемы = ОбработкаКартинок.Повернуть(_картинкаСхемы,0); //так нужно чтобы сделать БитНаПиксель 24, а не 32 как получается изначально

_картинкаСхемы = _картинкаСхемы.Преобразовать(ФорматКартинки.BMP);
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("BMP");
_картинкаСхемы.Записать(ИмяВременногоФайла);

В результате получается картинка нужного формата, и она корректно отображается на ТабДок.
7. kot-stas 103 04.08.17 16:52 Сейчас в теме
(6) Давненько не заглядывал сюда. По поводу оптимизации спасибо конечно) согласен, так правильнее и быстрее. В свое оправдание хочу сказать, что обработка писалась исключительно! в образовательных целях и код скорее написан для читаемости неподготовленным человеком, нежели с целью реального использования.
А тот факт, что код получил реальное применение (хоть и с доработками) - это вдвойне приятно ;)

На счет глубины цвета - давно было, не помню наверняка, но по моему достаточно было просто переписать процедуру вывода. Сигнатуры, адреса ключевых структур и их длина для 3й версии вне зависимости от глубины цвета по моему не меняются. Но подробнее конечно по ссылке на Вики, там все достаточно подробно).
8. starik-2005 3098 04.08.17 23:14 Сейчас в теме
Как-то делал на assembler'e в детстве вьювер PCX-картинок - 250 с чем-то байт занимало (это была полноценная COM-утилита, запускаемая из командной строки и выводившая файл на экран, переключаясь в VESA-режим 800х600х24). На 1С-е подобные велосипеды бессмысленны от слова "совсем". Вот если бы Вы JPEG или PNG прочитали - это было бы интересно, ибо в них какая-никакая математика есть. Даже в PCX она есть, а в BMP нет ничего - это тупой битмап (карта битов).
9. kot-stas 103 06.08.17 18:00 Сейчас в теме
(8) А зачем здесь эта информация? Или мы здесь *уями меряемся кто в детстве круче поделки делал? Статья в образовательных целях написана, вполне достаточна для представления о том, что представляет из себя работа с буфером двоичных данных и том как устроен bmp (хоть и не сложно, согласен)... Или когда только ленивый не выложил новую счет фактуру сюда - это нормально, а когда пусть и на не сложных примерах, пусть без особой практической пользы пишутся обзорные статьи про тот или иной функционал платформы - это не гут и лучше рефлексировать на свои столь же бесполезные поделки из детства?
10. starik-2005 3098 06.08.17 20:38 Сейчас в теме
(9) у меня все равно длиннее, если мериться. А если о функционале, то я и говорю, что примитивные примеры, конечно, не плохи сами по себе, но с PNG и JPEG было бы куда интереснее.
11. kot-stas 103 07.08.17 12:17 Сейчас в теме
(10) Ну вот и напишите, а то с длинной набитой на котах в отчетах трудно меряться)))
Оставьте свое сообщение