Формирование печатных форм в pdf
Интеграция - Файловый обмен (TXT, XML, DBF), FTP
Возникла задача (и, как показал поиск, не у меня одного) формирования печатных форм в формате pdf для отправки клиентам. Причем процесс этот должен был происходить практически полностью автоматически - в один-два клика. То, что я нашел на эту тему в сети меня не устроило по тем или иным причинам, поэтому пришлось писать свое. Первое с чем я столкнулся - это достаточно скудное количество информации на эту тему, очень мало примеров. Несколько дней разбирался сам, теперь решил поделиться опытом с вами. Америку, я конечно не открыл, но пару интересных решений в процессе написания родилось - возможно кому-то пригодится и сэкономит время.
Публикацию я решил оформить в виде статьи, поскольку написанная мной обработка имеет несколько прикладной характер и заточена под конкретную конфигурацию. Так что поделюсь с вами кодом, и постараюсь прокомментировать его максимально подробно.
Итак, сначала немного предыстории. Изучив вопрос, я остановил свой выбор на бесплатных виртуальных принтерах BullZip PDF Printer и PDFCreator, которые позволяют на выходе получать файлы pdf, а также файлы различных графических форматов. Обе утилиты имеют возможность автосохранения файлов без лишних вопросов пользователю. В принципе, для полуавтоматического создания печатных форм в электронном виде, этого достаточно. Мы можем написать в коде
ТабДок.ИмяПринтера = "PDFCreator"; //"BullZip PDF Printer";
ТабДок.Напечатать();
и в каталогах, указанных в настройках автосохранения, появятся нужные файлы. Но, во-первых, пользователь может что-нибудь в настройках изменить, во-вторых, принтер вообще может оказаться переименован или удален чьими-нибудь шаловливыми ручонками (то есть нам нужно как-то контролировать имя и вообще наличие виртуального принтера в системе), в-третьих, придется настроить автосохранение для каждого пользователя (если принтер не сетевой), в-четвертых, проблематично добиться вменяемого имени файла с помощью настроек. Да и вообще, мы же все хотим делать автоматически, а так пользователю придется самому создать письмо, указать адрес клиента, прикрепить нужные вложения - вероятность ошибки возрастает, ну и лениво конечно. Приходим к выводу, что нужно юзать COM-объект, самому устанавливать необходимые настройки и выполнять нужные действия, чтобы не взрывать потом мозг ни себе, ни пользователю.
Изначально имелось пожелание сохранять файлы в графическом формате, скажем jpeg или png. PDFCreator, по-моему мнению, обладает более гибкими возможностями, но, к сожалению, он не умеет разбивать изображения на страницы, поэтому при сохранении печатных форм в виде картинок, можно наблюдать только первую страницу документа. BullZip же такую функцию имеет, поэтому я начал работать с ним. Но вот его COM-интерфейс оказался довольно скудным, да и плюс ко всему, настройки свои утилита хранит в ini-файле. Соответственно тратится время на их чтение и запись, если мы хотим (а мы хотим!) в них что-то менять. Вобщем, чтобы не извращаться и не придумывать всякую ерунду, было принято решение сохранять печатные формы в pdf и использовать для этих целей PDFCreator. Полностью конечно "ерунды" избежать не удалось, но в целом задача была решена.
Собственно дальше код моей функции для формирования файлов с подробными комментариями в проблемных местах. Функция выдрана из модуля обработки с минимальными изменениями, поэтому имеет "узкие" места в виде привязки к конфигурации и конкретному виду документов. Но общий смысл понятен и при необходимости код легко может быть преобразован для конкретной задачи.
upd 14.04.2011
Сегодня понадобилось переписать обработку, сделав ее более универсальной. Теперь в главную функцию передается массив готовых табличных документов для конвертации в pdf. Для передачи имен файлов используется свойство табличного документа "ИспользуемоеИмяФайла", которое необходимо заполнить программно до вызова функции конвертации.
upd 03.05.2011
Выявил неявный баг. У табличного документа есть свойство "ИмяПараметровПечати". Оно отвечает за сохранение параметров печати, установленных пользователем, и их восстановление при следующем показе табличного документа. Так вот, если это свойство используется в конфигурации (а в типовых оно, как правило, используется), то при печати в pdf в указанных параметрах будет сохранен наш виртуальный pdf-принтер, и, если в следующий раз табличный документ будет печататься обычным способом, то 1С восстановит именно этот принтер для печати по-умолчанию (не путать с принтером по-умолчанию в Windows). Чтобы этого избежать, после формирования наших файлов, вернем табличному документу его старое имя принтера.
// Функция формирует файлы для отправки по электронной почте с помощью виртуального принтера PDFCreator,
// Возвращаемое значение: тип "Массив" - массив сформированных файлов pdf
// Параметры: ТабличныеДокументы - тип "Массив", массив табличных документов для конвертации
// Путь - тип "Строка", путь к каталогу, в котором будут создаваться конечные файлы pdf
//
Функция PDFCreator_СформироватьФайлыДляОтправки(ТабличныеДокументы, Путь) Экспорт
// Тут все ясно: пробуем создать COM-объект, получилось - хорошо, нет - на нет, как говорится, и суда нет
Попытка
УтилитаПечати = Новый COMОбъект("PDFCreator.clsPDFCreator");
Исключение
Сообщить("Не установлен драйвер принтера PDFCreator!", СтатусСообщения.Важное);
Возврат Неопределено;
КонецПопытки;
Состояние("Настройка виртуального принтера ...");
// Получим виртуальные принтеры, установленные в системе, если нет ни одного - создадим новый, если есть - будем использовать первый попавшийся
ПринтерыPDF = УтилитаПечати.cGetPDFCreatorPrinters();
Если ПринтерыPDF.Count() = 0 Тогда
УтилитаПечати.cAddPDFCreatorPrinter("PDFCreator");
ПринтерыPDF = УтилитаПечати.cGetPDFCreatorPrinters();
КонецЕсли;
ИмяПринтераPDF = ПринтерыPDF.Item(1);
// Запустим утилиту, в области уведомлений появится соответствующий значок очереди печати
УтилитаПечати.cStart();
// PDFCreator позволяет создавать несколько профилей с настройками - это очень удобно: мы не будем менять настройки по умолчанию, а создадим отдельный профиль для печати из 1С и будем его использовать. То есть для "ручной" печати пользователь может настроить принтер как ему вздумается.
// Проверим, существует ли профиль для печати документов из 1С, если нет - создадим
Если Не УтилитаПечати.cProfileExists("Печать 1С") Тогда
УтилитаПечати.cAddProfile("Печать 1С", УтилитаПечати.cStandardOptions);
КонецЕсли;
// Поскольку теоретически пользователь может изменить настройки и нашего профиля, а некоторые из них для нас критичны, будем записывать их принудительно каждый раз. Это настройки автосохранения, остальные - пусть меняет, если надо.
// Запишем настройки профиля, которые не должны меняться
НастройкиПоУмолчанию = УтилитаПечати.cReadOptions("Печать 1С");
НастройкиПоУмолчанию.UseAutosave = 1;
НастройкиПоУмолчанию.UseAutosaveDirectory = 1;
НастройкиПоУмолчанию.UseCreationDateNow = 1;
НастройкиПоУмолчанию.AutosaveDirectory = Путь;
// Подробно на каждой опции останавливаться не буду, думаю и так понятно. Поясню только принципиальный момент, на котором строится дальнейшая логика работы функции.
// Я долго пытался добиться более менее вменяемого и при этом уникального имени файла стандартными настройками - это оказалось довольно проблематично. В итоге я пришел к такой схеме: в качестве имени файла автосохранения используем предопределенную настройку Title - заголовок нашего документа. Поскольку табличный документ мы создаем программно, средствами 1С изменить его не удастся (есть лишь возможность задать его при выводе на экран, указав в качестве первого параметра метода Показать()). Соответственно, используя такую настройку, мы всегда будем получать файл вида "Табличный документ.pdf". Что ж, значит, придется переименовать его после. Если бы мы печатали один файл, можно было задать его имя сразу в настройках, но мы-то хотим печатать много и сразу, а в этом случае опции просто не будут успевать сохраняться. Короче говоря, экспериментальным путем я пришел именно к такому варианту.
НастройкиПоУмолчанию.AutosaveFileName = "Title"; // Здесь Title должно быть в угловых скобках, но редактор HTML воспринимает это как тег и сбивает разметку
НастройкиПоУмолчанию.AutosaveFormat = 0; // 0 = PDF, 1 = PNG, 2 = JPEG, 3 = BMP, 4 = PCX, 5 = TIFF, 6 = PS, 7 = EPS, 8 = TXT, 9 = PDF/A-1b, 10 = PDF/X, 11 = PSD, 12 = PCL, 13 = RAW
НастройкиПоУмолчанию.AutosaveStartStandardProgram = 0;
УтилитаПечати.cSaveOptions(НастройкиПоУмолчанию, "Печать 1С");
Состояние("Создание файлов ...");
// Делаем наши настройки текущими. Возможно как-то можно сделать активным конкретный профиль программно, но мне это не удалось, а так - заработало и ладно. По сути здесь мы подменяем настройки по умолчанию своими.
УтилитаПечати.cOptionsProfile = "Печать 1С"; // эта строка, по-моему, не работает, но так "красивше" =)
УтилитаПечати.cOptions = НастройкиПоУмолчанию;
// Собственно, начинаем штамповать наши файлы
МассивФайлов = Новый Массив;
Для Индекс = 0 По ТабличныеДокументы.Количество() - 1 Цикл
// Получаем табличный документ по индексу из массива. Цикл Для ... По ... используем для того, чтобы иметь возможность сразу получать индекс элемента из счетчика без применения метода Найти().
ТабДок = ТабличныеДокументы[Индекс];
// Запоминаем старое имя принтера, т.к. при использовании параметров печати, они будут сохраняться с нашим pdf-принтером
СтароеИмяПринтера = ТабДок.ИмяПринтера;
// Далее уже знакомый нам кусок кода. Все настройки сделаны - можем смело печатать.
ТабДок.ИмяПринтера = ИмяПринтераPDF;
ТабДок.Напечатать();
// Здесь одна особенность, которую я победил не очень хорошим способом. Помните, что у нас все файлы называются "Табличный документ.pdf"? Это нас не устраивает - надо переименовать, но поскольку принтер работает не мгновенно, необходимо сначала дождаться, пока файл сформируется и запишется на диск. Так что запускаем цикл и ждем пока файл появится. Да, грузится проц, но что поделать - это ненадолго.
// На случай, если что-то пойдет не так, ставим ограничение в 30 секунд, по истечении которых цикл прерываем принудительно
ФайлСформирован = Истина;
ФайлPDF = Новый Файл(Путь + "Табличный документ.pdf");
Порог = ТекущаяДата() + 30;
Пока Не ФайлPDF.Существует() И ФайлСформирован Цикл
ОбработкаПрерыванияПользователя();
Если ТекущаяДата() >= Порог Тогда
ФайлСформирован = Ложь;
КонецЕсли;
КонецЦикла;
// Наш файл уже существует, но еще не записан - ждем еще, но не более 30 секунд
Порог = ТекущаяДата() + 30;
Пока ФайлPDF.Размер() = 0 И ФайлСформирован Цикл
ОбработкаПрерыванияПользователя();
Если ТекущаяДата() >= Порог Тогда
ФайлСформирован = Ложь;
КонецЕсли;
КонецЦикла;
// Произошла исключительная ситуация - файл не был создан в течение длительного времени
Если Не ФайлСформирован Тогда
Сообщить("Ожидание отклика завершено. Файл не создан!", СтатусСообщения.Важное);
Попытка
УтилитаПечати.cClose();
Исключение
Сообщить("Нормальное завершение процесса печати невозможно!", СтатусСообщения.ОченьВажное);
КонецПопытки;
УтилитаПечати = Неопределено;
НастройкиПоУмолчанию = Неопределено;
Состояние();
Возврат Неопределено;
КонецЕсли;
// Вот теперь переименуем его. Используем свойство табличного документа "ИспользуемоеИмяФайла" (должно быть заполнено программно до вызова процедуры, предполагается, что имя файла указано без расширения), либо, если оно не заполнено, просто порядковый номер элемента.
НовоеПолноеИмя = Путь + ?(ЗначениеЗаполнено(ТабДок.ИспользуемоеИмяФайла), ТабДок.ИспользуемоеИмяФайла, "Табличный документ " + Строка(Индекс + 1)) + ".pdf";
ПереместитьФайл(ФайлPDF.ПолноеИмя, НовоеПолноеИмя) ;
// Добавим в массив вложений, который вернет в итоге наша функция
ФайлPDF = Новый Файл(НовоеПолноеИмя);
МассивФайлов.Добавить(ФайлPDF);
// Возвращаем старое имя принтера, чтобы не менялись параметры печати по-умолчанию
ТабДок.ИмяПринтера = СтароеИмяПринтера;
КонецЦикла;
// Закрываем утилиту - иконка в трее пропала. Что примечательно, закрывать раньше времени очередь печати нельзя, а то пропадут все задания, но так как мы с нетерпением ждем появления каждого файла и в этот момент уже дождались, то тут все ок.
УтилитаПечати.cClose();
УтилитаПечати = Неопределено;
НастройкиПоУмолчанию = Неопределено;
Состояние();
Возврат МассивФайлов;
Конецфункции
Ну а дальше уже дело техники, что с этими файлами делать... Я, например, использую встроенный в УТ почтовый клиент, создаю новое письмо, заполняю адрес из контактной информации контрагента, добавляю туда вложения и открываю письмо пользователю для просмотра и принятия решения об отправке, а pdf-ки с диска удаляю.
Естественно, мой код не претендует на истину в последней инстанции - может где и коряво получилось, но вобщем-то он работает и свою задачу выполняет. Более элегантного решения я во всяком случае не нашел. Принимаю конструктивную критику и предложения
upd 08.10.2010
Создал аналогичную функцию с использованием внешней компоненты Yoksel. Код проще и прозрачнее, файлы формируются намного быстрее, нет заморочек с искусственными задержками времени, но печатная форма добавляется в документ картинкой, причем не очень хорошего качества, плюс требуется создание временного файла на диске для последующей конвертации.
// Функция формирует файлы для отправки по электронной почте с помощью внешней компоненты Yoksel.dll
//
Функция Йоксель_СформироватьФайлыДляОтправки(ТабличныеДокументы, Путь)
Попытка
ЗагрузитьВнешнююКомпоненту(КаталогПрограммы() + "Yoksel.dll");
Йоксель = ПолучитьCOMОбъект("","Йоксель");
КонвертерPDF = Йоксель.СоздатьГрафическийКонвертерPDF();
Исключение
Предупреждение("Не удалось загрузить внешнюю компоненту Yoksel! Сообщите администратору системы!", 20);
Возврат Неопределено;
КонецПопытки;
МассивФайлов = Новый Массив;
Состояние("Создание файлов ...");
Для Индекс = 0 По ТабличныеДокументы.Количество() - 1 Цикл
// Получаем табличный документ
ТабДок = ТабличныеДокументы[Индекс];
// Формируем временный файл xls
ИмяФайлаБезРасширения = ?(ЗначениеЗаполнено(ТабДок.ИспользуемоеИмяФайла), ТабДок.ИспользуемоеИмяФайла, "Табличный документ " + Строка(Индекс + 1));
ТабДок.Записать(Путь + ИмяФайлаБезРасширения + ".xls", ТипФайлаТабличногоДокумента.XLS97);
// Конвертируем временный файл в формат pdf
Попытка
Таб = Йоксель.СоздатьТабличныйДокумент();
Таб.Открыть(Путь + ИмяФайлаБезРасширения + ".xls", "2");
КонвертерPDF.Документ = Таб;
КонвертерPDF.КоличествоБитНаПиксел = 24; //1, 4, 8, 24
КонвертерPDF.ПолеСлева = 1134; // в твипах (1 твип = 1/567 см)
КонвертерPDF.ЗаписатьВФайл(Путь + ИмяФайлаБезРасширения + ".pdf");
Исключение
УдалитьФайлы(Путь + ИмяФайлаБезРасширения + ".xls");
Сообщить(ОписаниеОшибки(), СтатусСообщения.Важное);
Возврат Неопределено;
КонецПопытки;
// Удаляем временный файл xls
УдалитьФайлы(Путь + ИмяФайлаБезРасширения + ".xls");
// Добавляем в массив вложений
ФайлPDF = Новый Файл(Путь + ИмяФайлаБезРасширения + ".pdf");
МассивФайлов.Добавить(ФайлPDF);
КонецЦикла;
Йоксель = Неопределено;
Состояние();
Возврат МассивФайлов;
КонецФункции
Вступайте в нашу телеграмм-группу Инфостарт
Вы можете заказать платную адаптацию этой статьи под ваши задачи на «Бирже заказов».
- 0% комиссии — оплата напрямую исполнителю;
- Исполнители любого масштаба — от отдельных специалистов до команд под проект;
- Прямой обмен контактами между заказчиком и исполнителем;
- Безопасная сделка — при необходимости;
- Рейтинги, кейсы и прозрачная система откликов.
См. также
Перенос данных 1C Файловый обмен (TXT, XML, DBF), FTP Системный администратор Разработчик 1С:Предприятие 8 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" с помощью правил конвертации будет максимально комфортным! | Можно бесплатно проверить перенос на вашем сервере!
50050 руб.
25.02.2015 192556 383 296
SALE! 10%
Перенос данных 1C Файловый обмен (TXT, XML, DBF), FTP Системный администратор Разработчик 1С:Предприятие 8 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. Не требуется синхронного обновления правил после обновления другой конфигурации, участвующей в обмене. Типовой обмен через планы обмена кнопкой Синхронизация вручную или автоматически по расписанию, или вручную обработкой.
27633 руб.
12.06.2017 165043 1009 329
Перенос данных 1C Взаиморасчеты Оптовая торговля Логистика, склад и ТМЦ Файловый обмен (TXT, XML, DBF), FTP Системный администратор Разработчик 1С:Предприятие 8 1С:Управление торговлей 10 1С:ERP Управление предприятием 2 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х Россия Управленческий учет Платные (руб)
Можно проверить до покупки, оставьте заявку! Воспользовались более 268 компаний! Перенос данных из УТ 10.3 в УТ 11 | из УТ 10.3 в КА 2 | из УТ 10.3 в ERP. Решение для перехода с УТ 10.3. Можно перенести начальные остатки, нормативно-справочную информацию и все возможные документы. При выгрузке можно установить отбор по периоду, организациям и складам.
50200 руб.
24.04.2015 211464 186 254
SALE! 10%
Перенос данных 1C Файловый обмен (TXT, XML, DBF), FTP Разработчик 1С:Предприятие 8 1С:Управление производственным предприятием 1С:ERP Управление предприятием 2 Бухгалтерский учет Управленческий учет Платные (руб)
Переносите справочную информацию, остатки и документы из УПП 1.3 в ERP 2.6 и КА 2.6 с помощью готовых правил. Переносится более 60 видов документов. Простой интерфейс и понятные настройки.
42000
37800 руб.
24.06.2020 73175 108 35
Операции по ВЭД Файловый обмен (TXT, XML, DBF), FTP Разработчик Бухгалтер 1С:Предприятие 8 1С:ERP Управление предприятием 2 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 Россия Бухгалтерский учет Платные (руб)
Федеральная таможенная служба России давно поддерживает унифицированный формат электронных документов для обмена с информационными системами предприятий. xmlns="urn:customs.ru:Information:ExchangeDocuments:". Структура, утвержденная комиссией Таможенного союза. Осталось только сделать загрузку в 1С из этого формата. На выходе - два документа ГТД по импорту и Поступление (акты, накладные) Обработка актуализирована на начало 2026 года (ставка НДС 22%)
24400 руб.
09.08.2016 97853 381 379
SALE! 10%
Перенос данных 1C Файловый обмен (TXT, XML, DBF), FTP Системный администратор Разработчик 1С:Предприятие 8 1С:Управление производственным предприятием 1С:Бухгалтерия 3.0 Россия Бухгалтерский учет Управленческий учет Платные (руб)
Переносите справочную информацию, остатки и документы из УПП 1.3 в Бухгалтерию 3.0 с помощью готовых правил. Переносится более 50 видов документов. Простой интерфейс и понятные настройки.
42000
37800 руб.
15.12.2021 37135 268 68
Перенос данных 1C Файловый обмен (TXT, XML, DBF), FTP Системный администратор Разработчик 1С:Предприятие 8 1С:Комплексная автоматизация 1.х 1С:Управление торговлей 10 1С:Управление производственным предприятием Россия Платные (руб)
Регулярный обмен, выгрузка, перенос из КА 1.1, УПП 1.3, УТ 10.3 для обмена с любыми конфигурациями, поддерживающими обмен в формате EnterpriseData (КД3) - БП 3.0, ERP, КА 2, УТ 11, Розница 3, УНФ 3 и другими. Правила для старых и доработанных конфигураций не требуют синхронного обновления и совместимы с новыми и будущими конфигурациями. Обмен по расписанию, через папку, FTP, почту.
27572 руб.
18.02.2016 209280 686 559
Перенос данных 1C Файловый обмен (TXT, XML, DBF), FTP Разработчик 1С:Предприятие 8 1С:Комплексная автоматизация 1.х 1С:Управление производственным предприятием 1С:Зарплата и Управление Персоналом 3.x Россия Бухгалтерский учет Платные (руб)
Правила переноса кадровых и расчетных данных и справочной информации из "1С:УПП1.3" или "1С:КА 1.1" в "1С:ЗУП 3.1 | Разработан в формате КД 2 (правила конвертации данных) | При выгрузке есть фильтр по организациям | Обновляется при выходе новых релизов 1С | Развитие алгоритмов | Расчетные документы переносятся в документ "Перенос данных" | Создаются документы "Начальная штатная расстановка" и "Начальная задолженность по зарплате", переносятся кадровые документы
58000 руб.
29.10.2018 64482 86 137
ФайлPDF = Новый Файл(Путь + "Title.pdf");
НовоеПолноеИмя = Путь + ?(ЗначениеЗаполнено(ТабличныйДокумент.ИспользуемоеИмяФайла), ТабличныйДокумент.ИспользуемоеИмяФайла, "Табличный документ " + Строка(1)) + ".pdf";
ФайлСформирован = Ложь;
Порог = ТекущаяДата() + 30;
Пока ТекущаяДата()<Порог цикл
ОбработкаПрерыванияПользователя();
Попытка
ПереместитьФайл(ФайлPDF.ПолноеИмя, НовоеПолноеИмя);
ФайлСформирован = Истина;
Break;
Исключение
Продолжить;
КонецПопытки;
КонецЦикла;
Если Не ФайлСформирован Тогда
Сообщить("Ожидание отклика завершено. Файл не создан!",СтатусСообщения.Важное);
Попытка
УтилитаПечати.cClose();
Исключение
Сообщить("Нормальное завершение процесса печати невозможно!", СтатусСообщения.ОченьВажное);
КонецПопытки;
УтилитаПечати = Неопределено;
НастройкиПоУмолчанию = Неопределено;
Состояние();
Возврат ложь;
КонецЕсли;
ПоказатьПопытка
ПринтерПДФ = Новый COMОбъект("PDFCreator.clsPDFCreator");
Исключение
Сообщить("Не установлен драйвер принтера PDFCreator!", СтатусСообщения.Важное);
Возврат Неопределено;
КонецПопытки;
ПринтерыPDF = ПринтерПДФ.cGetPDFCreatorPrinters();
Если ПринтерыPDF.Count() = 0 Тогда
ПринтерПДФ.cAddPDFCreatorPrinter("PDFCreator");
ПринтерыPDF = ПринтерПДФ.cGetPDFCreatorPrinters();
КонецЕсли;
ИмяПринтераPDF = ПринтерыPDF.Item(1);
ПринтерПДФ.cStart("/NoProcessingAtStartup");
ПринтерПДФ.cClearcache();
ПринтерПДФ.cPrinterStop = 1;
НаборОпций = ПринтерПДФ.cOptions();
НаборОпций.NoConfirmMessageSwitchingDefaultprinter = 1;
НаборОпций.UseAutosave = 1;
НаборОпций.UseAutosaveDirectory = 1;
НаборОпций.AutosaveFormat = 0; // PDF
НаборОпций.AutosaveDirectory = Путь;
НаборОпций.AutosaveFilename = "111.PDF";
НаборОпций.AutosaveStartStandardProgram = 0;
ПринтерПДФ.cOptions = НаборОпций;
Для Индекс = 0 По ТабличныеДокументы.Количество() - 1 Цикл
ТабДок = ТабличныеДокументы[Индекс];
ТабДок.ИмяПринтера = ИмяПринтераPDF;
ТабДок.Напечатать();
КонецЦикла;;
ПринтерПДФ.cCombineAll();
ПринтерПДФ.cPrinterStop = 0;
Счетчик = 0;
Пока ПринтерПДФ.cCountOfPrintjobs > 1 Цикл
Счетчик = Счетчик + 1;
ПринтерПДФ.cCombineAll();
Старт = ТекущаяДата();
Пока ТекущаяДата() <> Старт + 1 Цикл
КонецЦикла;
КонецЦикла;
Старт = ТекущаяДата();
Таймаут = 5;
Пока НЕ ЗначениеЗаполнено(ПринтерПДФ.cOutputFileName) ИЛИ (ТекущаяДата() - Старт < Таймаут) Цикл
КонецЦикла;
ПринтерПДФ.cClearcache();
ПринтерПДФ.cClose();
ПринтерПДФ = Неопределено;
Возврат Истина;
ПоказатьКак один из аналогов для решения подобной задачи:
начиная с 2007 версии МС офиса - есть бесплатное дополнение "Save as PDF & XPS" - в теории им можно порулить через Ole.
Естественно нужен сам офис, и нужно будет печатные формы пересохранять в xls или doc...
Но по большому счёту выбор инструмента определяется личными предпочтениями разработчика. Автору плюс за качественное описание.
А вообще согласен полностью: вариантов решения задачи - масса, и в каждом конкретном случае, разработчик сам выбирает приемлемый. Но в любом случае, думаю, неплохо иметь пару альтернативных про запас... ;)
А если кому-то чего-то не хватает в PDFCreator - добро пожаловать в его команду разработки!
License: GNU General Public License (GPL)
Кстати может кому пригодится - черновой вариант функции для печати через Universal Document Converter, прога платная правда(потому наверное буду юзать pdfcreator)
Функция PDFСформироватьФайлыДляОтправки(Ссылка, Печатнаяформа, ИмяФайла) Экспорт
Попытка
УтилитаПечати = Новый COMОбъект("UDC.APIWrapper");
Исключение
Сообщить("Не установлен драйвер принтера", СтатусСообщения.Важное);
//Сюда можно вставить код установки проги - которая в макете
//УникальныйИдентификатор = Новый УникальныйИдентификатор();
//ИмяВременногоФайла = КаталогВременныхФайлов() + УникальныйИдентификатор + ".exe";
//Макет = ПолучитьОбщийМакет("Макет");
//Макет.Записать(ИмяВременногоФайла);
//Сообщить(ИмяВременногоФайла);
//WshShell = Новый COMОбъект("WScript.Shell");
////WSHShell.Run(ИмяВременногоФайла,5);
//Выполнение=WshShell.exec(ИмяВременногоФайла);
//Пока Выполнение.Status=0 Цикл
// Сообщить("Идет настройка");
//КонецЦикла;
//Предупреждение("Кончили!");
//УдалитьФайлы(ИмяВременногоФайла);
Возврат Неопределено;
КонецПопытки;
Состояние("Настройка виртуального принтера ...");
УтилитаПечати.Activate();
УтилитаПечати.ActivationMode = 1;
// Получим виртуальные принтеры, установленные в системе, если нет ни одного - создадим новый, если есть - будем использовать первый попавшийся
itfPrinter = УтилитаПечати.Printers("Universal Document Converter");
itfProfile = itfPrinter.Profile;
УникальныйИдентификатор = Новый УникальныйИдентификатор();
ИмяВременногоФайла = КаталогВременныхФайлов() + УникальныйИдентификатор + ".xml";
Макет = ПолучитьОбщийМакет("ПрофильВиртуальногоПринтера");
Макет.Записать(ИмяВременногоФайла);
itfProfile.Load (ИмяВременногоФайла);
// Для Стр = 0 По (Печатнаяформа.КоличествоСтраниц - 1) Цикл
itfProfile.OutputLocation.FileName =ИмяФайла;
ИмяПринтераPDF =itfPrinter.Name;
ТабДок = Печатнаяформа;
ТабДок.ИмяПринтера = ИмяПринтераPDF;
ТабДок.АвтоМасштаб = Истина;
ТабДок.Напечатать();
УдалитьФайлы(ИмяВременногоФайла);
Возврат ТабДок;
Конецфункции
Вообще очень удобная штука, с названием документов проблем нет, как вариант (еще недоделал можно к названию добавлять номера страниц, к тому же профили печати хранить в макетах и менять если надо)
Можно сделать и процедуру
Код недоделан потому строго не судите, за основу брал эту статью, последние строчки для отладки,
В функцию передаются Ссылка - Ссылка на печатаемый документ, ПечатнаяФорма - ТабличныйДокумент, ИмяФайла - у меня это имя файла складывающееся из названия документа + расширение
PS (26)опечатка - SQL Server 2005
Кто это тебе такое сказал?
Вот тема, где выложен XLS-файл с прозрачной картинкой и PDF, который был из него получен (естественно с прозрачностью):
И вообще, как можно, видеть в теме, Ёпрст (заказчик этого дела) специально интересовался прозрачностью.
О работе из восьмерки и картинках с прозрачностью есть еще обсуждение здесь:
- функция не будет работать, если виртуальный принтер будет удален или переименован;
- все время меняется принтер в системе по-умолчанию;
- имя файла указывается явно в настройках автосохранения (попробуйте использовать этот код при пакетной печати и посмотрите, что будет происходить с файлами);
- непонятен смысл использования конструкции # Если Клиент, так как метод Напечатать() не работает на сервере;
З.Ы. Да, и этой темы, я кстати, не видел: со всеми свойствами и методами классов разбирался самостоятельно. Думаю, что имею право поделиться собственными наработками...
Плюсы: файлы формируются намного быстрее, код проще и нагляднее, не приходится прибегать к искусственным задержкам и прочим хитростям, не требует установки дополнительного приложения.
Минусы: печатная форма добавляется в документ одной картинкой, причем ее качество оставляет желать лучшего, нужен временный файл, сохраненный на диске, для последующей конвертации, мало настроек конвертера PDF.
В итоге добавил в свою обработку как дополнительную возможность, но от первоначального варианта не отказался - будем дальше в процессе использования пробовать оба.
З.Ы. Да... с прозрачностью я не разбирался - мне не надо. Вобщем, только укрепился в своем мнении: каждый способ имеет право на существование, у каждого свои недостатки и свои преимущества.
НастройкиПоУмолчанию. saveFileName = имяфайла;
В профиле имя отразилось, настройки сохранились. Но при печати не подхватывает профиль "печать 1с"
Как заставить принтер использовать выбранный профиль?
УтилитаПечати.cOptions = НастройкиПоУмолчанию;
Свойство saveFileName будет работать только для ручного сохранения: нужно отключить автосохранение и программа будет выводить соответствующий диалог, в котором и будет это имя использоваться.
но вот непорядок, скачал yoksel_comserver_hotfix_2010_06_29.rar c , зарегил
и во время выполнения кода
Попытка
ЗагрузитьВнешнююКомпоненту(КаталогПрограммы() + "Yoksel.dll");
Исключение
Предупреждение("Не удалось загрузить внешнюю компоненту Yoksel! Сообщите администратору системы!", 20);
Возврат Неопределено;
КонецПопытки;
у меня выскакивает ошибка Runtime error:
(ошибка в демо-базе yoksel_demo_config_1cv81.rar)
Может кто подскажет в чем подвох, поиск поюзал - проблем вподе подобных не возникает. Yoksel.dll лежит в каталоге bin.
ЗЫ Как вариант, ты скачал последнюю версию yoksel, совместима ли она с демо-конфой, попробуй на других использовать (напиши свой код, методы и свойства в справке есть) Тем более ты пишешь, что ошибка возникает во время выполнения кода, ну так найди это проблемное место в коде 1С и подумай.
ЗагрузитьВнешнююКомпоненту(КаталогПрограммы() + "Yoksel.dll");
Фишка в том, что если код заменить на следующий
Попытка
ЗагрузитьВнешнююКомпоненту(КаталогПрограммы() + "Yoksel111111111.dll");
Исключение
Предупреждение("Не удалось загрузить внешнюю компоненту Yoksel! Сообщите администратору системы!", 20);
Возврат Неопределено;
КонецПопытки;
тогда ошибки Runtime Error не будет, будет лишь Предупреждение (т.е. нормальная обработка исключительной ситуации)
даже я тебе больше скажу если ты напишешь вместо yoksel.dll зюзя.dll тоже самое будет
А у тебя другие ВК нормально работают?
Заработало! Оказалось, что за место метода
ЗагрузитьВнешнююКомпоненту(КаталогПрограммы() + "Yoksel.dll");
мне нужно использовать
ПодключитьВнешнююКомпоненту("Йоксель")
;)
Вот мой топик на мисте
:)
- Печатную форму из нескольких страниц можно сохранять в виде изображения в формате TIFF. Соответственно, "НастройкиПоУмолчанию.AutosaveFormat = 5;" В этом случае при просмотре стандартной программой просмотра изображений xp появляется внизу кнопочка перехода между страницами.
- Не совсем понятна проблема с получением нужного имени файла. Может это только в 8-ке так? В 7-ке используя "НастройкиПоУмолчанию.AutosaveFileName = "Title"; // Здесь Title должно быть в угловых скобках, но редактор HTML воспринимает это как тег и сбивает разметку" и затем в процедуре печати 1с "ИсхТабл.Показать("Счет_"+СокрЛП(Докум.НомерДок),,-1);" получалось нужное имя файла вида "Счет_[НомерДок].tif"
Если ТабДок.ОриентацияСтраницы = ОриентацияСтраницы.Ландшафт Тогда
//ШиринаСтраницыВТвипах = ТабДок.ВысотаСтраницы * 567/10;
//ВысотаСтраницыВТвипах = ТабДок.ШиринаСтраницы * 567/10;
ШиринаСтраницыВТвипах = 16839;
ВысотаСтраницыВТвипах = 11907;
Иначе
//ШиринаСтраницыВТвипах = ТабДок.ШиринаСтраницы * 567/10;
//ВысотаСтраницыВТвипах = ТабДок.ВысотаСтраницы * 567/10;
ШиринаСтраницыВТвипах = 11907;
ВысотаСтраницыВТвипах = 16839;
КонецЕсли;
Это для формата А4
Я давно использую этот алгоритм и PDF creator для массовых рассылок инфы клиентам
Для дополнительного удобства пользователей изменил немного общую форму "ПечатьДокументов"
Добавил на нее кнопочку PDF которая генерирует PDF файлик согласно алгоритму изложенному в статье а после этого помещает этот PDF файлик в буфер обмена виндовс. Статью про буфер обмена где то тут нашел давным-давно но не помню где именно.
Главное юзеры довольны очень.
На мой взгляд единственным коммерчески приемлемым решением является Yoksel.
Главное его преимущество, что он не требует установки никаких принтеров (скажем на 20 машинах), легко регистрируется и, проверено, работает без проблем.
Для обхода проблемы с высотой страницы я искусственно бью свой большой xls на несколько файлов, все их преобразовываю в pdfы, которые потом объединяю в один файл.
Хотя это конечно нельзя назвать нормальным решением.
Недорогих и тем более бесплатных приемлемых решений для печати в pdf пока, к сожалению, нет.
ПереместитьФайл(ФайлPDF.ПолноеИмя, НовоеПолноеИмя) ;
Как понимаю, 1С не "отпускает" первый файл.
Пришлось заменить на
КопироватьФайл(ФайлPDF.ПолноеИмя, НовоеПолноеИмя) ;
При этом не получается печатать массив файлов.
Ни кто не знает, как обойти проблему?
Автору однозначно, благодарность. Наши менеджеры порадовались.
Вообще хорошо бы посмотреть, что блокирует файл... может с правами какие-то нюансы?
Спасибо за такой пример, но есть одно но! Я совсем не понимаю почему происходит следующее:
1. Все документы, нужные в бумажном виде, печатаем на HP 2727
2. Когда надо в PDF, то запускают мою обработку, включающую ваш способ преобразования в PDF
3. Выбирают необходимые документы
4. Эти документы печатаются в PDF с синей печатью и подписью
5. Отправляются архивом на указанные емейл
6. Затем если снова надо печатать бумажные документы, то печать уходит на PDFCreator
Собственно, правится это путем открытия перед печатью пункта меню: Файл-Параметры Страницы, выставляется нужный принтер и до следующего использования обработки все хорошо, после ее применения опять вместо нужного принтера стоит PDFCreator
Непонятно сие по следующим причинам:
1. Ни кто про это не писал
2. Стоит ведь строка в коде: ТабДок.ИмяПринтера = СтароеИмяПринтера;
3. Если после этой строки добавить: ТабДок.Напечатать(); то старый принтер "запоминается", иначе остается PDFCreator
Буду благодарен, если кто-нибудь подскажет в чем может быть дело.
У меня было так: изначально в моей процедуре старое имя принтера (фактически - пустое) табличному документу не возвращалось, соответственно в базу сохранялись параметры с принтером PDFCreator, который и восстанавливался при последующем использовании этой печатной формы. То есть мне нужно было записать в базу пустое имя принтера для таких форм и добавить в процедуру строку ТабДок.ИмяПринтера = СтароеИмяПринтера; чтобы система продолжала работать в типовом режиме.
Обработка элементарная, написана за 5 минут (красиво и универсально делать не старался):
Процедура СброситьПринтерВПараметрахПечати(ТабДокументы)
Для каждого ТабДок Из ТабДокументы Цикл
ТабДок.ИмяПринтера = "";
КонецЦикла;
КонецПроцедуры
Процедура КнопкаВыполнитьНажатие(Кнопка)
Если Не ЗначениеЗаполнено(Документ) Тогда
Предупреждение("Не выбран документ!", 10, "Ошибка");
Возврат;
КонецЕсли;
Если ТипЗнч(Документ) = Тип("ДокументСсылка.РеализацияТоваровУслуг") Тогда
ДокументОбъект = Документ.ПолучитьОбъект();
СписокМакетов = Новый СписокЗначений();
СписокМакетов.Добавить("НакладнаяБезГТД");
СписокМакетов.Добавить(Справочники.ДополнительныеПечатныеФормы.НайтиПоНаименованию("Счет по накладной"));
МассивТабДокументов = Новый Массив;
Для каждого Элемент Из СписокМакетов Цикл
ТабДок = ДокументОбъект.ПолучитьПечатнуюФормуДокумента(Элемент.Значение);
Если ТипЗнч(ТабДок) = Тип("ТабличныйДокумент") Тогда
МассивТабДокументов.Добавить(ТабДок);
КонецЕсли;
КонецЦикла;
СброситьПринтерВПараметрахПечати(МассивТабДокументов);
Сообщить("Принтер в параметрах печати очищен.", СтатусСообщения.Информация);
Иначе
Предупреждение("Для выбранного типа документов сброс принтера в параметрах печати не предусмотрен.", 10);
КонецЕсли;
КонецПроцедуры
ПоказатьКак видно из кода, мне нужно было сбросить принтер только для 2-х печатных форм документа Реализация товаров и услуг.
ВАЖНО! Так как настройки параметров печати сохраняются для каждого пользователя отдельно, сброс принтера также должен выполняться для каждого "проблемного" пользователя. После сброса в программу желательно перезайти, чтобы установленные настройки могли сохраниться.
Не знаю, поможет ли это в вашем случае, но в любом случае советую пройтись отладчиком под пользователем с такой проблемой и посмотреть, какие параметры табличного документа получаем после выполнения процедуры печати в pdf, и какое имя принтера сохранено в базе (в типовых должно быть пустое). В крайнем случае попробуйте сохранять имя вашего основного принтера. В общем, нужно экспериментировать.
Считаю публикацию снова актуальной, в связи с ошибкой 1С в кодировках при записи pdf файла:
20006661 (SW707626) Сохранение табличного документа в формате PDF
Проблема:
При сохранении табличного документа в формате PDF, текст, написанный нестандартным шрифтом, сохраняется в PDF некорректно.
Дата публикации:
2012-08-02
Обсуждения:
Есть ли мысли по этому поводу?
Каким образом можно обходить ошибку?
Или это говорит нам о том, что 1С в вопросах PDF нельзя доверять вообще?
(80)
Наверное, пишете в 7-ке..
Йоксель корректно поддерживает(-л) mxl только семерочного формата, поэтому для корректного отображения форм используется промежуточное сохранение в xls. Или что именно Вам кажется "диким"? Оформление кода через Попытку? Так регистрация тут не при чем.. Библиотеки банально может не оказаться на машине, или Вы предлагаете лично это проверить у каждого из 70 пользователей?
Просто благодарен за выложенный (так давно) код, т.к. я его с успехом применил для решения данной проблемы.
Можно подробнее, какие необходимо использовать штрифты в табличном документе, чтобы его можно было корректно записать в pdf?
Я перепробовал парочку - ничего не вышло. Просто в итоговом документе - выделил всю таблицу и свойствах указал другой штрифт - Ариал, затем Таймс и т.д. Все тоже самое.
Может еще какую-то кодировку необходимо указывать?
Как минимум до платформы 8.2.19.80 есть проблема - если поле "перенасыщено" форматированием (жирный, наклонный, подчеркивание), то при определенных обстоятельства может получиться проблема при сохранении в PDF - файл просто не читается.
Я пока поймал эту ошибку, думал, что поседею.
Причем поймать условия, при которых это происходит (т.е. условия знал, не знал что именно влияет) сложно.
В итоге, убрал в строках подчеркивание из шрифта и всё заработало без проблем.
Какие-то проблемы с регистрацией? У меня dll регистрации не требует. Что я делаю не правильно?
ИсхТабл = СоздатьОбъект("Таблица");
...
...
ИсхТабл.Вывести();
ЗагрузитьВнешнююКомпоненту ("SpreadSheet.dll");
Таб = СоздатьОбъект ("ТабличныйДокумент");
Таб.ЗагрузитьИзТаблицы (ИсхТабл);
Конвертер = СоздатьОбъект ("Йоксель.ГрафическийКонвертер.PDF");
Конвертер.ВысотаСтраницы = 56.7*297;
Конвертер.ШиринаСтраницы = 56.7*210;
Конвертер.КоличествоБитНаПиксел = 24;
Конвертер.Документ = Таб;
Конвертер.ПолеСлева = 56.7*15;
Конвертер.ПолеСверху = 56.7*10;
Конвертер.ПолеСправа = 56.7*10;
Конвертер.ПолеСнизу = 56.7*5;
Данные = Конвертер.СтандартныеМетаданные;
Данные.Автор = глПользователь;
Данные.Заголовок = "шлю всем мой крутой документ";
Данные.Тема = "мой крутой документ";
Данные.КлючевыеСлова = "отчет, документ" ;
Данные.ГенераторОригинальногоДокумента = "1С:Клюшки & Кошки рулят";
Данные.ГенераторДокументаPDF = "Йоксель - yoksel.net.ru";
Час="";
Минута="";
Секунда="";
ТекущееВремя(Час,Минута,Секунда);
Данные.УстановитьДатуСоздания (ДатаГод(ТекущаяДата()),ДатаМесяц(ТекущаяДата()),ДатаЧисло(ТекущаяДата()),Час,Минута,Секунда);
Данные.УстановитьДатуМодификации (ДатаГод(ТекущаяДата()),ДатаМесяц(ТекущаяДата()),ДатаЧисло(ТекущаяДата()),Час,Минута,Секунда);
Конвертер.ЗаписатьВФайл (КаталогВременныхФайлов()+"Мой крутой документ.pdf");
ЗапуститьПриложение(КаталогВременныхФайлов()+"Мой крутой документ.pdf");
//ФС.УдалитьФайл(КаталогВременныхФайлов()+"Мой крутой документ.pdf");
ПоказатьЧто необходимо еще установить?
Оказывается, все зависит от версии.
Для версий до 2.0
УтилитаПечати = Новый COMОбъект("PDFCreator.clsPDFCreator");Для версий, начиная с 2.0 или 2.1 (у меня 2.1)
PDFCreator= Новый COMОбъект("PDFCreatorBeta.PDFCreatorObj");
PDFCreatorQueue= Новый COMОбъект("PDFCreatorBeta.JobQueue");А в версии 2.2 уже без Beta
PDFCreator= Новый COMОбъект("PDFCreator.PDFCreatorObj");
PDFCreatorQueue= Новый COMОбъект("PDFCreator.JobQueue");Методы тоже поменялись, примеры есть на оф. сайте
Если кому интересно, могу подрихтовать и выложить. Сейчас работает для Бух. для Украины.
ps только сейчас кстати додумался. стопудово у них почтовые клиенты картинки режут, а они не знают как их включить)))
ТабДок.Защита=Истина;
ВремФайл=ПолучитьИмяВременногоФайла("pdf");
ТабДок.Записать(ВремФайл,ТипФайлаТабличногоДокумента.PDF);
ЗапуститьПриложение(ВремФайл);
Вы можете заказать платную консультацию или разработку у автора. Будет создан приватный заказ на «Бирже заказов» для автора.
№ 75969
Создание 24.09.10 16:39
Обновление 03.05.11 17:08
Просмотры 89979
Загрузки 0
Рейтинг
214
Комментарии 105
Код открыт Не указано
Рубрики Файловый обмен (TXT, XML, DBF), FTP
Кому Разработчик
Тип файла Нет файла
Платформа 1С:Предприятие 8
Конфигурация 1C:Бухгалтерия
Операционная система Не имеет значения
Страна Россия
Отрасль Не имеет значения
Налоги Не имеет значения
Вид учета Не имеет значения
Доступ к файлу Бесплатно (free)