понедельник, 5 июля 2010 г.

Исправление ошибки масштабирования в SWTBCanvasFont

Потребовалось мне использовать пакет вывода текста в векторном формате совместно с графикой. Я воспользовался проектом SWTBCanvasFont. И вот на что я обратил внимание: если буквы увеличены, то они узкие, а если уменьшены, то широкие. При единичном масштабе искажений нет. Я нашёл ошибку в коэффициентах матрицы трансформации. Привожу скриншот исправления файла SWTBCanvasText:

Надеюсь, различия видны. И, напоследок, привожу результат сравнения результатов вывода оригинального и исправленного кода.

Слева в окне то, что было. Справа то, что стало. Заметно, что справа пропорции букв (отношение высоты к ширине) не зависят от масштаба, который варьирует от 2,0 до 0,5.

среда, 14 апреля 2010 г.

Исправление ошибки в подсказках на веб-страницах, генерируемых Microsoft Office Visio 2007

Я обратил внимание, что при наведении указателя мыши на заголовки панелей появляется урезанная подсказка. Вместо текста «Свернуть раздел "Перейти к странице"» отображается только «Свернуть раздел».

В исходном коде, в файле widgets.htm, присутствуют строки типа
<a id="exp01" title="Свернуть раздел "Перейти к странице"" href="javascript:widgets.ToggleWidget(hideGoto);"><p class="label">Перейти к странице</p></a>
Эти строки содержат вложенные двойные кавычки. Заменим их на код &quot;, в результате получим строки типа
<a id="exp01" title="Свернуть раздел &quot;Перейти к странице&quot;" href="javascript:widgets.ToggleWidget(hideGoto);"><p class="label">Перейти к странице</p></a>
Теперь, я надеюсь, подсказка отображается так, как и было задумано разработчиками Microsoft. А тестировщикам Microsoft, которые не заметили этой ошибки, выражаю общественное порицание.

вторник, 13 апреля 2010 г.

Печать фрагмента VML (EMZ) из javascript. Доработка для многостраничных документов

Недавно понадобилось решить задачу печати на принтере фрагмента страницы, подготовленной из многостраничного документа 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.

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