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.taglib; 017 018import org.opengion.hayabusa.common.HybsSystem; 019import org.opengion.hayabusa.common.HybsSystemException; 020import org.opengion.fukurou.util.StringUtil; 021import org.opengion.fukurou.util.ToString; 022import org.opengion.fukurou.util.XHTMLTag; 023import org.opengion.fukurou.util.Attributes; 024 025import org.opengion.fukurou.util.QrcodeImage; 026import static org.opengion.fukurou.util.QrcodeImage.ErrCrct; 027import static org.opengion.fukurou.util.QrcodeImage.EncMode; 028import static org.opengion.fukurou.util.StringUtil.nval ; 029 030import java.util.Locale ; 031 032/** 033 * QRコードに対応したイメージファイルを作成するタグです。 034 * 035 * QRコードで表示できる文字数は、バージョン、エンコードモード、エラー訂正レベル に依存します。 036 * また、イメージの大きさは、文字数と1セル辺りのピクセルに依存します。 037 * fileURLは、通常、システムリソースのFILE_URL(=filetemp)なので、fileURL="{@USER.ID}" と 038 * するのが一般的です。 039 * ファイル名は、初期値:rqcode ですが、拡張子はimageType(初期値:PNG)を小文字化して追加します。 040 * 拡張子が付いている場合は、そのまま使用されます。 041 * また、同一ファイル名の場合、ブラウザキャッシュのため、画像が更新されないことがあるため 042 * imgタグのsrc属性に、キャッシュの無効化のための引数を追加しています。 043 * 044 * @og.formSample 045 * ●形式:<og:qrCode fileURL="{@USER.ID}" > 046 * エンコードする文字列 047 * </og:qrCode > 048 * ●body:あり(EVAL_BODY_BUFFERED:BODYを評価し、{@XXXX} を解析します) 049 * 050 * または、 051 * 052 * ●形式:<og:qrCode value="エンコードする文字列" /> 053 * 054 * ●Tag定義: 055 * <og:qrCode 056 * value 【TAG】エンコードする文字列(または、BODY部に記述) 057 * version 【TAG】バージョン (2から40の整数)(初期値:5) 058 * encodeMode 【TAG】エンコードモード('N':数字モード 'A':英数字モード 'B':8bit byteモード)(初期値:B) 059 * errCorrect 【TAG】エラー訂正レベル ('L','M','Q','H')(初期値:M) 060 * imageType 【TAG】イメージファイル形式(PNG/JPEG)(初期値:PNG) 061 * pixel 【TAG】1セル辺りの塗りつぶしピクセル(初期値:3) 062 * fileURL 【TAG】QRイメージファイルを出力するディレクトリ(初期値:FILE_URL) 063 * filename 【TAG】QRイメージファイル名 (初期値:rqcode) 064 * textEncode 【TAG】byteモード時のテキスト文字エンコード(初期値:Charset.defaultCharset()) 7.2.3.0 (2020/04/10) 065 * caseKey 【TAG】このタグ自体を利用するかどうかの条件キーを指定します(初期値:null) 066 * caseVal 【TAG】このタグ自体を利用するかどうかの条件値を指定します(初期値:null) 067 * caseNN 【TAG】指定の値が、null/ゼロ文字列 でない場合(Not Null=NN)は、このタグは使用されます(初期値:判定しない) 068 * caseNull 【TAG】指定の値が、null/ゼロ文字列 の場合は、このタグは使用されます(初期値:判定しない) 069 * caseIf 【TAG】指定の値が、true/TRUE文字列の場合は、このタグは使用されます(初期値:判定しない) 070 * debug 【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false) 071 * > ... Body ... 072 * </og:qrCode> 073 * 074 * @og.rev 7.2.1.0 (2020/03/13) 新規作成 075 * @og.group 画面表示 076 * 077 * @version 7.2 078 * @author Kazuhiko Hasegawa 079 * @since JDK11.0, 080 */ 081public class QRcodeTag extends CommonTagSupport { 082 /** このプログラムのVERSION文字列を設定します。 {@value} */ 083 private static final String VERSION = "7.2.3.0 (2020/04/10)" ; 084 private static final long serialVersionUID = 723020200410L ; 085 086 private static final int MAX_ALT_SIZE = 50 ; // イメージに表示させる alt属性の文字数制限 087 088 private String value ; // エンコードする文字列(または、BODY部に記述) 089 private int version = QrcodeImage.DEF_VERSION ; // バージョン (2から40の整数)(初期値:5) 090 private EncMode encMode = EncMode.DEF; // エンコードモード('N':数字モード 'A':英数字モード 'B':8bit byteモード)(初期値:B) 091 private ErrCrct errCrct = ErrCrct.DEF; // エラー訂正レベル ('L','M','Q','H')(初期値:M) 092 private String imgType = QrcodeImage.IMAGE_TYPE; // イメージファイル形式(PNG/JPEG)(初期値:PNG) 093 private int pixel = QrcodeImage.PIXEL ; // 1セル辺りの塗りつぶしピクセル(初期値:3) 094 private String fileURL = HybsSystem.sys( "FILE_URL" ); // QRイメージファイルを出力するディレクトリ(初期値:FILE_URL/{@USER.ID}) 095 private String filename = "rqcode"; // QRイメージファイル名 (初期値:rqcode) 096 private String textEncode ; // byteモード時のテキスト文字エンコード(初期値:Charset.defaultCharset()) 7.2.3.0 (2020/04/10) 097 098 /** 099 * デフォルトコンストラクター 100 * 101 * @og.rev 7.2.1.0 (2020/03/13) 新規作成 102 */ 103 public QRcodeTag() { super(); } // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。 104 105 /** 106 * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。 107 * 108 * @return 後続処理の指示( EVAL_BODY_BUFFERED ) 109 */ 110 @Override 111 public int doStartTag() { 112 // caseKey 、caseVal 属性対応 113 if( useTag() ) { 114 if( value == null || value.length() <= 0 ) { 115 return EVAL_BODY_BUFFERED ; // Body を評価する 116 } 117 } 118 return SKIP_BODY ; // Body を評価しない 119 } 120 121 /** 122 * Taglibのタグ本体を処理する doAfterBody() を オーバーライドします。 123 * 124 * @return 後続処理の指示(SKIP_BODY) 125 */ 126 @Override 127 public int doAfterBody() { 128 value = getBodyString(); 129 130 return SKIP_BODY ; 131 } 132 133 /** 134 * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。 135 * 136 * @og.rev 7.2.3.0 (2020/04/10) textEncode byteモード時のテキスト文字エンコード追加 137 * 138 * @return 後続処理の指示 139 */ 140 @Override 141 public int doEndTag() { 142 debugPrint(); 143 // caseKey 、caseVal 属性対応 144 if( useTag() ) { 145 if( filename.indexOf( '.' ) < 0 ) { // 拡張子が存在しない 146 filename = filename + "." + imgType.toLowerCase(Locale.JAPAN); 147 } 148 149 try { 150 final String saveFile = HybsSystem.url2dir( fileURL,filename ); 151 152 final QrcodeImage qrcode = new QrcodeImage(); 153// qrcode.init( value,saveFile,version,encMode,errCrct,imgType,pixel ); 154 qrcode.init( value,saveFile,version,encMode,errCrct,imgType,pixel,textEncode ); // 7.2.3.0 (2020/04/10) 155 qrcode.saveImage(); 156 } 157 catch( final Throwable th ) { 158 final String errMsg = "QRコードが作成できませんでした。" + CR 159 + "指定のパラメータが正しいかどうかご確認ください。" + CR 160 + " version = [" + version + "] バージョン (2から40の整数)" + CR 161 + " encodeMode = [" + encMode + "] エンコードモード('N':数字 'A':英数字'B':byte)" + CR 162 + " errCorrect = [" + errCrct + "] エラー訂正レベル ('L','M','Q','H')" + CR 163 + " imageType = [" + imgType + "] イメージファイル形式(PNG/JPEG)" + CR 164 + " pixel = [" + pixel + "] 1セル辺りの塗りつぶしピクセル" ; 165 throw new HybsSystemException( errMsg,th ); 166 } 167 168 filename = filename + "?val=" + System.currentTimeMillis() ; // 同じファイル名の場合のキャッシュの無効化 169 final String src = StringUtil.urlAppend( getContextPath() , fileURL , filename ); 170 final String alt = value.substring( 0,Math.min( value.length() , MAX_ALT_SIZE ) ); 171 172 // 作成された QRコードのイメージを表示します。 173 final String img = XHTMLTag.img( 174 new Attributes() 175 .set( "src" , src ) 176 .set( "alt" , alt ) 177 .set( "title" , alt ) 178 ); 179 180 jspPrint( img ); 181 } 182 return EVAL_PAGE ; 183 } 184 185 /** 186 * タグリブオブジェクトをリリースします。 187 * キャッシュされて再利用されるので、フィールドの初期設定を行います。 188 * 189 * @og.rev 7.2.3.0 (2020/04/10) textEncode byteモード時のテキスト文字エンコード追加 190 */ 191 @Override 192 protected void release2() { 193 super.release2(); 194 value = null; // エンコードする文字列(または、BODY部に記述) 195 version = QrcodeImage.DEF_VERSION; // バージョン (2から40の整数)(初期値:5) 196 encMode = EncMode.DEF; // エンコードモード('N':数字モード 'A':英数字モード 'B':8bit byteモード)(初期値:B) 197 errCrct = ErrCrct.DEF ; // エラー訂正レベル ('L','M','Q','H')(初期値:M) 198 imgType = QrcodeImage.IMAGE_TYPE; // イメージファイル形式(PNG/JPEG)(初期値:PNG) 199 pixel = QrcodeImage.PIXEL ; // 1セル辺りの塗りつぶしピクセル(初期値:3) 200 fileURL = HybsSystem.sys( "FILE_URL" ); // QRイメージファイルを出力するディレクトリ(初期値:FILE_URL/{@USER.ID}) 201 filename = "rqcode"; // QRイメージファイル名 (初期値:rqcode) 202 textEncode = null; // 7.2.3.0 (2020/04/10) byteモード時のテキスト文字エンコード 203 } 204 205 /** 206 * 【TAG】エンコードする文字列(または、BODY部に記述)を指定します。 207 * 208 * @og.tag 209 * エンコードする文字列のバイト数は、バージョン、エンコードモード、エラー訂正レベルに依存します。 210 * また、イメージの大きさは、それらプラス1セル辺りのピクセルも影響します。 211 * 212 * @param val エンコードする文字列(または、BODY部に記述) 213 */ 214 public void setValue( final String val ) { 215 value = nval( getRequestParameter( val ),value ); 216 } 217 218 /** 219 * 【TAG】バージョン (2から40の整数)を指定します(初期値:5)。 220 * 221 * @og.tag 222 * エンコードする文字列のバイト数は、エラー訂正レベル、バージョン に依存します。 223 * 文字列のバイト数を増やす場合は、バージョンを適切に設定します。 224 * 225 * @param ver バージョン 226 */ 227 public void setVersion( final String ver ) { 228 version = nval( getRequestParameter( ver ),version ); 229 } 230 231 /** 232 * 【TAG】エンコードモード('N':数字モード 'A':英数字モード 'B':8bit byteモード)を指定します(初期値:B)。 233 * 234 * @og.tag 235 * エンコードする文字列の種類に応じて設定します。 236 * 日本語等を含む場合は、'B':8bit byteモード にしてください。 237 * 238 * @param mode エンコードモード 239 */ 240 public void setEncodeMode( final String mode ) { 241 final String em = nval( getRequestParameter( mode ),null ); 242 if( em != null ) { 243 encMode = EncMode.get( em.charAt(0) ); 244 } 245 } 246 247 /** 248 * 【TAG】エラー訂正レベル ('L','M','Q','H')を指定します(初期値:M)。 249 * 250 * @og.tag 251 * エンコードする文字列のバイト数は、エラー訂正レベル、バージョン に依存します。 252 * 通常、初期値のままで問題ありません。 253 * 254 * @param crct エラー訂正レベル 255 */ 256 public void setErrCorrect( final String crct ) { 257 final String ec = nval( getRequestParameter( crct ),null ); 258 if( ec != null ) { 259 errCrct = ErrCrct.get( ec.charAt(0) ); 260 } 261 } 262 263 /** 264 * 【TAG】イメージファイル形式(PNG/JPEG)を指定します(初期値:PNG)。 265 * 266 * @og.tag 267 * QRコードのイメージファイルの形式を指定します。 268 * 拡張子は自動的にイメージファイル形式(の小文字)がセットされます。 269 * 270 * @param type イメージファイル形式 271 */ 272 public void setImageType( final String type ) { 273 imgType = nval( getRequestParameter( type ),imgType ); 274 } 275 276 /** 277 * 【TAG】1セル辺りの塗りつぶしピクセルを指定します(初期値:3)。 278 * 279 * @og.tag 280 * QRコードのイメージファイルの形式を指定します。 281 * 拡張子は自動的にイメージファイル形式(の小文字)がセットされます。 282 * 283 * @param px ピクセル数 284 */ 285 public void setPixel( final String px ) { 286 pixel = nval( getRequestParameter( px ),pixel ); 287 } 288 289 /** 290 * 【TAG】 QRイメージファイルを出力するディレクトリを指定します(初期値:FILE_URL)。 291 * 292 * @og.tag 293 * この属性で指定されるディレクトリに、QRイメージファイルをセーブします。 294 * 指定方法は、通常の fileURL 属性と同様に、先頭が、'/' (UNIX) または、2文字目が、 295 * ":" (Windows)の場合は、指定のURLそのままのディレクトリに、そうでない場合は、 296 * FILE_URL 属性で指定のフォルダの下に、フォルダを作成します。 297 * 初期値は、FILE_URL になるため、通常は{@USER.ID}を指定する必要があります。 298 * 299 * @param url 保存先ディレクトリ名 300 * @see org.opengion.hayabusa.common.SystemData#FILE_URL 301 */ 302 public void setFileURL( final String url ) { 303 final String furl = nval( getRequestParameter( url ),null ); 304 if( furl != null ) { 305 fileURL = StringUtil.urlAppend( fileURL,furl ); 306 } 307 } 308 309 /** 310 * 【TAG】QRイメージファイル名をセットします(初期値:rqcode)。 311 * 312 * @og.tag 313 * ファイルを作成するときのファイル名をセットします。 314 * ファイル名の拡張子は、imageType属性の小文字を追加します。 315 * 拡張子付きで指定した場合(ファイル名に、ピリオドを含む場合)は、 316 * そのままの値を使用します。 317 * 318 * @param fname ファイル名 319 */ 320 public void setFilename( final String fname ) { 321 filename = nval( getRequestParameter( fname ),filename ); 322 } 323 324 /** 325 * 【TAG】byteモード時のテキスト文字エンコードをセットします(初期値:環境依存)。 326 * 327 * @og.tag 328 * テキストのエンコードの指定がない場合は、プラットフォーム依存のデフォルトの Charset です。 329 * java.nio.charset.Charset#defaultCharset() 330 * QRコードで、機種依存文字(①など)は、Windows-31J を指定しても読み取り側が対応していません。 331 * その場合は、UTF-8 を指定します。(必要なバイト数は当然増えます) 332 * 333 * 通常、何も指定しないか、UTF-8 を指定するかのどちらかになります。 334 * 335 * @og.rev 7.2.3.0 (2020/04/10) textEncode byteモード時のテキスト文字エンコード追加 336 * 337 * @param txtEnc テキスト文字エンコード 338 */ 339 public void setTextEncode( final String txtEnc ) { 340 textEncode = nval( getRequestParameter( txtEnc ),textEncode ); 341 } 342 343 /** 344 * このオブジェクトの文字列表現を返します。 345 * 基本的にデバッグ目的に使用します。 346 * 347 * @return このクラスの文字列表現 348 * @og.rtnNotNull 349 */ 350 @Override 351 public String toString() { 352 return ToString.title( this.getClass().getName() ) 353 .println( "VERSION" , VERSION ) 354 .println( "value" , value ) 355 .println( "version" , version ) 356 .println( "encMode" , encMode ) 357 .println( "errCrct" , errCrct ) 358 .println( "imgType" , imgType ) 359 .println( "pixel" , pixel ) 360 .println( "fileURL" , fileURL ) 361 .println( "filename" , filename ) 362 .fixForm().toString() ; 363 } 364} 365