001/* 002 * Copyright (c) 2009 The openGion Project. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 013 * either express or implied. See the License for the specific language 014 * governing permissions and limitations under the License. 015 */ 016package org.opengion.hayabusa.servlet; 017 018import org.opengion.fukurou.util.StringUtil; 019import org.opengion.hayabusa.common.HybsSystem; 020import org.opengion.hayabusa.common.HybsSystemException; 021 022import java.io.ByteArrayInputStream; 023import java.io.File; 024import java.util.Base64; 025import java.awt.image.BufferedImage; 026import javax.imageio.ImageIO; 027 028import java.time.LocalDateTime; 029import java.time.format.DateTimeFormatter; 030 031import java.io.IOException; 032import jakarta.servlet.ServletException; 033import jakarta.servlet.ServletConfig; 034import jakarta.servlet.http.HttpServlet; 035import jakarta.servlet.http.HttpServletRequest; 036import jakarta.servlet.http.HttpServletResponse; 037import jakarta.servlet.ServletOutputStream; 038import jakarta.servlet.annotation.WebServlet; 039import jakarta.servlet.annotation.WebInitParam; 040 041/** 042 * クライアントからBase64でエンコードして送信された画像ファイルを、 043 * ファイルに変換してセーブするサーブレットです。 044 * 045 * 想定される使い方は、クライアント側で、カメラ等で撮影された映像を 046 * canvasに書き込み、それを、Base64でPOSTする感じです。 047 * 048 * 一般的なサーブレットと同様に、デプロイメント・ディスクリプタ WEB-INF/web.xml に、 049 * servlet 要素と そのマッピング(servlet-mapping)を定義する必要があります。 050 * 051 * <servlet> 052 * <servlet-name>imageSave</servlet-name> 053 * <servlet-class>org.opengion.hayabusa.servlet.ImageSave</servlet-class> 054 * <init-param> 055 * <param-name>saveDir</param-name> 056 * <param-value>jsp/snapshot/</param-value> 057 * </init-param> 058 * <init-param> 059 * <param-name>debug</param-name> 060 * <param-value>false</param-value> 061 * </init-param> 062 * </servlet> 063 * 064 * <servlet-mapping> 065 * <servlet-name>imageSave</servlet-name> 066 * <url-pattern>/jsp/imageSave</url-pattern> 067 * </servlet-mapping> 068 * 069 * 一般には、http://サーバー:ポート/システムID/jsp/imageSave 070 * 引数;img=イメージファイル 071 * dir=ディレクトリ (初期値は、saveDir="jsp/snapshot/") 072 * file=ファイル名 (初期値は、filePtn="yyyyMMddHHmmssSSS" + ".png"(固定)) 073 * 形式のURL でPOSTします。 074 * 075 * @og.rev 7.4.2.1 (2021/05/21) 新規追加 076 * @og.group その他機能 077 * 078 * @version 7.4 079 * @author Kazuhiko Hasegawa 080 * @since JDK11, 081 */ 082@WebServlet( 083 urlPatterns = "/jsp/imageSave" , 084 initParams = { 085 @WebInitParam( name="saveDir" , value="jsp/snapshot/" ) 086 } 087) 088public class ImageSave extends HttpServlet { 089 private static final long serialVersionUID = 742120210521L ; 090 091 private final static DateTimeFormatter YMDH = DateTimeFormatter.ofPattern( "yyyyMMddHHmmssSSS" ); 092 093 private String saveDir = "jsp/snapshot/"; 094 private boolean isDebug = false; 095 096 /** 097 * Servlet の 初期値設定を行います。 098 * 099 * WEB-INF/web.xml ファイルで、<servlet> タグ内で初期値設定を行います。 100 * <init-param> 101 * <param-name>saveDir</param-name> 102 * <param-value>jsp/snapshot/</param-value> 103 * </init-param> 104 * 105 * @param config ServletConfigオブジェクト 106 */ 107 @Override 108 public void init( final ServletConfig config ) throws ServletException { 109 super.init( config ); 110 111 saveDir = StringUtil.nval( config.getInitParameter("saveDir") , saveDir ); 112 113 // boolean の StringUtil.nval は厳密チェックするので使わない。 114 isDebug = Boolean.parseBoolean( config.getInitParameter( "debug" ) ); 115 } 116 117 /** 118 * GET メソッドが呼ばれたときに実行します。 119 * 120 * 処理は、doPost へ振りなおしています。 121 * 122 * @param request HttpServletRequestオブジェクト 123 * @param response HttpServletResponseオブジェクト 124 * 125 * @og.rev 7.4.2.1 (2021/05/21) 新規追加 126 * 127 * @throws ServletException サーブレット関係のエラーが発生した場合、throw されます。 128 * @throws IOException 入出力エラーが発生したとき 129 */ 130 @Override 131 public void doGet( final HttpServletRequest request, final HttpServletResponse response ) 132 throws ServletException, IOException { 133 doPost( request,response ); 134 } 135 136 /** 137 * POST メソッドが呼ばれたときに実行します。 138 * 139 * @param request HttpServletRequestオブジェクト 140 * @param response HttpServletResponseオブジェクト 141 * 142 * @og.rev 7.4.2.1 (2021/05/21) 新規追加 143 * 144 * @throws ServletException サーブレット関係のエラーが発生した場合、throw されます。 145 * @throws IOException 入出力エラーが発生したとき 146 */ 147 @Override 148 public void doPost( final HttpServletRequest request, final HttpServletResponse response ) 149 throws ServletException, IOException { 150 151 // boolean の StringUtil.nval は厳密チェックするので使わない。 152 final String debugPrm = request.getParameter( "debug" ) ; 153 final boolean debug = StringUtil.isNull( debugPrm ) 154 ? isDebug // 未指定なら、初期値を使う 155 : Boolean.parseBoolean( debugPrm ); // "true"以外はfalse になる。 156 157 String data = request.getParameter( "img" ); 158 if( StringUtil.isNotNull( data ) ) { 159 // Javascriptのcanvas.toDataURL()関数から派生したデータを保存したい場合は、 160 // 空白をプラスに変換する必要があります。そうしないと、デコードされたデータが破損します。 161 data = data.replace(' ','+'); 162 163 // 相対パスを絶対パスに変換。ファイルセパレータも正規化されています。 164 final String dir = HybsSystem.url2dir( StringUtil.nval( request.getParameter( "dir" ),saveDir ) ); 165 if( debug ) { System.out.println( "dir=" + dir ); } 166 167 // ファイル名が無ければ、現在時刻.png 168 String file = request.getParameter( "file" ); 169 if( StringUtil.isNull( file ) ) { 170 final LocalDateTime nowDateTime = LocalDateTime.now(); 171 file = nowDateTime.format( YMDH ) + ".png"; 172 } 173 174 if( debug ) { System.out.println( "file=" + file ); } 175 176 // Base64をデコードしてファイルに戻す。 177 final byte[] bytes = Base64.getDecoder().decode(data); 178 try( ByteArrayInputStream input = new ByteArrayInputStream(bytes) ) { 179 final BufferedImage image = ImageIO.read(input); 180 final File output = new File( dir, file ); 181 final File parent = output.getParentFile(); 182 if( parent != null && !parent.exists() ) { // parent は null があり得る。存在しない場合のみ。 183 parent.mkdirs(); 184 } 185 ImageIO.write(image, "png", output); 186 if( debug ) { System.out.println( "output=" + output.getAbsolutePath() ); } 187 } 188 catch( final Throwable th ) { 189 final String errMsg = "Base64 デコード処理が失敗しました。" ; 190 throw new HybsSystemException( errMsg,th ); 191 } 192 } 193 } 194}