おしゃれに紙を並べたくて
要約
↓こういうのを作るスクリプト作りました。
挨拶
こんにちはたもったです。実に2か月ぶりの更新です。
時が流れるのは早いもので、ブログ開設当初はこれからビシビシ記事を上げていくぞと思っていたのに、気づけばAPEXを始めたりボードゲームアリーナにはまったりしてありえん時間が経っていました。誰かAPEXの勝ち方を教えてください。
本文
先日ヒカテクさん(http://hikatech.com)と話していて、紙をおしゃれに並べたいねという話になりました。これだけ聞くとなんのこっちゃという話なので下の画像をご覧ください。
上の画像のように、紙を縦横綺麗に並べて斜め視点から撮影するとグッとおしゃれになります。
引用元はビズメイト株式会社様と有限会社クローバー様のサイトです。両社とも僕とは全く関係ありませんが、素晴らしい並べっぷりでしたので引用させていただきました。
www.bizmates.jp
というわけで皆さんも自分の文書をおしゃれに並べてみたくなってきましたね。
本記事はそんなおしゃれ紙並べ画像を自動で生成するスクリプトの実装説明です。
ソースコード全文はこちら。
環境構築
OS:Windows10
使用言語:Python3
モジュール:
PIL
PyOpenGL
FreeGLUT
pdf2image
コード解説
PDFを画像にする前編と画像に画角をつけておしゃれにする後編に分けます。今回は前編です。
今回の実装では下の流れで画像を生成します。
PDFの各ページを画像に変換する
各ページ画像に影を付ける
影付きの画像を縦横並べる
縦横並べた画像を斜めから撮影しておしゃれ画像にする。
1.PDFの各ページを画像に変換する
in_pdfというフォルダから任意のPDFを拾ってきてout_imgというフォルダにパコパコ保存していきます。
もちろんin_pdfの中にPDFファイルが入っていないと動きません。out_imgはなければ自動で生成してくれます。
pdf_dir = pathlib.Path('in_pdf') if not pdf_dir.exists(): pdf_dir.mkdir() pdf_file = pathlib.Path('in_pdf/' + pdf) img_dir = pathlib.Path('out_img') if not img_dir.exists(): img_dir.mkdir() # PDFを画像に変換 base = pdf_file.stem images = pdf2image.convert_from_path(pdf_file, grayscale=True, size=1800) for index, image in enumerate(images): image.save(img_dir/pathlib.Path(base + '-{}.png'.format(index + 1)), 'png')
2.各ページ画像に影を付ける
画像を並べた時にリアリティを出すため、画像に影を付けました。makeShadowって調べたら出てきた関数を利用させてもらっています。
画像の背景の色味と影の色味を合わせる部分を足したのですが、そこがむちゃくちゃ遅いです。誰か改善して。
def makeShadow(image, iterations, border, offset, backgroundColour, shadowColour): # image: base image to give a drop shadow # iterations: number of times to apply the blur filter to the shadow # border: border to give the image to leave space for the shadow # offset: offset of the shadow as [x,y] # backgroundCOlour: colour of the background # shadowColour: colour of the drop shadow #Calculate the size of the shadow's image fullWidth = image.size[0] + abs(offset[0]) + 2*border fullHeight = image.size[1] + abs(offset[1]) + 2*border #Create the shadow's image. Match the parent image's mode. shadow = Image.new("L", (fullWidth, fullHeight), backgroundColour) print('\rSaving...make Shadow Image',end='') # Place the shadow, with the required offset shadowLeft = border + max(offset[0], 0) #if <0, push the rest of the image right shadowTop = border + max(offset[1], 0) #if <0, push the rest of the image down #Paste in the constant colour shadow.paste(shadowColour, [shadowLeft, shadowTop, shadowLeft + image.size[0], shadowTop + image.size[1] ]) # Apply the BLUR filter repeatedly for i in range(iterations): shadow = shadow.filter(ImageFilter.BLUR) print('\rSaving...ImageFilter.BLUR ' + str(i) + ' / ' + str(iterations),end='') # ここだけ追加。元のままだと影色と背景色が上手くなじまなかったのでshadowの色みをいじった。ココが遅い。 if shadow.mode != "RGB": shadow=shadow.convert("RGB") w,h = shadow.size print('\rSaving...Set color...\033[K',end='') for x in range(w): for y in range(h): r,g,b=shadow.getpixel((x,y)) # ここで色味いじり中、白色と設定したい背景色の差分を引くので注意 shadow.putpixel((x,y), (r-77, g-40, b-14)) print('\rSaving...Set color... ' + str(x) + ' / ' + str(w),end='') # Paste the original image on top of the shadow imgLeft = border - min(offset[0], 0) #if the shadow offset was <0, push right imgTop = border - min(offset[1], 0) #if the shadow offset was <0, push down shadow.paste(image, (imgLeft, imgTop)) return shadow
3.影付きの画像を縦横並べる
これは2次元リストになっている画像群を縦横良い感じに並べる関数があるのでそれを利用しました。
def convert_1d_to_2d(l, cols): return [l[i:i + cols] for i in range(0, len(l), cols)] # 2次元リストの画像から def concat_tile(im_list_2d): return cv2.vconcat([cv2.hconcat(im_list_h) for im_list_h in im_list_2d]) def makeTileImage(base, images): imgs = [] for index, image in enumerate(images): img = cv2.imread('out_img/shadow/' + base + '_shadow-{}.png'.format(index + 1)) imgs.append(img) result = convert_1d_to_2d(imgs, 6) im_tile = concat_tile(result)
今回はここまでです。