Pythonで2018年のカレンダーを作ってみた


こんにちは!Python Advent Calendar 13日目担当のしげるです。
最近はPythonを利用した機械学習が流行っています。その中で機械学習したデータをpdfなどの外部ファイルに出力することができたら新しい表現方法が増えるのではないでしょうか?

目的

pythonでpdf形式のカレンダーを作成する。
日付と画像(URL or path)を指定するだけで、簡単にカレンダーが作れるといいなー。

ソースコード

リポジトリ

環境構築

完成品を実行させるには、以下のコマンドで実行できます。
image_pathは、URL/pathに対応しており、簡単にカレンダーを作成できます。

 $ pip3 install reportlab
 $ git clone https://github.com/4geru/pdf-calendar.git
 $ python3 make_pdf.py 2018 1 image_path

流れ

カレンダー作成の手順は以下の通りです。
pdfに関する設定・文字の表示・線、画像の描画について取り上げていきます。

make_pdf.py
def make(year,month, img):
  pdf_canvas = set_info("{0:04d}-{1:02d}".format(year,month)) # pdfの設定をする
  print_title(pdf_canvas, year, month) # titleの表示
  print_image(pdf_canvas, img)
  print_box(pdf_canvas) # 箱の描画   
  print_word(pdf_canvas, year, month) # 日付の描画
  pdf_canvas.save() # pdfを保存

初期設定

pdfの描画画面の設定をします。

def set_info(filename):
  # 保存先とファイル名の設定
  pdf_canvas = canvas.Canvas("./calendar/{0}.pdf".format(filename), bottomup=False, pagesize=letter)  # 原点は左上

  # ファイル情報の登録(任意)
  pdf_canvas.setTitle(filename)
  pdf_canvas.setSubject(filename + 'のカレンダー')      
  pdf_canvas.setAuthor("4geru")

  # キャンバス情報の追加
  return pdf_canvas

文字の表示

色の修正

  • フォントの色の設定 HexColorと単色で色を変更できます
make_pdf.py
def same_month_color(weekday):
  #ef5350 red lighten-1
  if weekday == 0: return color.HexColor("0xef5350")
  #42a5f5 blue lighten-1 
  if weekday == 6: return color.HexColor("0x42a5f5")
  return color.black
  • フォントの変更 フォントはUnicodeCIDFont'HeiseiKakuGo-W5'を使っているが、 TTFontを利用すると、違うフォントも使えるようです。

文字の描画

make_pdf.py
def print_title(pdf_canvas, year, month):
  # フォントの設定
  font = 'HeiseiKakuGo-W5'
  pdfmetrics.registerFont(UnicodeCIDFont(font))
  pdf_canvas.setFont(font, 20)

  # 文字の描画
  pdf_canvas.drawString(config.space, config.title.height, "{0}年 {1}月のカレンダー".format(year, month))

線の描画

pdf_canvas.lineで線の描画ができます。
左から右へ・上から下へ線を伸ばすため、横線は左端・縦線は上の位置を決めます。

make_pdf.py
# カレンダーの線の表示
def print_box(pdf_canvas):
  pdf_canvas.setStrokeColor(color.black) # 色の設定
  step = config.step # 線と線の間隔
  # 縦の開始点
  top  = config.title.height + config.image.height + config.space * 2
  width = step * 7 # 横幅
  height = step * 5 # 縦
  left = (config.width - width)/2 # 横の開始点
  for i in range(0,8):
    x = left + step * i
    pdf_canvas.line(x , top, x, top + height)
  for i in range(0,6):
    y = top + step * i
    pdf_canvas.line(left, y, config.width - left, y)

写真の表示

pdfで画像を表示する場合は、PILを使って、画像を表示します。
PILを使っただけだと左の図になってしまいます。しかし、ImageをLoadした後に、transposeで上下逆に変更することにより、右の図のように表示できます。

画像のdrawInlineImageは、drawInlineImage(描画する画像,左の開始点,上の開始点, 横の長さ, 縦の長さ)で設定することができます。
左の開始点は、画像の横の長さに比例するので、適当な式が代入されています。
縦の開始点は、画像が上下反対に描画されるためその分下に描画しています。

make_pdf.py
def print_image(pdf_canvas, img):
  image = ''
  if img.find('http') == -1: # URL出なかった時
    image = Image.open(img).transpose(Image.FLIP_TOP_BOTTOM)
  else: # URLだった時
    f = io.BytesIO(urlopen(img).read())
    image = Image.open(f).transpose(Image.FLIP_TOP_BOTTOM)

  height = config.image.height # 縦の長さの設定
  # 縦に合わせて横の長さの設定
  width = image.width * config.image.height / image.height
  top = config.title.height + config.space
  pdf_canvas.drawInlineImage(image,config.width/2-width/2,top-height, width, height)

参考

最後に

もうすぐクリスマス・年明けですね。。。
Pythonカレンダーを使って、周りの友達や家族にオリジナルのカレンダーを作成したら喜ばれるのではないでしょうか?
ぜひ使ってみてください

追加

  • 2017/12/13 : 祝日を表示できるようにしました。
$ pip3 install jcal

で使えるようになります。