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 }