dak ブログ

python、rubyなどのプログラミング、MySQL、サーバーの設定などの備忘録。レゴの写真も。

PDF.js でテキストをハイライトする方法

2021-06-12 14:47:51 | javascript
PDF.js で特定の文字列を含むPDF要素をハイライトする方法のメモ。

ここでは、PDF.js と PDF描画用の html ファイルは以下のようなディレクトリに配置しています。
www
├── pdfjs  # pdf.js
│     ├── build
│     ├── LICENSE
│     └── web
│           └── compressed.tracemonkey-pldi-09.pdf  # このPDFを描画
└── test
     └── test_viewer.html  # PDF描画用の html ファイル

PDF から getTextContent() で PDF のテキスト要素を取得して、
テキストが特定の条件を満たす場合(ここでは JavaScript を含む場合)に
ハイライトするようにします。
page.getTextContent().then(function (textContent) {
  ...
  textContent.items.forEach(function (item) {
    if (item['str'].match(/JavaScript/)) {
      ...
    }
  });
);

ハイライトは、PDFのテキスト要素と同じ位置・サイズに半透明の div タグを描画します。
位置、サイズは以下のように設定します。
        var item_left = item['transform'][4];
        var item_top = item['transform'][5];

        var rect = [item_left, item_top,
                    item_left + item['width'], item_top + item['height']];

        var view_rect = viewport.convertToViewportRectangle(rect);
        var abs_width = Math.abs(view_rect[0] - view_rect[2]);
        var abs_height = Math.abs(view_rect[1] - view_rect[3]);
        var abs_left = canvas_left + Math.min(view_rect[0], view_rect[2]);
        var abs_top = canvas_top + Math.min(view_rect[1], view_rect[3]);

また、ハイライト用の div タグを hl_parent に追加しておき、ページ遷移した際には前のページの div タグが残らないように、
hl_parent 内の div タグを削除します。
  while (hl_parent.firstChild) {
    hl_parent.removeChild(hl_parent.firstChild);
  }

全ソースは以下の通り。

<html>
<head>

<title>highlight</title>
</head>
<body>

highlight



<canvas id="the-canvas" style="border: solid;1px;"></canvas>



<button id="prev">Previous</button>
<button id="next">Next</button>
   


Page: /



<script src="/www/pdfjs/build/pdf.js"></script>
<script type="text/javascript">
var url = '/www/pdfjs/web/compressed.tracemonkey-pldi-09.pdf';

var pdfjsLib = window['pdfjs-dist/build/pdf'];

pdfjsLib.GlobalWorkerOptions.workerSrc = '/www/pdfjs/build/pdf.worker.js';

var pdfDoc = null,
pageNum = 1,
pageRendering = false,
pageNumPending = null,
scale = 1.2,
canvas = document.getElementById('the-canvas'),
ctx = canvas.getContext('2d');

// ハイライト表示用のタグ
var hl_parent = document.getElementById('highlight_parent');

// canvas の位置
var canvas_rect = canvas.getBoundingClientRect();

// ページ内の特定テキストをハイライト
function highlightTexts(page) { while (hl_parent.firstChild) { hl_parent.removeChild(hl_parent.firstChild); }
page.getTextContent().then(function (textContent) {
var pageElement = canvas.parentElement;

var viewport = page.getViewport({'scale': scale});

// highlight
textContent.items.forEach(function (item) {
if (item['str'].match(/JavaScript/)) { var item_left = item['transform'][4]; var item_top = item['transform'][5]; var rect = [item_left, item_top, item_left + item['width'], item_top + item['height']]; var view_rect = viewport.convertToViewportRectangle(rect); var abs_width = Math.abs(view_rect[0] - view_rect[2]); var abs_height = Math.abs(view_rect[1] - view_rect[3]); var abs_left = canvas_left + Math.min(view_rect[0], view_rect[2]); var abs_top = canvas_top + Math.min(view_rect[1], view_rect[3]);
var style = 'position: absolute;'
+ ' opacity: 0.50;'
+ ' background-color: yellow;'
+ ' left:' + String(abs_left) + 'px;'
+ ' top:' + String(abs_top) + 'px;'
+ ' width:' + String(abs_width) + 'px;'
+ ' height: ' + String(abs_height) + 'px;';

var e = document.createElement('div');
e.setAttribute('style', style);
hl_parent.appendChild(e);
}
});
});
}

function renderPage(num) {
pageRendering = true;
// Using promise to fetch the page
pdfDoc.getPage(num).then(function(page) {
var viewport = page.getViewport({scale: scale});
canvas.height = viewport.height;
canvas.width = viewport.width;

// Render PDF page into canvas context
var renderContext = {
canvasContext: ctx,
viewport: viewport
};
var renderTask = page.render(renderContext);

// Wait for rendering to finish
renderTask.promise.then(function() {
// highlight
highlightTexts(page);

pageRendering = false;
if (pageNumPending !== null) {
// New page rendering is pending
renderPage(pageNumPending);
pageNumPending = null;
}
});
});

document.getElementById('page_num').textContent = num;
}

function queueRenderPage(num) {
if (pageRendering) {
pageNumPending = num;
} else {
renderPage(num);
}
}

function onPrevPage() {
if (pageNum <= 1) {
return;
}
pageNum--;
queueRenderPage(pageNum);
}
document.getElementById('prev').addEventListener('click', onPrevPage);


function onNextPage() {
if (pageNum >= pdfDoc.numPages) {
return;
}
pageNum++;
queueRenderPage(pageNum);
}
document.getElementById('next').addEventListener('click', onNextPage);

pdfjsLib.getDocument(url).promise.then(function(pdfDoc_) {
pdfDoc = pdfDoc_;
document.getElementById('page_count').textContent = pdfDoc.numPages;

// Initial/first page rendering
renderPage(pageNum);
});
</script>
</body>
</html>


web ページで pdf ファイルを表示する方法

2020-11-22 13:30:00 | javascript
web ページで pdf ファイルを表示する方法のメモ。

pdf.js を使うことで、web ページで pdf ファイルを表示することができます。

まず、pdf.js をダウンロードして web サーバ上に置きます。
pdf.js の入手先はこちら。
ここでは、以下のようなファイル構成とします。
www
├── data
│   └── pdf
│       └── sample.pdf  # 表示する PDF ファイル
├── pdfjs  # pdf.js
│   ├── build
│   ├── LICENSE
│   └── web
└── test
    └── test_viewer1.html  # テスト用の web ページの html ファイル

pdf.js による pdf 表示のシンプルな html は以下のようになります。
iframe の src には pdf.js 内の viewer.html を読み込み、file パラメータで pdf ファイル名を指定します。
<html>
<head>

<title>test viewer</title>
</head>
<body>

<iframe id="pdf_viewer"
        width="800"
        height="600"
        src="/www/pdfjs/web/viewer.html?file=/www/data/pdf/sample.pdf">
</iframe>
</body>
</html>


表示するページを javascript で制御することも可能です。
以下のように iframe の src に指定したURLに #page= でページ番号を指定することで、
リンクをクリックすると指定のページに遷移することができます。

例えば 3 ページに遷移する場合には、以下のように iframe の src を変更します。
document.getElementById('pdf_viewer').setAttribute('src', '/www/pdfjs/web/viewer.html?file=/www/data/pdf/sample.pdf#page=3');




JavaScriptの関数のソースを見る方法

2020-03-26 00:23:54 | javascript
JavaScriptの関数のソースを見る方法のメモ。

関数のソースは 関数名.toString() で見ることができる。
例えば、abc() という関数の場合、abc.toString() でソースを見ることができる。

以下は chrome のデバッガでの実行例。
> function abc() {
    return "abc";
  }
< undefined
> abc.toString();
< "function abc() {
    return "abc";
  }"


JavaScriptでURLを変更する方法

2019-10-08 01:11:45 | javascript
JavaScriptで現在表示中のページのURLを変更する方法のメモ。

以下、chrome の console での実行例。
> location.href
"https://blog.goo.ne.jp/dak-ikd/e/6c246c6c31d0f460e73ed0f98ff097a4"  <-- 現在のURL

> history.replaceState(null, null, "https://blog.goo.ne.jp/dak-ikd/e/a2f41210278a671fc272fa97b405d6e2?fm=entry_awc")
undefined

>location.href
"https://blog.goo.ne.jp/dak-ikd/e/a2f41210278a671fc272fa97b405d6e2?fm=entry_awc" <-- 変更後のURL


flotでの日付の目盛

2012-05-25 00:16:00 | javascript
日毎のデータをflotでグラフ描画する際には、plot() の第3引数で xaxis の指定を行います。
日付モードにするには mode: "time" にし、表示形式を timeformat で指定します。

<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<title>日付の目盛</title>
<script type="text/javascript" src="flot/jquery.js"></script>
<script type="text/javascript" src="flot/jquery.flot.js"></script>
</head>
<body>
日付の目盛<br>
<div id="graph_area" style="width:600px;height:300px"></div>
<script type="text/javascript">
$(function () {
      var time = new Date();

      // x軸は日数
      var data1 = [[0, 3], [1, 8], [2, 5], [3, 13]];

      for (var i = 0; i < data1.length; i++) {
        // getTime() はミリ秒
        data1[i][0] = time.getTime() + data1[i][0] * 24 * 60 * 60 * 1000;
      }

      $.plot($("#graph_area"),
             [
              {
                  data: data1,
                      label: "UU",
                      lines: { show: true },
                      points: { show: true },
                      },
              ]
             ,
             {
                  xaxis: { mode: "time", timeformat: "%m/%d" },
             }
             );
  });
</script>

</body>
</html>

flotでのクリックイベント

2012-05-21 16:22:43 | javascript
flotで、グラフの点をクリックしたときにその点の情報を表示させるようなサンプルプログラムです。

<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<title>クリックイベント</title>
<script type="text/javascript" src="flot/jquery.js"></script>
<script type="text/javascript" src="flot/jquery.flot.js"></script>
</head>
<body>
クリックイベント<br>
<br>
<div id="graph_area" style="width:600px;height:300px"></div><br>
<br>
<div id="label_area"></div><br>

<script type="text/javascript">
$(function () {
  var data = [
    [0, 3, { label: "a" }],
    [2, 8, { label: "b" }],
    [3, 5, { label: "c" }],
    [1, 4, { label: "d" }],
    [2, 4, { label: "e" }],
  ];


  $.plot($("#graph_area"),
    [
      {
        data: data,
        lines: { show: false },
        points: { show: true },
      },
    ],
    {
      grid: { hoverable: true, clickable: true },
    }
  );


  $("#graph_area").bind("plotclick", function (e, pos, item) {
    if (item) {
      $("#label_area").html("label: [" + data[item.dataIndex][2].label + "]");
    }
  });
});
</script>

</body>
</html>


クリックイベントは、$("#graph_area").bind("plotclick", function (e, pos, item) {...}); で設定します。
グラフの点をクリックされた場合には item に点の値が設定されているので、item の値を使ってイベント処理を行います。

上記のサンプルでは、item.dataIndex でデータの位置を取得し、配列の第3要素のハッシュの情報を取得しています。
plot() の引数の描画データの { data: ... } には普通は [x, y] の配列を指定しますが、上記のサンプルのように 3 要素以上を指定しても動作に問題はないようです。

以下は、[2.0, 8] の点をクリックした直後の画面です。



javascriptでグラフ描画

2012-05-15 23:52:31 | javascript
javascriptでグラフを描画する方法です。
jQueryベースのflotを使います。 描画したいデータの [x, y] のデータ列を data: に指定すれば、グラフを描画してくれます。


<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<title>折れ線グラフ</title>
<script type="text/javascript" src="flot/jquery.js"></script>
<script type="text/javascript" src="flot/jquery.flot.js"></script>
</head>
<body>
折れ線グラフ
<div id="graph" style="width:600px;height:300px"></div>
<script type="text/javascript">
$(function () {
var data1 = [[0, 3], [4, 8], [8, 5], [10, 13]];
var data2 = [[0, 0], [10, 20]];

$.plot($("#graph"),
[
{
data: data1,
label: "line1",
lines: { show: true },
points: { show: true },
},
{
data: data2,
label: "line2",
lines: { show: true },
},
]);
});
</script>
</body>
</html>




javascript でオブジェクトのプロパティを調べる

2007-03-15 22:23:53 | javascript
javascript でオブジェクトのプロパティにどんなものがあるのかを調べるには for (... in ...) を使えばOK。

var dbg = document.getElementById("dbg");
var obj = document.getElementById("...");
for (var k in obj) {
dbg.innerHTML += k + " : " + obj[k] + "
";
}