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