新宿中央公園キャンドルナイトの塗り絵用投稿・鑑賞サイトについて


はじめに

こんにちは、GxPの安藤(@rando-gxp)です。

この記事はグロースエクスパートナーズ Advent Calendar 2020の25日目、最終日の記事となります。

今回は本日(2020年12月25日)と明日(26日)の2日間、新宿中央公園で開催されるイベント「Candle Night @ Shinjuku Central Park -灯(ほし)に願いを-」(以下キャンドルナイト@新宿中央公園)の中で、弊社が開発した塗り絵用投稿・鑑賞サイトについてお話させて頂きます。

今回のイベントについて

本イベントは、参加者に塗り絵で装飾いただいたキャンドルで会場を彩る、今回で3回目の開催となる参加型のイベントです。

一般財団法人公園財団様、小田急電鉄社様、工学院大学様と弊社グロースエクスパートナーズで構成される実行委員会が主催するイベントとなります。

イベントの概要についての詳細が知りたい方は、以下のプレスリリースを見て頂ければと思います。

小田急電鉄社
工学院大学

本来は会場に集まって参加者の塗り絵をキャンドルとして飾るイベントですが、今回はオンラインでも楽しんでいただけるよう、弊社のITサービスの開発力を活かして何かできないか検討を重ね、結果として「塗り絵用投稿・鑑賞サイト」の作成を行うことになりました。

システム構成

塗り絵投稿・鑑賞サイトは、大きく分けて3つの機能があります。

  • ユーザ用
    • 画像撮影/投稿機能
    • 投稿画像再生機能
  • 管理者用
    • 投稿画像管理機能

各機能のおおまかなシステム構成は以下の通りです。

  • 共通
    • Java11
    • SpringBoot
  • ユーザ用
    • Vue.js
  • 管理者用
    • Thymeleaf

開発期間が短かったですが、開発チームとして未経験の技術要素にも触れてみたいという話になり、基本的には業務で使用したことのある技術を利用し工数の短縮を図り、Vue.jsのみ学習のために採用しました。

画像撮影/投稿機能

塗り絵の撮影と、撮影された画像を投稿するための機能です。

「塗り絵を撮影する」ボタンを押下すると、カメラでの撮影をするか保存済の画像を選択することができます。
どちらかのアクションを行うと、撮影/選択された画像がページ上に表示されます。

利用規約についての同意のチェックボックスを付けたうえで「塗り絵を投稿する」ボタンを押下すると、画像が投稿されます。

投稿画像再生機能

投稿された画像の中で、表示可能な画像をスライドショー形式で表示する機能です。

投稿画像管理機能

投稿画像管理機能は、名前の通り管理者ユーザのみが利用できる機能です。
ユーザが投稿した画像の中から、公開しても問題ない画像を選択・移動するための機能となります。

今回のシステムの素案では、この部分を画像認識APIに任せることで自動化したいという要望もありました。
しかし、開発チーム内で議論した結果、現存する画像認識のAPIで公序良俗に反するような画像を全てカットすることはできないのではないかという結論に至ったため、画像を手動で選別する機能を作成することになりました。

本システムでは、画像は3つの領域に分けて保管されています。

  • 一時保管領域
    • ユーザが投稿した際に格納される領域
  • 公開領域
    • ユーザに公開しても問題無い画像を格納する領域
  • 非公開領域
    • 公序良俗に反するような画像や、撮影に失敗している画像を格納する領域

今回私は主にこの管理機能の実装を担当しました。

苦労した点

今回のシステムで一番苦労したのは、大量の画像をどのように処理するかという点でした。

想定としては3000枚の画像を処理する必要があるということで、大量の画像情報をまとめて取得しようとすると、データ送信量が大きすぎるため画像再生機能への遷移に時間がかかる、スライドショーで時折画像が読み込まれない、といった問題が発生しました。

解決策として、Server側(Java側)で、撮影・投稿された画像をそのまま表示するのではなく、圧縮したものを表示するように修正しました。
具体的には、JavaのImageクラスのgetScaledInstanceメソッドを用いて圧縮しました。

メソッド使用例
BufferedImage sourceImage = ImageIO.read(new File("test.png"));
int width = sourceImage.getWidth();
int height = sourceImage.getHeight();
int maxSize = 400; // 圧縮後画像の長辺の最大ピクセル数
double ratio = 0;
if ( width > height) {
    ratio = (double)maxSize / (double)width;
} else {
    ratio = (double)maxSize / (double)height;
}

int shrinkedWidth = (int)(width * ratio);
int shrinkedHeight = (int)(height * ratio);
int imageType = sourceImage.getType();
BufferedImage image = new BufferedImage(shrinkedWidth, shrinkedHeight, imageType);

int scale = Image.SCALE_FAST; // 速度優先
image.getGraphics().drawImage(sourceImage.getScaledInstance(shrinkedWidth, shrinkedHeight, scale), 0, 0, null);

その結果、画像再生機能への遷移はスムーズになり、スライドショーで画像が読み込まれない問題も解消しました。

まとめ

今回、機能数は多くありませんでしたが、開発期間が短かったこともあり、かなりあわただしい開発になりました。
ただ、開発の開始時点でイメージされていたシステムをきちんと実現することはできたのではないかと思います。

ちなみに今回のイベントのテーマ「灯(ほし)に願いを」には、昨今のコロナ事情で様々な活動が制限される中で、キャンドルを「灯(ほし)」に見立てて、「会いたい人」「行きたいところ」「2021年をどんな1年にしたいか」など、一人ひとりの願いを込めたキャンドルを灯していただきたいという思いが込められているそうです。
皆さまもオンラインでイベントに参加してみてはいかがでしょうか?

Candle Night @ Shinjuku Central Park -灯(ほし)に願いを- オンラインサイト

参考

Spring-MVCの散歩道 応用の森(Java編)