forked from netshade/Cocoa-Touch-Barcodes
-
Notifications
You must be signed in to change notification settings - Fork 0
/
JapanPostBarcode.m
323 lines (292 loc) · 10.4 KB
/
JapanPostBarcode.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
//
// JapanPostBarcode.m
// BarcodePod
//
// Created by 佐藤 昭 on Mon Jun 30 2003.
// Copyright (c) 2003 SatoAkira. All rights reserved.
//
#import "JapanPostBarcode.h"
@implementation JapanPostBarcode
#define MILLIMETERPERPOINT 0.3527777777777777 // base72.0 //
#define JP_DESCENDER_BOTTOM 0.0 // 最下段基準線(mm) //
#define JP_TRACK_BOTTOM 1.2 // 中段下基準線(mm) //
#define JP_TRACK_TOP 2.4 // 中段上基準線(mm) //
#define JP_ASCENDER_TOP 3.6 // 最上段基準線(mm) //
#define JP_ASCENDER_MASK (0x222)
#define JP_DESCENDER_MASK (0x111)
// -----------------------------------------------------------------------------------
// Constants
// -----------------------------------------------------------------------------------
// Each hex constant represents a 4-bar code of the barcode corresponding to a single number or letter. The digits represent bars in this fashion: //
// 0 - タイミングバー (JP_TRACK_BOTTOM to JP_TRACK_TOP) //
// 1 - 下セミロングバー (JP_DESCENDER_BOTTOM to JP_TRACK_TOP) //
// 2 - 上セミロングバー (JP_TRACK_BOTTOM to JP_ASCENDER_TOP) //
// 3 - ロングバー (JP_DESCENDER_BOTTOM to JP_ASCENDER_TOP) //
unsigned int openBracketLength = 2;
unsigned int openBracket = 0x31; // スタートコード //
unsigned int closeBracketLength = 2;
unsigned int closeBracket = 0x13; // ストップコード //
NSString *barFormat = @"101010101010101010101010";
unsigned int numberLength = 3;
unsigned int numberCodesOfJapan[] = {
0x030, // - //
0x003, // CC7 . //
0x333, // CC8 / //
0x300, // 0 //
0x330, // 1 //
0x312, // 2 //
0x132, // 3 //
0x321, // 4 //
0x303, // 5 //
0x123, // 6 //
0x231, // 7 //
0x213, // 8 //
0x033, // 9 //
0x120, // CC1 : //
0x102, // CC2 ; //
0x210, // CC3 < //
0x012, // CC4 = //
0x201, // CC5 > //
0x021 // CC6 ? //
};
double japanpost_barTop(unsigned int hexDigit,double size) { // mm単位で返す。 //
return (hexDigit & JP_ASCENDER_MASK) ? JP_ASCENDER_TOP * size / 10.0 : JP_TRACK_TOP * size / 10.0;
}
double japanpost_barBottom(unsigned int hexDigit,double size) { // mm単位で返す。 //
return (hexDigit & JP_DESCENDER_MASK) ? JP_DESCENDER_BOTTOM * size / 10.0 : JP_TRACK_BOTTOM * size / 10.0;
}
unsigned int japanpost_characterDescriptor(unichar character) {
return numberCodesOfJapan[character - '-'];
}
unsigned int japanpost_barDescriptor(unsigned int descriptor,unsigned int bar,unsigned int bars)
{
unsigned int shift = (bars - 1 - (bar / 2)) * 4; // 4ビットずつで1つのバーを表す。bar / 2 番目 //
unsigned int mask = 0xF << shift; // 0xfは4ビット分 //
return (descriptor & mask) >> shift;
}
- (unsigned int)_barDescriptor:(unsigned int)index
// barcode is [self initiator][self barcode][self terminator] //
// 2 * numberLength がほぼ定数に近い働きをしており、これを変数にすることが難しい。よって'A'~'Z'は2文字の扱いをした。 //
{
unsigned int bar;
unsigned int hexDigit;
unsigned int descriptor;
unsigned int contentLength = [japanpostContents length];
if ([[self initiator] length] > index) {
bar = index % [[self initiator] length];
hexDigit = openBracket;
descriptor = japanpost_barDescriptor(hexDigit,bar,openBracketLength);
}
else {
if (index >= (contentLength + 1) * (2 * numberLength) + [[self initiator] length]) {
bar = (index - [[self initiator] length] - (contentLength + 1) * (2 * numberLength)) % [[self terminator] length];
hexDigit = closeBracket;
descriptor = japanpost_barDescriptor(hexDigit,bar,closeBracketLength);
}
else {
unsigned int digit = (index - [[self initiator] length]) / (2 * numberLength); // 何文字目か //
bar = (index - [[self initiator] length]) % (2 * numberLength); // 1文字の中の何番目のバーになるか //
if (digit != contentLength) {
hexDigit = japanpost_characterDescriptor( [[self japanpostContents] characterAtIndex:digit] );
descriptor = japanpost_barDescriptor( hexDigit, bar,numberLength);
}
else { // last digit is checksum
hexDigit = japanpost_characterDescriptor( [self checkDigit] );
descriptor = japanpost_barDescriptor( hexDigit, bar,numberLength);
}
}
}
return descriptor;
}
- (NSString *)japanpostContents {
return japanpostContents;
}
// override //
- (id)initWithContent:(NSString *)inContent printsCaption:(BOOL)inPrints andBarWidth:(float)inBarWidth andHeight:(float)inHeight andFontSize:(float)inFontSize andCheckDigit:(char)inDigit
// inPrints,inBarWidth,inFontSize,inDigitは意味を持たない。 //
{
if ((nil != inContent) && (nil != (self = [super init]))) {
[self setContent:inContent];
if ((8.0 <= inHeight) && (11.5 >= inHeight))
[self setHeight:inHeight];
else
[self setHeight:10.0];
}
return self;
}
- (void)setHeight:(float)inHeight
// inHeight:ポイント単位 //
{
if (8.5 > inHeight)
height = 8.5;
else {
if (11.5 < inHeight)
height = 11.5;
else
height = inHeight;
}
barWidth = (float)((double)height / (double)6.0);
[self calculateWidth];
}
- (void)setBarWidth:(float)inBarWidth
// inBarWidth:point単位 //
{
if (1.3333333333333333 > inBarWidth) // 8.0 / 6.0 //
barWidth = 1.3333333333333333;
else {
if (1.9166666666667 < inBarWidth) // 11.5 / 6.0 //
barWidth = 1.9166666666667;
else
barWidth = inBarWidth;
}
height = (float)((double)6.0 * (double)barWidth);
[self calculateWidth];
}
- (void)generateChecksum
{
unsigned int i,cd;
unichar uChar,character;
unsigned int checkValue = 0;
for (i = 0; i < [japanpostContents length]; i++) {
uChar = [japanpostContents characterAtIndex:i];
if ('-' == uChar)
checkValue += 10; // 10 //
else {
if ((',' == uChar) || ('/' == uChar))
checkValue += (uChar - '-') + 16; // 17 or 18 //
else {
if (('0' <= uChar) && ('9' >= uChar))
checkValue += uChar - '0'; // 0 ~ 9 //
else {
checkValue += uChar - ':' + 11; // 11 ~ 16 //
}
}
}
}
cd = 19 * (checkValue / 19 + 1) - checkValue;
if ((0 <= cd) && (10 > cd))
character = '0' + cd;
else {
if (10 == cd)
character = '-';
else {
if ((10 < cd) && (16 >= cd))
character = ':' + cd - 11;
else
character = '-' + cd - 16;
}
}
[self setCheckDigit:character];
}
- (void)setContent:(NSString *)inContent
// 大文字化する。20文字に揃える。使用できない文字を排除する。郵便番号の整合性はチェックしない。 //
{
unichar uChar;
unsigned int i;
NSString *uppercaseString = [inContent uppercaseString];
NSMutableString *tempStr = [NSMutableString string];
NSMutableString *tempContents = [NSMutableString string];
NSString *tenStr = @"0123456789";
unsigned int maxLength = 20; // 郵便番号7文字+住居表示番号13文字 //
for (i = 0; i < [uppercaseString length]; i++) {
uChar = [uppercaseString characterAtIndex:i];
if (('A' <= uChar) && ('Z' >= uChar)) {
if ('K' > uChar) {
[tempStr appendString:@":"]; // CC1 //
[tempStr appendString:[tenStr substringWithRange:NSMakeRange((unsigned int)(uChar - 'A'),1)]];
[tempContents appendString:[NSString stringWithCharacters:&uChar length:1]];
}
else {
if ('U' > uChar) {
[tempStr appendString:@";"]; // CC2 //
[tempStr appendString:[tenStr substringWithRange:NSMakeRange((unsigned int)(uChar - 'K'),1)]];
[tempContents appendString:[NSString stringWithCharacters:&uChar length:1]];
}
else { // ('Z' >= uChar) //
[tempStr appendString:@"<"]; // CC3 //
[tempStr appendString:[tenStr substringWithRange:NSMakeRange((unsigned int)(uChar - 'U'),1)]];
[tempContents appendString:[NSString stringWithCharacters:&uChar length:1]];
}
}
}
else {
if (('-' == uChar) || (('0' <= uChar) && ('9' >= uChar))) {
[tempStr appendString:[NSString stringWithCharacters:&uChar length:1]];
[tempContents appendString:[NSString stringWithCharacters:&uChar length:1]];
} // 使用できない文字を排除する。 //
}
}
if (maxLength > [tempStr length]) {
for (i = [tempStr length]; i < maxLength; i++)
[tempStr appendString:@"="]; // CC4 //
}
else {
if (maxLength < [tempStr length]) {
unsigned int validCount;
unsigned int tempL = [tempStr length];
NSString *tempCStr = [NSString stringWithString:tempContents];
[tempStr deleteCharactersInRange:NSMakeRange(maxLength,tempL - maxLength)];
tempL = [tempStr length];
validCount = 0;
for (i = 0; i < [tempStr length]; i++) {
uChar = [tempStr characterAtIndex:i];
if (('-' == uChar) || (('0' <= uChar) && ('9' >= uChar))) // 'A'~'Z'も制御文字+数字文字になっているのでカウントできる。 //
validCount++;
}
tempContents = [NSMutableString stringWithString:[tempCStr substringWithRange:NSMakeRange(0,validCount)]];
}
}
[japanpostContents release];
japanpostContents = [[NSString allocWithZone:[self zone]] initWithString:tempStr];
[content release];
content = [[NSString allocWithZone:[self zone]] initWithString:tempContents];
[self generateChecksum];
}
- (BOOL)isContentValid
{
unsigned int i;
unichar uChar;
BOOL result = YES;
for (i = 0; i < 7; i++) {
uChar = [content characterAtIndex:i];
if (('0' > uChar) || ('9' < uChar)) {
result = NO;
break;
}
}
return result;
}
- (NSString *)barcode
// japanpostContentsを参照するところがNKDBarcodeと異なる。 //
{
unsigned int i;
NSMutableString *theReturn = [NSMutableString string];
for (i = 0; i < [japanpostContents length]; i++)
[theReturn appendString:[self _encodeChar:[japanpostContents characterAtIndex:i]]];
if (checkDigit != -1)
[theReturn appendString:[self _encodeChar:checkDigit]];
return theReturn;
}
- (BOOL)printsCaption {
return NO;
}
- (NSString *)initiator {
return [barFormat substringToIndex:2 * openBracketLength];
}
- (NSString *)terminator {
return [barFormat substringToIndex:2 * closeBracketLength - 1]; // 最後の"0"は不要 //
}
- (float)barTop:(int)index {
return (float)(japanpost_barTop([self _barDescriptor:(unsigned int)index],(double)height) / (double)MILLIMETERPERPOINT);
}
- (float)barBottom:(int)index {
return (float)(japanpost_barBottom([self _barDescriptor:(unsigned int)index],(double)height) / (double)MILLIMETERPERPOINT);
}
- (NSString *)_encodeChar:(char)inChar {
return [barFormat substringToIndex:2 * numberLength];
}
- (void)calculateWidth
{
[self setWidth:(float)((double)[[self completeBarcode] length] * (double)[self barWidth])];
}
@end