タイトルだけ見たら、なんのこっちゃ?という感じかもですが、
こんな感じのWebページを作りたいってことです・・・・あれ?やっぱり分からない。(を
つまり、BOOTHなんかで同人誌の電子ファイルを買うわけですよ。すると、同人誌のデータがPDFで手に入ります。当然ファイルサーバとか NAS とかに保存するんですが、何冊も買ってるとどんどんファイルが増えていく。だけど、PDF って Windows Exproler とかで表紙一覧ができない。ファイル名だけズラズラ並んでても、「ん?これ、どんなんだっけ??」ってなるわけです。困りますね。
なんで、Web 使ってサムネイル化できないか?というのが要求なわけです。
サムネイルつきのリスト画面って、何が面倒かちうと、コンテンツ(この場合はPDF ファイル)と、その表紙になる JPEG が両方必要になって、ファイルの管理がごちゃっとしちゃうのが嫌なんですね。
じゃあ、どーするか?サムネイルはデータベースに突っ込んじゃえば?なんなら、コンテンツそのものもデータベースに突っ込んじゃえば??というお話です。
なお、貼り付けたイメージは、BOOTHでエフ屋さんという同人サークルさんの作品です。気になる方はどうぞ
データをDBに入力する
さて本題、まずデータをデータベースに取り込まないと話にならんので、取り込みます。
取り込むべきサムネイル画像を作りましょう。
# convert Futanari_Elf_chan__sub_quest__DL__Lsize.pdf\[0\] -resize 600x600 ./title.jpg
ImageMagick で PDF の最初のページ、つまり表紙を JPEG 化します。
本当は JPEG ファイルを生成せず、そのままデータベースに送り込みたいんですが、どーも ImageMagick は STDOUT に処理結果を出したりできないっぽく、しょうがないのでファイルにしてます。
んで、生成したファイルをデータベースに送り込みます。
#! /usr/local/bin/python3.7
# -*- coding:utf-8 -*-
import io
import os
import sys
import subprocess
import psycopg2
args = sys.argv
filename = os.path.basename(args[1])
titlepage = open('title.jpg' , 'rb').read()
conn = psycopg2.connect("dbname=book host=******** user=pgsql")
cur = conn.cursor()
sql = "INSERT INTO book (title_page , filename) values (%s , %s)"
btitlepage = psycopg2.Binary(titlepage)
cur.execute(sql , (btitlepage , filename))
conn.commit()
cur.close()
conn.close()
Python のスクリプトです。本当は psql コマンドで INSERT したいんですが、psql コマンドで bytea データを INSERTしようと思ったら、PostgreSQL のデータディレクトリに対象ファイル置いておかないと駄目とか、なんだかなぁな仕様があるようで、仕方ないからこんな Python スクリプトを使ってます。
CGIでデータを取り出す
んでまって、データベースに格納した bytea データを JPEG として取り出す CGI。これがこの記事の本体だったりします。
いやね、そんなん、大したことないやろ?ちょっと調べたら出てくるやろ?って思うやん?
出てこないのよ、これが。Python 2 を使った記事は見つかるけど、Python 3 の実装例がまるでみつからん。ちうわけで、この記事です。
#! /usr/local/bin/python3.7
# -*- coding:utf-8 -*-
import cgi
import io
import sys
import psycopg2
args = sys.argv
conn = psycopg2.connect("dbname=book host=******* user=pgsql")
cur = conn.cursor()
print("Content-Type: image/jpeg")
print()
form = cgi.FieldStorage()
id = form["id"].value
cur.execute("SELECT title_page FROM book WHERE id = (%s)" , (id))
res = cur.fetchone()
sys.stdout.flush()
sys.stdout.buffer.write(res[0])
以上、実装例でした。
いや、これだけじゃ分からんですよね。
ポイントは、sys.stdout を使うというところです。ちうか、それだけです。
Python2 を使った実装だと、SQL から取り出した res[0] を print するだけでいいらしいのですが、Python3 はそれでは動きません。Python 2 と 3 の大きな違いはデータ型が厳密になったことで、バイナリを print できないようになったということなんでしょう。
意図的にバイナリデータを、標準出力に送りだす。という実装をしないといけない。っていうことでした。
コメントする