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 */ 016 package org.opengion.fukurou.util; 017 018 import java.awt.Component; 019 import java.awt.Graphics; 020 import java.awt.image.BufferedImage; 021 022 import java.io.File; 023 import java.io.IOException; 024 import javax.imageio.ImageIO; 025 026 import com.swetake.util.Qrcode; 027 028 /** 029 * QrcodeImage ã¯ã€?¼“次å…?ƒãƒ¼ã‚³ãƒ¼ãƒ‰ã? QRコードイメージを生æˆã™ã‚? 030 * 独立ã—ãŸã‚³ãƒ³ãƒã?ãƒãƒ³ãƒˆã§ã™ã? 031 * ã“ã“ã§ã®ä½¿ã?–¹ã¯ã€å?期化時ã«ã€ã‚¨ãƒ³ã‚³ãƒ¼ãƒ‰ã™ã‚‹æ–‡å—å?(120Byte以å†?ã¨ã€? 032 * 出力ファイルåã‚’æŒ?®šã—ã¦ã€Graphics ã«æç”»ã—ãŸQRコードイメージã‚? 033 * JPEG 変æ›ã—ã?æŒ?®šã?ファイルã«ä¸Šæ›¸ãä¿å˜ã—ã¦ã?¾ã™ã? 034 * QRコード作æ?ã«ã€http://www.swetake.com/ ã® Qrcode クラスを使用ã—ã¦ã?¾ã™ã? 035 * ã“れãŒã?2004/11/7 ver.0.50beta9 ã¨ã®ã“ã¨ãªã®ã§ã€å‹•作ãƒã‚§ãƒ?‚¯ã€ãŠã‚ˆã?ã€? 036 * 製å“ã¨ã—ã¦ã®ä¿è¨¼ã¨ã?†æ„味ã§ã¯ã€ã¾ã?½¿ãˆã‚‹ãƒ¬ãƒ™ãƒ«ã§ã¯ã‚りã¾ã›ã‚“ãŒã? 037 * コード計算ã•ãˆãƒã‚°ã£ã¦ã?ªã‘れã°ä½¿ãˆã†ã‚‹ç‚ºã€è©¦é¨“的導å?致ã—ã¾ã™ã? 038 * 039 * @version 4.0 040 * @author Kazuhiko Hasegawa 041 * @since JDK5.0, 042 */ 043 public class QrcodeImage extends Component { 044 private static final long serialVersionUID = 400020050131L ; 045 046 /** エラー訂æ£ãƒ¬ãƒ™ãƒ« ('L','M','Q','H') H ã¨M ã®ã¿ã‚µãƒã?ãƒ?*/ 047 public static enum ErrCrct { 048 H(0),M(1); 049 private int no; 050 public static final ErrCrct DEF = M; 051 ErrCrct(int no) { this.no = no; } 052 public int getNo() { return no; } 053 public char getCh() { 054 final char ch ; 055 switch(this) { 056 case H: ch = 'H'; break; 057 case M: 058 default: ch = 'M'; break; 059 } 060 return ch ; 061 } 062 public static ErrCrct get( final char ch ) { 063 final ErrCrct rtn ; 064 switch(ch) { 065 case 'H': rtn = H; break; 066 case 'M': 067 default: rtn = M; break; 068 } 069 return rtn ; 070 } 071 }; 072 073 /** エンコードモーãƒ?('N':æ•°å—モーãƒ?'A':英数å—モードã?'B':8bit byteモーãƒ? */ 074 public static enum EncMode { 075 N(0),A(1),B(1); 076 private int no; 077 public static final EncMode DEF = B; 078 EncMode(int no) { this.no = no; } 079 public int getNo() { return no; } 080 public char getCh() { 081 final char ch ; 082 switch(this) { 083 case N: ch = 'N'; break; 084 case A: ch = 'A'; break; 085 case B: 086 default: ch = 'B'; break; 087 } 088 return ch ; 089 } 090 public static EncMode get( final char ch ) { 091 final EncMode rtn ; 092 switch(ch) { 093 case 'N': rtn = N; break; 094 case 'A': rtn = A; break; 095 case 'B': 096 default: rtn = B; break; 097 } 098 return rtn ; 099 } 100 }; 101 102 /** ãƒã?ジョン (1ã‹ã‚‰40ã®æ•´æ•°ã€?ã‚’è¨å®šã™ã‚‹ã¨è‡ªå‹•è¨å®šã«ãªã‚Šã¾ã™ã?) åˆæœŸå€¤:{@value} */ 103 public static final int VERSION = 5; 104 105 /** セルã®ãƒžã?ジン åˆæœŸå€¤:{@value} */ 106 public static final int MARGIN = 4; 107 108 /** ?‘セル辺りã?塗りã¤ã¶ã—ピクセル åˆæœŸå€¤:{@value} */ 109 public static final int PIXEL = 3; 110 111 /** 出力イメージã®ã‚¿ã‚¤ãƒ?PNG/JPEG) åˆæœŸå€¤:{@value} */ 112 public static final String IMAGE_TYPE = "PNG"; 113 114 private String qrData; 115 private String saveFile; 116 private String imgType = IMAGE_TYPE ; 117 private ErrCrct errCo = ErrCrct.DEF ; 118 private EncMode encMd = EncMode.DEF ; 119 private int version = VERSION ; 120 private int pixel = PIXEL ; 121 122 private int imageSize ; 123 124 /** 125 * åˆæœŸåŒ–メソãƒ?ƒ‰ 126 * 127 * エラー訂æ£ãƒ¬ãƒ™ãƒ«:M , マã?ジン:4(セルåˆ? , 塗りã¤ã¶ã—ピクセル:3 128 * エンコードモーãƒ?B(ãƒã‚¤ãƒŠãƒª) ã€ãƒãƒ¼ã‚¸ãƒ§ãƒ³:5 , イメージã®ã‚¿ã‚¤ãƒ?PNG 129 * ã«åˆæœŸåŒ–ã•れã¾ã™ã? 130 * 131 * @param qrData エンコードã™ã‚‹æ–‡å—å?(120Byte 以å†? 132 * @param saveFile 出力ファイルå? 133 */ 134 public void init( final String qrData,final String saveFile ) { 135 init( qrData,saveFile,VERSION,EncMode.DEF,ErrCrct.DEF,IMAGE_TYPE,PIXEL ); 136 } 137 138 /** 139 * åˆæœŸåŒ–メソãƒ?ƒ‰ 140 * 141 * エラー訂æ£ãƒ¬ãƒ™ãƒ«:M , マã?ジン:4(セルåˆ? , 塗りã¤ã¶ã—ピクセル:3 142 * イメージã®ã‚¿ã‚¤ãƒ?PNG ã«åˆæœŸåŒ–ã•れã¾ã™ã? 143 * 144 * @param qrData エンコードã™ã‚‹æ–‡å—å?(120Byte 以å†? 145 * @param saveFile 出力ファイルå? 146 * @param version ãƒã?ジョン (1ã‹ã‚‰40ã®æ•´æ•°ã€?ã‚’è¨å®šã™ã‚‹ã¨è‡ªå‹•è¨å®šã«ãªã‚Šã¾ã™ã?) 147 * @param encMd エンコードモーãƒ?('N':æ•°å—モーãƒ?'A':英数å—モードã?'B':8bit byteモーãƒ? 148 */ 149 public void init( final String qrData,final String saveFile,final int version,final EncMode encMd ) { 150 init( qrData,saveFile,version,encMd,ErrCrct.DEF,IMAGE_TYPE,PIXEL ); 151 } 152 153 /** 154 * åˆæœŸåŒ–メソãƒ?ƒ‰ 155 * 156 * エラー訂æ£ãƒ¬ãƒ™ãƒ«:M , マã?ジン:4(セルåˆ? , 塗りã¤ã¶ã—ピクセル:3 157 * 158 * @param qrData エンコードã™ã‚‹æ–‡å—å?(120Byte 以å†? 159 * @param saveFile 出力ファイルå? 160 * @param version ãƒã?ジョン (1ã‹ã‚‰40ã®æ•´æ•°ã€?ã‚’è¨å®šã™ã‚‹ã¨è‡ªå‹•è¨å®šã«ãªã‚Šã¾ã™ã?) 161 * @param encMd エンコードモーãƒ?'N':æ•°å—モーãƒ?'A':英数å—モードã?'B':8bit byteモーãƒ? 162 * @param errCo エラー訂æ£ãƒ¬ãƒ™ãƒ« ('L','M','Q','H') 163 * @param imgType イメージファイル形å¼?PNG/JPEG) 164 * @param pixel ?‘セル辺りã?塗りã¤ã¶ã—ピクセル 165 */ 166 public void init( final String qrData,final String saveFile,final int version,final EncMode encMd, 167 final ErrCrct errCo ,final String imgType,final int pixel ) { 168 169 this.qrData = qrData; 170 this.saveFile = saveFile; 171 this.imgType = imgType; 172 this.errCo = errCo; 173 this.encMd = encMd; 174 this.version = version; 175 this.pixel = pixel; 176 177 imageSize = ( MARGIN*2 + 17 + version*4 )*pixel; 178 } 179 180 /** 181 * æç”»å‡¦ç?‚’行ã„ã¾ã™ã? 182 * 183 * @param gpx Graphicsオブジェクãƒ? 184 */ 185 @Override 186 public void paint( final Graphics gpx ) { 187 Qrcode qrc =new Qrcode(); 188 qrc.setQrcodeErrorCorrect(errCo.getCh()); 189 qrc.setQrcodeEncodeMode(encMd.getCh()); 190 qrc.setQrcodeVersion(version); 191 192 // byte[] dt =qrData.getBytes(); 193 byte[] dt =qrData.getBytes( StringUtil.DEFAULT_CHARSET ); // 5.5.2.6 (2012/05/25) findbugs対å¿? 194 boolean[][] sfg = qrc.calQrcode( dt ); 195 196 int size = sfg.length; 197 int mgn = MARGIN*pixel ; 198 for( int i=0; i<size; i++ ) { 199 for( int j=0; j<size; j++ ) { 200 if( sfg[j][i] ) { 201 gpx.fillRect( mgn+j*pixel,mgn+i*pixel,pixel,pixel ); 202 } 203 } 204 } 205 } 206 207 /** 208 * æç”»å‡¦ç?‚’行ã„ã¾ã™ã? 209 * 210 */ 211 public void saveImage() { 212 // 出力用イメージã®ç”Ÿæ? 213 BufferedImage image = new BufferedImage(imageSize, imageSize, BufferedImage.TYPE_INT_BGR ); 214 215 // イメージã‹ã‚‰ã‚°ãƒ©ãƒ•ã‚£ãƒ?‚¯ã‚³ãƒ³ãƒ?‚ストをå–å¾? 216 Graphics grph = image.getGraphics(); 217 grph.setColor( java.awt.Color.WHITE ); 218 grph.fillRect( 0,0,imageSize, imageSize ); 219 grph.setColor( java.awt.Color.BLACK ); 220 221 // JEditorPane ã‚’ã‚¤ãƒ¡ãƒ¼ã‚¸ã«æ›¸ãè¾¼ã‚? 222 // paintComponent 㯠proteced ãªã®ã§ä½¿ç”¨ã§ããªã? 223 paint( grph ); 224 225 // 使ã?µ‚ã‚ã£ãŸã‚°ãƒ©ãƒ•ã‚£ãƒ?‚¯ã‚³ãƒ³ãƒ?‚ストを開放 226 grph.dispose(); 227 228 try { 229 // イメージã®å‡ºåŠ?Image I/O を使用 230 ImageIO.write( image, imgType, new File( saveFile ) ); 231 } catch ( IOException ex ) { 232 String errMsg = "イメージファイルã®å‡ºåŠ›ã«å¤±æ•—ã—ã¾ã—ãŸã€? 233 + "File=[" + saveFile + "]" ; 234 throw new RuntimeException( errMsg,ex ); 235 } 236 } 237 238 /** 239 * メイン処ç?§ã™ã? 240 * java org.opengion.fukurou.util.QrcodeImage "Encode_String" [Saev Filename] 241 * 242 * @param args 引数æ–?—å?é…å? 243 */ 244 public static void main( final String[] args ) { 245 if( args.length == 0 ) { 246 LogWriter.log( "Usage: java org.opengion.fukurou.util.QrcodeImage [Encode String] [Saev Filename]" ); 247 return ; 248 } 249 250 String qrcode = args[0]; 251 String file = (args.length > 1) ? args[1] : "img.png"; 252 253 QrcodeImage qrImage = new QrcodeImage(); 254 qrImage.init( qrcode,file ); 255 qrImage.saveImage(); 256 } 257 258 /** 259 * å†?ƒ¨ãƒ??タを標準å?力ã¸å‡ºåŠ›ã—ã¾ã™ã? 260 * 261 */ 262 public static void printQcData() { 263 char[] strJ = new char[] { 'H','M' }; 264 char[] strK = new char[] { 'N','A','B' }; 265 266 for( int i=0; i<QC_DATA.length; i++ ) { 267 System.out.print( "version=[" + (i+1) + "] " ); 268 for( int j=0; j<QC_DATA[i].length; j++ ) { 269 char errCo = strJ[j]; 270 for( int k=0; k<QC_DATA[i][j].length; k++ ) { 271 System.out.print( errCo + strK[k] + "=[" + QC_DATA[i][j][k] + "] " ); 272 } 273 } 274 System.out.println(); 275 } 276 } 277 278 /** 279 * ãƒã?ジョンæƒ??ã‚’å–å¾—ã—ã¾ã™ã? 280 * 281 * @param errCo エラー訂æ£ãƒ¬ãƒ™ãƒ« ('L','M','Q','H') 282 * @param encMd エンコードモーãƒ?('N':æ•°å—モーãƒ?'A':英数å—モードã?'B':8bit byteモーãƒ? 283 * @param len 対象ç¯?›² 284 * 285 * @return ãƒã?ジョンæƒ?? 286 */ 287 public static int getVersion( final ErrCrct errCo, final EncMode encMd, final int len ) { 288 int errCoInt = errCo.getNo() ; 289 int encMdInt = encMd.getNo() ; 290 291 int rtn = -1; 292 for( int i=0; i<QC_DATA.length; i++ ) { 293 if( QC_DATA[i][errCoInt][encMdInt] >= len ) { 294 rtn = i; 295 break; 296 } 297 } 298 299 if( rtn < 0 ) { 300 String errMsg = "ãƒ??ã‚¿é‡ãŒå¯¾è±¡ç¯?›²ã‚’è¶?ˆã¦ã?¾ã™ã?エラーレベルã‚??モードを調整ã—ã¦ãã ã•ã„ã€? 301 + "ErrCo:" + errCo + " EncMd:" + encMd + " len=[" + len + "]" 302 + " MaxLen=[" + QC_DATA[QC_DATA.length-1][errCoInt][encMdInt] + "]" ; 303 throw new RuntimeException( errMsg ); 304 } 305 306 return rtn + 1 ; 307 } 308 309 /** 310 * æœ?¤§ã‚µã‚¤ã‚ºã‚’å–å¾—ã—ã¾ã™ã? 311 * 312 * @param version ãƒã?ジョンæƒ?? 313 * @param errCo エラー訂æ£ãƒ¬ãƒ™ãƒ« ('L','M','Q','H') 314 * @param encMd エンコードモーãƒ?('N':æ•°å—モーãƒ?'A':英数å—モードã?'B':8bit byteモーãƒ? 315 * 316 * @return æœ?¤§ã‚µã‚¤ã‚º 317 */ 318 public static int getMaxSize( final int version, final ErrCrct errCo, final EncMode encMd ) { 319 int errCoInt = errCo.getNo() ; 320 int encMdInt = encMd.getNo() ; 321 322 return QC_DATA[version][errCoInt][encMdInt] ; 323 } 324 325 // version 0 ??39 => 1 ??40 326 // errCo H,M 0:H 1:M 327 // encMd N,A,B 0:N 1:A 2:B 328 private static final int[][][] QC_DATA = new int[][][] { 329 {{ 17 , 10 , 4 } , { 34 , 20 , 8 }} , 330 {{ 34 , 20 , 8 } , { 63 , 38 , 16 }} , 331 {{ 58 , 35 , 15 } , { 101 , 61 , 26 }} , 332 {{ 82 , 50 , 21 } , { 149 , 90 , 38 }} , 333 {{ 106 , 64 , 27 } , { 202 , 122 , 52 }} , 334 {{ 139 , 84 , 36 } , { 255 , 154 , 65 }} , 335 {{ 154 , 93 , 39 } , { 293 , 178 , 75 }} , 336 {{ 202 , 122 , 52 } , { 365 , 221 , 93 }} , 337 {{ 235 , 143 , 60 } , { 432 , 262 , 111 }} , 338 {{ 288 , 174 , 74 } , { 513 , 311 , 131 }} , 339 {{ 331 , 200 , 85 } , { 604 , 366 , 155 }} , 340 {{ 374 , 227 , 96 } , { 691 , 419 , 177 }} , 341 {{ 427 , 259 , 109 } , { 796 , 483 , 204 }} , 342 {{ 468 , 283 , 120 } , { 871 , 528 , 223 }} , 343 {{ 530 , 321 , 136 } , { 991 , 600 , 254 }} , 344 {{ 602 , 365 , 154 } , { 1082 , 656 , 277 }} , 345 {{ 674 , 408 , 173 } , { 1212 , 734 , 310 }} , 346 {{ 746 , 452 , 191 } , { 1346 , 816 , 345 }} , 347 {{ 813 , 493 , 208 } , { 1500 , 909 , 384 }} , 348 {{ 919 , 557 , 235 } , { 1600 , 970 , 410 }} , 349 {{ 969 , 587 , 248 } , { 1708 , 1035 , 438 }} , 350 {{ 1056 , 640 , 270 } , { 1872 , 1134 , 480 }} , 351 {{ 1108 , 672 , 284 } , { 2059 , 1248 , 528 }} , 352 {{ 1228 , 744 , 315 } , { 2188 , 1326 , 561 }} , 353 {{ 1286 , 779 , 330 } , { 2395 , 1451 , 614 }} , 354 {{ 1425 , 864 , 365 } , { 2544 , 1542 , 652 }} , 355 {{ 1501 , 910 , 385 } , { 2701 , 1637 , 692 }} , 356 {{ 1581 , 958 , 405 } , { 2857 , 1732 , 732 }} , 357 {{ 1677 , 1016 , 430 } , { 3035 , 1839 , 778 }} , 358 {{ 1782 , 1080 , 457 } , { 3289 , 1994 , 843 }} , 359 {{ 1897 , 1150 , 486 } , { 3486 , 2113 , 894 }} , 360 {{ 2022 , 1226 , 518 } , { 3693 , 2238 , 947 }} , 361 {{ 2157 , 1307 , 553 } , { 3909 , 2369 , 1002 }} , 362 {{ 2301 , 1394 , 590 } , { 4134 , 2506 , 1060 }} , 363 {{ 2361 , 1431 , 605 } , { 4343 , 2632 , 1113 }} , 364 {{ 2524 , 1530 , 647 } , { 4588 , 2780 , 1176 }} , 365 {{ 2625 , 1591 , 673 } , { 4775 , 2894 , 1224 }} , 366 {{ 2735 , 1658 , 701 } , { 5039 , 3054 , 1292 }} , 367 {{ 2927 , 1774 , 750 } , { 5313 , 3220 , 1362 }} , 368 {{ 3057 , 1852 , 784 } , { 5596 , 3391 , 1435 }} } ; 369 }