カテゴリ:TIPSとかKludgeとか( 23 )

近デジ画像の余白の除去をネタにAForge.NETを使ってみた。

 近デジネタの続きと言えば続きなのだが。

 近デジのPDFの画像形式がJPEG 2000からJPEGになったので、拙作のKinDigDLでもJPEGファイルで出力する機能を付けてみたわけだが、そもそもこれは何に使うのかという話である。

 言うまでもなく、近デジ生のPDFだと満足できない場合にはソース画像を自分でバンバンする(この懐かCM、いったい何人に通じるのか)ためのものだ。
 近デジ生画像の問題点は、ざっと挙げると;
  1. 白黒のマイクロフィルムから起こしたものは、かなり余分な「余白」が付いている。
    余分な余白というのは馬から落ちて落馬した的であるが、つまり、本来の「本の余白」の外に、本を置いた「台」の部分が映り込んでいる為、その部分が「余分」ということである。

  2. 殆どが「見開き」の状態(1画像で左右2ページ)なので、環境によっては読みにくい。やはりホントのページ単位にしたい。

  3. 画像のコントラストがまちまちで、読みにくいものも散見される。

  4. ノイズ・リダクションくらい掛けたいじゃない。

あたりだろうか。

 この分野に関しては、既に実装されている方がおられる。
 hitode909さんの記事、「近デジの画像の余白を取って左右に分割する」が嚆矢だろうか。

 ちゃんとした処理に関してはhitode909さんや、ultraistさんが公開されているソースなどを参照して欲しい。

 俺は「画像処理?何それうまいの」な人なので、こーゆー分野には手を出さないようにしてる。確かに以前、画像処理用のコンポーネントを作ったことはあるが、テメエの必要に応じた極めてプリミティブなもので、いわゆる「イメージ処理」的な機能は殆ど無い。

 ただ、興味はあるわけで、勉強方々ちと自分でも試してみようと思ったわけだ。

 先人の実装では、ImageMagikやOpenCVといった定番ソフトでバンバンしている例が多いように見受けられた。同じ事をやっても仕方がないので、ちょっと探してみると、AForge.NETというイイ感じのフレームワークを見つけた。
  1. LGPLのオープンソース、しかもC#での実装なので自分の勉強になる。

  2. イメージ処理、動画処理、ニューラルネットにファジー処理…など、その筋なネタで構成されており、「実験」という男のロマンが感じられるw
つーあたりが魅力である。

 おまけに、名前が良い
 恵方寺と訓じればなにやら縁起が良さそうだし、個人的にはもう、アフォ毛としか読めないわけで、これは萌えるではないかw

 というわけで(どんなわけだ)、ちょっと試してみた。
 いきなりhitode909さんレベルは俺にとってはあまりに敷居が高いので、簡単なところで、余白の除去から。

More
[PR]
by SIGNAL-9 | 2013-01-30 13:56 | TIPSとかKludgeとか

【近デジ】近デジPDFダウンローダー 置いときます。

■2017/01/05追記
 近デジ廃止に伴い、当方の事情で勝手ながら以下のように変更しました。今後、もしも手を加えるようなことがあれば、こちらを直すことになりますが、現状では基本的に機能追加はありませんので、必要な方だけどうぞ。
  1. プログラム名をNDLDLに変更しました。
  2. .Net Frameworkを4.6に変更しました。
  3. -q オプションは廃止しました。
  4. -t オプションで、通信タイムアウトを指定できるようにしました。
  5. iTextSharpライブラリをスタティックリンクしました。

 新しいプログラムは
NDLDL.zip
 として置いておきます。伸長パスワードは同じです。
■2015/03/30追記
 ダウンロード先を近デジ(kindai.ndl.go.jp)ではなく、
 デジタルコレクション(dl.ndl.go.jp)に切り替えるオプションを追加しました。
 -q を指定するか、引数のURLがdl.ndl.go.jpだったらdl.ndl.go.jpからダウンロード
 します(近デジとデジタルコレクションは、インターネット公開PDFに関しては同一なのでどちらから取っても同じです)。
 またデフォルトのダウンロードコマ数を20→50にしました。
 KinDigModが例外吐いてまともに動かなかった…すみませんiTextSharpを付け間違えてました(爆)。
 (誰も教えてくれなかったということは使ってる人がいないのか…)
 今回ので上書き(EXEとDLL両方とも)してもらえれば動くと思います。

■2013/03/28追記
03/28 15:00に更新しました。
 JPEG出力のところを見直したので、微妙にメモリ所要量が少なくなってます。
 (微々たるものなのでどーでもいい事ですけど)
 ついでに、JPEG 2000もエクスポートできるようにしました。
 (これも今となっては意味ないですが)
 機能追加はないので、必要ない方はアップグレードする必要は無いです。

■2013/01/22追記
 01/22 12:12に、更新しました。
・目次が編集できる KinDigMod を追加。
・これに合わせてKinDigDLにオプション追加。
既にお使いの方、ダウンロードして上書きしてください。
-----------------------
 近デジPDFダウンロードの問い合わせをメールで数本もらったんで、面倒くさいので(爆)、現時点の実行ファイルをダウンロードできるようにしときます。

 正式公開するような工数が取れないので、正直言ってクオリティ低いです(てゆーか、作りかけです。個人的に用が足りてるので放置プレー)。
  1. マニュアルとか親切なインストーラとかを作っている暇がありません。
     よって、使用には最低限のパソコンの知識(コマンドプロンプトの使い方など)が必要です。

  2. サポートも出来ないです。
    簡単なご質問とかご感想とかはこのエントリにコメントくれれば対応できるかも知れないですが。

  3. 一般公開向けのテストも十分に行っていないので、環境によっては上手く動かない場合もあると思います。

 つまるところ、
本ソフトウェアは、signal9.exblog.jpの中の人によって「現状のまま」、かつ明示か暗黙であるかを問わず、一切の保証を付けずに提供されるものです。

 ここでいう保証とは、市場性・特定目的に対する適合性・権利侵害の不在についての暗黙の保証も含みますが、それに限定されるものではありません。
 signal9.exblog.jpの中の人は、その原因がいかなるものであろうと、責任の根拠が契約・厳格責任・不法行為(過失その他を含む)のいずれであろうと、本ソフトウェアの使用に起因する一切の直接損害、間接損害、偶発的損害、特別損害、懲戒的損害、派生的損害について何らの責任も負いません。
 signal9.exblog.jpの中の人が、そのような損害の発生する可能性について知らされていた場合も同様です。ここでいう損害には、代替物またはサービスの提供、使用機会、データ、または利益の喪失、業務の中断等も含まれますが、それに限定されるものではありません。
 さらにsignal9.exblog.jpの中の人は、本ソフトウェアの改良・サポートの義務を負いません。

 以上ご納得の上でしたら、どうぞ。

More
[PR]
by SIGNAL-9 | 2013-01-11 11:14 | TIPSとかKludgeとか

近デジ PDFダウンロード 「目次」に対応してみた。

 くらひと様にコメントでご質問頂いた内容に関して、自分の備忘もかねて補足しておく。

 というかホントのことをいうと、「目次」に関してはまったく頭が及んでなかったので、コメントに答える為に改めて見直してみたら「あ。できそうじゃん」と思い、ウソいってたらマズイので実際に試してみたというわけだ(笑)。

 最終コマ数を取得する為に、ビューワの画面をGETしていることは既に述べたが、このページの中にはいわゆる「書誌情報」も含まれている。
 また、このページはJavaScriptでインタフェイスを切り替えているだけで、元々1ページの中に目次の情報も含まれている。

 例によって
 http://kindai.ndl.go.jp/info:ndljp/pid/1137942
 このページをサンプルとする。

 ブラウザでこのページのソースを表示してみると、そのhtmlの中に書誌情報・目次情報が埋め込まれていることが確認できる。

 コメントにも書いたとおり;
  •  「タイトル」・「著者」・「出版者」などは、 class="simple-metadata-list"(簡易表示用)あるいは class="detail-metadata-list"(詳細表示用)とタグ付けされたブロックに含まれている。
  •  「目次情報」(がある場合)は、class="ndltree" の下に存在する。この class の startContentNo が目次のコマ数、title が目次見だしのようである。

PDFにはいくつか「目次」処理を行う手段があるが、ここではもっともノーマルな「しおり」(ブックマーク)として、ndltreeのデータを使うことを考えてみる。

 何度も繰り返しているように、本来はこの部分は構造化文書(html.xml)としてきちんとパースするべきである。だが、残念なことに.netではいわゆる「HTMLパーサー」が標準としては提供されていない。
 もちろんxmlパーサーで代用することは可能だろうが、近デジの提供するhtmlがvalidなxmlとして解釈できるかどうかがよく判らないし、真面目にhtmlパーサーを作ると面倒くさいので(爆)、例によって単なる検索で処理してみた。

 まずはndltreeブロックの明細行を検索して、PDFの「しおり」付けに必要な最低限のデータ、startContentNoとtitleを取得する。

 下の例で、DocHtmlは近デジ画面からGETしたhtmlを格納したString、TocInfoは startContentNo,Title のリストである。



string Reg_anchor =
"<input type=\"hidden\" value=\"startContentNo=(?<startContentNo>.*?)\".+?class=\"ndltree-item ndltree-label\" title=\"(?<title>.*?)\">";
Regex re = new Regex(Reg_anchor, RegexOptions.IgnoreCase | RegexOptions.Singleline);
System.Text.RegularExpressions.MatchCollection mc = re.Matches(DocHtml);

foreach (System.Text.RegularExpressions.Match m in mc) {
startNo = m.Groups["startContentNo"].Value;
Title = m.Groups["title"].Value;
TocInfo.Add(TocStartNo, TocTitle);
}



 こんな感じで、startContentNoとtitleのリストを作る。

 今回、俺はiTextSharpを使っているのだが、「しおり」生成のところはかなり悩んだ―というか、書き方がよく判らなかった(今でもよく判ってない)のだが、PDFを結合するために使用しているPdfCopyオブジェクトに、以下のダンドリで処理するとなんとなく上手くいくようである。

訂正:PdfDestinationの値がおかしかったので直した。ズームを継承するにはマイナスを入れろとドキュメントに書いてあるのでそのとおりにしたが、これでホントに良いのかどうか不安だなぁ。


ここで、copyオブジェクトはPdfCopy型であり、個別PDFを結合した結果が格納されている。


PdfContentByte cb = copy.DirectContent;
PdfOutline root = cb.RootOutline;
PdfWriter wrt = cb.PdfWriter;
wrt.ViewerPreferences = PdfWriter.PageModeUseOutlines; // しおり開くモード
PdfOutline oline = new PdfOutline(root, PdfAction.GotoLocalPage(1, new PdfDestination(0,-1.0F,-1.0F,0.0F), wrt), "Contents");
for (int i = 0; i < TocInfo.Count; i++) {
PdfOutline oline1 = new PdfOutline(oline, PdfAction.GotoLocalPage(TocInfo[i].startNo, new PdfDestination(0,-1.0F,-1.0F,0.0F), wrt), TocInfo[i].title);
}



 ようするに、copyオブジェクトのRootOutlineを取得し、そこにまずトップノード(ここでは"Contents"という見だし)を作成し、その配下(section)として、取得した目次情報を追加してしまう、という処理である。
 PDFのOutlineオブジェクトはもちろん階層化できるのだが、どうも近デジデータはフラットなデータのようなので、そのまんまループで回して貼り付けている。

 ということで、この機能を追加してはき出させたPDFはこうなる。
c0071416_13474395.jpg


 なるほど、ある種の文書はやっぱり目次があった方が圧倒的に便利である。

 気づかせて下さった くらひと様 に感謝申し上げます。
[PR]
by signal-9 | 2012-07-24 13:49 | TIPSとかKludgeとか

近デジ PDF一括ダウンローダー 自動版 一応完成

 ちょっとだけ気が向いたので、前回作ったモノを改善。

 追加したのは、
  1. PIDだけではなく、近デジの検索画面で張られるURL(http://kindai.ndl.go.jp/info:ndljp/pid/ほにゃらら)を入れたら、最後の/の後ろの「ほにゃらら」をPIDと見なして受け入れるようにした。
     自分で使ってみたら、ブラウザで検索画面を使っていて「お、これはおもしろそうだな」と思ったら、文書のリンクをそのままコピーしてコマンドラインに貼り付けるという方がラクだと気づいたので(気づくのが遅い)。

  2. PDFの結合。
     別DLLが必要になるのでちょっと迷ったが、iTextSharpをそのまんま使わせてもらった。
     最新版のVer 5.3.0でも、いわゆる「Web表示用に最適化」(Linearized PDF)には対応していないらしいのがちょっと残念だが、ローカル保存・ローカル閲覧が主目的なので無問題。
     これで、今まで使っていなかった文書名や作者名から、ファイル名を生成すると同時にPDFのプロパティに突っ込むことにした。iFilter経由で検索に使う予定。


 ブラウザで近デジ検索画面で検索して、一括DLしたい文書のURLをコピペして、バッチファイルを作成する。


TEST_KinDigDL.exe http://kindai.ndl.go.jp/info:ndljp/pid/ほにゃらら
TEST_KinDigDL.exe http://kindai.ndl.go.jp/info:ndljp/pid/ほげほげ
……


 で、適当な時間(寝てるときでもいいのだが、処理的にはスリープしてる時間の方が圧倒的に長いので、パソコン使ってる裏ででも特に痛痒感は感じない)に、このバッチファイルを動かすと、いつの間にやら本毎にPDFができているという寸法である。

 元々汚かったコードがますます汚くなったキライはあるが、個人的には結構ラクになった。
 で、いきおいで80冊くらいダウンロードしてしまったのだが、よく考えたら、こんなに読む時間がないや(爆)

 のんびりとだが、目を通せて面白かったモノは、今後このブログのネタにするつもり。
[PR]
by signal-9 | 2012-07-20 16:27 | TIPSとかKludgeとか

近デジ PDFで全部ダウンロード やや自動編

 さて、同じコトを考えてる人や実際にやってる人もいるので、何を今更車輪の再発明なのだが、前回テストした内容を一連で実行する簡単なテストプログラムを実装してみる。

 まず何で作るかであるが、Windows環境であまり面倒無く動いて欲しいのと、余り詳しくないC#の勉強方々、C# (.NET 3.5) を選択してみた。

 ざっくり仕様は以下の通り。バカみたいにプリミティブ。
  1. コマンドラインで実行する。
  2. コマンドライン引数としてPIDと書き込み先のディレクトリ(、必要に応じてプロクシのURL)を指定する。
  3. PIDによって近デジのビューワ画面にアクセスし、最終コマ数を取得する。
  4. 1から最終コマまで10コマずつ、ダウンロードのGETリクエストを発行し、戻ってきたのが"application/pdf"だったら、引数で指定したディレクトリに固定のファイル名(PIDと開始・終了コマ)で出力する。ただし、同じ名前のファイルが既にあったら、二重ダウンロードしないためダウンロードをスキップする
  5. ファイルに出力したら、30秒間スリープする

 元々の力不足に加え何も考えずにダァーっと書き下してしまったので、ヒドいコード(ホントにヒドい。つーか勉強の為と思ってC#を使ったが、あんまり勉強になってない)だが、とりあえず意図通り動くことは確認できた。

 以下は、実行時の画面のキャプチャである。
c0071416_17402865.jpg

 結果、ディレクトリにはこのようにPDFが取得できた。
c0071416_1740406.jpg

 で、作ってみた感想なのだが。
  1. 予想通りとはいえ30秒のスリープは、やはり待つ身にはしんどい。
     そこそこのPC+回線状況で49コマ取得するのに2分17秒かかっているが、都合4回スリープしてるので、その内2分、処理時間の87%はただ寝てるだけで何もしていない(笑)
     前回も書いたとおり、もう少し何とかできる余地がないわけではないが、そーゆーことは考えないことにした(爆)。

  2. Cookiesはサーバから渡されるが、何に使うものか判らないので、今のところダミーで受け取るだけにしている。
     動作的には問題ないように思えるが、ホントは解析が必要なのだろうな。

  3. エラー処理に代表されるステータス管理の部分が真面目に作ったら面倒そう。
     サーバがヘッダにセットしてくる"Reason"などのヘッダの値を使うのかもしれないが、今のところ良くわからないので、処理した結果返ってくるtext/htmlを解釈する必要があるのだろうが、このテストプログラムではいっさいネグッて、単にエラーとして読み捨てている。

  4.  気が向いたらPDFの結合まで自前でやってみたくなるかもしれないので、文書名や著者名などもいちおう取得してみたが、今は使っていない(画面に表示するだけ)。
     PDFの結合処理などはiTextみたいな便利なライブラリがあるので、そんなに大変ではないのはわかってるのだが、今は気が向いてないので放置。
     で、この辺の文書情報も仕方なくHTMLを読んで取得しているが、APIとしてサポートするべきだと思う。

 まとめると、やはり根本的には近デジがいわゆるWeb API的な設計ではないことはやはり問題だと思う。

 そのうちに海外の同種のサービスと比べられて、みんな侘しいキモチになりそうなので、次回リファインの際にはこのあたりガンバッてもらいたいものだ。

 つーかその前に10コマ/30秒制限の撤廃を希望。

 …ということで、ものすご~くニッチな用途だしテスト用(俺個人用)だし、酷いバグが残っていることが確実(ぉい)なので、公開は控えておくが、欲しい人いるかなぁ?

 とりあえず、コメント付いたら考えることにする(^^;)
[PR]
by signal-9 | 2012-07-11 17:44 | TIPSとかKludgeとか

近デジ PDFで全部ダウンロード 半自動編

【検索ジャンパーの方のための追記】
「結局どうなったのか」だけお求めの方は、こちらの記事をご参照ください。


 「近デジ」こと「国立国会図書館 近代デジタルライブラリー」は本好きにとってはお宝の山と言えるわけだが。

 こういうものはどんどん称揚・翼賛すべきなんであろうが、近年リニューアルされたシステムでも相変わらず、「一冊全部ダウンロード」しにくいのは非常に不満なのである。

 元々データ化することが価値であるし、システムもかなりガンバッてリファインしてくれたのは認めるし、「今の時代だったらオンライン閲覧できればいいじゃん」というのはごもっともなのだが、やっぱり一冊纏まったPDFでローカルに持っておきたいというのが人情というモノだろう…って俺だけかもしれないが。

 「近デジ」ではPDFでダウンロードする手段は標準でサポートされているが、性能上の理由で
  1. 10コマ(ページ)単位でないとダメ

  2. 1回のダウンロード毎に30秒程度アクセス間隔を空けないとダメ
という、中々にシブちんな仕様なのである。

 こういう、単純にスケールアウトで解決できるであろう問題は、そんなにバカみたいにカネはかからないはずだと思うのだが、そこはそれ、天下の国会図書館なので、俺のごとき愚民が思いもよらぬような大人の事情がきっとあるのであろう。

 ブーブー文句を言ってても仕方がないので、無いのなら作ってしまえホトトギス、とりあえず一冊全部まとめてダウンロードするにはどうしたらよいか、ちょっと調べ始めたわけである。

 例として、

 「太古日本のピラミッド 酒井勝軍 著 (国教宣明団, 1934)」

 をまとめてダウンロードすることを考えてみる。
 「なんでよりにもよってそんなヘンな本が例なの?」とかそーゆーことは気にしないように。

(1) PIDを確認する。

 ダウンロードしたい文書のPID(つまり文書番号)を調べる。
 この番号は、「検索結果」の文書名のリンクを見ればわかる。
c0071416_17304482.jpg

  http://kindai.ndl.go.jp/info:ndljp/pid/1137942

 この一番最後の「1137942」が「太古日本のピラミッド」のPIDである。

(2) 最終コマを確認する。

 上のリンクをクリックして、ビューワーが表示されると、その文書の最終コマ数がコマ数指定のドロップダウンの横に表示される。

c0071416_17302822.jpg


 この値はソースのhtmlでいうと フォーム "form-item-information" の lastContentNo の値なので、自動化する場合はこれを取得すれば良さそうだ。

 なぜこの「最終コマ数」が必要なのかというと、近デジの現在のビューワーの「印刷」(PDFはこれで返してくる)の機能は、以前と違い、コマオーバーした時にはエラーを示すhtmlを返すように変更されたようだからである。
 俺の記憶では、以前は確かオーバしていてもコマ数の終わりまではダウンロードしてくれていた。これはシステム的には改悪と評価せざるを得ない。

 この文書の場合、最終コマは49なので、例えば最終ペ-ジまで取得したくて、41-50 と指定するとエラーが発生する。この場合、41-49としなければいけない。


【2012/07/13訂正】
「お知らせ」によれば、
「「印刷する」ボタンによるPDF出力の際、終了コマを省略した場合は上限まで出力するようにしました。
例)コマ数「1-」と入力 → 1コマ目から最大出力コマ目までを出力。全コマ数がそれ以下の場合は、最終コマまで出力。
とのことだった。記述に気がつかなかった俺の完全な誤認だったので、この直前の段は撤回する。

 エラーになると、application/pdfではなく text/htmlを返してくるので、エラー処理を自動にする場合にはresultのcontentsTypeがapplication/pdfであるかチェックするといった方法が必要だろう。

(3) 「印刷」(PDF出力)で行われていることを調べてみる。

 ビューワーの「印刷」を使い、1から10コマをPDFでダウンロードする操作で、どのようなリクエストが近デジサーバに行われているのかを見てみると;

http://kindai.ndl.go.jp/view/pdf/digidepo_1137942.pdf?
pdfOutputRangeType=R&pdfPageSize=&pdfOutputRanges=1-10


という GETリクエスト であることがわかる(戻りはApplication/pdfのストリーム)。

 つまり、

http://kindai.ndl.go.jp/view/pdf/digidepo_【PID】.pdf?
pdfOutputRangeType=R&pdfPageSize=&pdfOutputRanges=【開始コマ】-【終了コマ】


 これで、PDFが戻ってくるわけだ。どうやら積極的にクッキーを使っている節もない、単純なGETリクエストである。。

 一回のアクセスで最大10コマまで取得できるので、先頭の1コマ目から、49コマを最後まで取得するには;
pdfOutputRanges=1-10
pdfOutputRanges=11-20
pdfOutputRanges=21-30
pdfOutputRanges=31-40
pdfOutputRanges=41-49

という5回のGETリクエストを繰り返せばよいようだ。

 ただし、一回ごとのリクエストの間は30秒以上空けろ、という条件がある。

 「今の時代に30秒間隔ですか!」という悪態はとりあえず飲み込んでおこう。
 どのみちこの間隔はサーバ側でチェックされており、短い間隔で3回ほどリクエストすると、エラーになってダウンロードできなくなる。

 まあ、この制限を誤魔化す手はいくらも考えられるが、岡崎図書館事件を忘れてはいけない。

 いきなり威力業務妨害容疑で引っ張られて拘留取り調べなんてことにはなりたくないので、一回ごとのリクエストには必ず30秒スリープするようにしよう。

 コマ数が多い文書だとかなり時間がかかることになるが、そこは我慢である。

(4) テスト。

 ここまで判ったことで、実際に問題なくダウンロードできるか試してみよう。
 いきなりスクリプトだのプログラムだのを作るのは面倒なので、適当なありもので試してみることにする。

 必要なのは、指定したURLにGETを発行して戻りをファイルに保存する何か取得した複数のPDFをひとつに結合する何か、である。

 どちらもフリーウェアで適当なものが入手できるはずだ。

 ここでは手前味噌だが、一例として拙作のhttpget.exeを使ってみる。
httpget "http://kindai.ndl.go.jp/view/pdf/digidepo_1137942.pdf?pdfOutputRangeType=R&pdfPageSize=&pdfOutputRanges=1-10" DUMMY01.PDF
sleep 30
httpget "http://kindai.ndl.go.jp/view/pdf/digidepo_1137942.pdf?pdfOutputRangeType=R&pdfPageSize=&pdfOutputRanges=11-20" DUMMY02.PDF
sleep 30
httpget "http://kindai.ndl.go.jp/view/pdf/digidepo_1137942.pdf?pdfOutputRangeType=R&pdfPageSize=&pdfOutputRanges=21-30" DUMMY03.PDF
sleep 30
httpget "http://kindai.ndl.go.jp/view/pdf/digidepo_1137942.pdf?pdfOutputRangeType=R&pdfPageSize=&pdfOutputRanges=31-40" DUMMY04.PDF
sleep 30
httpget "http://kindai.ndl.go.jp/view/pdf/digidepo_1137942.pdf?pdfOutputRangeType=R&pdfPageSize=&pdfOutputRanges=41-49" DUMMY05.PDF


 というバッチファイルを作る(実際はループで回すべきだが、ここでは説明の為ベタ書き)。

 これを動かして、カレントディレクトリにDUMMY01からDUMMY05.PDFの5個が出来れば成功である。

 後は必要に応じてPDFを結合すればいい。PDF結合ツールは本家 Acrobat X 始め色々あるのでお好きなモノを。

 とまあ、以上のように近デジダウンロードは比較的単純であることが判った。

 もちろん、フツーの人はいちいちバッチファイルを作るようなことはしないで、WSHでもPowerShell、ExcelのVBAでも、要は http get が出来るモノで汎用的なツールを作成するのがよいだろう。

 ということで次回は簡単なコマンドラインプログラムを作ってみる予定。予定は未定。
[PR]
by signal-9 | 2012-07-10 17:36 | TIPSとかKludgeとか

備忘:C#でちょっとヘンなところ。【撤回】


 このエントリを書いたときには完全にボケていた。
 事実誤認に基づく曲解が含まれておりデタラメなので撤回する。

 自分への戒めとしてこのまま晒しておくが、内容はダメのダメダメなので読まないで下さい(爆)


久しぶりに(年甲斐もなく)ちょっと小さなツールを作っていた。

ディレクトリを指定して、子どものディレクトリを全部ナメて、jpegファイルを探して、EXIFが付いていたらその撮影日を取得してファイル名をリネームし…みたいな、ありがちなものなのだが。

(1) C#のコマンドライン引数の解釈、ヘンじゃないか?
 
特になにも考えずに
Main(string[] args)
で、args[0]、args[1]と取ろうとしたら、値が期待とずれている。

foo "C:\Program files\" "c:\bar baz\dammy.log"

とやった場合、第一パラメータ "C:\Program files\" は

C:\Program と files"

と解釈されるようだ。

ようするに、2個目の\がリテラルのエスケープと解釈されてるわけだが、これって前(Win32)からそうだったけ? ちなみにEnvironment.GetCommandLineArgsを通しても同じ解釈である。

まあ、

foo "C:\Program files" "c:\bar baz\dammy.log"

にすりゃ良いといえば良いのだが、なんか違和感を感じるんだよなぁ。

(2) System.IO.PathTooLongException

もうひとつ、こっちはちょっと俺的には致命的。
System.IO.FileやDirectoryでは、例えばFileInfoなどでSystem.IO.PathTooLongExceptionつー例外があって、これ見逃してたのだが、いわゆるLong UNCつーの? MAX_PATHの制限があいかわらず260バイトなんだな。

 これは困った。

 深いディレクトリ(作れてるんだからOSは一応サポートしてるはず。エクスプローラとかでも操作はできないが)が.NETからだと読めない書けない (つーか実現する手段が思い浮ばない)。
System.IO.FileやDirectoryはstaticなのでInheritもできないし、けっきょくWin32のお世話にならなきゃいけないの?

…Win32のラッパ作るほど暇ではないので、.NETにはお引き取り願った今日この頃です(爆)
[PR]
by signal-9 | 2012-06-25 17:52 | TIPSとかKludgeとか

ThunderBird 2.0のアドレス帳に自前のLDAPサーバを指定する

以下、prefs.jsとかの知識がある前提での覚え書き。
  1. 検索フィルタの指定を行う

  2. 単一のLDAPサーバでもフィルタ条件を変えたエントリを複数用意しておくと、便利な場合がある。例えば「全社」のデータが入っているディレクトリがある場合、フィルタ無しの全社とは別に、自分の所属する組織だけフィルタしたエントリも作っておく、的な。
    LDAPサーバのプロパティの名前を変えて同じサーバを複数登録し、普通に「LDAPディレクトリサーバのプロパティ」→「詳細」→「検索フィルタ」でいちおうRFC2254っぽくフィルタを書ける。
    例えば、

    全社:(&(mail=*)(objectclass=*))

    特定のドメインの人だけ:(&(|(mail=*\@foo\.*)(mail=*\@baz\.foo\.*))(objectclass=*))

    特殊文字(@やドット)のエスケープは自分でやらないとダメ(な場合があるみたいなのでやっとくのが吉)。
    また、ちょっと複雑なものを書くとクラッシュする場合もあるようなので慎重に。

  3. Mozilla定義のアトリビュート名と自分のLDAPがあっていない場合

  4. 昔の Netscape4.xx だと

    user_pref("ldap_2.servers.myldap.attributes.cn", "氏名:cn;lang-ja,cn");

    みたいに指定できたが、ThunderBird2.0 でもMozilla定義のアトリビュート名→自分のアトリビュート名の対比を指定する。

    例えばMozillaで"Company"と定義されている会社名データが、自分のLDAPでは"companyname"という名前だった場合;

    user_pref("ldap_2.servers.myldap.attrmap.Company", "companyname");

    という定義を追加する。

    ただし現在のバージョン(2.0.0.23)では言語サブタイプがついている場合には複数のアトリビュートは指定できないみたいだ(Netscapeでは可能だった)。

    user_pref("ldap_2.servers.myldap.attrmap.DisplayName", "cn;lang-ja,commonname"); // これはNGだった

    この場合、";lang-ja"を除くか、"cn;lang-ja"だけにすると動作する。

  5. 送信メール作成画面の宛先指定欄のドロップダウンリストに、例えば「会社名」とか「組織名」みたいな付加情報を付けたい

  6. デフォルトだとDisplayName(名前)とメアドしか表示されないので、同姓同名が多い巨大ディレクトリの場合、「はてこの人どこの誰だっけ」となるのが面倒。

    user_pref("mail.autoComplete.commentColumn", 2); // 1 にすると、検索しているディレクトリ名が表示されるので、2にする。

    これでコメントカラムが有効になるので、そのコメントのフォーマットを、参照している自分のLDAPのアトリビュート名に変更する。LDAPのアトリビュート名は[]で括れば指定できるようである。;

    user_pref("ldap_2.servers.myldap.autoComplete.commentFormat", "[divisionshortname;lang-ja]");
    user_pref("ldap_2.servers.myldap.autoComplete.nameFormat", "[cn;lang-ja]");

参考になるサイト
LDAP in Mozilla Thunderbird
Mail and news settings
アドレス帳の隠し設定
[PR]
by signal-9 | 2009-09-18 12:50 | TIPSとかKludgeとか

Proxy.pacをCGI(ASP.NET)でユーザ毎に切り替えてみるテスト。

 Proxy.pacで利用者にプロキシ設定を配っているのだが、「人によってその設定を変えたい」という話。
 例えば、ユーザAでログインした場合にはA-プロキシを使わせ、ユーザBだったらB-プロキシを使わせ…というのをどうしたらいいか。

 いちいちログイン画面出して…つーのはNGだし、お金もかけたくないからアリモノだけでなんとかしたい。

 もちろん、マトモな方法としては グループ・ポリシーでProxy設定を行うなどの方法が正解なのはわかってるのだが、ちょっと思いついたのが、Proxy.pac自体をロードする時にユーザIDに応じて差し替えちゃえばいいんじゃね?というアイディア。

 既存のProxy.pac共有サーバは、利用者と同じドメインに入っているIISなので、とりあえずはそのまんまWindows認証を流用してみることにする。

  1. IISに統合Windows認証ありの仮想ディレクトリ ProxyPac を作成する。

  2. URL: http://myserver/ProxyPac/
    なぜ認証ありにするかというと、WindowsのログインユーザIDをキーに処理を振り分けるため。IEとFireFoxでは統合Windows認証(NTLM)の時にはパススルー(ダイアログ無し)でログインできるので、その機能を使う。本当はちゃんとweb.configを使う方がいいんだろうが、仮想ディレクトリのプロパティで設定。利用者は同じドメインのユーザなので、このディレクトリにはアクセスできる。

  3. テスト用のスクリプトを用意。やることはProxy.PACファイルをMIMEタイプを付けてクライアント返すこと。

  4. 例えばこんな感じ(以下は例のための例)。ファイル名はProxyPac.aspxとする。

    protected void Page_Load(object sender, EventArgs e) {
    string uname;
    string filename;
    uname = HttpContext.Current.User.Identity.Name; // ドメイン名¥ユーザIDが返る
    if ( uname == "mydomain\\userID" ) { // ¥記号はエスケープね
    filename = MapPath("Special.pac"); // 特別なプロキシ設定ファイル
    } else {
    filename = MapPath("Normal.pac"); // 標準的なプロキシ設定ファイル
    }
    if(System.IO.File.Exists(filename)) {
    System.IO.FileInfo fileInfo = new System.IO.FileInfo(filename);
    long nSize = fileInfo.Length;
    Response.Clear();
    Response.ContentType = "application/x-ns-proxy-autoconfig"; // pacのMIMEタイプ
    Response.WriteFile(filename, 0, nSize);
    Response.End();
    }
    }
    ここではあらかじめ用意した別ファイルの設定ファイルを読み込んで返しているが、実際にはPAC単体のデバッグが終わったらASPXの中にハードコード(コピペ)しちゃう方が速度的に有利かも。
     つーか、俺的には最終的にやりたいのは人+URLなどの諸条件によってダミーのプロクシに飛ばして…みたいなことなんで、得られたIDでADを引き直して、取得した条件でJavascriptを動的に書き換えて…的なことをやっている。

  5. IEブラウザ側で、このサーバ(myserver)を明示的にイントラネットに属させる。

  6. 「インターネットオプション」→セキュリティ→ローカルイントラネットの「サイト」→詳細設定で、myserverを登録する。

     これをやらないと、たぶんIEを立ち上げた都度、プロキシファイルを読み込むために認証ダイアログが出る。おそらく、起動したときにはプロキシ情報が読み込まれていないため、そのサーバがイントラなのかどうか判断が出来ないためだろう。

     ちなみにFireFoxの場合、元々NTLMの自動ログインを有効にするためにはnetwork.automatic-ntlm-auth.trusted-urisにmyserverを登録する必要があり、その設定だけで大丈夫みたい。

  7. ブラウザ側で自動プロキシ設定URLを http://myserver/ProxyPac/ProxyPac.aspx に切り替えてテスト。

  8. 試したのはIE8とFireFox3.5だけ(今回のターゲットがそれしかないんで)

挙動的にはよさげだが、保守運用がめんどくさいかなぁ。
[PR]
by signal-9 | 2009-09-15 18:02 | TIPSとかKludgeとか

WSS3.0(Windows SharePoint Service)のトラブルシュート。

 こういう仕事は基本的に受けないのだが、加藤あい似の担当者の女性の美脚に迷ってウカウカと受けてしまったWindows SharePoint Serviceの立ち上げのお手伝い。

「インストールは終わって画面はちゃんと出るし操作もできるので、基本的な設定はできてると思うんですが検索機能が動かないんです」

「はあ」
(ううううううんミニスカは目の毒だなぁウレシイけど)

「よく見てみたら『イベントビューワー』に何かエラーも出てるし」

「はあ」
(なんつーかこのミニスカつーの発明した奴にはノォベル賞をやりたいよなマジで)

と、脳内勃起していても仕方ないんでちょっとググッみると、確かにちょいと問題があるようである。

■問題:「WSS3.0で基本認証のみ有効のサイトは検索エンジンがクロールできない」
 単純に言うと;
  1. WSSの画面でいくら検索をかけても結果が表示されない
  2. イベントビューワにエラーコード 2436 などが表示されている
 これはMSのサイトでも明示されているとおりの仕様ではある。このクローラは認証にフォームやBASICを使っていると使用できない。

 で、どうするかなんである。困っている美脚を放置するなんてことができるか? いやできはしないのである!

 確かに上のMSのサイトには(日本語のものは明らかに誤訳-フォーム認証の訳をそのまま引きうつしている-なので、英語版を参照のこと)手順が書いてあるが、この「手順」を読んでそのまんま理解できるやつはそう多くはなかろう。
 というか、明らかに不備がある。日本語のは論外としても英語版でさえ説明不足もいいところである。

 Webを漁ると、いくつか解決策を提示しているサイトもある。例えばCodenameさんのBlogとかquick2seekさんのサイトとか。
 だが、WSSという仕掛けはネットワーク含めた環境の設計がけっこう重要な要素で、この環境で上手くいったからそのまんま適用できるというわけでもない。美脚もこのあたりはやってみたらしいのだが上手くいかなかったと。

「うううううん。基本認証諦めるってわけにはいかないんですか? 元々イントラで使う仕掛けだし御社はちゃんとAD動いてるし」

「それがこのサーバ、運営委託していてhttpアクセスには必ずプロキシを経由しなきゃいけないんですぅ」

「…ヤリイカかぁ。こりゃあWindows認証は通らないわなぁ」

 ファーム構成つーことになると話は厄介だが、幸いなことに単純なシングルサーバだ。
 で、こうしてみた。

 話の都合上、サーバ名(NetBios名)をfoo, DNS名をfoo.bar.co.jpとする。
  1. まずインストール時にWSSが勝手に作ったSharePotal-80 Webアプリケーションを削除。
    別にそのまま使ってもいいのだが、美脚が弄り回した環境をいったん綺麗にしちゃいたいので(笑)
  2. Webアプリケーションを自前で作成しなおす。
     「アプリケーション構成の管理」→「Webアプリケーションの作成または拡張」→「新しいWebアプリケーションの作成」
     新しいIISWebサイトを作成する
     ポート80 / ホストヘッダ指定なし
     認証プロバイダ:NTLM
     URL:/foo.bar.co.jp:80
     検索サーバ:foo
  3. 「アプリケーション構成の管理」→「Webアプリケーションの作成または拡張」→「既存Webアプリケーションの拡張」で、上で作ったWebアプリケーションを拡張する。
     「新しいWebサイトを作成する」:ただしこのときポートは上で使っていたのと変えてしまう。ここでは9080を指定。
     ポート9080 / ホストヘッダ指定なし
     認証プロバイダ:NTLM
     URL:foo.bar.co.jp:9080
     「領域」:イントラネット
  4. 「認証プロバイダ」で、
     「規定」サイトが「匿名アクセスの有効化」・統合Windows認証であることを確認。
     「イントラネット」を「匿名アクセスの有効化」「基本認証」をON

    この状態で、IISの管理画面でディレクトリセキュリティを確認すると
    foo.bar.co.jp:80 → 匿名許可・統合Windows認証
    foo.bar.co.jp:9080 → 匿名許可・基本認証
    になっているはず。
  5. iisreset。

 大筋こんな感じで。

 つまり、どうもmssearchは領域「規定」で定義されたサイトをクロールするようなので、そこだけNTLM認証にし(http://foo.bar.co.jp:80)、一般アクセスには同じサイトをポートを変えて見せてしまう(http://foo.bar.co.jp:9080)というセンである(今考えたらポート番号が逆の方がよかったなぁ)。

 これで良しとは思わないが-「ファームにしたい」なぁとか思った瞬間に破綻する-、とりあえず検索できるようになり美脚からソンケーの眼差しで見られたので、これでいいや(爆)

 で、美脚ともう暫く過ごしたかったので、ついでに細かい問題も。

■PDF検索設定
  1. IFilter入手&インストール。このとき合わせて17×17ドットのアイコン(pdficon_small.gif)も入手しておく。
  2. すでにWSSが導入済みで、Searchが動いている場合には一時停止
  3. MSの資料どおりレジストリの設定
    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shared Tools\Web Server Extensions\12.0\Search\Applications\GUID\Gather\Search\Extensions\ExtensionList\
    38
    REG_SZ
    pdf
    を新規作成。
  4. 前で入手したアイコンGIF(pdficon_small.gif)を \Program Files\Common FIles\Microsoft Shared\Web Server extensions\12\TEMPLATE\IMAGES にコピーする。
  5. \Program Files\Common FIles\Microsoft Shared\Web Server extensions\12\TEMPLATE\XML にあるDOCICON.XMLのセクションに以下の行追加。
    <Mapping Key="pdf" Value="pdficon_small.gif" OpenControl=""/>



  6. できればサーバ再起動(できなければsearchサービスを起動)。
ちなみにフルクロールはcmdで
stsadm -o spsearch -action fullcrawlstart
だが、この設定をやる前にすでにアップ済みのPDFがある場合には、フルクロールしても対象にならない模様。
事前登録済みのPDFファイルは削除して再登録が確実。

■XML Webパーツで「タイムアウト」が発生する

 外部のニュースサイトを設定してFeedを表示させようとしたら「Webパーツがタイムアウトしました」が出る。

 この話はMSの解説にもある。
  1. WSSのweb.config(IISからみるとwebroot/VirtualDirectory配下のサイト個別のweb.config)をエディタで開く
  2. 以下のセクションを追記する
    <system.net>
    <defaultProxy>
    <proxy proxyaddress="http://プロクシ:ポート" bypassonlocal = "true"/>
    </defaultProxy>
    </system.net>



  3. iisreset
 XML Webパーツを配置して、適当なニュースサイト(こことか)を指定して、適当なxsltを設定してやったらウマいことニュースが表示された。

 「すっごーい」

 「はは。いやいや。でもこれだと毎度毎度読みに行っちゃうんで、ホントはサーバ側で適当なタイミングで取得したデータを表示するだけにした方がいいと思いますよ。ちょっとしたスクリプトを作らないとだめですけど」

 「…えっと、よくわからないんですけど」

 あああああああああああカワイイなあ畜生しようがねぇオジサン作っちゃおうかなぁオネエちゃん綺麗だし(爆)
[PR]
by SIGNAL-9 | 2008-07-31 12:04 | TIPSとかKludgeとか