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