Недавно понадобилось решить задачу печати на принтере фрагмента страницы, подготовленной из многостраничного документа MS Visio. Подобная задача для одностраничного документа была решена
ранее. Отличие можно заметить, в левой колонке добавлен раздел "Перейти к странице".
Кроме того, здесь добавлено две функции:
- изменение текста и размера заголовка;
- копирование фрагмента в MS Word 2003 или MS Word 2007.
Задача была решена в три этапа.
1. С использованием архиватора
gzip.exe из файлов *.emz получены высота и ширина изображения в пикселах. Формат командной строки:
gzip.exe -d -k -f -S ""emz vml_1.emz
В результате разархивирования создан файл
vml_1, который содержит изображение в формате EMF.Получить ширину и высоту можно, например, следующей процедурой, написанной на Delphi:
procedure TForm1.GetEMZHeader(const FileName: String;
out Height: Integer; out Width: Integer);
var
VMLMetafile: TMetafile;
lpENHMETAHEADERSIZE: DWORD;
lpENHMETAHEADER: PENHMETAHEADER;
Rect: TRect;
begin
VMLMetafile := TMetafile.Create;
VMLMetafile.LoadFromFile(FileName);
lpENHMETAHEADERSIZE := GetEnhMetaFileHeader(VMLMetafile.Handle, 0, nil);
if (lpENHMETAHEADERSIZE > 0) then
begin
GetMem(lpENHMETAHEADER, lpENHMETAHEADERSIZE);
GetEnhMetaFileHeader(VMLMetafile.Handle, lpENHMETAHEADERSIZE, lpENHMETAHEADER);
Rect := lpENHMETAHEADER^.rclFrame;
Width := Round(Abs(Rect.Right - Rect.Left)/1e3/2.54*72);
Height := Round(Abs(Rect.Bottom - Rect.Top)/1e3/2.54*72);
FreeMem(lpENHMETAHEADER, lpENHMETAHEADERSIZE);
end;
VMLMetafile.Free;
end;
Полученные данные сохраняются в файл sizes.xml, который помещается в ту же папку, в которой лежат файлы *.emz. Содержимое этого файла может быть следующим:
<root>
<vml_1.emz Height="5885" Width="7420"/>
<vml_10.emz Height="5413" Width="6964"/>
<vml_11.emz Height="5543" Width="7188"/>
<vml_12.emz Height="5438" Width="7362"/>
<vml_13.emz Height="3144" Width="6467"/>
<vml_14.emz Height="5469" Width="6790"/>
<vml_15.emz Height="5227" Width="7046"/>
<vml_2.emz Height="5544" Width="7397"/>
<vml_3.emz Height="5414" Width="6934"/>
<vml_4.emz Height="5506" Width="6907"/>
<vml_5.emz Height="5797" Width="7233"/>
<vml_6.emz Height="5420" Width="6721"/>
<vml_7.emz Height="4909" Width="7030"/>
<vml_8.emz Height="5298" Width="6882"/>
<vml_9.emz Height="5403" Width="6863"/>
root>
В той же папке создаются два файла: vml_print.js и vml_print.htm. Содержимое первого файла:
function print_fragment() {
var image = parent.frmDrawing.document.all['ConvertedImage'];
var pixelWidth = image.style.pixelWidth;
var pixelHeight = image.style.pixelHeight;
var winWidth = parent.frmDrawing.document.body.clientWidth;
var winHeight = parent.frmDrawing.document.body.clientHeight;
var winScrollLeft = parent.frmDrawing.document.body.scrollLeft;
var winScrollTop = parent.frmDrawing.document.body.scrollTop;
var newWidth = winWidth / pixelWidth;
var newHeight = winHeight / pixelHeight;
var newXOffset = winScrollLeft / pixelWidth;
var newYOffset = winScrollTop / pixelHeight;
// Чтение ширины и высоты изображения emz из sizes.xml
var xmlDoc = new ActiveXObject("MSXML2.DOMDocument");
xmlDoc.async = false;
xmlDoc.validateOnParse = true;
xmlDoc.load("sizes.xml");
var htmFileName = parent.frmDrawing.location.pathname;
var htmFileName = htmFileName.replace(".htm", ".emz").split("/");
var emzFileName = htmFileName[htmFileName.length-1]
var H = xmlDoc.selectSingleNode("root/"+emzFileName+"/@Height").text;
var W = xmlDoc.selectSingleNode("root/"+emzFileName+"/@Width").text;
// Открытие окна
var win = window.open("vml_print.htm", "vml_print",
"width="+winWidth+",height="+winHeight+",scrollbars=yes,resizable=yes");
// Заголовок
win.document.all["title1"].innerText = parent.g_FileList[parent.g_CurPageIndex].PageName;
// Атрибуты контейнера
var container = win.document.all["container"];
container.style.height = winHeight+"px";
container.style.width = winWidth+"px";
// Атрибуты изображения
var content = win.document.all["content"];
content.setAttribute("src", emzFileName);
content.setAttribute("croptop", newYOffset);
content.setAttribute("cropbottom", 1-newHeight-newYOffset);
content.setAttribute("cropleft", newXOffset);
content.setAttribute("cropright", 1-newWidth-newXOffset);
win.document.forms[0].H2.setAttribute("value", H);
win.document.forms[0].W2.setAttribute("value", W);
}
Содержимое второго файла:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html xmlns:v="urn:schemas-microsoft-com:vml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1251">
<style type="text/css">
v\:* { behavior: url(#default#VML); }
</style>
</head>
<script type="text/jscript" language="jscript">
// Печать текущего фрагмента
window.print();
function titleChange() {
// Изменение текста заголовка
var title1 = document.all["title1"].innerText;
title1 = prompt("Изменение текста заголовка", title1);
if (title1 != null)
document.all["title1"].innerText = title1;
// Изменение размера шрифта
var titleFontSize = document.all["title1"].style.fontSize;
titleFontSize = prompt("Изменение размера шрифта", titleFontSize);
if (titleFontSize != null)
document.all["title1"].style.fontSize = titleFontSize;
}
function copyToWord() {
if (confirm("Копировать теущий фрагмент в Microsoft Word?")) {
var file_name = window.location.pathname;
file_name = file_name.replace(/^\//, ""); // Убрать лидирующий слеш
var content = document.all["content"];
file_name = file_name.replace(/vml_print.htm/, content.getAttribute("src"));
file_name = file_name.replace(/\//g, "\\"); // Заменить прямые слеши на обратные
file_name = file_name.replace(/%20/g, " "); // Заменить %20 на пробел
var H2 = document.getElementById("H2").value;
var W2 = document.getElementById("W2").value;
if ((H2 < 1) || (W2 < 1)) {
alert("Ошибка! Размеры рисунка не заданы!");
return;
}
var content = document.all["content"];
var ct = content.getAttribute("croptop");
var cb = content.getAttribute("cropbottom");
var cl = content.getAttribute("cropleft");
var cr = content.getAttribute("cropright");
try {
var Word = new ActiveXObject("Word.Application");
var Doc = Word.Documents.Add();
Word.Selection.InlineShapes.AddPicture(file_name, false, true);
var InlineShape = Doc.InlineShapes.Item(1);
var W1 = InlineShape.Width;
var H1 = InlineShape.Height;
InlineShape.PictureFormat.CropTop = H2 * ct;
InlineShape.PictureFormat.CropBottom = H2 * cb;
InlineShape.PictureFormat.CropLeft = W2 * cl;
InlineShape.PictureFormat.CropRight = W2 * cr;
InlineShape.Width = W1;
InlineShape.Height = H1*(1-ct-cb)/(1-cl-cr);
Word.visible = true;
InlineShape.LockAspectRatio = 4; // msoTrue
}
catch(err) {
txt = "На странице произошла ошибка.\n\n";
txt += "Описание: " + err.description + "\n\n";
alert(txt);
}
}
}
</script>
<body>
<h1 id="title1" align="center" style="font-size:200%" onclick="titleChange()">Название схемы</h1>
<center>
<v:rect id="container" onclick="copyToWord()" strokecolor="gray" strokeweight="1pt"
style="position:relative; height:500px; width:800px">
<v:imagedata id="content" croptop="0" cropbottom="0" cropleft="0" cropright="0"
src="vml_1.emz" />
</v:rect>
</center>
<form>
<input id="H2" type="hidden" value="0" />
<input id="W2" type="hidden" value="0" />
</form>
</body>
</html>
Подключение функции печати реализуется в файле
widgets.htm также, как описано в
предыдущем сообщении.
При клике на пункт меню "Печать"
откроется окно, содержащее заголовок и фрагмент изображения.
При клике на заголовок "Схема 4" будет предложено изменить текст заголовка и увеличение размера шрифта (в процентах или пикселах).
При клике на изображение будет предложено скопировать фрагмент в MS Word.
При копировании заголовок не используется. Ещё есть возможность по клику правой кнопкой открыть контекстное меню и выбрать пункт "Предварительный просмотр...", из которого изменить представление (масштаб, колонтитулы, ориентация и т.п.) и распечатать страницу.