PDF を R2L へ変換するコマンド作成 (Rust 編)

以前 PDF を R2L にする方法を調査したのですが、もっと簡単にインストールできて使えるコマンド形式にしてみます!

いい加減に何かに使いたいと思っていたので Rust 書こうと思いまして調べてみるとライブラリがあったので試してみます。

意気込んだのはよかったのですが、コピーを作成するだけでも10数秒かかってしまったので断念です。

僕の Rust の書き方が悪いのか(゚∀゚)?

J-F-Liu/lopdf: A Rust library for PDF document manipulation.
lopdf – Cargo: packages for Rust

extern crate lopdf;
use lopdf::{Document, Object, Dictionary, Stream, StringFormat};
use lopdf::content::{Content, Operation};
use Object::Reference;
use std::iter::FromIterator;

fn main() {
    let mut doc = Document::load("ex1.pdf").unwrap();
    doc.save("modified.pdf").unwrap();
}

PDF を R2L (右綴じ) にする方法

最近自炊をしているのですがマンガは大体右綴じになっています。
なのですが、ScanSnap のソフトで PDF にすると左綴じになってしまいます。
おそらく PDF の仕様で、指定がないと左綴じがデフォルトということだと思ってます。

このままだと PDF 対応のアプリを使っても逆にスクロールしてしまいます。
なので右綴じに変更する方法を調べてみました。

調べる前はコマンドでもあるのだろうと思っていたのですが、なかなか手軽そうなものがありませんでした。
色々調べた中である程度取っ付きやすそうな Python にしました。

Python の pdfrw

https://github.com/pmaupin/pdfrw

基本的には
https://hanepjiv.blogspot.jp/2014/11/pdfpython.html
こちらの方が作成されているものを使ったのですが、ScanSnap からの PDF だと、うまく動作しなかったので、pdfr2l 関数をちょっと調整しました。

def pdfr2l(a_src, a_dest):
    """
    pdfr2l
    """
    # --------------------------------------------------------------------------
    src = PdfReader(a_src)
    dest = PdfWriter()

    # dest.addpages(src.pages)

    dest.trailer = src

    # print dest.trailer.Root

    if dest.trailer.Root.ViewerPreferences:
        dest.trailer.Root.ViewerPreferences = PdfDict(Direction=PdfName.R2L)
    else:
        dest.trailer.Root.ViewerPreferences = PdfDict()
        dest.trailer.Root.ViewerPreferences.Direction = PdfName.R2L

    dest.trailer.Root.PageLayout = PdfName.TwoColumnRight

    dest.write(a_dest)

具体的には
dest.addpages(src.pages)
をコメントアウト。
dest.trailer.Root.ViewerPreferences = PdfDict()
を追加しました。

本家が bitbucket なのですが普段から GitHub の方しか使っていないので GitHub の方へ調整した版をあげました。
https://github.com/INORIA/pdf-r2l-script

その他の方法

Adobe Acrobat

有料ですが一番安心のソフトです。ただし、一冊一冊対応しないといけないので増えてくると大変です。
プログラムを書くのが面倒、または書けないという方はこちらを使うことになります。

Perl の PDF::API2 モジュール

http://toga.vegalta.org/wordpress/2016/05/15/830

PHP の TCPDF

http://tohokuaiki.hateblo.jp/entry/set-binding-direction-with-tcpdf
https://github.com/tecnickcom/tcpdf

Java の iText

http://d.hatena.ne.jp/kiwanami/20101215/1292400269

所感

なかなか面倒です。普通にバイナリ一発でできるコマンドとか提供してくれていると楽なのですが∧( ‘Θ’ )∧

参考

http://www.adobe.com/devnet/pdf.html

http://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/pdf_reference_1-7.pdf

時刻更新時に the NTP socket is in use, exiting というエラーメッセージ

時刻の更新を行おうとして ntpdate で更新しようと以下のコマンドを入力しました。

ntpdate ntp1.jst.mfeed.ad.jp

そうすると、以下のエラーが発生しました。

 5 Mar 23:13:28 ntpdate[2322]: the NTP socket is in use, exiting

どうやら更新に利用するソケットが ntp もしくは ntpd によって使用されているので更新に失敗しているようです。
時刻更新用のサーバーが稼働しているので放っておけば勝手に更新されるとは思いますが、強制的に更新させます。

ntp サービスを停止させます。(RedHat や CentOS 系なら ntpd になると思います)

service ntp stop

先ほどのコマンドを実行します。

ntpdate ntp1.jst.mfeed.ad.jp

今度は更新されるはずです。
更新が終わると ntp サーバーを稼働させます。

service ntp start

これで時刻を強制的に更新することができました。

JavaScript でファイルダウンロードさせる

JavaScript で動的に作成した CSV ファイルをダウンロードさせる為に window.location = ‘url’; などでリダイレクトをかけていたのですが、これを実行した時点でページの読み込みが終了してしまいます。

iframe を利用したリダイレクトがあったので利用してみました。
http://stackoverflow.com/questions/3749231/download-file-using-javascript-jquery

var downloadURL = function downloadURL(url) {
    var hiddenIFrameID = 'hiddenDownloader',
        iframe = document.getElementById(hiddenIFrameID);
    if (iframe === null) {
        iframe = document.createElement('iframe');
        iframe.id = hiddenIFrameID;
        iframe.style.display = 'none';
        document.body.appendChild(iframe);
    }
    iframe.src = url;
};

行っていることは、’hiddenDownload’ という ID の要素があれば取得、なければ iframe を作成してその iframe の src にファイルのURL を指定しているようです。

CSV のファイルURLが https://blog.gfb.io/list.csv だとすると、以下のようなコードになります。

downloadURL('https://blog.gfb.io/list.csv');

この関数を実行すると、ダウンロードが開始されてページの読み込みも問題なく継続されました。

ただ、そのまま更新ボタンを押すとまたダウンロードが開始されるのをどうしようかと思っています。

WordPress の管理者権限

WordPress の管理者権限について調べてみました。

WordPress 1.0 系の初期の頃には、User Levels というもので権限管理を行っていたようです。しかし、柔軟性がないなどで今(最新版は 3.8.1)は、ロールとケイパビリティというもので管理を行っているようです。

ロール(role)

ロールというのは、

特権管理者
管理者
編集者
投稿者
寄稿者
購読者

などというユーザーに対して割り当てることのできるものです。割り当てられたロール(役割)によって管理画面で行えることが限られてきます。

ケイパビリティ(capability)

ケイパビリティというのは、これはある操作を実行する権限を表していて、ロールに対して割り当てることができるものです。

例えば “購読者” というロールは “read” というケイパビリティを持っています。
read というケイパビリティは管理画面のダッシュボードとユーザーのプロフィールを閲覧することのできる権限です。
なので “購読者” は管理画面で ダッシュボードと自分のプロフィールを閲覧することができます。逆にいいますと、それしかできません。

投稿者になると、投稿に必要なケイパビリティは一通り持っています。

記事の削除(delete_posts, delete_published_posts)
記事の編集(edit_posts, edit_published_posts)
記事の公開(publish_posts)
ダッシュボードとプロフィールの閲覧(read)
ファイルのアップロード(upload_files)

まとめ

WordPress の権限管理はロールとケイパビリティというものを使用して、ケイパビリティという単位で権限をロールに対して割り当てて、そのロールのユーザーを作成することで権限管理をおこなっています。

[GAE] 初期状態を触ってみる – ハンドラ追加

前回、初期状態のGAEアプリケーションを眺めてみました。今回は、初期状態に手を加えて見ようと思います。

初期状態では、http://[domain]/ へのアクセス、つまりルートへのアクセス時のみ Hello world! を表示するようになっていました。
今回は、http://[domain]/ja へアクセスしたら “こんにちは!” と表示するようにハンドラを追加してみます。

初期状態で MainHandler というクラスがあるので、その中身全てまるまるその下にコピーします。そしてクラス名を MainJAHandler に変更します。

class MainHandler(webapp2.RequestHandler):
    def get(self):
        self.response.write('Hello world!')


class MainJSHandler(webapp2.RequestHandler):
    def get(self):
        self.response.write('Hello world!')

これでハンドラの追加が出来ました。しかしこれでは、 Hello world! と出力されますので、 'Hello world!' の部分を u'こんにちは!' に変更します。これだけで “こんにちは!” と出力するハンドラが完成しました。

次に、ソースコードに日本語(マルチバイト)が追加されたので、文字コーディングを指定してあげないといけません。

# coding: utf-8

上記の一行を main.py の2行目付近に追加してください。

最後にルーティングを追加します。現状のままでは、 “/” (ルート)へアクセスが合った場合 MainHandler に処理が送られるようにしかなっていません。なのでそこに “/ja” へアクセスがあった場合、MainJAHandler を使用するように指定してあげます。
webapp2 の WSGIApplication へ新たなルーティングを追加します。

('/', MainHandler)の次に , ('/ja', MainJAHandler) を追加します。

これで、全ての作業が終了です。出来上がったコードは以下になります。

#!/usr/bin/env python
# coding: utf-8

import webapp2


class MainHandler(webapp2.RequestHandler):
    def get(self):
        self.response.write('Hello world!')


class MainJAHandler(webapp2.RequestHandler):
    def get(self):
        self.response.write(u'こんにちは!')


app = webapp2.WSGIApplication([
    ('/', MainHandler), ('/ja', MainJAHandler)
], debug=True)

あとは、Google App Engine Launcher で起動して / と /ja にアクセスしてそれぞれ Hello world! , こんにちは! と表示されていると完成です。

[GAE] 初期状態を眺めてみる

前回作成した、Google App Engine Launcher の初期状態のアプリケーションを眺めて理解しようと思います。

前回作成した状態で Parent Directory で指定したフォルダにあるファイルは以下の4つになります。

アプリケーションを Run するとmain.pyc も作成されていると思いますが、これは main.py から自動で作成されたファイルですので今回は関係ありません。

app.yaml

GAE を利用する際に必ず必要なアプリケーションの設定ファイルです。
中身は次の用になっています。

application: python-basic-wsgi
version: 1
runtime: python27
api_version: 1
threadsafe: yes

handlers:
- url: /favicon\.ico
  static_files: favicon.ico
  upload: favicon\.ico

- url: .*
  script: main.app

libraries:
- name: webapp2
  version: "2.5.2"
application
アプリケーション固有の識別子です。名前と言ってもいいと思います。
version
アプリケーションのバージョン番号です。
runtime
動作する言語を指定します。python だけだと古いバージョンの Python の環境で動作するので 2.7 を使用するには python27 と指定しなければなりません。
api_version
使用する API のバージョンです。現状は 1 で問題ないようです。
threadsafe
yes で同時リクエストを利用するようになります。
handlers
リクエストされたURLをどのように処理するのかを設定します。

url
リクエストされた url がマッチする場合それ以下の指定に従って処理されます。正規表現を使用します。

static_files
urlにマッチしたものを指定した静的ファイルへのアクセスとして処理します。正規表現を使用します。
upload
Googleのサーバーにアップロードするファイルを指定します。参考
libraries
使用するライブラリを指定します。サードーパーティのライブラリを使用する際にも指定します。

初期設定で設定されている動作は、
http://…/favicon.ico というリクエストがあった場合は /favicon.ico というファイルを参照してください。
アップロードするファイルは favicon.ico です。

それ以外の全てのアクセスは main.app スクリプトを使用して処理してください。(main.app は main.py の app 変数を利用してくださいという意味です。)

という感じになります。

favicon.ico

favicon.ico はアイコンのページのアイコンのようなもので、Chrome だとタブの左に表示されている小さな画像になります。

index.yaml

アプリケーションで利用するデータストアのクエリ使用するインデックスが記述されるファイルです。単純なクエリ用には自動で生成されるので、今はなにも記述する必要はありません。
参考

main.py

これが Hello world! と出力するだけの WSGI アプリケーションのコードが記述されている python スクリプトになります。

import webapp2

class MainHandler(webapp2.RequestHandler):
    def get(self):
        self.response.write('Hello world!')

app = webapp2.WSGIApplication([
    ('/', MainHandler)
], debug=True)

MainHandler というリクエストを扱うクラスを定義します。
それを ‘/’ というリクエストの際に使用するという設定の webapp2 の WSGI アプリケーションを app という変数に代入しています。

app という変数に代入しただけで動作しているのは、app.yaml

- url: .*
  script: main.app

と指定しているためです。main.app は main.py の app 変数を利用することになります。

メニュー

[GAE] 初めてのWSGIアプリケーション

参考

http://d.hatena.ne.jp/matsuza/20080413/1208092235
https://developers.google.com/appengine/docs/python/config/appconfig

[GAE] アプリケーションの新規作成 – 基本のWSGIアプリケーション

GAEを利用して WSGI アプリケーションを作成するには、GAE用のフレームワーク webapp2 を使用します。

まず GAE 用に作成したアプリケーションを Google のサーバーに Deploy するために、Google App Engin SDK For Python をダウンロード、インストールします。
https://developers.google.com/appengine/downloads#Google_App_Engine_SDK_for_Python

Google App Engine Launcher というソフトがインストールされるので、これを使用していきます。

アプリケーションの新規作成

アプリケーションを新規作成するには、Google App Engine Launcher を起動して、File -> Create New Application … を選択します。
Application Name に任意の名前を入力します。ここでは python-basic-wsgi とします。
Parent Directory にソースを置きたい場所を選択して Create を押します。これでアプリケーションの新規作成は完了しました。

GAE に追加されたアプリケーションを選択した Run ボタンを押してアプリケーションを起動させます。
gae-create-a-new-wsgi-app1
無事起動ができて Stop ボタンが押せるようになったら、 Browse ボタンを押して実際に Web ブラウザで確認します。
gae-create-a-new-wsgi-app2
Hello world! と出力されると無事アプリケーションを作成することができました。
gae-create-a-new-wsgi-app3

[GAE] 初めてのWSGIアプリケーション

GAE での WSGI アプリケーションの作成方法の記録です。

GAE とは Google App Engine の略で、Googleが提供しているホスティングサービスのことです。

WSGI アプリケーションに関連したものを少しずつまとめていこうかと思います。

  1. 基本のWSGIアプリケーション


ちゃんとした記事っぽくなると…いいかなと思います。

iptables 基礎

ufw 等に逃げてたのでそろそろ基礎的な部分を調べました。

基本的な構文

iptables スイッチ チェーン オプション -j アクション

大まかにですが、こんな感じかと思います。
※オプション、アクション等は私が勝手につけただけです。

チェーン

チェーンは、どこからの通信なのかを指定できます。受信するパケットに適用したり、送信するパケットに適用したりできます。
初めから定義されているチェーンは3つあります。

INPUT 受信するパケットに対して指定の指定です。
OUTPUT 送信するパケットに対して指定の指定です。
FORWARD これは転送を行うパケットに対しての指定です。これは設定するPCをルーターとして利用する場合に利用します。

アクション

アクションは、パケットを許可するのか、破棄するのかを指定します。
許可するには ACCEPT。破棄するには DROP を指定します。

スイッチ

チェーンの前にあるスイッチは、チェーンに追加したり、チェーンに指定がない場合のデフォルトの設定などができます。

-P : 初期設定

iptables -P チェーン アクション

パケットの指定がされていないパケットに対しての、デフォルトの設定を行います。

例えば受信するパケットをデフォルトで破棄するには次のようになります。

iptables -P INPUT DROP

-A : 追加

iptables -A チェーン オプション -j アクション

チェーンに対して新たなルールを追加します。
オプションに当てはまるチェーンのパケットを、アクションで処理する。
のような感じになります。

オプション
オプションは、プロトコル・ポート番号・モジュールを指定することができます。これはパケットの種類を細かく指定して許可するために使用します。

例えば ssh のパケットを受信するには tcp プロトコルの 22 番ポートを開放します

iptables -A INPUT -p tcp --dport 22 -j ACCEPT

-p がプロトコル。続く –dport がポート番号 になります。–dport は -p のオプション的な扱いのようなので –dport だけを指定することはできません。

IPアドレスで直接許可したり、制限をかけたりすることもできます。IPを指定するには -s (source) を使用します。IPアドレスにはマスクを使用することもできます。マスクを利用すると IP アドレスの範囲を一気に指定することができます。
192.168.0.0/16 や 192.168.0.0/255.255.255.0 のどちらの形でも記述可能です。


# 192.168.0.8 の ssh を許可する場合
iptables -A INPUT -s 192.168.0.8 -p tcp --dport 22 -j ACCEPT
# 192.168.0.0 ~ 192.168.0.255 からの ssh を許可する場合
iptables -A INPUT -s 192.168.0.0/255.255.255.0 -p tcp --dport 22 -j ACCEPT

モジュール

-m モジュール

これは個別に設定されている機能を有効化してより細かくパケットを制限できます。
例えばローカルネットワーク内限定だと思いますが、macアドレスによって許可することも可能です。
mac アドレスを判定するには mac モジュールを指定します。

-m mac --mac-source 00:50:8D:FD:E6:32

などのように指定できます。

ある程度わかった(かも)ので、いくつか例を作ってみます。

# 受信パケットをデフォルトで破棄
iptables -P INPUT DROP

# ssh のポート開放。
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
# ローカルに対してのみ ssh 開放
iptables -A INPUT -s 192.168.0.0/24 -p tcp --dport 22 -j ACCEPT

# apache の 80 番開放
iptables -A INPUT -p tcp --dport 80 -j ACCEPT

# mysql の開放
iptables -A INPUT -p tcp --dport 3306 -j ACCEPT

# SSL の開放
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

これで、基礎的な部分はできるようになりました…?

参考

http://wiki.centos.org/HowTos/Network/IPTables