Python3でPostgreSQLに入れた画像ファイルをCGIで表示する

| コメント(0) | トラックバック(0)

タイトルだけ見たら、なんのこっちゃ?という感じかもですが、

こんな感じの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 できないようになったということなんでしょう。

意図的にバイナリデータを、標準出力に送りだす。という実装をしないといけない。っていうことでした。

トラックバック(0)

トラックバックURL: http://horliy.seri.gr.jp/MTcgi/mt-tb.cgi/104

コメントする

このブログ記事について

このページは、ほーりーが2020年7月 4日 00:24に書いたブログ記事です。

ひとつ前のブログ記事は「Graylog で Fortigate のログを眺めてみる」です。

次のブログ記事は「Xeon の世代間スペック差」です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。