問題集からプリントを作成するためにGimpとpython-fuを使ってみた。

 約2年前、「本の電子化を補助するためにGimppython-fuを使ってみた。」という記事を書いたがあまりに日本語情報が少ないためか、python-fuというキーワードでリンク先に指定されているようだ。

 最近は、自分のためというより子供のためGimppython-fuを使っている。うちの子供は中学生なのだが、いつも一回、問題を解いたきりでお終い。できても、できなくてもそれっきりという教材が多い。
これでは、定着できるはずもない。

そこで、問題集をスキャンしてgimpで編集してプリント化することを思いついたのだが、やはりページ数が多くて、見開きで1枚のプリントを作成するだけでも同じことの繰り返し。この手間が大変なのだ。

そこで、以前使ったgimppython-fuの組み合わせでなんとかしようと思い立った次第である。

 ご多分にもれず、python-fuを手なずけるには苦労したが、すったもんだのあげくにやっと動くものができたのでメモ書きしておく。

このコードを働かせるための条件は、以下の通りである。
条件から外れるとうまく動かない可能性がある。

  1. スキャンデータはjpg形式で日本語の入らないフォルダとファイル名で保存する。(例えば'C:\2in1\tmp074.jpg')
  2. ファイル名は半角英字からなる文字部(例えば'tmp')の後に3桁の数値部(例えば'001')と'.jpg'という規則で付ける
  3. 数値部はできればページ番号に合わせるとあとから参照しやすい。
  4. 数値部はフォルダー内でユニーク(単一値)でなければならない。

以下にコードが扱うデータとその機能の概略説明する

スキャン元は過去問集で横書きのページ振り(左ページがページ番号小)が採用されている。
縦書きの国語の問題が混じっているがページの番号は横書き方式が縦書き部にも適用されている。
画像データはページ番号をファイル名に含んでいる。
コードは使用者にデータフォルダのパスと'.jpg'というファイルエクステンション、処理のスタートページとエンドページの入力を求める。
コードスタートページの値からファイル名を計算し見開き分の二つの画像データを合成する。
合成後に単色化とスプラインカーブで画像のボケを減少させる。
左ページのファイル名のエクステンションの前に'w'を付加した名前でデータを保存する。

私が使っているgimp上での作動条件としては以下のものがある。
ユーザー名をOillerとするとコードを置く場所は
   C:\Documents and Settings\Oiller\.gimp-2.8\plug-ins
Gimpのメニューにスタートポイントが作成されるがその位置は
   メニューバー/PyScripts/My 7th python-fu
Gimpのメニューバー上では、何か画像が表示されていないと自作のメニューにフォーカスが移動できないので作動させる前に何か無関係な画像を読み込ませることが必要

コード例:example7.py

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


# This tells Python to load the Gimp module 
from gimpfu import *
import os, glob

control_points = [0,0, 200,100, 234,234, 255,255]

def get3degit(num):
  s = '000'+str(num)
  p = len(s)-3
  r = s[p:]
  return r

# create an output function that redirects to gimp's Error Console
def gprint( text ):
   pdb.gimp_message(text)
   return 

def past2_2images_in_1(start_page, end_page):
  pages = 
  pagestext = '['
  for i in range(int(start_page), int(end_page), 2):
    j = i + 1
    page = 
    page.append(get3degit(i))
    page.append(get3degit(j))
    pagetext = '['+get3degit(i)+','+get3degit(j)+']'
    #gprint(pagetext)
    pages.append(page)
    pagestext = pagestext + pagetext + ','
  pagestext = pagestext.rstrip(',')+']'
  #gprint(pagestext)
  return pages

def combine2in1(my_dir, my_ext, my_taple):
  #右ページのファイル名を作成する(ワイルドカードを含む)
  Right_key = my_dir+'\*'+my_taple[1]+my_ext

  #該当するファイルのリストを得る
  Right_files = glob.glob(Right_key)
  #gprint(Right_key+':'+Right_files[0])

  #イメージファイルのロード
  Right_image = pdb.gimp_file_load(Right_files[0], '')
  Right_image_width = Right_image.width

  #イメージを表示する
  Right_disp = pdb.gimp_display_new(Right_image)

  #アクティブレイヤーを変数Right_default_layerに代入する
  Right_default_layer = pdb.gimp_image_get_active_layer(Right_image)

  #すべてを選択する
  pdb.gimp_selection_all(Right_image)

  #クリップボードにコピーする
  non_empty = pdb.gimp_edit_copy(Right_default_layer)

  #右イメージの表示を終了する
  pdb.gimp_display_delete(Right_disp)

  #サーチキーとなるファイル名を作成する。(ワイルドカードを含む)
  Left_key = my_dir+'\*'+my_taple[0]+my_ext

  #該当するファイルのリストを得る
  Left_files = glob.glob(Left_key)

  #リストの先頭のファイル名を得る
  Left_file = Left_files[0]
  #gprint(Left_key+':'+Left_file)

  #左ページのイメージをロードする
  Left_image = pdb.gimp_file_load(Left_file, '')
  Left_width = Left_image.width

  #左イメージを表示する
  Left_disp = pdb.gimp_display_new(Left_image)

  #左イメージのアクティブレイヤーを変数に代入する
  Left_default_layer = pdb.gimp_image_get_active_layer(Left_image)

  #クリップボードの内容を貼り付けると
  #貼り付けたものはフローティングかつアクティブレイヤーになる
  floating_layer = pdb.gimp_edit_paste(Left_default_layer, False)

  #フローティングレイヤーの位置決めをする
  pdb.gimp_layer_set_offsets(floating_layer, Left_image.width, 0)

  #フローティングレイヤーを通常のレイヤーに変換する
  pdb.gimp_floating_sel_to_layer(floating_layer)

  #新しいキャンバスの幅と高さを計算する
  new_width = Left_image.width + Right_image_width
  new_height = Left_image.height

  #キャンバスの大きさを拡張する
  pdb.gimp_image_resize(Left_image, new_width, new_height, 0, 0)

  #ビジブルなレイヤーを統合する
  pdb.gimp_image_merge_visible_layers(Left_image, EXPAND_AS_NECESSARY)

  #左イメージのアクティブレイヤーを変数に代入する
  Left_default_layer = pdb.gimp_image_get_active_layer(Left_image)

  #デフォルトレイヤーを指定して脱色する
  pdb.gimp_desaturate(Left_default_layer)

  #デフォルトレイヤーにトーンカーブを適用する
  pdb.gimp_curves_spline(Left_default_layer, HISTOGRAM_VALUE, 8, control_points)

  #保存ファイル名を作成する
  name = Left_file.rsplit('.')
  SaveName = name[0]+'w.'+name[1]
  pdb.gimp_file_save(Left_image, Left_default_layer, SaveName, SaveName)

  #イメージを閉じる
  pdb.gimp_display_delete(Left_disp)

  return



# This is the function that will perform actual actions
def my_script_main_function(image, drawable, directory, ext, suffix, start_value, end_value) :
  combi_list = past2_2images_in_1(start_value,end_value)
  if os.path.exists(directory):
    for taple in combi_list:
      combine2in1(directory, ext, taple)
  else:
    pdb.gimp_message("No such directory: %s" %(directory))
  return

# This is the plugin registration function
# I have written each of its parameters on a different line 
register(
  "script07",    
  "This program combine 2 images into the one image",   
  "This script does nothing and is extremely good at it",
  "Oiller", 
  "Placed on Public Domain", 
  "November 2013",
  "/PyScripts/My 7th Python-Fu", 
  "*", 
  [
    (PF_DIRNAME, "directory", "Directory", 'C:\\2in1'),
    (PF_STRING, "ext", "File extension, including dot", '.jpg'),
    (PF_STRING, "suffix", "Suffix for sharped file", "_a"),
    (PF_INT, 'start_value', 'Start page number is ', 74),
    (PF_INT, 'end_value', 'End page number is ', 75)
  ], 
  [],
  my_script_main_function,
)

main()

参考にしたサイトへのリンク

python-fuの紹介(英語)
http://www.exp-media.com/content/extending-gimp-python-python-fu-plugins-part-1

GIMP python 仕様書(英語)
http://www.gimp.org/docs/python/index.html