DreamerDreamのブログ

夢想家の夢です。〜揚げたてのモヤっとしたものをラフレシアと共に〜

PythonでJPEGファイルからPDFファイルを作成、PDFファイルからJPEGファイルを生成する 備忘録

「複数のjpegファイルを集めて1つのPDFファイルにしたい」と調べてpythonのライブラリ「img2pdf」を発見しました。

pipでインストール出来るとのことで早速インストールを試みましたが、

sudo pip3 install img2pdf

 

エラー!!

....(略)

src/qpdf/annotation.cpp:9:10: 致命的エラー: qpdf/Constants.h: No such file or directory

     #include <qpdf/Constants.h>

              ^~~~~~~~~~~~~~~~~~

    コンパイルを停止しました。

    error: command 'gcc' failed with exit status 1

 

どうやらgccというライブラリが不良のようで、調べてもよく解らなかったのですが、結論としてはpipのバージョンが低いのが原因だったようです。

pip3 install --upgrade pip  

でアップデートしたら問題なくインストール出来ました。

<参考>

Python3 - pip をアップデートする方法

 

コード

#!python3

import img2pdf

 

path_pdf = '(PDF出力のフルパス.pdf)'

path_imgdir = '(画像のあるディレクトリ)'

#明示的にリストを作る(os.listdirとかで一覧作ってもOK!)

filenames = ['test_3715.jpg','test_0719.jpg','test_9163551.jpg']

#フルパスのリスト

images = [ path_imgdir + p for p in filenames ]

#PDF生成

with open( path_pdf , "wb") as f:

    f.write(img2pdf.convert(images))

 

これで JPEG => PDF への変換が出来ました。

ちなみに、JPEG以外のPNGやGIFではエラーが出てしまうので他の形式の場合は一度JPEGに変換する必要があるようです。

 

<参考>

python - 複数のjpegファイルを一つのpdfファイルに変換したい - スタック・オーバーフロー

 

 

逆に、PDF => JPEG への変換も当然同じライブラリでできるだろうと思っていましたが、似た名前で別物のライブラリが必要だそうです。

こちらは「pdf2image」というライブラリ。

先程のが「img2pdf」なのでちょっと違う。

ここでライブラリ名の「2(two)」が「to」を意味していると初めて気が付きました。「img to pdf」ということなのですね!ナルホド!そういえば2のつくライブラリって結構ありますね。^^:そういう意味だったのか、気付かなかった。。

 

pdf2imageライブラリのインストールは先程と同じpipで出来ます。

sudo pip3 install pdf2image

 

このライブラリはpopplerというPDF作成ライブラリのラッパライブラリだそうで、popplerをインストールする必要があるようです。

CentOSの場合は

sudo yum install poppler-utils.x86_64 

で無事にインストール出来ました。

 

コード

# -*- coding: utf-8 -*-

from pathlib import Path

from pdf2image import convert_from_path

 

# PDFファイルのパス

pdf_path = Path("(PDFファイルのフルパス)")

#outputのディレクトリパス

img_path=Path("(変換した画像を保存するディレクトリ)/jpgs")

 

#変換はこの部分だけ

convert_from_path(pdf_path, output_folder=img_path,fmt='jpeg',output_file=pdf_path.stem)

 

 

<参考>

PDFファイルの画像ファイルへの変換 - Qiita

 

例えば、「testpdf.pdf」というPDFファイルを変換すると

「jpgs」ディレクトリに

testpdf0001-1.jpg  testpdf0001-2.jpg  testpdf0001-3.jpg  testpdf0001-4.jpg  testpdf0001-5.jpg  testpdf0001-6.jpg  testpdf0001-7.jpg 

という画像が保存されます。

 

変換も日本語に対応しているようです。

 

左側がjpeg変換したファイル、右が元のPDFです。

ほとんど一緒で見分けが付きません。

f:id:DreamerDream:20220330133823p:plain

 

拡大すると「画像」だということが解ります。

f:id:DreamerDream:20220330133839p:plain

 

今回は以上です。

指紋センサー「DY50」をタッチセンサー連動で指紋認証させる

指紋センサーについて最終回です。

前回はLEDのON-OFF操作が自由に出来るようになりました。

dreamerdream.hateblo.jp

 

前々回は内蔵のタッチセンサーを扱えるようになりました。

dreamerdream.hateblo.jp

 

今回は「タッチセンサーが反応したらLED点灯させて指紋認証し、指が離れたらLEDを消灯する」という動作になるよう過去2つのプログラムを組み合わせます。

 

このように動きます。

youtu.be

 

コードです。

#!/usr/bin/python3

# -*- coding: utf-8 -*-

 

from pyfingerprint.pyfingerprint import PyFingerprint

import hashlib

import time

import RPi.GPIO as GPIO

import sys

import os

import atexit

 

#TouchSenser

Senser = 18

 

f = None

f_finger = False

 

## Tries to initialize the sensor

try:

    f = PyFingerprint('/dev/serial0', 57600, 0xFFFFFFFF, 0x00000000)

    if ( f.verifyPassword() == False ):

        raise ValueError('The given fingerprint sensor password is wrong!')

 

except Exception as e:

    print('The fingerprint sensor could not be initialized!')

    print('Exception message: ' + str(e))

    exit(1)

 

#print('Currently used templates: ' + str(f.getTemplateCount()) +'/'+ str(f.getStorageCapacity()))

 

def search():

  print('Waiting for finger...')

 

  ## Wait that finger is read

  for i in range(5):

    if( f.readImage() ):

      break

    time.sleep(1)

    if 4<=i:

      return 0

 

  try:

    f.led_off()

 

    ## Converts read image to characteristics and stores it in charbuffer 1

    f.convertImage(0x01)

 

    ## Searchs template

    result = f.searchTemplate()

 

    positionNumber = result[0]

    accuracyScore = result[1]

 

 

    if ( positionNumber == -1 ):

      print('No match found!')

      time.sleep(1)

      return 0

 

    else:

      print('Found template at position #' + str(positionNumber))

      print('The accuracy score is: ' + str(accuracyScore))

      f.loadTemplate(positionNumber, 0x01)

      characterics = str(f.downloadCharacteristics(0x01)).encode('utf-8')

      print('SHA-2 hash of template: ' + hashlib.sha256(characterics).hexdigest())

 

  except:

    return 0

 

 

def senser_callback( gpio_pin ):

  global f_finger

  if GPIO.input(Senser) == 0 and f_finger is False:

    f_finger = True

    try:

      f.led_on()

    except:

      pass

    search()

 

def end():

  GPIO.cleanup()

 

def standby():

  global f_finger

  GPIO.setmode(GPIO.BCM)

  GPIO.setup(Senser, GPIO.IN, pull_up_down=GPIO.PUD_UP)

  GPIO.add_event_detect(Senser, GPIO.BOTH, bouncetime=50)  

  GPIO.add_event_callback(Senser, senser_callback)  # setInterrupt

  atexit.register(end)

 

  while True:

    if GPIO.input(Senser) == 1:

      print('.')

      try:

        f.led_off()

      except:

        pass

      f_finger = False

    time.sleep(5)

 

if __name__=='__main__':

  standby()

 

けっこうヤッツケ感があるコードで改善の余地がありますがひとまず狙いどおりに動いたので今回の目的は達成しました。

 

今回は認証成功時にサンプルの通りに文字列吐かせてるだけですが、これで何かしら操作をすれば「指紋認証式◯◯」の完成!となります。

f:id:DreamerDream:20220218090537p:plain

<pizeroでのモジュールだけの最小構成>

 

 

また、課題も見つかりました。

高頻度にしつこく認証させていると最終的にシリアル受信に失敗してエラー吐いてモジュール自体が止まります。

 

一度モジュール自体がエラーで止まってしまうとラズパイを再起動させてもシリアル信号自体を受け付けなくなっているので通信確立できません。もしモジュールの再起動命令が存在していたとしても送れません。これは致命的です。

改善策としてエラー時にはFETで物理的にモジュール自体の電源を一度断って再起動させることにしました。(2秒ぐらい電源を切ると確実に通信確率できます。)

f:id:DreamerDream:20220218222652p:plain

見事な空中配線^^;

電源制御に使用したFETはNchパワーMOSFET 2SK4017(Q) (60V5A)

 

作成予定の指紋認証ロックシステムの最小構成の動作確認をした動画です。

3Dプリンターで作ったロック機構と連動させました。

youtu.be

エラー時でも自動でモジュールの電源遮断して再起動までバッチリです。

 

指紋認証モジュール、なかなか使えます。

面白かったのでもう一個買いましたとさ^^v以上です。

指紋センサー「DY50」のLEDを消したり点けたりする方法 備忘録

前回、指紋認証モジュールを動かしましたがデフォルトの状態ではpython2で動いていました。

dreamerdream.hateblo.jp

 

 

LED制御の前に、実装時にはpython3で動かしたいのでなんとかならないかと力技ですがパッケージをまるっとコピーしてみました。

中身がシリアル通信だけなのでまあ問題ないだろうと踏んで・・・

 

sudo cp -r /usr/lib/python2.7/dist-packages/pyfingerprint /usr/lib/python3/dist-packages/

 

 

実行

sudo python3 /usr/share/doc/python-fingerprint/examples/example_index.py 

これですんなり動きました。

 

さて、指紋センサーのDY50は電源をつけると緑のLEDが点灯します。

指紋を読み取っていてもいなくても点灯しっぱなしです。しかも結構明るい!

f:id:DreamerDream:20220216143105p:plain

LEDは省エネというもののこれではLEDの寿命が心配になりますし、屋外で使うとなると夜には目立ちすぎです。

 

この動画は読み取り完了時にLEDは消えてますよね、もともとそういう仕様?どうなってるんだろ?

www.youtube.com

 

今回の目標はこの明るすぎるLEDを消すことです。

 

おそらく同じ種類のモジュールと思われるコマンド一覧表を発見!

http://www.kyohritsu.jp/eclib/OTHER/DATASHEET/SENSOR/sen308fsm13sp.pdf

データシート

https://cdn-shop.adafruit.com/datasheets/ZFM+user+manualV15.pdf

これによると電源投入時の初期化に500msかかるそうですからできるだけ物理的に電源遮断はしたくありません。

読んでもLEDの制御に関する記述は無さそうです。

 

色々ググってもなかなかそれらしき記述がなくて最終的には物理的に電源遮断でLEDをOFFにする方向で考えないと駄目か・・・と諦めかけていましたが、このデータシートに

https://www.velleman.eu/downloads/29/infosheets/vma329_datasheet.pdf

 

このような記述を発見しました。

f:id:DreamerDream:20220217112825p:plain

OpenLED,CloseLEDですと??

説明にはバックライトをOpenするのとCloseするとあります。バックライト?じゃないし・・点灯消灯ってOpen,Closeなんて表記するんだっけ???

そもそも写ってるモジュールの形が違うっぽい・・・

・・・なんか違う気がするけど試しにpyfingerprintライブラリにこのアドレスナンバーを移植してみました。

 /usr/lib/python3/dist-packages/pyfingerprint/pyfingerprint.py

の変数宣言に

##LED

FINGERPRINT_CLOSELED = 0x51

FINGERPRINT_OPENLED = 0x50

 

と追記し、クラスの中に

    def led_off(self):

        packetPayload = (

            FINGERPRINT_CLOSELED,

        )

        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)

        receivedPacket = self.__readPacket()

 

    def led_on(self):

        packetPayload = (

            FINGERPRINT_OPENLED,

        )

 

        self.__writePacket(FINGERPRINT_COMMANDPACKET, packetPayload)

        receivedPacket = self.__readPacket()

 

と追記(self.__readPacket()は使ってないけど入れとかないとエラーが出ます。)

f:id:DreamerDream:20220217114741p:plain

で、サンプルの

 /usr/share/doc/python-fingerprint/examples/example_index.py

をコピペ改造して

/usr/share/doc/python-fingerprint/examples/example_led_on_off.py

 

を作成

f:id:DreamerDream:20220217114949p:plain

1が入力されたらアドレスナンバー50をシリアルで送信、0だと51を送信するというだけです。

 

実行!

youtu.be

 

なんと!ダメ元でしたが大成功!です。^^;まじか・・・

 

ということで前回のタッチセンサーとこのLED制御を組み合わせると「タッチされた時だけLEDを点灯させて読み取る」ということが出来るようになりますね。

 

他にもシステムのエラー時に点滅させたり割と自由に制御可能になります。

 

次回はタッチセンサーと組み合わせます。

指紋センサー「DY50」をRaspberryPiのGPIOから直接動かす方法 備忘録

前回Arduinoを使って指紋センサーを動かしました。

dreamerdream.hateblo.jp

 

このモジュールについて事前にいろいろ調べたのですが、出てくる作例はラズパイのGPIOから直接ではなくUSBシリアル変換アダプタを使うというものばかりです。

 

シリアル変換アダプタ↓

 

YouTubeに出ている動画も例外なくUSBシリアル変換モジュールを使ってのものばかり(執筆時点)。

youtu.be

 

前回Arduinoでの実験では3.3Vできちんと動作確認したのでこの変換機は不要ではないのでしょうか?(というか取りたい!)

つまり作例ではこうなっているものを

f:id:DreamerDream:20220216122036p:plain

GPIOに直接接続してこうしたいわけです。

f:id:DreamerDream:20220216122047p:plain

回路がすごくスッキリします。

実際にはpizeroで使いたいの構想なのでアダプタがあるとすっごい邪魔!

 

えー、結論からすると、取れます!直接動かせました。

今回はその備忘録です。

 

RaspberryPiのGPIOにあるRXD,TXD端子からのシリアル通信についてこちらのサイトが詳しいので参考にさせていただきました。

ラズパイ3など、Bluetooth搭載のラズパイでGPIOのシリアル通信をするにはすこし面倒な設定の変更が必要だそうです。

www.ingenious.jp

 

シリアルコンソールの無効化

最初に

cat /boot/cmdline.txt

 

で現在の設定を一度確認してみます。

console=serial0,115200 console=tty1 root=PARTUUID=acc2f6a1-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait quiet splash plymouth.ignore-serial-consoles

 

この「serial0,115200」を取り除く必要があるそうです。

他のサイトではこれを直接消している例もありましたが、ラズパイの設定から王道の消し方があるみたいなのでそちらを実行します。

 

sudo raspi-config

でInterfaceOptionを選択

f:id:DreamerDream:20220216122452p:plain

リシアルを選択します。

f:id:DreamerDream:20220216122505p:plain

シリアルからのログインは「いいえ」を選択します。

f:id:DreamerDream:20220216122516p:plain

シリアルを有効にして

f:id:DreamerDream:20220216122540p:plain

finishで終了して再起動するとGPIOのシリアルが有効になります。

f:id:DreamerDream:20220216122553p:plain

cat /boot/cmdline.txt

でもう一度確認すると最初のものからserial以降が取れています。

console=tty1 root=PARTUUID=acc2f6a1-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait quiet splash plymouth.ignore-serial-consoles

 

 

Bleutoothモジュールの切り替え

次に、Bluetoothの搭載されたラズパイではデフォルトでBluetoothのシンボリックリンクがメインになっているそうで、メインの/dev/serial0をGPIOに変更する作業が必要とのことです。

 

sudo nano /boot/config.txt

 

で最終行に

dtoverlay=disable-bt 

 

を追記します。

 

現在の状態を確認

 ls -l /dev | grep serial

 

serial0にttyS0(bluetooth)、serial1にttyAMA0(GPIOserial)が割り当てられれています。

lrwxrwxrwx  1 root root           5  2月 16 19:57 serial0 -> ttyS0

lrwxrwxrwx  1 root root           7  2月 16 19:57 serial1 -> ttyAMA0

 

設定を反映させるために再起動させます。

sudo reboot

再度確認すると

ls -l /dev | grep serial

 

GPIOserialがメインのserial0に割り当てられるようになりました。

lrwxrwxrwx  1 root root           7  2月 16 20:05 serial0 -> ttyAMA0

lrwxrwxrwx  1 root root           5  2月 16 20:05 serial1 -> ttyS0

 

 

そして、使わないBluetoothを無効化します。

sudo systemctl disable hciuart

 

もしBluetoothを使う場合はminiuart-btの設定をすればラズパイの速度は落ちるものの使えるという情報も得ましたがBluetoothを使う予定が無いので今回は試しません。

 

以上でGPIO上のTXD,RXD端子のシリアル通信の準備が整いました。

 

 

指紋モジュールライブラリのインストール

指紋モジュールのライブラリのインストールはライブラリ本家のこちらのページを参考にさせていただきます。

tutorials-raspberrypi.com

 

以降のコマンドは、最初に

sudo bash

 

を打ってrootでコマンド操作する必要があります。

 

パッケージソースのインストール

 wget -O - http://apt.pm-codeworks.de/pm-codeworks.de.gpg | apt-key add -

 wget http://apt.pm-codeworks.de/pm-codeworks.list -P /etc/apt/sources.list.d/

 

パッケージの更新とpythonライブラリのインストール

apt-get update

 apt-get install python-fingerprint

エラーが発生した場合は以下を実行(エラーがなければ特に何もインストールされない)

apt-get -f install

rootを出ます。

exit

 

 

指紋モジュールとラズパイの接続

f:id:DreamerDream:20220216143105p:plain

Arduinoの時と同じようにGNDと3.3Vに接続します。

センサのRXをラズパイのTXDに、センサのTXをラズパイのRXD端子に接続します。

f:id:DreamerDream:20220216144021p:plain

 

サンプルプログラム実行

サンプルプログラムを実行しますが、そのままだとUSB変換機に繋がったシリアル接続を読みにいくので、先に設定した/dev/serial0に変更します。

sudo nano /usr/share/doc/python-fingerprint/examples/example_index.py

でソースを変更

f:id:DreamerDream:20220216142820p:plain

/dev/ttyUSB0 を /dev/serial0 に書き直します。

ボーレートはArduinoの場合は9600指定しましたがデフォルトでOK?のようです。

 

※書きながら気が付きましたが、もしかしたら、上記の「Bluetoothモジュールの切り替え」をせずともttyAMA0を直接指定してやるだけで良かったのかもしれません・・・(試してません)

 

実行すると

sudo python2 /usr/share/doc/python-fingerprint/examples/example_index.py 

指紋が登録されているとTrueだというリストです。

Currently used templates: 1/150

Please enter the index page (0, 1, 2, 3) you want to see: 0

Template at position #0 is used: False

Template at position #1 is used: True

Template at position #2 is used: False

Template at position #3 is used: False

ただ使われているか否か、それだけ。

 

/usr/share/doc/python-fingerprint/examples/

ディレクトリの中には他にも

example_delete.py          example_downloadimage.py   example_enroll.py          example_generaterandom.py  example_index.py           example_search.py  

というサンプルファイルが入っています。

 

example_enroll.py は指紋を読み取ります。

保存する番号を押し1度指を置いて案内が出たら離し、再度置くと登録されます。

example_search.pyは指紋から登録した番号を表示します。

example_delete.pyは登録した指紋を番号から消します。

example_generaterandom.pyはランダム数字を返すようで、用途は不明です。

面白いのは

example_downloadimage.py

を実行すると読み取った指紋のbmp画像が/tmpディレクトリに保存されます。

実際に読み取ったらこんな感じ↓

f:id:DreamerDream:20220216150818j:plain

白黒でしっかりと読み取れているのが解ります。

最終的にこの動画のようにきちんと動作しました。

(撮影が面倒なので動画は拝借したもの)

www.youtube.com

 

今回は狙い通りにラズパイから直接指紋認証モジュールを動かすことに成功しました。

ただ通電している間はずっとLEDが点灯しっぱなしのようなので実際に機器に組み込むには少し対策が必要なようです。

python-fingerprintの実体ファイルは

/usr/lib/python2.7/dist-packages/pyfingerprint/pyfingerprint.py

にあり、ざっくりと見た限り基本的にはモジュールとシリアル通信しているだけっぽいです。これならもしかしたらpython3でも動くかな?

 

指紋認証に使わない配線はタッチセンサー

DY50 | innomatic

この記事によると実は無接続の2本の線は独立したタッチセンサーのようです。

実際に試してみました。

youtu.be

 

きちんと反応の良いタッチセンサーが機能しています。

指がガラス面に触れた時にLOW出力になるようです。

簡単なコードですが一応貼っておきます。

 

タッチセンサーはT-3Vを3.3Vに、T-OUTをGPIO18に繋いでいます。

 touch_test.py 

#!/usr/bin/python3

#coding:utf-8

 

import RPi.GPIO as GPIO

import sys

import os

import atexit

import time

 

#TouchSenser

Senser = 18

 

def senser_callback(gpio_pin):

  #ピンの値を出力

  print( GPIO.input(Senser) )

 

def end():

  #GPIOの開放

  GPIO.cleanup()

 

def standby():

  #GPIO初期化

  GPIO.setmode(GPIO.BCM)

  #内部プルアップ設定

  GPIO.setup(Senser, GPIO.IN, pull_up_down=GPIO.PUD_UP)

  #割り込み背動作設定とチャタリング対策

  GPIO.add_event_detect(Senser, GPIO.BOTH, bouncetime=50)

  #コールバック指定

  GPIO.add_event_callback(Senser, senser_callback) 

  #終了時指定

  atexit.register(end)

 

  #無限ループ

  while True:

    time.sleep(60)

 

if __name__=='__main__':

  standby()

 

これを使ってタッチセンサーが感知したときだけ指紋認証するようコードを組めばLEDが長持ちするかもしれません。

 

まだサンプルしか見ていませんが、「ZFM-20」でググると兄弟分のモジュールも沢山ヒットしますのでスタンバイモードなど参考になる術が見つかるかもしれません。

 

同じようにラズパイで動くか不安でモジュールの購入を悩んでいる方の参考になれば幸いです。

 

次回は、点灯しっぱなしのLEDをなんとかするお話です。

dreamerdream.hateblo.jp

 

指紋センサー「DY50」をArduinoで動かしてみた

今作成しているもので指紋センサーを使いたくなったので、amazonで売られている指紋センサーモジュール「DY50」 (FPM 10A) を購入してみました。

 

目標はRaspberryPiで動かすことなのですが、ひとまずセンサーが届いたので動作例の多いArduinoで実験します。

 

といっても、Arduinoからライブラリを拝借して動かすだけなのでとても簡単です。

Adafruit Fingerprint Sensor Library - Arduino Reference

ここから、最新バージョンをArduinoIDEに入れるだけです。

f:id:DreamerDream:20220215225909p:plain

 

ダウンロードした.zipファイルはArduino IDEでzipのままインストールできます。

f:id:DreamerDream:20220217091415p:plain

やっぱりArduinoは楽チンです。

 

センサーは上からGND、RX、TX、3V3、他不要コネクタが並んでいます。

f:id:DreamerDream:20220215230848p:plain

これを素直にArduinoに繋ぐだけですが、今回の最終目的はラズパイで動かすことなので作例で多い5Vの電源端子からではなく3.3Vに接続します。

実はこのセンサー、事前に調べると「最低電圧が3.6V必要なのでラズパイでは5Vに接続してレベル変換しないと動かせない」など、端子には3.3Vと書かれているものの情報が錯綜していて使えるかどうかとても不安な代物なのです。

 

[センサー] ー [Arduino]

GND   -   GND

RX   -   2

TX   -   3

3V3   -   3.3V

 

線が色分けされていないので間違わないよう気をつけながら差し込みます。

f:id:DreamerDream:20220215230540p:plain

ArduinoIDEのシリアルモニターを開くと早速接続されているようです。

ボーレートは9600

f:id:DreamerDream:20220215230607p:plain

難なく動きました。(サンプル動かしただけなので当然です)

f:id:DreamerDream:20220215230620p:plain

 

5Vでないと駄目なのか?心配していましたが何事もなくひとまず3.3Vで動きました。

動画で見たものは赤色のライトだったのですが僕が購入したものは緑ライトでしたのでバージョンが違うのかもしれません。

youtu.be

 

次回はこのセンサーをラズパイで動かします。

 

dreamerdream.hateblo.jp

 

Djangoの使い方⑮モデルを使わずに、動的にファイルをアップロード、ダウンロードする

Djangoではファイルのアップロード&ダウンロード機能が備わっていますが基本的には静的なものです。

たとえばユーザーによって保管場所を変えたりディレクトリを作成したり、アクセスされるタイミングによってダウンロードファイルを変えたりと動的にファイルの制御をしたいことがあるものです。

 

アップロード

HTML(必要な部分だけ)

<form id="upload" method="post" action="" enctype="multipart/form-data">

    {% csrf_token %}

        <input type="file" name="upload">

        <button type="submit">送信する</button>

</form>

これだけ。 csrf_tokenは地味に忘れがちなので要注意。

f:id:DreamerDream:20220120121848p:plain

このformタグに enctype="multipart/form-data" が書かれていないとアップロードデータがNoneになってしまいますので超注意です。

 

 

pythonコード(必要な部分だけ)

def upload( request ):

     #POSTリクエストのみ

    if request.method == 'POST':

        file = request.FILES.get('upload')

        #ファイルが無い場合は処理しない

        if file is not None:

            #アップロードされた元のファイル名

            name = file.name

            #ファイルタイプ

            type = file.content_type

            #データのサイズ(単位はbyte)

            size = file.size 

            #read() は一気に読み込むのでファイルが大きい場合はメモリリソースを食うので非推奨

            #data = file.read()

            if size < 1000000: #1MB以下のみ処理する

                #実際に保存するディレクトリとファイル名

                filename = '/dev/shm/testupload'

                full_filename = os.path.join("media", "files", filename )

                #書き込む

                fout = open( full_filename, "wb+")

                #chunks()でデータを分割しながら保存

                for chunk in file.chunks():

                    fout.write( chunk )

                fout.close()

こうするとアップロードされたファイルは任意の場所に任意のファイル名で(例の場合は /dev/shm/testupload )保存されます。

 

 

ダウンロード

HTML記述は無し。アクセスされたら即ダウンロード開始。

 

python(必要な部分のみ)

viewファイルで

from django.http import FileResponse

 

filename = 'ダウンロードファイル名.txt'

filepath = '/dev/shm/testupload'

return FileResponse(  open(filepath, "rb") , as_attachment=True, filename=filename)

 

これだけ。

FileResponseをインポートすることと、as_attachmentがTrueだと即ダウンロード、Falseだとブラウザで開くという動きになるようです。

 

ダウンロードされるfilenameを任意で変更できるのは面白いですね。

例えば /download/photo にアクセスされると、「今日のおすすめの写真.jpg」ファイルがダウンロードされる。

f:id:DreamerDream:20220120123114j:plain

というような使い方ができるわけですね^^。

 

<参考>

https://living-sun.com/ja/python/718042-django-simplest-way-to-save-file-to-folder-on-disk-without-using-a-model-python-django-file-upload-upload.html

 

前の記事

dreamerdream.hateblo.jp

 

CentOS8 から CentOS8Stream へ移行した 備忘録

2022年、新年あけましておめでとうございます。

f:id:DreamerDream:20220101100129p:plain

 

2021/12/31をもってサポート終了したCentOS8からの移行先として情報を待っていましたが、移行先としてベストな選択肢は未だ無さそうです。

 

ひとまず簡単に移行できるとされているStreamへ新年早々移行してみました。

 

<参考>

CentOS Linux 8 から CentOS Stream 8 へ移行する - Qiita

 

現在の状態を確認

$ cat /etc/centos-release

CentOS Linux release 8.5.2111

 

$ uname -mrsv

Linux 4.18.0-348.2.1.el8_5.x86_6

 

 

移行するには

dnf install centos-release-stream

dnf swap centos-{linux,stream}-repos

dnf distro-sync

 

この3つのコマンドを打つだけだそうです^^;ほんまかいな?

 

不安ななのでひとまずVPSのイメージバックアップとCentOS8のupdateを済ませておいてから上記のコマンドを試しました。

 

「?!」

385パッケージもアップグレードがあったのですが、びっくりするぐらい素直に終了しました。。。

 

再起動後再度状態を確認

$ cat /etc/centos-release

CentOS Stream release 8

 

$ uname -mrsv

Linux 4.18.0-348.2.1.el8_5.x86_64

 

提供しているWebサービスにも特に異常は出て無さそうです。

 

そして既にCentOS9Streamもリリースされているそうですが、まだ情報が少なそうなので様子見です。

kampa.me