Как распечатать html файл

Обновлено: 07.07.2024

Программирование => WinAPI & Visual C++ => Тема начата: jur от 02-05-2017 12:42

Да здравствует фирма Микрософт, никогда не дающая нам расслабиться и утратить тонус! :-)

Все было хорошо до недавних пор. Я как раз успел расслабиться - ан нет! В 10-й Винде (на некоторых компьютерах) моя старая приборная программа перестала печатать файлы HTML, которые я подготавливаю в программе. Они очень простые: картинка, несколько строк текста и все. Теперь стало выскакивать окошко с ошибкой:

"This file does not have a program associated with it for performing this action. Please install a program or, if one is already installed, create an association in the Default Programs control panel."

Ассоциации на месте (HTM и HTML привязаны к Firefox). Печатаю посредством ShellExecuteEx указав:
lpExecInfo.lpVerb = "print";
и
lpExecInfo.lpFile = "C:\1my\_Work\Temp\tmp_report.html"

А ведь все было так хорошо.

Покопавшись в Интернете я начал осознавать, что масленица коту закончилась. Нужно делать печать "по-взрослому". Но как?! Для моего случая, как ни странно, ничего не нашел.

Вот моя среда разработки:
- Windows 10 x64 и x86 (на двух компах)
- Visual Studio 2008 (более новые пробую по чуть-чуть, но полностью удовлетворяет и эта)
- Модуль для печати - самая обычная DLL-ка, никаких MFC или CLR, просто C++
- Проект под x86

Микрософт по этому поводу говорит следующее: "Используй XPS Print API", а на соответствующей странице еще страшнее: "[The XPS Print API is not supported and may be altered or unavailable in the future. Client applications should use the Print Document Package API instead.]".

Помогите, пожалуйста, с наименьшими кровопотерями решить эту, в общем-то несложную, задачу! Может кто знает простой класс или простой и доходчивый пример?

P.S. В другой DLL-ке я печатаю на принтере картинку - никаких проблем. В этом случае я просто использую WinGDI.

А конечная цель в чём? Судя по названию файла, печатается какой-то отчёт. Если так, то я сейчас поступаю так: формирую макет для отчёта в виде файла EMF. Затем, изменяющиеся элементы прибавляю к нему, используя WINAPI GDI, далее вывожу итог на печать.

Надо отметить, что меня тоже мучает поиск надёжной системы отображения и печати.

В составе VS входит CrystalReports — гибкая система создания отчетов. Стандартный источник для отчетов - БД, но API позволяет ввести данные напрямую. Я через нее печатал на принтер, экспортировал в PDF и XLS. А конечная цель в чём? Судя по названию файла, печатается какой-то отчёт.
Если так, то я сейчас поступаю так: формирую макет для отчёта в виде файла EMF. Затем, изменяющиеся элементы прибавляю к нему, используя WINAPI GDI, далее вывожу итог на печать.

Глянул я на этот формат. Он, зараза, двоичный. Замучаешься заготовки делать, а уж что-то в них корректировать - просто невозможно (без соответствующей программы). Правильно я про Микрософт сказал: по их мнению гораздо интереснее на лыжах, в гамаке и с аквалангом! :-)

В составе VS входит CrystalReports — гибкая система создания отчетов. Стандартный источник для отчетов - БД, но API позволяет ввести данные напрямую. Я через нее печатал на принтер, экспортировал в PDF и XLS.

Мне бы попроще чего-нибудь. Ведь не может быть, чтобы нельзя было просто и элементарно распечатать HTML-файл!

Мне бы попроще чего-нибудь. Ведь не может быть, чтобы нельзя было просто и элементарно распечатать HTML-файл!

А тогда зачем заморачиваться?

Начнём с того, что Ваша программа НИКОГДА САМА не печатала HTML.

Печатаю посредством ShellExecuteEx указав:
lpExecInfo.lpVerb = "print";
и
lpExecInfo.lpFile = "C:\1my\_Work\Temp\tmp_report.html"

А то, что при новой инсталляции изменяются ассоциации типов с приложениями, так при чём здесь микрософт? Пользователь сам может их изменить. У меня, например, они ассоциированы с текстовым редактором.

Ассоциации на месте (HTM и HTML привязаны к Firefox).
This file does not have a program associated with it for performing this action.

Наконец-то! Как там у Архимеда? Эврика? Вот она и есть! :-)

А то, что при новой инсталляции изменяются ассоциации типов с приложениями, так при чём здесь микрософт? Пользователь сам может их изменить. У меня, например, они ассоциированы с текстовым редактором.

Так-то оно так, но прокопавшись полтора дня я так и не нашел этой информации. У Честертона отец Браун хорошо сказал: "Где нужно прятать лист? В лесу." Это он стопудово про Интернет. :-)

Ассоциации на месте (HTM и HTML привязаны к Firefox).
This file does not have a program associated with it for performing this action. Надо посмотреть, что делает ассоциативный с HTML print и, либо поменть его, либо (что предпочтительней) использовать его сторочку.

Весь Интернет ломится от подобных вопросов. Поэтому привожу образец моего кода. Возможно он кому-нибудь поможет.

Thank you David, works excellent, just as expected!
sprintf(sfile, "%s%s%s%s", "mshtml.dll,PrintHTML \"", cwd, afile, "\"");
ShellExecute(NULL, "open", "rundll32.exe", sfile, NULL, SW_SHOWNORMAL);
*/
void Print_Report_to_Printer()
CString sfile;

sfile.Format("mshtml.dll,PrintHTML \"%s\"", Path_report_tmp); // Path_report_tmp вроде такого: "C:\Temp\tmp_report.html"

ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);
ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
ShExecInfo.lpVerb = "open";
ShExecInfo.lpFile = "rundll32.exe";
ShExecInfo.lpParameters = sfile;
ShExecInfo.nShow = SW_SHOWNORMAL;

if( ShellExecuteEx(&ShExecInfo) ) if( ShExecInfo.hProcess ) WaitForSingleObject(ShExecInfo.hProcess, INFINITE); // Жду завершения диалога печати
CloseHandle( ShExecInfo.hProcess );
>
>
else UtilsR1_ShowLastErrorMessage("Print_Report_to_Printer() error"); // Показывает пояснительный текст последней ошибки
>
>

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

P.S. Спасибо друзья! Вы меня здорово подтолкнули в поисках решения! Оказалось, что все не просто, а очень просто. Как у Е. Айсберга :-)

Вот это, зря, другой специалист, будь то врач, пекарь, токарь, не обязан знать внутреннее устройство формата. Если требуется распечатать отдельно, например, снимок в формате А0, то хорошо бы сделать такую кнопочку.

Глянул я на этот формат. Он, зараза, двоичный. Замучаешься заготовки делать, а уж что-то в них корректировать - просто невозможно (без соответствующей программы).

EMF шаблоны я создаю преимущественно средствами CAD.

Если будет цель в создании полноценного печатающего приложения, то я бы начал изучение с того, как происходит рисование в Windows. Затем, перешёл бы к изучению печати, настройкам принтера и диалогу печати.

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

Все верно. Но я смотрю с точки зрения реальной жизни. Позвонил врач из Бангладеш, просит: "Мне бы картинку уменьшить чуток. ". Нет ничего легче, чем сказать: "Открой в Блокноте файл шаблона такой-то и в строчке такой-то исправь "width="512"" на "width: 75%"" (просто пример). Так гораздо меньше мороки, проверено.

Если будет цель в создании полноценного печатающего приложения, то я бы начал изучение с того, как происходит рисование в Windows. Затем, перешёл бы к изучению печати, настройкам принтера и диалогу печати.

Так я-ж в первом посте написал, что печатаю на принтере картинку с текстами, все нормально, никаких проблем.

Весь Интернет ломится от подобных вопросов. Поэтому привожу образец моего кода. Возможно он кому-нибудь поможет.

Только опять прежние грабли. А если в след. версии опять что-то изменится?

Собственно под "посмотреть" я имел ввиду "получить из реестра код печати для данного типа файла". Те не кодить строчку жёстко, а "читать" то, что настроено в реестре.

Находится в два приёма:

1. в HKEY_CLASSES_ROOT ищем расширение файла, например .html и смотрим стандартное значение (грубо говоря ник) - это htmlfile

2. в HKEY_CLASSES_ROOT\<ник> ищем подключ \shell\print\command и используем его стандартное значение в программе

Только опять прежние грабли. А если в след. версии опять что-то изменится?

С Микрософтом все может быть! :-)

Собственно под "посмотреть" я имел ввиду "получить из реестра код печати для данного типа файла". Те не кодить строчку жёстко, а "читать" то, что настроено в реестре.
Находится в два приёма:
1. в HKEY_CLASSES_ROOT ищем расширение файла, например .html и смотрим стандартное значение (грубо говоря ник) - это htmlfile
2. в HKEY_CLASSES_ROOT\<ник> ищем подключ \shell\print\command и используем его стандартное значение в программе

Темное это дело. Под ключом [HKEY_CLASSES_ROOT\.html] лежат:

С какими-то неудобоваримыми значениями.

Под ключом [HKEY_CLASSES_ROOT\htmlfile] тоже что-то не то:

[HKEY_CLASSES_ROOT\htmlfile\shell\Print\command]
@="\"C:\\Program Files (x86)\\Microsoft Office\\Office12\\msohtmed.exe\" /p %1"

А вот в ветке . printto похоже на правду:

Что-то такое можно сообразить. Кстати, а почему ShellExecuteEx с вербом "print" не рОбит? Ведь указано же что с этим файлом делать, как печатать!

В этой связи возникает новый вопрос: как на этапе компиляции узнать, под Виндой какой разрядности я работаю? Т.е. не TARGET (который 32 или 64 бита), а именно разрядность Винды. Че-то я этого никак не найду.

Спасибо за помощь, друзья!

Кстати, а почему ShellExecuteEx с вербом "print" не рОбит? Ведь указано же что с этим файлом делать, как печатать!

Как всё запущено. :( Учите матчасть. Кто такая фантастическая ShellExecute, которая каким-то волшебным образом может сделать ВСЁ: открыть любой файл, распечатать его (может ваще тогда другие программы не нужны, раз есть такая волшебница)? Как это работает, если в Проводнике кликнуть на файл правой кнопкой и в контекстном меню выбрать a la Печатать, Открыть и тп? Да просто щёлкнуть два раза по файлу? И зачем эти ключи в реестре? И как они со всем этим связаны? Но начать лучше с вопроса: что такое Shell? Как всё запущено. :( Учите матчасть. Кто такая фантастическая ShellExecute, которая каким-то волшебным образом может сделать ВСЁ: открыть любой файл, распечатать его (может ваще тогда другие программы не нужны, раз есть такая волшебница)? Как это работает, если в Проводнике кликнуть на файл правой кнопкой и в контекстном меню выбрать a la Печатать, Открыть и тп? Да просто щёлкнуть два раза по файлу? И зачем эти ключи в реестре? И как они со всем этим связаны? Но начать лучше с вопроса: что такое Shell?

Знамо запущено! :-) Для всего на свете места "на чердаке" может и не хватить. Не сомневаюсь, что про Shell написано очень много полезного и интересного, но мне-то это зачем? Мои задачи довольно просты. Просто в кои-то веки понадобилось напечатать HTML-файл и все. К тому же мне непонятно, чего этому ShellExecute еще нужно, если ключи в реестре говорят, как следует печатать этот файл? А в хелпе по этой команде ничего полезного по ее применению (как в моем случае) не говорится. "Куда крестьянину податься. " (С) Впрочем, хоть и не на все последующие века, но хотя бы на годы вперед я проблему решил :-)

Так оно-ж, зараза, похоже только к таргету относится. Да и то, нужно самому ручками прописывать в обоих опциях компилирования (Debug/Release). А у меня выскочила такая смешная проблема:

Несколько советов по печати из браузера на принтер или в документ PDF с помощью CSS

Несмотря на то, что мы все чаще смотрим на наши экраны, печать все еще актуальна.

Мой основной вариант использования для изучения печати обычно - это печать в формате PDF. Я мог бы создать что-нибудь в браузере, и я хочу сделать это доступным в формате PDF.

Браузеры делают это очень просто: Chrome по умолчанию имеет значение «Сохранить» при попытке распечатать документ, а принтер недоступен, а в Safari есть специальная кнопка в строке меню:

Safari Export PDF

Распечатать CSS

Некоторые общие вещи, которые вы, возможно, захотите сделать при печати, - это скрыть некоторые части документа, возможно, нижний колонтитул, что-то в заголовке, боковой панели.

Возможно, вы захотите использовать для печати другой шрифт, что вполне допустимо.

Если у вас есть большой CSS для печати, вам лучше использовать для него отдельный файл. Браузеры будут загружать его только при печати:

CSS @media print

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

будет применяться только к печатным документам.

Ссылки

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

CSS предлагает отличный способ решить эту проблему, отредактировав контент, добавив ссылку после <a> текст тега, используя:

Я нацелен a[href*='//'] сделать это только для внешних ссылок. У меня могут быть внутренние ссылки для навигации и внутреннего индексирования, что в большинстве случаев будет бесполезно. Если вы также хотите, чтобы распечатывались внутренние ссылки, просто выполните:

Поля страницы

Вы можете добавить поля на каждую страницу. cm или же in - хороший аппарат для печати на бумаге.

@page также можно использовать для таргетинга только на первую страницу, используя @page :first , или только левую и правую страницы, используя @page :left и @page: right .

Разрывы страниц

Возможно, вы захотите добавить разрыв страницы после некоторых элементов или перед ними. Использовать page-break-after и page-break-before :

Не разбивайте изображения посередине

Я испытал это с Firefox: изображения по умолчанию обрезаются посередине и продолжают на следующей странице. Это также может случиться с текстом.

и оберните свои изображения в p тег. Таргетинг img прямо в моих тестах не работало.

Это относится и к другому контенту, а не только к изображениям. Если вы заметили, что что-то режется, когда вы не хотите, используйте это свойство.

Размер PDF

При попытке распечатать более 400 страниц PDF с изображениями в Chrome изначально был получен файл размером более 100 МБ, хотя общий размер изображений был не таким большим.

Я пробовал использовать Firefox и Safari, и размер был меньше 10 МБ.

После нескольких экспериментов выяснилось, что у Chrome есть 3 способа распечатать HTML в PDF:

  • ❌ Не печатайте его с помощью системного диалога.
  • ❌ Не нажимайте «Открыть PDF в режиме предварительного просмотра»
  • ✅ Вместо этого нажмите кнопку «Сохранить», которая появляется в диалоговом окне печати Chrome.

The right way to print in Chrome

Это создает PDF-файл намного быстрее, чем два других способа, и имеет гораздо меньший размер.

HTML PDF

Что необходимо для конвертации HTML файла в PDF файл или как можно создать PDF версию Вашего HTML файла

Файлы типа HTML или файлы с расширением .html можно легко конвертировать в PDF с помощью PDF принтера.

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

Таким образом, Вы можете создать PDF версию любого файла, который можно распечатать. Просто откройте файл с помощью ридера, нажмите кнопку печати, выберите виртуальный PDF принтер и нажмите кнопку «Печать». Если у Вас есть устройство для чтения файла HTML и если ридер может распечатать файл, то Вы можете преобразовать файл в формат PDF.

PDF Принтер

  1. Установите PDF24 Creator
  2. Откройте .html файл с помощью ридера, который может открыть файл.
  3. Распечатайте файл на виртуальном PDF24 PDF принтере.
  4. Помощник PDF24 открывает окно, в котором Вы можете сохранять новый файл как PDF, отправлять по его email, факсу или редактировать.

Альтернативный способ того, как преобразовать HTML файл в PDF файл

PDF24 предоставляет несколько онлайн инструментов, которые могут быть использованы для создания PDF файлов. Поддерживаемые типы файлов добавляются по мере поступления и, возможно, формат файла HTML также уже поддерживается. Служба конвертации имеет различные интерфейсы. Два из них являются следующими:

Онлайн PDF Конвертер от PDF24 поддерживает множество файлов, которые могут быть преобразованы в PDF. Просто выберите файл HTML, из которого Вы хотели бы получить PDF версию, нажмите кнопку «конвертировать», и Вы получите PDF версию файла.

Онлайн PDF Конвертер


Блок страницы состоит из области страницы, где располагается содержимое и области полей, окружающей область страницы. Правило @page используется для изменения некоторых css-свойств при печати документа. Изменить можно только поля элемента margin , а также задать разрывы страниц в указанном месте.

Можно задавать отдельные поля документа внутри правила @page , такие как margin-top , margin-right , margin-bottom , margin-left :

2. Разрывы страниц

Управлять разрывами страниц можно с помощью свойств page-break-before , page-break-after и page-break-inside . Данные свойства применяются к блочным элементам, для которых свойство position имеет значение relative или static .

page-break-before
Значения:
auto Значение по умолчанию, задает автоматические разрывы страниц.
always Всегда добавляет разрыв страницы перед элементом.
avoid Отменяет размещение разрыва перед элементом, если это возможно.
left Добавляет один или два разрыва страниц перед элементом, чтобы следующая страница форматировалась как левая страница. Элемент будет печататься, начиная с верха левой страницы, т.е. на странице слева от корешка. При двусторонней распечатке будет выводиться на оборотной стороне листа бумаги.
right Добавляет один или два разрыва страниц перед элементом. Элемент будет печататься, начиная с верха правой границы. Следующая страница будет форматироваться как правая страница.
inherit Наследует это свойство от родительского элемента.

page-break-after
Значения:
auto Значение по умолчанию, задает автоматические разрывы страниц.
always Всегда добавляет разрыв страницы после элемента.
avoid Отменяет добавление разрыва после элемента, если это возможно.
left Добавляет один или два разрыва страниц после элемента так, чтобы следующая страница форматировалась как левая страница. Элемент будет печататься, начиная с верха левой страницы, т.е. на странице слева от корешка. При двусторонней распечатке будет выводиться на оборотной стороне листа бумаги.
right Добавляет один или два разрыва страниц после элемента так, чтобы следующая страница форматировалась как правая страница. Элемент будет печататься, начиная с верха правой границы.
inherit Наследует это свойство от родительского элемента.

Свойство page-break-inside говорит браузеру, может ли страница разрываться внутри элемента или нет. Но в случае, если элемент оказывается длиннее страницы, то разрыв неизбежен.

Читайте также: