From 4ee35caf2d34fda282d15470ffe57ed50a8b0dc2 Mon Sep 17 00:00:00 2001 From: Mortimer <874607211@qq.com> Date: Wed, 31 May 2017 16:43:26 +0800 Subject: [PATCH] last --- iDearQRCode.xcodeproj/project.pbxproj | 2263 ++++++++++++++++- .../@3x/btn_addCell.imageset/Contents.json | 0 .../btn_\346\267\273\345\212\240@2x.png" | Bin .../btn_\346\267\273\345\212\240@3x.png" | Bin .../@3x/icon_delete).imageset/Contents.json | 0 .../icon_\345\210\240\351\231\244(2)@2x.png" | Bin .../icon_\345\210\240\351\231\244(2)@3x.png" | Bin iDearQRCode/BaseQRCode/BaseModel.h | 22 + iDearQRCode/BaseQRCode/BaseModel.m | 13 + iDearQRCode/BaseQRCode/BaseTableViewCell.h | 23 + iDearQRCode/BaseQRCode/BaseTableViewCell.m | 43 + iDearQRCode/BaseQRCode/BaseViewController.h | 6 + iDearQRCode/BaseQRCode/BaseViewController.m | 119 +- iDearQRCode/MainVC/QRCViewController.m | 7 +- .../YQNetworking/Cache/YQCacheManager.h | 107 + .../YQNetworking/Cache/YQCacheManager.m | 241 ++ .../YQNetworking/Cache/YQDiskCache.h | 57 + .../YQNetworking/Cache/YQDiskCache.m | 109 + .../YQNetworking/Cache/YQLRUManager.h | 46 + .../YQNetworking/Cache/YQLRUManager.m | 93 + .../YQNetworking/Cache/YQMemoryCache.h | 32 + .../YQNetworking/Cache/YQMemoryCache.m | 59 + .../YQNetworking+RequestManager.h | 30 + .../YQNetworking+RequestManager.m | 64 + .../NetManager/YQNetworking/YQNetworking.h | 285 +++ .../NetManager/YQNetworking/YQNetworking.m | 483 ++++ iDearQRCode/Manager/UserManager/KeyManager.h | 19 + iDearQRCode/Manager/UserManager/KeyManager.m | 59 + iDearQRCode/Manager/UserManager/UserManager.h | 33 + iDearQRCode/Manager/UserManager/UserManager.m | 76 + .../Manager/UserManager/UserModel/UserModel.h | 20 + .../Manager/UserManager/UserModel/UserModel.m | 46 + iDearQRCode/Me/View/PersonHeadView.h | 6 +- iDearQRCode/Me/View/PersonHeadView.m | 17 +- iDearQRCode/Me/personViewController.m | 47 +- iDearQRCode/OtherVC/Controller/PickDetailVc.m | 196 +- iDearQRCode/OtherVC/Controller/PickingVC.m | 484 ++-- .../Controller/ResultDisplayController.h | 12 + .../Controller/ResultDisplayController.m | 15 +- iDearQRCode/OtherVC/Model/PickDetailModel.h | 13 + iDearQRCode/OtherVC/Model/PickDetailModel.m | 13 + iDearQRCode/OtherVC/Model/PickingViewModel.h | 10 +- iDearQRCode/OtherVC/Model/PickingViewModel.m | 28 +- .../PreloadVC/Controller/NewPreloadVC.h | 13 + .../PreloadVC/Controller/NewPreloadVC.m | 257 ++ .../PreloadVC/Controller/PartSearchView.h | 17 + .../PreloadVC/Controller/PartSearchView.m | 236 ++ .../PreloadVC/Controller/PreloadDetailVC.h | 15 + .../PreloadVC/Controller/PreloadDetailVC.m | 216 ++ .../Controller/PreloadViewController.h | 13 + .../Controller/PreloadViewController.m | 527 ++++ .../PreloadVC/Model/PreloadViewModel.h | 32 + .../PreloadVC/Model/PreloadViewModel.m | 150 ++ .../PreloadVC/Model/PrereloadCellModel.h | 20 + .../PreloadVC/Model/PrereloadCellModel.m | 13 + .../OtherVC/PreloadVC/View/NewPartCell.h | 23 + .../OtherVC/PreloadVC/View/NewPartCell.m | 150 ++ .../PreloadVC/View/NewPartNumberView.h | 25 + .../PreloadVC/View/NewPartNumberView.m | 199 ++ .../PreloadVC/View/PreloadDetailCell.h | 20 + .../PreloadVC/View/PreloadDetailCell.m | 244 ++ .../PreloadVC/View/PreloadDetailView.h | 16 + .../PreloadVC/View/PreloadDetailView.m | 133 + .../OtherVC/PreloadVC/View/PreloadNewView.h | 21 + .../OtherVC/PreloadVC/View/PreloadNewView.m | 136 + .../OtherVC/PreloadVC/View/PrereloadCell.h | 28 + .../OtherVC/PreloadVC/View/PrereloadCell.m | 353 +++ iDearQRCode/OtherVC/QRCodeVC/QRCodeResultVC.h | 15 + iDearQRCode/OtherVC/QRCodeVC/QRCodeResultVC.m | 55 + iDearQRCode/OtherVC/QRCodeVC/QRCodeVC.h | 34 + iDearQRCode/OtherVC/QRCodeVC/QRCodeVC.m | 303 +++ .../OtherVC/QRCodeVC/View/QRCodeResultView.h | 18 + .../OtherVC/QRCodeVC/View/QRCodeResultView.m | 232 ++ iDearQRCode/OtherVC/View/PickDateView.m | 6 +- iDearQRCode/OtherVC/View/PickDetailFootView.h | 14 + iDearQRCode/OtherVC/View/PickDetailFootView.m | 96 + iDearQRCode/OtherVC/View/PickDetailView.h | 16 + iDearQRCode/OtherVC/View/PickDetailView.m | 229 ++ iDearQRCode/OtherVC/View/PickingCell.h | 4 +- iDearQRCode/OtherVC/View/PickingCell.m | 29 +- iDearQRCode/OtherVC/View/PickingFootView.h | 13 +- iDearQRCode/OtherVC/View/PickingFootView.m | 53 +- iDearQRCode/OtherVC/View/PickingHeadView.h | 17 +- iDearQRCode/OtherVC/View/PickingHeadView.m | 24 +- .../Category/UIImage+Common/UIImage+Common.h | 4 + .../Category/UIImage+Common/UIImage+Common.m | 26 + .../Tools/Category/UIImage+Normalimage.h | 16 - .../Tools/Category/UIImage+Normalimage.m | 35 - .../CodeScan.bundle/device_scan@2x.png | Bin 0 -> 336 bytes .../qrcode_Scan_weixin_Line@2x.png | Bin 0 -> 1500 bytes .../qrcode_scan_btn_flash_down@2x.png | Bin 0 -> 938 bytes .../qrcode_scan_btn_flash_nor@2x.png | Bin 0 -> 1173 bytes .../qrcode_scan_btn_myqrcode_down@2x.png | Bin 0 -> 1327 bytes .../qrcode_scan_btn_myqrcode_nor@2x.png | Bin 0 -> 1603 bytes .../qrcode_scan_btn_photo_down@2x.png | Bin 0 -> 980 bytes .../qrcode_scan_btn_photo_nor@2x.png | Bin 0 -> 1243 bytes .../qrcode_scan_btn_scan_off@2x.png | Bin 0 -> 956 bytes .../CodeScan.bundle/qrcode_scan_full_net.png | Bin 0 -> 4878 bytes .../qrcode_scan_light_green@2x.png | Bin 0 -> 801 bytes .../CodeScan.bundle/qrcode_scan_part_net.png | Bin 0 -> 4637 bytes .../qrcode_scan_titlebar_back_nor@2x.png | Bin 0 -> 185 bytes .../qrcode_scan_titlebar_back_pressed@2x.png | Bin 0 -> 164 bytes .../Class/UIActionSheet+LBXAlertAction.h | 17 + .../Class/UIActionSheet+LBXAlertAction.m | 46 + ...ontroller+supportedInterfaceOrientations.h | 13 + ...ontroller+supportedInterfaceOrientations.m | 21 + .../Class/UIAlertView+LBXAlertAction.h | 21 + .../Class/UIAlertView+LBXAlertAction.m | 41 + .../LBXScan/LBXAlertAction/LBXAlertAction.h | 47 + .../LBXScan/LBXAlertAction/LBXAlertAction.m | 217 ++ .../Tools/LBXScan/LBXScanLineAnimation.h | 29 + .../Tools/LBXScan/LBXScanLineAnimation.m | 163 ++ iDearQRCode/Tools/LBXScan/LBXScanNative.h | 86 + iDearQRCode/Tools/LBXScan/LBXScanNative.m | 458 ++++ .../Tools/LBXScan/LBXScanNetAnimation.h | 29 + .../Tools/LBXScan/LBXScanNetAnimation.m | 99 + iDearQRCode/Tools/LBXScan/LBXScanResult.h | 30 + iDearQRCode/Tools/LBXScan/LBXScanResult.m | 25 + .../Tools/LBXScan/LBXScanVideoZoomView.h | 19 + .../Tools/LBXScan/LBXScanVideoZoomView.m | 128 + iDearQRCode/Tools/LBXScan/LBXScanView.h | 62 + iDearQRCode/Tools/LBXScan/LBXScanView.m | 416 +++ .../Tools/LBXScan/LBXScanViewController.h | 84 + .../Tools/LBXScan/LBXScanViewController.m | 226 ++ iDearQRCode/Tools/LBXScan/LBXScanViewStyle.h | 125 + iDearQRCode/Tools/LBXScan/LBXScanViewStyle.m | 50 + iDearQRCode/Tools/LBXScan/LBXScanWrapper.h | 212 ++ iDearQRCode/Tools/LBXScan/LBXScanWrapper.m | 650 +++++ iDearQRCode/Tools/LBXScan/LBXZXCapture.h | 70 + iDearQRCode/Tools/LBXScan/LBXZXCapture.m | 608 +++++ .../Tools/LBXScan/LBXZXCaptureDelegate.h | 31 + iDearQRCode/Tools/LBXScan/ZXingWrapper.h | 75 + iDearQRCode/Tools/LBXScan/ZXingWrapper.m | 165 ++ iDearQRCode/Tools/Lib/ViewModelClass.h | 4 +- iDearQRCode/Tools/Lib/ZYThirdPartService.m | 26 +- .../Tools/ZXingObjC/ZXMultiFormatReader.h | 41 + .../Tools/ZXingObjC/ZXMultiFormatReader.m | 164 ++ .../Tools/ZXingObjC/ZXMultiFormatWriter.h | 27 + .../Tools/ZXingObjC/ZXMultiFormatWriter.m | 96 + iDearQRCode/Tools/ZXingObjC/ZXingObjC.h | 34 + .../ZXingObjC/aztec/ZXAztecDetectorResult.h | 32 + .../ZXingObjC/aztec/ZXAztecDetectorResult.m | 35 + .../Tools/ZXingObjC/aztec/ZXAztecReader.h | 26 + .../Tools/ZXingObjC/aztec/ZXAztecReader.m | 89 + .../Tools/ZXingObjC/aztec/ZXAztecWriter.h | 21 + .../Tools/ZXingObjC/aztec/ZXAztecWriter.m | 89 + .../Tools/ZXingObjC/aztec/ZXingObjCAztec.h | 32 + .../ZXingObjC/aztec/decoder/ZXAztecDecoder.h | 30 + .../ZXingObjC/aztec/decoder/ZXAztecDecoder.m | 351 +++ .../aztec/detector/ZXAztecDetector.h | 45 + .../aztec/detector/ZXAztecDetector.m | 619 +++++ .../aztec/encoder/ZXAztecBinaryShiftToken.h | 23 + .../aztec/encoder/ZXAztecBinaryShiftToken.m | 59 + .../ZXingObjC/aztec/encoder/ZXAztecCode.h | 49 + .../ZXingObjC/aztec/encoder/ZXAztecCode.m | 21 + .../ZXingObjC/aztec/encoder/ZXAztecEncoder.h | 48 + .../ZXingObjC/aztec/encoder/ZXAztecEncoder.m | 335 +++ .../aztec/encoder/ZXAztecHighLevelEncoder.h | 50 + .../aztec/encoder/ZXAztecHighLevelEncoder.m | 294 +++ .../aztec/encoder/ZXAztecSimpleToken.h | 23 + .../aztec/encoder/ZXAztecSimpleToken.m | 55 + .../ZXingObjC/aztec/encoder/ZXAztecState.h | 49 + .../ZXingObjC/aztec/encoder/ZXAztecState.m | 132 + .../ZXingObjC/aztec/encoder/ZXAztecToken.h | 29 + .../ZXingObjC/aztec/encoder/ZXAztecToken.m | 51 + .../client/ZXCGImageLuminanceSource.h | 57 + .../client/ZXCGImageLuminanceSource.m | 308 +++ .../Tools/ZXingObjC/client/ZXCapture.h | 60 + .../Tools/ZXingObjC/client/ZXCapture.m | 544 ++++ .../ZXingObjC/client/ZXCaptureDelegate.h | 31 + iDearQRCode/Tools/ZXingObjC/client/ZXImage.h | 32 + iDearQRCode/Tools/ZXingObjC/client/ZXImage.m | 135 + .../result/ZXAbstractDoCoMoResultParser.h | 28 + .../result/ZXAbstractDoCoMoResultParser.m | 29 + .../result/ZXAddressBookAUResultParser.h | 25 + .../result/ZXAddressBookAUResultParser.m | 80 + .../result/ZXAddressBookDoCoMoResultParser.h | 35 + .../result/ZXAddressBookDoCoMoResultParser.m | 75 + .../client/result/ZXAddressBookParsedResult.h | 93 + .../client/result/ZXAddressBookParsedResult.m | 94 + .../client/result/ZXBizcardResultParser.h | 26 + .../client/result/ZXBizcardResultParser.m | 87 + .../result/ZXBookmarkDoCoMoResultParser.h | 21 + .../result/ZXBookmarkDoCoMoResultParser.m | 41 + .../client/result/ZXCalendarParsedResult.h | 43 + .../client/result/ZXCalendarParsedResult.m | 164 ++ .../result/ZXEmailAddressParsedResult.h | 46 + .../result/ZXEmailAddressParsedResult.m | 60 + .../result/ZXEmailAddressResultParser.h | 25 + .../result/ZXEmailAddressResultParser.m | 78 + .../client/result/ZXEmailDoCoMoResultParser.h | 34 + .../client/result/ZXEmailDoCoMoResultParser.m | 56 + .../result/ZXExpandedProductParsedResult.h | 54 + .../result/ZXExpandedProductParsedResult.m | 119 + .../result/ZXExpandedProductResultParser.h | 24 + .../result/ZXExpandedProductResultParser.m | 162 ++ .../client/result/ZXGeoParsedResult.h | 45 + .../client/result/ZXGeoParsedResult.m | 62 + .../client/result/ZXGeoResultParser.h | 26 + .../client/result/ZXGeoResultParser.m | 70 + .../client/result/ZXISBNParsedResult.h | 26 + .../client/result/ZXISBNParsedResult.m | 37 + .../client/result/ZXISBNResultParser.h | 24 + .../client/result/ZXISBNResultParser.m | 41 + .../ZXingObjC/client/result/ZXParsedResult.h | 39 + .../ZXingObjC/client/result/ZXParsedResult.m | 61 + .../client/result/ZXParsedResultType.h | 37 + .../client/result/ZXProductParsedResult.h | 29 + .../client/result/ZXProductParsedResult.m | 46 + .../client/result/ZXProductResultParser.h | 24 + .../client/result/ZXProductResultParser.m | 45 + .../ZXingObjC/client/result/ZXResultParser.h | 50 + .../ZXingObjC/client/result/ZXResultParser.m | 317 +++ .../client/result/ZXSMSMMSResultParser.h | 34 + .../client/result/ZXSMSMMSResultParser.m | 83 + .../client/result/ZXSMSParsedResult.h | 32 + .../client/result/ZXSMSParsedResult.m | 97 + .../client/result/ZXSMSTOMMSTOResultParser.h | 29 + .../client/result/ZXSMSTOMMSTOResultParser.m | 40 + .../client/result/ZXSMTPResultParser.h | 25 + .../client/result/ZXSMTPResultParser.m | 44 + .../client/result/ZXTelParsedResult.h | 28 + .../client/result/ZXTelParsedResult.m | 42 + .../client/result/ZXTelResultParser.h | 24 + .../client/result/ZXTelResultParser.m | 35 + .../client/result/ZXTextParsedResult.h | 31 + .../client/result/ZXTextParsedResult.m | 39 + .../client/result/ZXURIParsedResult.h | 37 + .../client/result/ZXURIParsedResult.m | 80 + .../client/result/ZXURIResultParser.h | 26 + .../client/result/ZXURIResultParser.m | 66 + .../client/result/ZXURLTOResultParser.h | 26 + .../client/result/ZXURLTOResultParser.m | 37 + .../client/result/ZXVCardResultParser.h | 28 + .../client/result/ZXVCardResultParser.m | 356 +++ .../client/result/ZXVEventResultParser.h | 25 + .../client/result/ZXVEventResultParser.m | 108 + .../client/result/ZXVINParsedResult.h | 37 + .../client/result/ZXVINParsedResult.m | 54 + .../client/result/ZXVINResultParser.h | 24 + .../client/result/ZXVINResultParser.m | 219 ++ .../client/result/ZXWifiParsedResult.h | 31 + .../client/result/ZXWifiParsedResult.m | 54 + .../client/result/ZXWifiResultParser.h | 28 + .../client/result/ZXWifiResultParser.m | 42 + .../Tools/ZXingObjC/common/ZXBitArray.h | 132 + .../Tools/ZXingObjC/common/ZXBitArray.m | 348 +++ .../Tools/ZXingObjC/common/ZXBitMatrix.h | 153 ++ .../Tools/ZXingObjC/common/ZXBitMatrix.m | 377 +++ .../Tools/ZXingObjC/common/ZXBitSource.h | 57 + .../Tools/ZXingObjC/common/ZXBitSource.m | 84 + .../Tools/ZXingObjC/common/ZXBoolArray.h | 24 + .../Tools/ZXingObjC/common/ZXBoolArray.m | 36 + .../Tools/ZXingObjC/common/ZXByteArray.h | 25 + .../Tools/ZXingObjC/common/ZXByteArray.m | 76 + .../ZXingObjC/common/ZXCharacterSetECI.h | 40 + .../ZXingObjC/common/ZXCharacterSetECI.m | 94 + .../Tools/ZXingObjC/common/ZXDecoderResult.h | 45 + .../Tools/ZXingObjC/common/ZXDecoderResult.m | 45 + .../ZXingObjC/common/ZXDefaultGridSampler.h | 23 + .../ZXingObjC/common/ZXDefaultGridSampler.m | 91 + .../Tools/ZXingObjC/common/ZXDetectorResult.h | 31 + .../Tools/ZXingObjC/common/ZXDetectorResult.m | 31 + .../common/ZXGlobalHistogramBinarizer.h | 37 + .../common/ZXGlobalHistogramBinarizer.m | 199 ++ .../Tools/ZXingObjC/common/ZXGridSampler.h | 93 + .../Tools/ZXingObjC/common/ZXGridSampler.m | 122 + .../ZXingObjC/common/ZXHybridBinarizer.h | 38 + .../ZXingObjC/common/ZXHybridBinarizer.m | 223 ++ .../Tools/ZXingObjC/common/ZXIntArray.h | 27 + .../Tools/ZXingObjC/common/ZXIntArray.m | 95 + .../ZXingObjC/common/ZXPerspectiveTransform.h | 32 + .../ZXingObjC/common/ZXPerspectiveTransform.m | 128 + .../Tools/ZXingObjC/common/ZXStringUtils.h | 33 + .../Tools/ZXingObjC/common/ZXStringUtils.m | 188 ++ .../ZXingObjC/common/detector/ZXMathUtils.h | 23 + .../ZXingObjC/common/detector/ZXMathUtils.m | 37 + .../detector/ZXMonochromeRectangleDetector.h | 40 + .../detector/ZXMonochromeRectangleDetector.m | 209 ++ .../detector/ZXWhiteRectangleDetector.h | 45 + .../detector/ZXWhiteRectangleDetector.m | 311 +++ .../common/reedsolomon/ZXGenericGF.h | 87 + .../common/reedsolomon/ZXGenericGF.m | 178 ++ .../common/reedsolomon/ZXGenericGFPoly.h | 64 + .../common/reedsolomon/ZXGenericGFPoly.m | 246 ++ .../common/reedsolomon/ZXReedSolomonDecoder.h | 51 + .../common/reedsolomon/ZXReedSolomonDecoder.m | 189 ++ .../common/reedsolomon/ZXReedSolomonEncoder.h | 27 + .../common/reedsolomon/ZXReedSolomonEncoder.m | 88 + .../Tools/ZXingObjC/core/ZXBarcodeFormat.h | 71 + .../Tools/ZXingObjC/core/ZXBinarizer.h | 74 + .../Tools/ZXingObjC/core/ZXBinarizer.m | 123 + .../Tools/ZXingObjC/core/ZXBinaryBitmap.h | 99 + .../Tools/ZXingObjC/core/ZXBinaryBitmap.m | 98 + .../Tools/ZXingObjC/core/ZXByteMatrix.h | 30 + .../Tools/ZXingObjC/core/ZXByteMatrix.m | 94 + .../Tools/ZXingObjC/core/ZXDecodeHints.h | 97 + .../Tools/ZXingObjC/core/ZXDecodeHints.m | 77 + .../Tools/ZXingObjC/core/ZXDimension.h | 27 + .../Tools/ZXingObjC/core/ZXDimension.m | 50 + .../Tools/ZXingObjC/core/ZXEncodeHints.h | 112 + .../Tools/ZXingObjC/core/ZXEncodeHints.m | 25 + iDearQRCode/Tools/ZXingObjC/core/ZXErrors.h | 61 + iDearQRCode/Tools/ZXingObjC/core/ZXErrors.m | 35 + .../core/ZXInvertedLuminanceSource.h | 27 + .../core/ZXInvertedLuminanceSource.m | 86 + .../Tools/ZXingObjC/core/ZXLuminanceSource.h | 108 + .../Tools/ZXingObjC/core/ZXLuminanceSource.m | 92 + .../core/ZXPlanarYUVLuminanceSource.h | 44 + .../core/ZXPlanarYUVLuminanceSource.m | 147 ++ .../ZXingObjC/core/ZXRGBLuminanceSource.h | 27 + .../ZXingObjC/core/ZXRGBLuminanceSource.m | 136 + iDearQRCode/Tools/ZXingObjC/core/ZXReader.h | 59 + iDearQRCode/Tools/ZXingObjC/core/ZXResult.h | 66 + iDearQRCode/Tools/ZXingObjC/core/ZXResult.m | 82 + .../ZXingObjC/core/ZXResultMetadataType.h | 91 + .../Tools/ZXingObjC/core/ZXResultPoint.h | 41 + .../Tools/ZXingObjC/core/ZXResultPoint.m | 99 + .../ZXingObjC/core/ZXResultPointCallback.h | 27 + iDearQRCode/Tools/ZXingObjC/core/ZXWriter.h | 46 + .../Tools/ZXingObjC/core/ZXingObjCCore.h | 77 + .../ZXingObjC/datamatrix/ZXDataMatrixReader.h | 26 + .../ZXingObjC/datamatrix/ZXDataMatrixReader.m | 173 ++ .../ZXingObjC/datamatrix/ZXDataMatrixWriter.h | 24 + .../ZXingObjC/datamatrix/ZXDataMatrixWriter.m | 169 ++ .../datamatrix/ZXingObjCDataMatrix.h | 31 + .../decoder/ZXDataMatrixBitMatrixParser.h | 38 + .../decoder/ZXDataMatrixBitMatrixParser.m | 429 ++++ .../decoder/ZXDataMatrixDataBlock.h | 41 + .../decoder/ZXDataMatrixDataBlock.m | 92 + .../ZXDataMatrixDecodedBitStreamParser.h | 29 + .../ZXDataMatrixDecodedBitStreamParser.m | 497 ++++ .../datamatrix/decoder/ZXDataMatrixDecoder.h | 47 + .../datamatrix/decoder/ZXDataMatrixDecoder.m | 135 + .../datamatrix/decoder/ZXDataMatrixVersion.h | 66 + .../datamatrix/decoder/ZXDataMatrixVersion.m | 348 +++ .../detector/ZXDataMatrixDetector.h | 35 + .../detector/ZXDataMatrixDetector.m | 359 +++ .../encoder/ZXDataMatrixASCIIEncoder.h | 21 + .../encoder/ZXDataMatrixASCIIEncoder.m | 79 + .../encoder/ZXDataMatrixBase256Encoder.h | 21 + .../encoder/ZXDataMatrixBase256Encoder.m | 78 + .../encoder/ZXDataMatrixC40Encoder.h | 25 + .../encoder/ZXDataMatrixC40Encoder.m | 181 ++ .../encoder/ZXDataMatrixDefaultPlacement.h | 41 + .../encoder/ZXDataMatrixDefaultPlacement.m | 181 ++ .../encoder/ZXDataMatrixEdifactEncoder.h | 21 + .../encoder/ZXDataMatrixEdifactEncoder.m | 142 ++ .../datamatrix/encoder/ZXDataMatrixEncoder.h | 24 + .../encoder/ZXDataMatrixEncoderContext.h | 48 + .../encoder/ZXDataMatrixEncoderContext.m | 111 + .../encoder/ZXDataMatrixErrorCorrection.h | 33 + .../encoder/ZXDataMatrixErrorCorrection.m | 171 ++ .../encoder/ZXDataMatrixHighLevelEncoder.h | 135 + .../encoder/ZXDataMatrixHighLevelEncoder.m | 431 ++++ .../encoder/ZXDataMatrixSymbolInfo.h | 63 + .../encoder/ZXDataMatrixSymbolInfo.m | 220 ++ .../encoder/ZXDataMatrixSymbolInfo144.h | 21 + .../encoder/ZXDataMatrixSymbolInfo144.m | 33 + .../encoder/ZXDataMatrixTextEncoder.h | 21 + .../encoder/ZXDataMatrixTextEncoder.m | 84 + .../encoder/ZXDataMatrixX12Encoder.h | 21 + .../encoder/ZXDataMatrixX12Encoder.m | 84 + .../ZXingObjC/maxicode/ZXMaxiCodeReader.h | 26 + .../ZXingObjC/maxicode/ZXMaxiCodeReader.m | 128 + .../ZXingObjC/maxicode/ZXingObjCMaxiCode.h | 24 + .../decoder/ZXMaxiCodeBitMatrixParser.h | 24 + .../decoder/ZXMaxiCodeBitMatrixParser.m | 90 + .../ZXMaxiCodeDecodedBitStreamParser.h | 27 + .../ZXMaxiCodeDecodedBitStreamParser.m | 203 ++ .../maxicode/decoder/ZXMaxiCodeDecoder.h | 28 + .../maxicode/decoder/ZXMaxiCodeDecoder.m | 134 + .../ZXingObjC/multi/ZXByQuadrantReader.h | 30 + .../ZXingObjC/multi/ZXByQuadrantReader.m | 121 + .../multi/ZXGenericMultipleBarcodeReader.h | 37 + .../multi/ZXGenericMultipleBarcodeReader.m | 140 + .../ZXingObjC/multi/ZXMultipleBarcodeReader.h | 30 + .../Tools/ZXingObjC/oned/ZXCodaBarReader.h | 32 + .../Tools/ZXingObjC/oned/ZXCodaBarReader.m | 367 +++ .../Tools/ZXingObjC/oned/ZXCodaBarWriter.h | 24 + .../Tools/ZXingObjC/oned/ZXCodaBarWriter.m | 140 + .../Tools/ZXingObjC/oned/ZXCode128Reader.h | 40 + .../Tools/ZXingObjC/oned/ZXCode128Reader.m | 534 ++++ .../Tools/ZXingObjC/oned/ZXCode128Writer.h | 24 + .../Tools/ZXingObjC/oned/ZXCode128Writer.m | 188 ++ .../Tools/ZXingObjC/oned/ZXCode39Reader.h | 57 + .../Tools/ZXingObjC/oned/ZXCode39Reader.m | 310 +++ .../Tools/ZXingObjC/oned/ZXCode39Writer.h | 24 + .../Tools/ZXingObjC/oned/ZXCode39Writer.m | 74 + .../Tools/ZXingObjC/oned/ZXCode93Reader.h | 24 + .../Tools/ZXingObjC/oned/ZXCode93Reader.m | 291 +++ .../Tools/ZXingObjC/oned/ZXEAN13Reader.h | 26 + .../Tools/ZXingObjC/oned/ZXEAN13Reader.m | 146 ++ .../Tools/ZXingObjC/oned/ZXEAN13Writer.h | 24 + .../Tools/ZXingObjC/oned/ZXEAN13Writer.m | 78 + .../Tools/ZXingObjC/oned/ZXEAN8Reader.h | 24 + .../Tools/ZXingObjC/oned/ZXEAN8Reader.m | 74 + .../Tools/ZXingObjC/oned/ZXEAN8Writer.h | 24 + .../Tools/ZXingObjC/oned/ZXEAN8Writer.m | 63 + .../oned/ZXEANManufacturerOrgSupport.h | 27 + .../oned/ZXEANManufacturerOrgSupport.m | 178 ++ .../Tools/ZXingObjC/oned/ZXITFReader.h | 39 + .../Tools/ZXingObjC/oned/ZXITFReader.m | 356 +++ .../Tools/ZXingObjC/oned/ZXITFWriter.h | 24 + .../Tools/ZXingObjC/oned/ZXITFWriter.m | 62 + .../ZXingObjC/oned/ZXMultiFormatOneDReader.h | 25 + .../ZXingObjC/oned/ZXMultiFormatOneDReader.m | 111 + .../oned/ZXMultiFormatUPCEANReader.h | 30 + .../oned/ZXMultiFormatUPCEANReader.m | 112 + .../Tools/ZXingObjC/oned/ZXOneDReader.h | 32 + .../Tools/ZXingObjC/oned/ZXOneDReader.m | 267 ++ .../oned/ZXOneDimensionalCodeWriter.h | 30 + .../oned/ZXOneDimensionalCodeWriter.m | 115 + .../Tools/ZXingObjC/oned/ZXUPCAReader.h | 24 + .../Tools/ZXingObjC/oned/ZXUPCAReader.m | 114 + .../Tools/ZXingObjC/oned/ZXUPCAWriter.h | 24 + .../Tools/ZXingObjC/oned/ZXUPCAWriter.m | 67 + .../oned/ZXUPCEANExtension2Support.h | 27 + .../oned/ZXUPCEANExtension2Support.m | 114 + .../oned/ZXUPCEANExtension5Support.h | 27 + .../oned/ZXUPCEANExtension5Support.m | 183 ++ .../ZXingObjC/oned/ZXUPCEANExtensionSupport.h | 23 + .../ZXingObjC/oned/ZXUPCEANExtensionSupport.m | 62 + .../Tools/ZXingObjC/oned/ZXUPCEANReader.h | 116 + .../Tools/ZXingObjC/oned/ZXUPCEANReader.m | 385 +++ .../Tools/ZXingObjC/oned/ZXUPCEANWriter.h | 25 + .../Tools/ZXingObjC/oned/ZXUPCEANWriter.m | 29 + .../Tools/ZXingObjC/oned/ZXUPCEReader.h | 29 + .../Tools/ZXingObjC/oned/ZXUPCEReader.m | 154 ++ .../Tools/ZXingObjC/oned/ZXingObjCOneD.h | 92 + .../ZXingObjC/oned/rss/ZXAbstractRSSReader.h | 43 + .../ZXingObjC/oned/rss/ZXAbstractRSSReader.m | 161 ++ .../Tools/ZXingObjC/oned/rss/ZXRSS14Reader.h | 26 + .../Tools/ZXingObjC/oned/rss/ZXRSS14Reader.m | 440 ++++ .../ZXingObjC/oned/rss/ZXRSSDataCharacter.h | 24 + .../ZXingObjC/oned/rss/ZXRSSDataCharacter.m | 47 + .../ZXingObjC/oned/rss/ZXRSSFinderPattern.h | 29 + .../ZXingObjC/oned/rss/ZXRSSFinderPattern.m | 45 + .../Tools/ZXingObjC/oned/rss/ZXRSSPair.h | 29 + .../Tools/ZXingObjC/oned/rss/ZXRSSPair.m | 40 + .../Tools/ZXingObjC/oned/rss/ZXRSSUtils.h | 28 + .../Tools/ZXingObjC/oned/rss/ZXRSSUtils.m | 156 ++ .../oned/rss/expanded/ZXBitArrayBuilder.h | 23 + .../oned/rss/expanded/ZXBitArrayBuilder.m | 70 + .../oned/rss/expanded/ZXRSSExpandedPair.h | 29 + .../oned/rss/expanded/ZXRSSExpandedPair.m | 67 + .../oned/rss/expanded/ZXRSSExpandedReader.h | 27 + .../oned/rss/expanded/ZXRSSExpandedReader.m | 742 ++++++ .../oned/rss/expanded/ZXRSSExpandedRow.h | 31 + .../oned/rss/expanded/ZXRSSExpandedRow.m | 58 + .../rss/expanded/decoders/ZXAI013103decoder.h | 21 + .../rss/expanded/decoders/ZXAI013103decoder.m | 30 + .../rss/expanded/decoders/ZXAI01320xDecoder.h | 21 + .../rss/expanded/decoders/ZXAI01320xDecoder.m | 36 + .../rss/expanded/decoders/ZXAI01392xDecoder.h | 21 + .../rss/expanded/decoders/ZXAI01392xDecoder.m | 42 + .../rss/expanded/decoders/ZXAI01393xDecoder.h | 21 + .../rss/expanded/decoders/ZXAI01393xDecoder.m | 61 + .../expanded/decoders/ZXAI013x0x1xDecoder.h | 23 + .../expanded/decoders/ZXAI013x0x1xDecoder.m | 90 + .../rss/expanded/decoders/ZXAI013x0xDecoder.h | 21 + .../rss/expanded/decoders/ZXAI013x0xDecoder.m | 40 + .../rss/expanded/decoders/ZXAI01AndOtherAIs.h | 21 + .../rss/expanded/decoders/ZXAI01AndOtherAIs.m | 37 + .../rss/expanded/decoders/ZXAI01decoder.h | 26 + .../rss/expanded/decoders/ZXAI01decoder.m | 63 + .../expanded/decoders/ZXAI01weightDecoder.h | 25 + .../expanded/decoders/ZXAI01weightDecoder.m | 51 + .../decoders/ZXAbstractExpandedDecoder.h | 28 + .../decoders/ZXAbstractExpandedDecoder.m | 95 + .../rss/expanded/decoders/ZXAnyAIDecoder.h | 21 + .../rss/expanded/decoders/ZXAnyAIDecoder.m | 29 + .../decoders/ZXRSSExpandedBlockParsedResult.h | 27 + .../decoders/ZXRSSExpandedBlockParsedResult.m | 35 + .../ZXRSSExpandedCurrentParsingState.h | 28 + .../ZXRSSExpandedCurrentParsingState.m | 65 + .../decoders/ZXRSSExpandedDecodedChar.h | 28 + .../decoders/ZXRSSExpandedDecodedChar.m | 35 + .../ZXRSSExpandedDecodedInformation.h | 28 + .../ZXRSSExpandedDecodedInformation.m | 41 + .../decoders/ZXRSSExpandedDecodedNumeric.h | 32 + .../decoders/ZXRSSExpandedDecodedNumeric.m | 52 + .../decoders/ZXRSSExpandedDecodedObject.h | 23 + .../decoders/ZXRSSExpandedDecodedObject.m | 29 + .../decoders/ZXRSSExpandedFieldParser.h | 21 + .../decoders/ZXRSSExpandedFieldParser.m | 319 +++ .../ZXRSSExpandedGeneralAppIdDecoder.h | 27 + .../ZXRSSExpandedGeneralAppIdDecoder.m | 517 ++++ .../Tools/ZXingObjC/pdf417/ZXPDF417Common.h | 42 + .../Tools/ZXingObjC/pdf417/ZXPDF417Common.m | 468 ++++ .../Tools/ZXingObjC/pdf417/ZXPDF417Reader.h | 30 + .../Tools/ZXingObjC/pdf417/ZXPDF417Reader.m | 134 + .../ZXingObjC/pdf417/ZXPDF417ResultMetadata.h | 24 + .../ZXingObjC/pdf417/ZXPDF417ResultMetadata.m | 21 + .../Tools/ZXingObjC/pdf417/ZXPDF417Writer.h | 21 + .../Tools/ZXingObjC/pdf417/ZXPDF417Writer.m | 153 ++ .../Tools/ZXingObjC/pdf417/ZXingObjCPDF417.h | 34 + .../pdf417/decoder/ZXPDF417BarcodeMetadata.h | 28 + .../pdf417/decoder/ZXPDF417BarcodeMetadata.m | 35 + .../pdf417/decoder/ZXPDF417BarcodeValue.h | 34 + .../pdf417/decoder/ZXPDF417BarcodeValue.m | 67 + .../pdf417/decoder/ZXPDF417BoundingBox.h | 37 + .../pdf417/decoder/ZXPDF417BoundingBox.m | 135 + .../pdf417/decoder/ZXPDF417Codeword.h | 31 + .../pdf417/decoder/ZXPDF417Codeword.m | 56 + .../pdf417/decoder/ZXPDF417CodewordDecoder.h | 21 + .../pdf417/decoder/ZXPDF417CodewordDecoder.m | 114 + .../decoder/ZXPDF417DecodedBitStreamParser.h | 26 + .../decoder/ZXPDF417DecodedBitStreamParser.m | 643 +++++ .../pdf417/decoder/ZXPDF417DetectionResult.h | 31 + .../pdf417/decoder/ZXPDF417DetectionResult.m | 303 +++ .../decoder/ZXPDF417DetectionResultColumn.h | 30 + .../decoder/ZXPDF417DetectionResultColumn.m | 91 + ...XPDF417DetectionResultRowIndicatorColumn.h | 30 + ...XPDF417DetectionResultRowIndicatorColumn.m | 265 ++ .../pdf417/decoder/ZXPDF417ScanningDecoder.h | 31 + .../pdf417/decoder/ZXPDF417ScanningDecoder.m | 685 +++++ .../ZXingObjC/pdf417/decoder/ec/ZXModulusGF.h | 40 + .../ZXingObjC/pdf417/decoder/ec/ZXModulusGF.m | 115 + .../pdf417/decoder/ec/ZXModulusPoly.h | 34 + .../pdf417/decoder/ec/ZXModulusPoly.m | 263 ++ .../decoder/ec/ZXPDF417ECErrorCorrection.h | 32 + .../decoder/ec/ZXPDF417ECErrorCorrection.m | 181 ++ .../pdf417/detector/ZXPDF417Detector.h | 36 + .../pdf417/detector/ZXPDF417Detector.m | 348 +++ .../pdf417/detector/ZXPDF417DetectorResult.h | 26 + .../pdf417/detector/ZXPDF417DetectorResult.m | 31 + .../Tools/ZXingObjC/pdf417/encoder/ZXPDF417.h | 55 + .../Tools/ZXingObjC/pdf417/encoder/ZXPDF417.m | 733 ++++++ .../pdf417/encoder/ZXPDF417BarcodeMatrix.h | 38 + .../pdf417/encoder/ZXPDF417BarcodeMatrix.m | 86 + .../pdf417/encoder/ZXPDF417BarcodeRow.h | 60 + .../pdf417/encoder/ZXPDF417BarcodeRow.m | 63 + .../pdf417/encoder/ZXPDF417Dimensions.h | 29 + .../pdf417/encoder/ZXPDF417Dimensions.m | 32 + .../pdf417/encoder/ZXPDF417ErrorCorrection.h | 51 + .../pdf417/encoder/ZXPDF417ErrorCorrection.m | 176 ++ .../pdf417/encoder/ZXPDF417HighLevelEncoder.h | 37 + .../pdf417/encoder/ZXPDF417HighLevelEncoder.m | 586 +++++ .../Tools/ZXingObjC/qrcode/ZXQRCodeReader.h | 28 + .../Tools/ZXingObjC/qrcode/ZXQRCodeReader.m | 218 ++ .../Tools/ZXingObjC/qrcode/ZXQRCodeWriter.h | 24 + .../Tools/ZXingObjC/qrcode/ZXQRCodeWriter.m | 94 + .../Tools/ZXingObjC/qrcode/ZXingObjCQRCode.h | 39 + .../qrcode/decoder/ZXQRCodeBitMatrixParser.h | 72 + .../qrcode/decoder/ZXQRCodeBitMatrixParser.m | 223 ++ .../qrcode/decoder/ZXQRCodeDataBlock.h | 44 + .../qrcode/decoder/ZXQRCodeDataBlock.m | 98 + .../qrcode/decoder/ZXQRCodeDataMask.h | 48 + .../qrcode/decoder/ZXQRCodeDataMask.m | 196 ++ .../decoder/ZXQRCodeDecodedBitStreamParser.h | 33 + .../decoder/ZXQRCodeDecodedBitStreamParser.m | 338 +++ .../qrcode/decoder/ZXQRCodeDecoder.h | 50 + .../qrcode/decoder/ZXQRCodeDecoder.m | 191 ++ .../qrcode/decoder/ZXQRCodeDecoderMetaData.h | 34 + .../qrcode/decoder/ZXQRCodeDecoderMetaData.m | 40 + .../decoder/ZXQRCodeErrorCorrectionLevel.h | 55 + .../decoder/ZXQRCodeErrorCorrectionLevel.m | 87 + .../decoder/ZXQRCodeFormatInformation.h | 39 + .../decoder/ZXQRCodeFormatInformation.m | 138 + .../ZXingObjC/qrcode/decoder/ZXQRCodeMode.h | 56 + .../ZXingObjC/qrcode/decoder/ZXQRCodeMode.m | 172 ++ .../qrcode/decoder/ZXQRCodeVersion.h | 71 + .../qrcode/decoder/ZXQRCodeVersion.m | 497 ++++ .../detector/ZXQRCodeAlignmentPattern.h | 39 + .../detector/ZXQRCodeAlignmentPattern.m | 51 + .../detector/ZXQRCodeAlignmentPatternFinder.h | 55 + .../detector/ZXQRCodeAlignmentPatternFinder.m | 239 ++ .../qrcode/detector/ZXQRCodeDetector.h | 69 + .../qrcode/detector/ZXQRCodeDetector.m | 331 +++ .../qrcode/detector/ZXQRCodeFinderPattern.h | 48 + .../qrcode/detector/ZXQRCodeFinderPattern.m | 59 + .../detector/ZXQRCodeFinderPatternFinder.h | 71 + .../detector/ZXQRCodeFinderPatternFinder.m | 570 +++++ .../detector/ZXQRCodeFinderPatternInfo.h | 31 + .../detector/ZXQRCodeFinderPatternInfo.m | 32 + .../Tools/ZXingObjC/qrcode/encoder/ZXQRCode.h | 31 + .../Tools/ZXingObjC/qrcode/encoder/ZXQRCode.m | 58 + .../qrcode/encoder/ZXQRCodeBlockPair.h | 26 + .../qrcode/encoder/ZXQRCodeBlockPair.m | 30 + .../qrcode/encoder/ZXQRCodeEncoder.h | 87 + .../qrcode/encoder/ZXQRCodeEncoder.m | 563 ++++ .../qrcode/encoder/ZXQRCodeMaskUtil.h | 53 + .../qrcode/encoder/ZXQRCodeMaskUtil.m | 190 ++ .../qrcode/encoder/ZXQRCodeMatrixUtil.h | 91 + .../qrcode/encoder/ZXQRCodeMatrixUtil.m | 466 ++++ .../qrcode/multi/ZXQRCodeMultiReader.h | 25 + .../qrcode/multi/ZXQRCodeMultiReader.m | 147 ++ .../qrcode/multi/detector/ZXMultiDetector.h | 30 + .../qrcode/multi/detector/ZXMultiDetector.m | 45 + .../detector/ZXMultiFinderPatternFinder.h | 36 + .../detector/ZXMultiFinderPatternFinder.m | 240 ++ iDearQRCode/iDear_Public.h | 6 +- 593 files changed, 57306 insertions(+), 467 deletions(-) rename "iDearQRCode/Assets.xcassets/@3x/btn_\346\267\273\345\212\240.imageset/Contents.json" => iDearQRCode/Assets.xcassets/@3x/btn_addCell.imageset/Contents.json (100%) rename "iDearQRCode/Assets.xcassets/@3x/btn_\346\267\273\345\212\240.imageset/btn_\346\267\273\345\212\240@2x.png" => "iDearQRCode/Assets.xcassets/@3x/btn_addCell.imageset/btn_\346\267\273\345\212\240@2x.png" (100%) rename "iDearQRCode/Assets.xcassets/@3x/btn_\346\267\273\345\212\240.imageset/btn_\346\267\273\345\212\240@3x.png" => "iDearQRCode/Assets.xcassets/@3x/btn_addCell.imageset/btn_\346\267\273\345\212\240@3x.png" (100%) rename "iDearQRCode/Assets.xcassets/@3x/icon_\345\210\240\351\231\244(2).imageset/Contents.json" => iDearQRCode/Assets.xcassets/@3x/icon_delete).imageset/Contents.json (100%) rename "iDearQRCode/Assets.xcassets/@3x/icon_\345\210\240\351\231\244(2).imageset/icon_\345\210\240\351\231\244(2)@2x.png" => "iDearQRCode/Assets.xcassets/@3x/icon_delete).imageset/icon_\345\210\240\351\231\244(2)@2x.png" (100%) rename "iDearQRCode/Assets.xcassets/@3x/icon_\345\210\240\351\231\244(2).imageset/icon_\345\210\240\351\231\244(2)@3x.png" => "iDearQRCode/Assets.xcassets/@3x/icon_delete).imageset/icon_\345\210\240\351\231\244(2)@3x.png" (100%) create mode 100644 iDearQRCode/BaseQRCode/BaseModel.h create mode 100644 iDearQRCode/BaseQRCode/BaseModel.m create mode 100644 iDearQRCode/BaseQRCode/BaseTableViewCell.h create mode 100644 iDearQRCode/BaseQRCode/BaseTableViewCell.m create mode 100755 iDearQRCode/Manager/NetManager/YQNetworking/Cache/YQCacheManager.h create mode 100755 iDearQRCode/Manager/NetManager/YQNetworking/Cache/YQCacheManager.m create mode 100755 iDearQRCode/Manager/NetManager/YQNetworking/Cache/YQDiskCache.h create mode 100755 iDearQRCode/Manager/NetManager/YQNetworking/Cache/YQDiskCache.m create mode 100755 iDearQRCode/Manager/NetManager/YQNetworking/Cache/YQLRUManager.h create mode 100755 iDearQRCode/Manager/NetManager/YQNetworking/Cache/YQLRUManager.m create mode 100755 iDearQRCode/Manager/NetManager/YQNetworking/Cache/YQMemoryCache.h create mode 100755 iDearQRCode/Manager/NetManager/YQNetworking/Cache/YQMemoryCache.m create mode 100755 iDearQRCode/Manager/NetManager/YQNetworking/RequestManager/YQNetworking+RequestManager.h create mode 100755 iDearQRCode/Manager/NetManager/YQNetworking/RequestManager/YQNetworking+RequestManager.m create mode 100755 iDearQRCode/Manager/NetManager/YQNetworking/YQNetworking.h create mode 100755 iDearQRCode/Manager/NetManager/YQNetworking/YQNetworking.m create mode 100644 iDearQRCode/Manager/UserManager/KeyManager.h create mode 100644 iDearQRCode/Manager/UserManager/KeyManager.m create mode 100644 iDearQRCode/Manager/UserManager/UserManager.h create mode 100644 iDearQRCode/Manager/UserManager/UserManager.m create mode 100644 iDearQRCode/Manager/UserManager/UserModel/UserModel.h create mode 100644 iDearQRCode/Manager/UserManager/UserModel/UserModel.m create mode 100644 iDearQRCode/OtherVC/Model/PickDetailModel.h create mode 100644 iDearQRCode/OtherVC/Model/PickDetailModel.m create mode 100644 iDearQRCode/OtherVC/PreloadVC/Controller/NewPreloadVC.h create mode 100644 iDearQRCode/OtherVC/PreloadVC/Controller/NewPreloadVC.m create mode 100644 iDearQRCode/OtherVC/PreloadVC/Controller/PartSearchView.h create mode 100644 iDearQRCode/OtherVC/PreloadVC/Controller/PartSearchView.m create mode 100644 iDearQRCode/OtherVC/PreloadVC/Controller/PreloadDetailVC.h create mode 100644 iDearQRCode/OtherVC/PreloadVC/Controller/PreloadDetailVC.m create mode 100644 iDearQRCode/OtherVC/PreloadVC/Controller/PreloadViewController.h create mode 100644 iDearQRCode/OtherVC/PreloadVC/Controller/PreloadViewController.m create mode 100644 iDearQRCode/OtherVC/PreloadVC/Model/PreloadViewModel.h create mode 100644 iDearQRCode/OtherVC/PreloadVC/Model/PreloadViewModel.m create mode 100644 iDearQRCode/OtherVC/PreloadVC/Model/PrereloadCellModel.h create mode 100644 iDearQRCode/OtherVC/PreloadVC/Model/PrereloadCellModel.m create mode 100644 iDearQRCode/OtherVC/PreloadVC/View/NewPartCell.h create mode 100644 iDearQRCode/OtherVC/PreloadVC/View/NewPartCell.m create mode 100644 iDearQRCode/OtherVC/PreloadVC/View/NewPartNumberView.h create mode 100644 iDearQRCode/OtherVC/PreloadVC/View/NewPartNumberView.m create mode 100644 iDearQRCode/OtherVC/PreloadVC/View/PreloadDetailCell.h create mode 100644 iDearQRCode/OtherVC/PreloadVC/View/PreloadDetailCell.m create mode 100644 iDearQRCode/OtherVC/PreloadVC/View/PreloadDetailView.h create mode 100644 iDearQRCode/OtherVC/PreloadVC/View/PreloadDetailView.m create mode 100644 iDearQRCode/OtherVC/PreloadVC/View/PreloadNewView.h create mode 100644 iDearQRCode/OtherVC/PreloadVC/View/PreloadNewView.m create mode 100644 iDearQRCode/OtherVC/PreloadVC/View/PrereloadCell.h create mode 100644 iDearQRCode/OtherVC/PreloadVC/View/PrereloadCell.m create mode 100644 iDearQRCode/OtherVC/QRCodeVC/QRCodeResultVC.h create mode 100644 iDearQRCode/OtherVC/QRCodeVC/QRCodeResultVC.m create mode 100644 iDearQRCode/OtherVC/QRCodeVC/QRCodeVC.h create mode 100644 iDearQRCode/OtherVC/QRCodeVC/QRCodeVC.m create mode 100644 iDearQRCode/OtherVC/QRCodeVC/View/QRCodeResultView.h create mode 100644 iDearQRCode/OtherVC/QRCodeVC/View/QRCodeResultView.m create mode 100644 iDearQRCode/OtherVC/View/PickDetailFootView.h create mode 100644 iDearQRCode/OtherVC/View/PickDetailFootView.m create mode 100644 iDearQRCode/OtherVC/View/PickDetailView.h create mode 100644 iDearQRCode/OtherVC/View/PickDetailView.m delete mode 100644 iDearQRCode/Tools/Category/UIImage+Normalimage.h delete mode 100644 iDearQRCode/Tools/Category/UIImage+Normalimage.m create mode 100755 iDearQRCode/Tools/LBXScan/CodeScan.bundle/device_scan@2x.png create mode 100755 iDearQRCode/Tools/LBXScan/CodeScan.bundle/qrcode_Scan_weixin_Line@2x.png create mode 100755 iDearQRCode/Tools/LBXScan/CodeScan.bundle/qrcode_scan_btn_flash_down@2x.png create mode 100755 iDearQRCode/Tools/LBXScan/CodeScan.bundle/qrcode_scan_btn_flash_nor@2x.png create mode 100755 iDearQRCode/Tools/LBXScan/CodeScan.bundle/qrcode_scan_btn_myqrcode_down@2x.png create mode 100755 iDearQRCode/Tools/LBXScan/CodeScan.bundle/qrcode_scan_btn_myqrcode_nor@2x.png create mode 100755 iDearQRCode/Tools/LBXScan/CodeScan.bundle/qrcode_scan_btn_photo_down@2x.png create mode 100755 iDearQRCode/Tools/LBXScan/CodeScan.bundle/qrcode_scan_btn_photo_nor@2x.png create mode 100755 iDearQRCode/Tools/LBXScan/CodeScan.bundle/qrcode_scan_btn_scan_off@2x.png create mode 100755 iDearQRCode/Tools/LBXScan/CodeScan.bundle/qrcode_scan_full_net.png create mode 100755 iDearQRCode/Tools/LBXScan/CodeScan.bundle/qrcode_scan_light_green@2x.png create mode 100755 iDearQRCode/Tools/LBXScan/CodeScan.bundle/qrcode_scan_part_net.png create mode 100755 iDearQRCode/Tools/LBXScan/CodeScan.bundle/qrcode_scan_titlebar_back_nor@2x.png create mode 100755 iDearQRCode/Tools/LBXScan/CodeScan.bundle/qrcode_scan_titlebar_back_pressed@2x.png create mode 100755 iDearQRCode/Tools/LBXScan/LBXAlertAction/Class/UIActionSheet+LBXAlertAction.h create mode 100755 iDearQRCode/Tools/LBXScan/LBXAlertAction/Class/UIActionSheet+LBXAlertAction.m create mode 100755 iDearQRCode/Tools/LBXScan/LBXAlertAction/Class/UIAlertController+supportedInterfaceOrientations.h create mode 100755 iDearQRCode/Tools/LBXScan/LBXAlertAction/Class/UIAlertController+supportedInterfaceOrientations.m create mode 100755 iDearQRCode/Tools/LBXScan/LBXAlertAction/Class/UIAlertView+LBXAlertAction.h create mode 100755 iDearQRCode/Tools/LBXScan/LBXAlertAction/Class/UIAlertView+LBXAlertAction.m create mode 100755 iDearQRCode/Tools/LBXScan/LBXAlertAction/LBXAlertAction.h create mode 100755 iDearQRCode/Tools/LBXScan/LBXAlertAction/LBXAlertAction.m create mode 100755 iDearQRCode/Tools/LBXScan/LBXScanLineAnimation.h create mode 100755 iDearQRCode/Tools/LBXScan/LBXScanLineAnimation.m create mode 100755 iDearQRCode/Tools/LBXScan/LBXScanNative.h create mode 100755 iDearQRCode/Tools/LBXScan/LBXScanNative.m create mode 100755 iDearQRCode/Tools/LBXScan/LBXScanNetAnimation.h create mode 100755 iDearQRCode/Tools/LBXScan/LBXScanNetAnimation.m create mode 100755 iDearQRCode/Tools/LBXScan/LBXScanResult.h create mode 100755 iDearQRCode/Tools/LBXScan/LBXScanResult.m create mode 100755 iDearQRCode/Tools/LBXScan/LBXScanVideoZoomView.h create mode 100755 iDearQRCode/Tools/LBXScan/LBXScanVideoZoomView.m create mode 100755 iDearQRCode/Tools/LBXScan/LBXScanView.h create mode 100755 iDearQRCode/Tools/LBXScan/LBXScanView.m create mode 100755 iDearQRCode/Tools/LBXScan/LBXScanViewController.h create mode 100755 iDearQRCode/Tools/LBXScan/LBXScanViewController.m create mode 100755 iDearQRCode/Tools/LBXScan/LBXScanViewStyle.h create mode 100755 iDearQRCode/Tools/LBXScan/LBXScanViewStyle.m create mode 100755 iDearQRCode/Tools/LBXScan/LBXScanWrapper.h create mode 100755 iDearQRCode/Tools/LBXScan/LBXScanWrapper.m create mode 100755 iDearQRCode/Tools/LBXScan/LBXZXCapture.h create mode 100755 iDearQRCode/Tools/LBXScan/LBXZXCapture.m create mode 100755 iDearQRCode/Tools/LBXScan/LBXZXCaptureDelegate.h create mode 100755 iDearQRCode/Tools/LBXScan/ZXingWrapper.h create mode 100755 iDearQRCode/Tools/LBXScan/ZXingWrapper.m create mode 100755 iDearQRCode/Tools/ZXingObjC/ZXMultiFormatReader.h create mode 100755 iDearQRCode/Tools/ZXingObjC/ZXMultiFormatReader.m create mode 100755 iDearQRCode/Tools/ZXingObjC/ZXMultiFormatWriter.h create mode 100755 iDearQRCode/Tools/ZXingObjC/ZXMultiFormatWriter.m create mode 100755 iDearQRCode/Tools/ZXingObjC/ZXingObjC.h create mode 100755 iDearQRCode/Tools/ZXingObjC/aztec/ZXAztecDetectorResult.h create mode 100755 iDearQRCode/Tools/ZXingObjC/aztec/ZXAztecDetectorResult.m create mode 100755 iDearQRCode/Tools/ZXingObjC/aztec/ZXAztecReader.h create mode 100755 iDearQRCode/Tools/ZXingObjC/aztec/ZXAztecReader.m create mode 100755 iDearQRCode/Tools/ZXingObjC/aztec/ZXAztecWriter.h create mode 100755 iDearQRCode/Tools/ZXingObjC/aztec/ZXAztecWriter.m create mode 100755 iDearQRCode/Tools/ZXingObjC/aztec/ZXingObjCAztec.h create mode 100755 iDearQRCode/Tools/ZXingObjC/aztec/decoder/ZXAztecDecoder.h create mode 100755 iDearQRCode/Tools/ZXingObjC/aztec/decoder/ZXAztecDecoder.m create mode 100755 iDearQRCode/Tools/ZXingObjC/aztec/detector/ZXAztecDetector.h create mode 100755 iDearQRCode/Tools/ZXingObjC/aztec/detector/ZXAztecDetector.m create mode 100755 iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecBinaryShiftToken.h create mode 100755 iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecBinaryShiftToken.m create mode 100755 iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecCode.h create mode 100755 iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecCode.m create mode 100755 iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecEncoder.h create mode 100755 iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecEncoder.m create mode 100755 iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecHighLevelEncoder.h create mode 100755 iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecHighLevelEncoder.m create mode 100755 iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecSimpleToken.h create mode 100755 iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecSimpleToken.m create mode 100755 iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecState.h create mode 100755 iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecState.m create mode 100755 iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecToken.h create mode 100755 iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecToken.m create mode 100755 iDearQRCode/Tools/ZXingObjC/client/ZXCGImageLuminanceSource.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/ZXCGImageLuminanceSource.m create mode 100755 iDearQRCode/Tools/ZXingObjC/client/ZXCapture.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/ZXCapture.m create mode 100755 iDearQRCode/Tools/ZXingObjC/client/ZXCaptureDelegate.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/ZXImage.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/ZXImage.m create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXAbstractDoCoMoResultParser.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXAbstractDoCoMoResultParser.m create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXAddressBookAUResultParser.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXAddressBookAUResultParser.m create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXAddressBookDoCoMoResultParser.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXAddressBookDoCoMoResultParser.m create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXAddressBookParsedResult.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXAddressBookParsedResult.m create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXBizcardResultParser.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXBizcardResultParser.m create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXBookmarkDoCoMoResultParser.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXBookmarkDoCoMoResultParser.m create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXCalendarParsedResult.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXCalendarParsedResult.m create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXEmailAddressParsedResult.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXEmailAddressParsedResult.m create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXEmailAddressResultParser.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXEmailAddressResultParser.m create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXEmailDoCoMoResultParser.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXEmailDoCoMoResultParser.m create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXExpandedProductParsedResult.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXExpandedProductParsedResult.m create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXExpandedProductResultParser.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXExpandedProductResultParser.m create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXGeoParsedResult.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXGeoParsedResult.m create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXGeoResultParser.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXGeoResultParser.m create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXISBNParsedResult.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXISBNParsedResult.m create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXISBNResultParser.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXISBNResultParser.m create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXParsedResult.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXParsedResult.m create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXParsedResultType.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXProductParsedResult.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXProductParsedResult.m create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXProductResultParser.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXProductResultParser.m create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXResultParser.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXResultParser.m create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXSMSMMSResultParser.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXSMSMMSResultParser.m create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXSMSParsedResult.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXSMSParsedResult.m create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXSMSTOMMSTOResultParser.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXSMSTOMMSTOResultParser.m create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXSMTPResultParser.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXSMTPResultParser.m create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXTelParsedResult.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXTelParsedResult.m create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXTelResultParser.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXTelResultParser.m create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXTextParsedResult.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXTextParsedResult.m create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXURIParsedResult.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXURIParsedResult.m create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXURIResultParser.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXURIResultParser.m create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXURLTOResultParser.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXURLTOResultParser.m create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXVCardResultParser.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXVCardResultParser.m create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXVEventResultParser.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXVEventResultParser.m create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXVINParsedResult.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXVINParsedResult.m create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXVINResultParser.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXVINResultParser.m create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXWifiParsedResult.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXWifiParsedResult.m create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXWifiResultParser.h create mode 100755 iDearQRCode/Tools/ZXingObjC/client/result/ZXWifiResultParser.m create mode 100755 iDearQRCode/Tools/ZXingObjC/common/ZXBitArray.h create mode 100755 iDearQRCode/Tools/ZXingObjC/common/ZXBitArray.m create mode 100755 iDearQRCode/Tools/ZXingObjC/common/ZXBitMatrix.h create mode 100755 iDearQRCode/Tools/ZXingObjC/common/ZXBitMatrix.m create mode 100755 iDearQRCode/Tools/ZXingObjC/common/ZXBitSource.h create mode 100755 iDearQRCode/Tools/ZXingObjC/common/ZXBitSource.m create mode 100755 iDearQRCode/Tools/ZXingObjC/common/ZXBoolArray.h create mode 100755 iDearQRCode/Tools/ZXingObjC/common/ZXBoolArray.m create mode 100755 iDearQRCode/Tools/ZXingObjC/common/ZXByteArray.h create mode 100755 iDearQRCode/Tools/ZXingObjC/common/ZXByteArray.m create mode 100755 iDearQRCode/Tools/ZXingObjC/common/ZXCharacterSetECI.h create mode 100755 iDearQRCode/Tools/ZXingObjC/common/ZXCharacterSetECI.m create mode 100755 iDearQRCode/Tools/ZXingObjC/common/ZXDecoderResult.h create mode 100755 iDearQRCode/Tools/ZXingObjC/common/ZXDecoderResult.m create mode 100755 iDearQRCode/Tools/ZXingObjC/common/ZXDefaultGridSampler.h create mode 100755 iDearQRCode/Tools/ZXingObjC/common/ZXDefaultGridSampler.m create mode 100755 iDearQRCode/Tools/ZXingObjC/common/ZXDetectorResult.h create mode 100755 iDearQRCode/Tools/ZXingObjC/common/ZXDetectorResult.m create mode 100755 iDearQRCode/Tools/ZXingObjC/common/ZXGlobalHistogramBinarizer.h create mode 100755 iDearQRCode/Tools/ZXingObjC/common/ZXGlobalHistogramBinarizer.m create mode 100755 iDearQRCode/Tools/ZXingObjC/common/ZXGridSampler.h create mode 100755 iDearQRCode/Tools/ZXingObjC/common/ZXGridSampler.m create mode 100755 iDearQRCode/Tools/ZXingObjC/common/ZXHybridBinarizer.h create mode 100755 iDearQRCode/Tools/ZXingObjC/common/ZXHybridBinarizer.m create mode 100755 iDearQRCode/Tools/ZXingObjC/common/ZXIntArray.h create mode 100755 iDearQRCode/Tools/ZXingObjC/common/ZXIntArray.m create mode 100755 iDearQRCode/Tools/ZXingObjC/common/ZXPerspectiveTransform.h create mode 100755 iDearQRCode/Tools/ZXingObjC/common/ZXPerspectiveTransform.m create mode 100755 iDearQRCode/Tools/ZXingObjC/common/ZXStringUtils.h create mode 100755 iDearQRCode/Tools/ZXingObjC/common/ZXStringUtils.m create mode 100755 iDearQRCode/Tools/ZXingObjC/common/detector/ZXMathUtils.h create mode 100755 iDearQRCode/Tools/ZXingObjC/common/detector/ZXMathUtils.m create mode 100755 iDearQRCode/Tools/ZXingObjC/common/detector/ZXMonochromeRectangleDetector.h create mode 100755 iDearQRCode/Tools/ZXingObjC/common/detector/ZXMonochromeRectangleDetector.m create mode 100755 iDearQRCode/Tools/ZXingObjC/common/detector/ZXWhiteRectangleDetector.h create mode 100755 iDearQRCode/Tools/ZXingObjC/common/detector/ZXWhiteRectangleDetector.m create mode 100755 iDearQRCode/Tools/ZXingObjC/common/reedsolomon/ZXGenericGF.h create mode 100755 iDearQRCode/Tools/ZXingObjC/common/reedsolomon/ZXGenericGF.m create mode 100755 iDearQRCode/Tools/ZXingObjC/common/reedsolomon/ZXGenericGFPoly.h create mode 100755 iDearQRCode/Tools/ZXingObjC/common/reedsolomon/ZXGenericGFPoly.m create mode 100755 iDearQRCode/Tools/ZXingObjC/common/reedsolomon/ZXReedSolomonDecoder.h create mode 100755 iDearQRCode/Tools/ZXingObjC/common/reedsolomon/ZXReedSolomonDecoder.m create mode 100755 iDearQRCode/Tools/ZXingObjC/common/reedsolomon/ZXReedSolomonEncoder.h create mode 100755 iDearQRCode/Tools/ZXingObjC/common/reedsolomon/ZXReedSolomonEncoder.m create mode 100755 iDearQRCode/Tools/ZXingObjC/core/ZXBarcodeFormat.h create mode 100755 iDearQRCode/Tools/ZXingObjC/core/ZXBinarizer.h create mode 100755 iDearQRCode/Tools/ZXingObjC/core/ZXBinarizer.m create mode 100755 iDearQRCode/Tools/ZXingObjC/core/ZXBinaryBitmap.h create mode 100755 iDearQRCode/Tools/ZXingObjC/core/ZXBinaryBitmap.m create mode 100755 iDearQRCode/Tools/ZXingObjC/core/ZXByteMatrix.h create mode 100755 iDearQRCode/Tools/ZXingObjC/core/ZXByteMatrix.m create mode 100755 iDearQRCode/Tools/ZXingObjC/core/ZXDecodeHints.h create mode 100755 iDearQRCode/Tools/ZXingObjC/core/ZXDecodeHints.m create mode 100755 iDearQRCode/Tools/ZXingObjC/core/ZXDimension.h create mode 100755 iDearQRCode/Tools/ZXingObjC/core/ZXDimension.m create mode 100755 iDearQRCode/Tools/ZXingObjC/core/ZXEncodeHints.h create mode 100755 iDearQRCode/Tools/ZXingObjC/core/ZXEncodeHints.m create mode 100755 iDearQRCode/Tools/ZXingObjC/core/ZXErrors.h create mode 100755 iDearQRCode/Tools/ZXingObjC/core/ZXErrors.m create mode 100755 iDearQRCode/Tools/ZXingObjC/core/ZXInvertedLuminanceSource.h create mode 100755 iDearQRCode/Tools/ZXingObjC/core/ZXInvertedLuminanceSource.m create mode 100755 iDearQRCode/Tools/ZXingObjC/core/ZXLuminanceSource.h create mode 100755 iDearQRCode/Tools/ZXingObjC/core/ZXLuminanceSource.m create mode 100755 iDearQRCode/Tools/ZXingObjC/core/ZXPlanarYUVLuminanceSource.h create mode 100755 iDearQRCode/Tools/ZXingObjC/core/ZXPlanarYUVLuminanceSource.m create mode 100755 iDearQRCode/Tools/ZXingObjC/core/ZXRGBLuminanceSource.h create mode 100755 iDearQRCode/Tools/ZXingObjC/core/ZXRGBLuminanceSource.m create mode 100755 iDearQRCode/Tools/ZXingObjC/core/ZXReader.h create mode 100755 iDearQRCode/Tools/ZXingObjC/core/ZXResult.h create mode 100755 iDearQRCode/Tools/ZXingObjC/core/ZXResult.m create mode 100755 iDearQRCode/Tools/ZXingObjC/core/ZXResultMetadataType.h create mode 100755 iDearQRCode/Tools/ZXingObjC/core/ZXResultPoint.h create mode 100755 iDearQRCode/Tools/ZXingObjC/core/ZXResultPoint.m create mode 100755 iDearQRCode/Tools/ZXingObjC/core/ZXResultPointCallback.h create mode 100755 iDearQRCode/Tools/ZXingObjC/core/ZXWriter.h create mode 100755 iDearQRCode/Tools/ZXingObjC/core/ZXingObjCCore.h create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/ZXDataMatrixReader.h create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/ZXDataMatrixReader.m create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/ZXDataMatrixWriter.h create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/ZXDataMatrixWriter.m create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/ZXingObjCDataMatrix.h create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/decoder/ZXDataMatrixBitMatrixParser.h create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/decoder/ZXDataMatrixBitMatrixParser.m create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/decoder/ZXDataMatrixDataBlock.h create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/decoder/ZXDataMatrixDataBlock.m create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/decoder/ZXDataMatrixDecodedBitStreamParser.h create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/decoder/ZXDataMatrixDecodedBitStreamParser.m create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/decoder/ZXDataMatrixDecoder.h create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/decoder/ZXDataMatrixDecoder.m create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/decoder/ZXDataMatrixVersion.h create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/decoder/ZXDataMatrixVersion.m create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/detector/ZXDataMatrixDetector.h create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/detector/ZXDataMatrixDetector.m create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixASCIIEncoder.h create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixASCIIEncoder.m create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixBase256Encoder.h create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixBase256Encoder.m create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixC40Encoder.h create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixC40Encoder.m create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixDefaultPlacement.h create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixDefaultPlacement.m create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixEdifactEncoder.h create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixEdifactEncoder.m create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixEncoder.h create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixEncoderContext.h create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixEncoderContext.m create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixErrorCorrection.h create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixErrorCorrection.m create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixHighLevelEncoder.h create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixHighLevelEncoder.m create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixSymbolInfo.h create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixSymbolInfo.m create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixSymbolInfo144.h create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixSymbolInfo144.m create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixTextEncoder.h create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixTextEncoder.m create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixX12Encoder.h create mode 100755 iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixX12Encoder.m create mode 100755 iDearQRCode/Tools/ZXingObjC/maxicode/ZXMaxiCodeReader.h create mode 100755 iDearQRCode/Tools/ZXingObjC/maxicode/ZXMaxiCodeReader.m create mode 100755 iDearQRCode/Tools/ZXingObjC/maxicode/ZXingObjCMaxiCode.h create mode 100755 iDearQRCode/Tools/ZXingObjC/maxicode/decoder/ZXMaxiCodeBitMatrixParser.h create mode 100755 iDearQRCode/Tools/ZXingObjC/maxicode/decoder/ZXMaxiCodeBitMatrixParser.m create mode 100755 iDearQRCode/Tools/ZXingObjC/maxicode/decoder/ZXMaxiCodeDecodedBitStreamParser.h create mode 100755 iDearQRCode/Tools/ZXingObjC/maxicode/decoder/ZXMaxiCodeDecodedBitStreamParser.m create mode 100755 iDearQRCode/Tools/ZXingObjC/maxicode/decoder/ZXMaxiCodeDecoder.h create mode 100755 iDearQRCode/Tools/ZXingObjC/maxicode/decoder/ZXMaxiCodeDecoder.m create mode 100755 iDearQRCode/Tools/ZXingObjC/multi/ZXByQuadrantReader.h create mode 100755 iDearQRCode/Tools/ZXingObjC/multi/ZXByQuadrantReader.m create mode 100755 iDearQRCode/Tools/ZXingObjC/multi/ZXGenericMultipleBarcodeReader.h create mode 100755 iDearQRCode/Tools/ZXingObjC/multi/ZXGenericMultipleBarcodeReader.m create mode 100755 iDearQRCode/Tools/ZXingObjC/multi/ZXMultipleBarcodeReader.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXCodaBarReader.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXCodaBarReader.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXCodaBarWriter.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXCodaBarWriter.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXCode128Reader.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXCode128Reader.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXCode128Writer.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXCode128Writer.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXCode39Reader.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXCode39Reader.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXCode39Writer.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXCode39Writer.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXCode93Reader.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXCode93Reader.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXEAN13Reader.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXEAN13Reader.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXEAN13Writer.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXEAN13Writer.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXEAN8Reader.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXEAN8Reader.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXEAN8Writer.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXEAN8Writer.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXEANManufacturerOrgSupport.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXEANManufacturerOrgSupport.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXITFReader.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXITFReader.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXITFWriter.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXITFWriter.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXMultiFormatOneDReader.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXMultiFormatOneDReader.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXMultiFormatUPCEANReader.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXMultiFormatUPCEANReader.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXOneDReader.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXOneDReader.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXOneDimensionalCodeWriter.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXOneDimensionalCodeWriter.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXUPCAReader.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXUPCAReader.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXUPCAWriter.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXUPCAWriter.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEANExtension2Support.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEANExtension2Support.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEANExtension5Support.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEANExtension5Support.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEANExtensionSupport.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEANExtensionSupport.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEANReader.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEANReader.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEANWriter.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEANWriter.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEReader.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEReader.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/ZXingObjCOneD.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/ZXAbstractRSSReader.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/ZXAbstractRSSReader.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/ZXRSS14Reader.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/ZXRSS14Reader.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/ZXRSSDataCharacter.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/ZXRSSDataCharacter.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/ZXRSSFinderPattern.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/ZXRSSFinderPattern.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/ZXRSSPair.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/ZXRSSPair.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/ZXRSSUtils.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/ZXRSSUtils.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/ZXBitArrayBuilder.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/ZXBitArrayBuilder.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/ZXRSSExpandedPair.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/ZXRSSExpandedPair.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/ZXRSSExpandedReader.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/ZXRSSExpandedReader.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/ZXRSSExpandedRow.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/ZXRSSExpandedRow.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI013103decoder.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI013103decoder.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01320xDecoder.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01320xDecoder.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01392xDecoder.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01392xDecoder.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01393xDecoder.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01393xDecoder.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI013x0x1xDecoder.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI013x0x1xDecoder.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI013x0xDecoder.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI013x0xDecoder.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01AndOtherAIs.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01AndOtherAIs.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01decoder.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01decoder.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01weightDecoder.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01weightDecoder.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAbstractExpandedDecoder.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAbstractExpandedDecoder.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAnyAIDecoder.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAnyAIDecoder.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedBlockParsedResult.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedBlockParsedResult.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedCurrentParsingState.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedCurrentParsingState.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedDecodedChar.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedDecodedChar.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedDecodedInformation.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedDecodedInformation.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedDecodedNumeric.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedDecodedNumeric.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedDecodedObject.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedDecodedObject.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedFieldParser.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedFieldParser.m create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedGeneralAppIdDecoder.h create mode 100755 iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedGeneralAppIdDecoder.m create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/ZXPDF417Common.h create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/ZXPDF417Common.m create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/ZXPDF417Reader.h create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/ZXPDF417Reader.m create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/ZXPDF417ResultMetadata.h create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/ZXPDF417ResultMetadata.m create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/ZXPDF417Writer.h create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/ZXPDF417Writer.m create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/ZXingObjCPDF417.h create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417BarcodeMetadata.h create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417BarcodeMetadata.m create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417BarcodeValue.h create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417BarcodeValue.m create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417BoundingBox.h create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417BoundingBox.m create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417Codeword.h create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417Codeword.m create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417CodewordDecoder.h create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417CodewordDecoder.m create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417DecodedBitStreamParser.h create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417DecodedBitStreamParser.m create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417DetectionResult.h create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417DetectionResult.m create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417DetectionResultColumn.h create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417DetectionResultColumn.m create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417DetectionResultRowIndicatorColumn.h create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417DetectionResultRowIndicatorColumn.m create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417ScanningDecoder.h create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417ScanningDecoder.m create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ec/ZXModulusGF.h create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ec/ZXModulusGF.m create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ec/ZXModulusPoly.h create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ec/ZXModulusPoly.m create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ec/ZXPDF417ECErrorCorrection.h create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ec/ZXPDF417ECErrorCorrection.m create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/detector/ZXPDF417Detector.h create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/detector/ZXPDF417Detector.m create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/detector/ZXPDF417DetectorResult.h create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/detector/ZXPDF417DetectorResult.m create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417.h create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417.m create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417BarcodeMatrix.h create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417BarcodeMatrix.m create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417BarcodeRow.h create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417BarcodeRow.m create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417Dimensions.h create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417Dimensions.m create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417ErrorCorrection.h create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417ErrorCorrection.m create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417HighLevelEncoder.h create mode 100755 iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417HighLevelEncoder.m create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/ZXQRCodeReader.h create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/ZXQRCodeReader.m create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/ZXQRCodeWriter.h create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/ZXQRCodeWriter.m create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/ZXingObjCQRCode.h create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeBitMatrixParser.h create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeBitMatrixParser.m create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeDataBlock.h create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeDataBlock.m create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeDataMask.h create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeDataMask.m create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeDecodedBitStreamParser.h create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeDecodedBitStreamParser.m create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeDecoder.h create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeDecoder.m create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeDecoderMetaData.h create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeDecoderMetaData.m create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeErrorCorrectionLevel.h create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeErrorCorrectionLevel.m create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeFormatInformation.h create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeFormatInformation.m create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeMode.h create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeMode.m create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeVersion.h create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeVersion.m create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeAlignmentPattern.h create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeAlignmentPattern.m create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeAlignmentPatternFinder.h create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeAlignmentPatternFinder.m create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeDetector.h create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeDetector.m create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeFinderPattern.h create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeFinderPattern.m create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeFinderPatternFinder.h create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeFinderPatternFinder.m create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeFinderPatternInfo.h create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeFinderPatternInfo.m create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/encoder/ZXQRCode.h create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/encoder/ZXQRCode.m create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/encoder/ZXQRCodeBlockPair.h create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/encoder/ZXQRCodeBlockPair.m create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/encoder/ZXQRCodeEncoder.h create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/encoder/ZXQRCodeEncoder.m create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/encoder/ZXQRCodeMaskUtil.h create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/encoder/ZXQRCodeMaskUtil.m create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/encoder/ZXQRCodeMatrixUtil.h create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/encoder/ZXQRCodeMatrixUtil.m create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/multi/ZXQRCodeMultiReader.h create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/multi/ZXQRCodeMultiReader.m create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/multi/detector/ZXMultiDetector.h create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/multi/detector/ZXMultiDetector.m create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/multi/detector/ZXMultiFinderPatternFinder.h create mode 100755 iDearQRCode/Tools/ZXingObjC/qrcode/multi/detector/ZXMultiFinderPatternFinder.m diff --git a/iDearQRCode.xcodeproj/project.pbxproj b/iDearQRCode.xcodeproj/project.pbxproj index 3f301b2..99520cf 100644 --- a/iDearQRCode.xcodeproj/project.pbxproj +++ b/iDearQRCode.xcodeproj/project.pbxproj @@ -7,6 +7,15 @@ objects = { /* Begin PBXBuildFile section */ + 110B9BE21ED281D700EC58DB /* BaseTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 110B9BE11ED281D700EC58DB /* BaseTableViewCell.m */; }; + 110B9BE51ED2845500EC58DB /* BaseModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 110B9BE41ED2845500EC58DB /* BaseModel.m */; }; + 110B9BE81ED2906700EC58DB /* PrereloadCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 110B9BE71ED2906700EC58DB /* PrereloadCell.m */; }; + 110B9BEB1ED2908C00EC58DB /* PrereloadCellModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 110B9BEA1ED2908C00EC58DB /* PrereloadCellModel.m */; }; + 110B9BEE1ED291C100EC58DB /* PreloadViewModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 110B9BED1ED291C100EC58DB /* PreloadViewModel.m */; }; + 110B9BF11ED2932F00EC58DB /* PreloadDetailVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 110B9BF01ED2932F00EC58DB /* PreloadDetailVC.m */; }; + 110B9BF71ED2B96200EC58DB /* PickDetailModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 110B9BF61ED2B96200EC58DB /* PickDetailModel.m */; }; + 110B9BFA1ED2BEEC00EC58DB /* PickDetailView.m in Sources */ = {isa = PBXBuildFile; fileRef = 110B9BF91ED2BEEC00EC58DB /* PickDetailView.m */; }; + 110B9BFD1ED2BF0700EC58DB /* PickDetailFootView.m in Sources */ = {isa = PBXBuildFile; fileRef = 110B9BFC1ED2BF0700EC58DB /* PickDetailFootView.m */; }; 1121BFC51EC990BD0002D73C /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 1121BFC41EC990BD0002D73C /* main.m */; }; 1121BFC81EC990BD0002D73C /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1121BFC71EC990BD0002D73C /* AppDelegate.m */; }; 1121BFCB1EC990BD0002D73C /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1121BFCA1EC990BD0002D73C /* ViewController.m */; }; @@ -34,6 +43,7 @@ 11346AB21ECED3ED00BFDD69 /* UITableView+SDAutoTableViewCellHeight.m in Sources */ = {isa = PBXBuildFile; fileRef = 11346AAF1ECED3ED00BFDD69 /* UITableView+SDAutoTableViewCellHeight.m */; }; 11346AB31ECED3ED00BFDD69 /* UIView+SDAutoLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 11346AB11ECED3ED00BFDD69 /* UIView+SDAutoLayout.m */; }; 11346AB61ECEE02D00BFDD69 /* PickAlert.m in Sources */ = {isa = PBXBuildFile; fileRef = 11346AB51ECEE02D00BFDD69 /* PickAlert.m */; }; + 113580DB1ED7BEB80069E21E /* PartSearchView.m in Sources */ = {isa = PBXBuildFile; fileRef = 113580DA1ED7BEB80069E21E /* PartSearchView.m */; }; 1148290A1ECBDD6100BBCBF3 /* MKAnnotationView+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 114828E41ECBDD6100BBCBF3 /* MKAnnotationView+WebCache.m */; }; 1148290B1ECBDD6100BBCBF3 /* NSData+ImageContentType.m in Sources */ = {isa = PBXBuildFile; fileRef = 114828E61ECBDD6100BBCBF3 /* NSData+ImageContentType.m */; }; 1148290C1ECBDD6100BBCBF3 /* NSImage+WebCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 114828E81ECBDD6100BBCBF3 /* NSImage+WebCache.m */; }; @@ -57,6 +67,17 @@ 114829261ECC1DEC00BBCBF3 /* PickingCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 114829251ECC1DEC00BBCBF3 /* PickingCell.m */; }; 114829291ECC1E0000BBCBF3 /* PickingModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 114829281ECC1E0000BBCBF3 /* PickingModel.m */; }; 1148292C1ECC222F00BBCBF3 /* PickingHeadView.m in Sources */ = {isa = PBXBuildFile; fileRef = 1148292B1ECC222F00BBCBF3 /* PickingHeadView.m */; }; + 1179FBE71ED56E5D0071ED45 /* PreloadDetailView.m in Sources */ = {isa = PBXBuildFile; fileRef = 1179FBE61ED56E5D0071ED45 /* PreloadDetailView.m */; }; + 1179FBEA1ED577570071ED45 /* PreloadDetailCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 1179FBE91ED577570071ED45 /* PreloadDetailCell.m */; }; + 118E68EF1ED92C9300B62015 /* YQNetworking+RequestManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 118E68EE1ED92C9300B62015 /* YQNetworking+RequestManager.m */; }; + 118E68F91ED92C9900B62015 /* YQCacheManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 118E68F21ED92C9900B62015 /* YQCacheManager.m */; }; + 118E68FA1ED92C9900B62015 /* YQDiskCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 118E68F41ED92C9900B62015 /* YQDiskCache.m */; }; + 118E68FB1ED92C9900B62015 /* YQLRUManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 118E68F61ED92C9900B62015 /* YQLRUManager.m */; }; + 118E68FC1ED92C9900B62015 /* YQMemoryCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 118E68F81ED92C9900B62015 /* YQMemoryCache.m */; }; + 118E68FF1ED92CA000B62015 /* YQNetworking.m in Sources */ = {isa = PBXBuildFile; fileRef = 118E68FE1ED92CA000B62015 /* YQNetworking.m */; }; + 118E69041ED94D5600B62015 /* UserModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 118E69031ED94D5600B62015 /* UserModel.m */; }; + 118E69071ED94DC900B62015 /* UserManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 118E69061ED94DC900B62015 /* UserManager.m */; }; + 118E690A1ED951BF00B62015 /* KeyManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 118E69091ED951BF00B62015 /* KeyManager.m */; }; 119AB2B91ED15E87003DBF5A /* AFHTTPSessionManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 119AB2921ED15E87003DBF5A /* AFHTTPSessionManager.m */; }; 119AB2BA1ED15E87003DBF5A /* AFNetworkReachabilityManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 119AB2951ED15E87003DBF5A /* AFNetworkReachabilityManager.m */; }; 119AB2BB1ED15E87003DBF5A /* AFSecurityPolicy.m in Sources */ = {isa = PBXBuildFile; fileRef = 119AB2971ED15E87003DBF5A /* AFSecurityPolicy.m */; }; @@ -99,6 +120,10 @@ 11C243541ED022F1007F69C6 /* NSDate+Extension.m in Sources */ = {isa = PBXBuildFile; fileRef = 11C243531ED022F1007F69C6 /* NSDate+Extension.m */; }; 11C2435A1ED045C7007F69C6 /* PickDetailVc.m in Sources */ = {isa = PBXBuildFile; fileRef = 11C243591ED045C7007F69C6 /* PickDetailVc.m */; }; 11C6C66C1ECDB47E00C2A9E8 /* PickingFootView.m in Sources */ = {isa = PBXBuildFile; fileRef = 11C6C66B1ECDB47E00C2A9E8 /* PickingFootView.m */; }; + 11DE26F31ED685D300DCDE78 /* NewPreloadVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 11DE26F21ED685D300DCDE78 /* NewPreloadVC.m */; }; + 11DE26F61ED6A69000DCDE78 /* PreloadNewView.m in Sources */ = {isa = PBXBuildFile; fileRef = 11DE26F51ED6A69000DCDE78 /* PreloadNewView.m */; }; + 11DE26F91ED6B66800DCDE78 /* NewPartCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 11DE26F81ED6B66800DCDE78 /* NewPartCell.m */; }; + 11DE26FC1ED6DBDF00DCDE78 /* NewPartNumberView.m in Sources */ = {isa = PBXBuildFile; fileRef = 11DE26FB1ED6DBDF00DCDE78 /* NewPartNumberView.m */; }; 11E3E9601ECA8CEF00D72EE1 /* SheetView.m in Sources */ = {isa = PBXBuildFile; fileRef = 11E3E95F1ECA8CEF00D72EE1 /* SheetView.m */; }; 11E3E9651ECA9A3400D72EE1 /* SheetViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 11E3E9641ECA9A3400D72EE1 /* SheetViewCell.m */; }; 11E3E9951ECAA6F600D72EE1 /* MJRefreshAutoFooter.m in Sources */ = {isa = PBXBuildFile; fileRef = 11E3E9691ECAA6F600D72EE1 /* MJRefreshAutoFooter.m */; }; @@ -143,11 +168,250 @@ 11E3E9FC1ECAC90D00D72EE1 /* NSString+Validate.m in Sources */ = {isa = PBXBuildFile; fileRef = 11E3E9E91ECAC90D00D72EE1 /* NSString+Validate.m */; }; 11E3E9FD1ECAC90D00D72EE1 /* UIBarButtonItem+Item.m in Sources */ = {isa = PBXBuildFile; fileRef = 11E3E9EB1ECAC90D00D72EE1 /* UIBarButtonItem+Item.m */; }; 11E3E9FE1ECAC90D00D72EE1 /* UIImage+Common.m in Sources */ = {isa = PBXBuildFile; fileRef = 11E3E9EE1ECAC90D00D72EE1 /* UIImage+Common.m */; }; - 11E3E9FF1ECAC90D00D72EE1 /* UIImage+Normalimage.m in Sources */ = {isa = PBXBuildFile; fileRef = 11E3E9F01ECAC90D00D72EE1 /* UIImage+Normalimage.m */; }; 11E3EA001ECAC90D00D72EE1 /* UIView+Common.m in Sources */ = {isa = PBXBuildFile; fileRef = 11E3E9F31ECAC90D00D72EE1 /* UIView+Common.m */; }; 11E3EA011ECAC90D00D72EE1 /* UIViewController+Common.m in Sources */ = {isa = PBXBuildFile; fileRef = 11E3E9F61ECAC90D00D72EE1 /* UIViewController+Common.m */; }; 11E3EA061ECAEDAD00D72EE1 /* PersonTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 11E3EA051ECAEDAD00D72EE1 /* PersonTableViewCell.m */; }; 11E3EA091ECAF71B00D72EE1 /* PersonHeadView.m in Sources */ = {isa = PBXBuildFile; fileRef = 11E3EA081ECAF71B00D72EE1 /* PersonHeadView.m */; }; + 11F7AE391ED4043F00A9F224 /* CodeScan.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 11F7AE171ED4043F00A9F224 /* CodeScan.bundle */; }; + 11F7AE3A1ED4043F00A9F224 /* UIActionSheet+LBXAlertAction.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE1B1ED4043F00A9F224 /* UIActionSheet+LBXAlertAction.m */; }; + 11F7AE3B1ED4043F00A9F224 /* UIAlertController+supportedInterfaceOrientations.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE1D1ED4043F00A9F224 /* UIAlertController+supportedInterfaceOrientations.m */; }; + 11F7AE3C1ED4043F00A9F224 /* UIAlertView+LBXAlertAction.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE1F1ED4043F00A9F224 /* UIAlertView+LBXAlertAction.m */; }; + 11F7AE3D1ED4043F00A9F224 /* LBXAlertAction.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE211ED4043F00A9F224 /* LBXAlertAction.m */; }; + 11F7AE3E1ED4043F00A9F224 /* LBXScanLineAnimation.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE231ED4043F00A9F224 /* LBXScanLineAnimation.m */; }; + 11F7AE3F1ED4043F00A9F224 /* LBXScanNative.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE251ED4043F00A9F224 /* LBXScanNative.m */; }; + 11F7AE401ED4043F00A9F224 /* LBXScanNetAnimation.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE271ED4043F00A9F224 /* LBXScanNetAnimation.m */; }; + 11F7AE411ED4043F00A9F224 /* LBXScanResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE291ED4043F00A9F224 /* LBXScanResult.m */; }; + 11F7AE421ED4043F00A9F224 /* LBXScanVideoZoomView.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE2B1ED4043F00A9F224 /* LBXScanVideoZoomView.m */; }; + 11F7AE431ED4043F00A9F224 /* LBXScanView.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE2D1ED4043F00A9F224 /* LBXScanView.m */; }; + 11F7AE441ED4043F00A9F224 /* LBXScanViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE2F1ED4043F00A9F224 /* LBXScanViewController.m */; }; + 11F7AE451ED4043F00A9F224 /* LBXScanViewStyle.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE311ED4043F00A9F224 /* LBXScanViewStyle.m */; }; + 11F7AE461ED4043F00A9F224 /* LBXScanWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE331ED4043F00A9F224 /* LBXScanWrapper.m */; }; + 11F7AE471ED4043F00A9F224 /* LBXZXCapture.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE351ED4043F00A9F224 /* LBXZXCapture.m */; }; + 11F7AE481ED4043F00A9F224 /* ZXingWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE381ED4043F00A9F224 /* ZXingWrapper.m */; }; + 11F7AE4B1ED404E800A9F224 /* QRCodeVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE4A1ED404E800A9F224 /* QRCodeVC.m */; }; + 11F7B0361ED40AB300A9F224 /* ZXAztecDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE501ED40AB300A9F224 /* ZXAztecDecoder.m */; }; + 11F7B0371ED40AB300A9F224 /* ZXAztecDetector.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE531ED40AB300A9F224 /* ZXAztecDetector.m */; }; + 11F7B0381ED40AB300A9F224 /* ZXAztecBinaryShiftToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE561ED40AB300A9F224 /* ZXAztecBinaryShiftToken.m */; }; + 11F7B0391ED40AB300A9F224 /* ZXAztecCode.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE581ED40AB300A9F224 /* ZXAztecCode.m */; }; + 11F7B03A1ED40AB300A9F224 /* ZXAztecEncoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE5A1ED40AB300A9F224 /* ZXAztecEncoder.m */; }; + 11F7B03B1ED40AB300A9F224 /* ZXAztecHighLevelEncoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE5C1ED40AB300A9F224 /* ZXAztecHighLevelEncoder.m */; }; + 11F7B03C1ED40AB300A9F224 /* ZXAztecSimpleToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE5E1ED40AB300A9F224 /* ZXAztecSimpleToken.m */; }; + 11F7B03D1ED40AB300A9F224 /* ZXAztecState.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE601ED40AB300A9F224 /* ZXAztecState.m */; }; + 11F7B03E1ED40AB300A9F224 /* ZXAztecToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE621ED40AB300A9F224 /* ZXAztecToken.m */; }; + 11F7B03F1ED40AB300A9F224 /* ZXAztecDetectorResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE641ED40AB300A9F224 /* ZXAztecDetectorResult.m */; }; + 11F7B0401ED40AB300A9F224 /* ZXAztecReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE661ED40AB300A9F224 /* ZXAztecReader.m */; }; + 11F7B0411ED40AB300A9F224 /* ZXAztecWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE681ED40AB300A9F224 /* ZXAztecWriter.m */; }; + 11F7B0421ED40AB300A9F224 /* ZXAbstractDoCoMoResultParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE6D1ED40AB300A9F224 /* ZXAbstractDoCoMoResultParser.m */; }; + 11F7B0431ED40AB300A9F224 /* ZXAddressBookAUResultParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE6F1ED40AB300A9F224 /* ZXAddressBookAUResultParser.m */; }; + 11F7B0441ED40AB300A9F224 /* ZXAddressBookDoCoMoResultParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE711ED40AB300A9F224 /* ZXAddressBookDoCoMoResultParser.m */; }; + 11F7B0451ED40AB300A9F224 /* ZXAddressBookParsedResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE731ED40AB300A9F224 /* ZXAddressBookParsedResult.m */; }; + 11F7B0461ED40AB300A9F224 /* ZXBizcardResultParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE751ED40AB300A9F224 /* ZXBizcardResultParser.m */; }; + 11F7B0471ED40AB300A9F224 /* ZXBookmarkDoCoMoResultParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE771ED40AB300A9F224 /* ZXBookmarkDoCoMoResultParser.m */; }; + 11F7B0481ED40AB300A9F224 /* ZXCalendarParsedResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE791ED40AB300A9F224 /* ZXCalendarParsedResult.m */; }; + 11F7B0491ED40AB300A9F224 /* ZXEmailAddressParsedResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE7B1ED40AB300A9F224 /* ZXEmailAddressParsedResult.m */; }; + 11F7B04A1ED40AB300A9F224 /* ZXEmailAddressResultParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE7D1ED40AB300A9F224 /* ZXEmailAddressResultParser.m */; }; + 11F7B04B1ED40AB300A9F224 /* ZXEmailDoCoMoResultParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE7F1ED40AB300A9F224 /* ZXEmailDoCoMoResultParser.m */; }; + 11F7B04C1ED40AB300A9F224 /* ZXExpandedProductParsedResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE811ED40AB300A9F224 /* ZXExpandedProductParsedResult.m */; }; + 11F7B04D1ED40AB300A9F224 /* ZXExpandedProductResultParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE831ED40AB300A9F224 /* ZXExpandedProductResultParser.m */; }; + 11F7B04E1ED40AB300A9F224 /* ZXGeoParsedResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE851ED40AB300A9F224 /* ZXGeoParsedResult.m */; }; + 11F7B04F1ED40AB300A9F224 /* ZXGeoResultParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE871ED40AB300A9F224 /* ZXGeoResultParser.m */; }; + 11F7B0501ED40AB300A9F224 /* ZXISBNParsedResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE891ED40AB300A9F224 /* ZXISBNParsedResult.m */; }; + 11F7B0511ED40AB300A9F224 /* ZXISBNResultParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE8B1ED40AB300A9F224 /* ZXISBNResultParser.m */; }; + 11F7B0521ED40AB300A9F224 /* ZXParsedResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE8D1ED40AB300A9F224 /* ZXParsedResult.m */; }; + 11F7B0531ED40AB300A9F224 /* ZXProductParsedResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE901ED40AB300A9F224 /* ZXProductParsedResult.m */; }; + 11F7B0541ED40AB300A9F224 /* ZXProductResultParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE921ED40AB300A9F224 /* ZXProductResultParser.m */; }; + 11F7B0551ED40AB300A9F224 /* ZXResultParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE941ED40AB300A9F224 /* ZXResultParser.m */; }; + 11F7B0561ED40AB300A9F224 /* ZXSMSMMSResultParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE961ED40AB300A9F224 /* ZXSMSMMSResultParser.m */; }; + 11F7B0571ED40AB300A9F224 /* ZXSMSParsedResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE981ED40AB300A9F224 /* ZXSMSParsedResult.m */; }; + 11F7B0581ED40AB300A9F224 /* ZXSMSTOMMSTOResultParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE9A1ED40AB300A9F224 /* ZXSMSTOMMSTOResultParser.m */; }; + 11F7B0591ED40AB300A9F224 /* ZXSMTPResultParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE9C1ED40AB300A9F224 /* ZXSMTPResultParser.m */; }; + 11F7B05A1ED40AB300A9F224 /* ZXTelParsedResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AE9E1ED40AB300A9F224 /* ZXTelParsedResult.m */; }; + 11F7B05B1ED40AB300A9F224 /* ZXTelResultParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AEA01ED40AB300A9F224 /* ZXTelResultParser.m */; }; + 11F7B05C1ED40AB300A9F224 /* ZXTextParsedResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AEA21ED40AB300A9F224 /* ZXTextParsedResult.m */; }; + 11F7B05D1ED40AB300A9F224 /* ZXURIParsedResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AEA41ED40AB300A9F224 /* ZXURIParsedResult.m */; }; + 11F7B05E1ED40AB300A9F224 /* ZXURIResultParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AEA61ED40AB300A9F224 /* ZXURIResultParser.m */; }; + 11F7B05F1ED40AB300A9F224 /* ZXURLTOResultParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AEA81ED40AB300A9F224 /* ZXURLTOResultParser.m */; }; + 11F7B0601ED40AB300A9F224 /* ZXVCardResultParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AEAA1ED40AB300A9F224 /* ZXVCardResultParser.m */; }; + 11F7B0611ED40AB300A9F224 /* ZXVEventResultParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AEAC1ED40AB300A9F224 /* ZXVEventResultParser.m */; }; + 11F7B0621ED40AB300A9F224 /* ZXVINParsedResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AEAE1ED40AB300A9F224 /* ZXVINParsedResult.m */; }; + 11F7B0631ED40AB300A9F224 /* ZXVINResultParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AEB01ED40AB300A9F224 /* ZXVINResultParser.m */; }; + 11F7B0641ED40AB300A9F224 /* ZXWifiParsedResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AEB21ED40AB300A9F224 /* ZXWifiParsedResult.m */; }; + 11F7B0651ED40AB300A9F224 /* ZXWifiResultParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AEB41ED40AB300A9F224 /* ZXWifiResultParser.m */; }; + 11F7B0661ED40AB300A9F224 /* ZXCapture.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AEB61ED40AB300A9F224 /* ZXCapture.m */; }; + 11F7B0671ED40AB300A9F224 /* ZXCGImageLuminanceSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AEB91ED40AB300A9F224 /* ZXCGImageLuminanceSource.m */; }; + 11F7B0681ED40AB300A9F224 /* ZXImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AEBB1ED40AB300A9F224 /* ZXImage.m */; }; + 11F7B0691ED40AB300A9F224 /* ZXMathUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AEBF1ED40AB300A9F224 /* ZXMathUtils.m */; }; + 11F7B06A1ED40AB300A9F224 /* ZXMonochromeRectangleDetector.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AEC11ED40AB300A9F224 /* ZXMonochromeRectangleDetector.m */; }; + 11F7B06B1ED40AB300A9F224 /* ZXWhiteRectangleDetector.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AEC31ED40AB300A9F224 /* ZXWhiteRectangleDetector.m */; }; + 11F7B06C1ED40AB300A9F224 /* ZXGenericGF.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AEC61ED40AB300A9F224 /* ZXGenericGF.m */; }; + 11F7B06D1ED40AB300A9F224 /* ZXGenericGFPoly.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AEC81ED40AB300A9F224 /* ZXGenericGFPoly.m */; }; + 11F7B06E1ED40AB300A9F224 /* ZXReedSolomonDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AECA1ED40AB300A9F224 /* ZXReedSolomonDecoder.m */; }; + 11F7B06F1ED40AB300A9F224 /* ZXReedSolomonEncoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AECC1ED40AB300A9F224 /* ZXReedSolomonEncoder.m */; }; + 11F7B0701ED40AB300A9F224 /* ZXBitArray.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AECE1ED40AB300A9F224 /* ZXBitArray.m */; }; + 11F7B0711ED40AB300A9F224 /* ZXBitMatrix.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AED01ED40AB300A9F224 /* ZXBitMatrix.m */; }; + 11F7B0721ED40AB300A9F224 /* ZXBitSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AED21ED40AB300A9F224 /* ZXBitSource.m */; }; + 11F7B0731ED40AB300A9F224 /* ZXBoolArray.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AED41ED40AB300A9F224 /* ZXBoolArray.m */; }; + 11F7B0741ED40AB300A9F224 /* ZXByteArray.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AED61ED40AB300A9F224 /* ZXByteArray.m */; }; + 11F7B0751ED40AB300A9F224 /* ZXCharacterSetECI.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AED81ED40AB300A9F224 /* ZXCharacterSetECI.m */; }; + 11F7B0761ED40AB300A9F224 /* ZXDecoderResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AEDA1ED40AB300A9F224 /* ZXDecoderResult.m */; }; + 11F7B0771ED40AB300A9F224 /* ZXDefaultGridSampler.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AEDC1ED40AB300A9F224 /* ZXDefaultGridSampler.m */; }; + 11F7B0781ED40AB300A9F224 /* ZXDetectorResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AEDE1ED40AB300A9F224 /* ZXDetectorResult.m */; }; + 11F7B0791ED40AB300A9F224 /* ZXGlobalHistogramBinarizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AEE01ED40AB300A9F224 /* ZXGlobalHistogramBinarizer.m */; }; + 11F7B07A1ED40AB300A9F224 /* ZXGridSampler.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AEE21ED40AB300A9F224 /* ZXGridSampler.m */; }; + 11F7B07B1ED40AB300A9F224 /* ZXHybridBinarizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AEE41ED40AB300A9F224 /* ZXHybridBinarizer.m */; }; + 11F7B07C1ED40AB300A9F224 /* ZXIntArray.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AEE61ED40AB300A9F224 /* ZXIntArray.m */; }; + 11F7B07D1ED40AB300A9F224 /* ZXPerspectiveTransform.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AEE81ED40AB300A9F224 /* ZXPerspectiveTransform.m */; }; + 11F7B07E1ED40AB300A9F224 /* ZXStringUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AEEA1ED40AB300A9F224 /* ZXStringUtils.m */; }; + 11F7B07F1ED40AB300A9F224 /* ZXBinarizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AEEE1ED40AB300A9F224 /* ZXBinarizer.m */; }; + 11F7B0801ED40AB300A9F224 /* ZXBinaryBitmap.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AEF01ED40AB300A9F224 /* ZXBinaryBitmap.m */; }; + 11F7B0811ED40AB300A9F224 /* ZXByteMatrix.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AEF21ED40AB300A9F224 /* ZXByteMatrix.m */; }; + 11F7B0821ED40AB300A9F224 /* ZXDecodeHints.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AEF41ED40AB300A9F224 /* ZXDecodeHints.m */; }; + 11F7B0831ED40AB300A9F224 /* ZXDimension.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AEF61ED40AB300A9F224 /* ZXDimension.m */; }; + 11F7B0841ED40AB300A9F224 /* ZXEncodeHints.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AEF81ED40AB300A9F224 /* ZXEncodeHints.m */; }; + 11F7B0851ED40AB300A9F224 /* ZXErrors.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AEFA1ED40AB300A9F224 /* ZXErrors.m */; }; + 11F7B0861ED40AB300A9F224 /* ZXInvertedLuminanceSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AEFD1ED40AB300A9F224 /* ZXInvertedLuminanceSource.m */; }; + 11F7B0871ED40AB300A9F224 /* ZXLuminanceSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AEFF1ED40AB300A9F224 /* ZXLuminanceSource.m */; }; + 11F7B0881ED40AB300A9F224 /* ZXPlanarYUVLuminanceSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF011ED40AB300A9F224 /* ZXPlanarYUVLuminanceSource.m */; }; + 11F7B0891ED40AB300A9F224 /* ZXResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF041ED40AB300A9F224 /* ZXResult.m */; }; + 11F7B08A1ED40AB300A9F224 /* ZXResultPoint.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF071ED40AB300A9F224 /* ZXResultPoint.m */; }; + 11F7B08B1ED40AB300A9F224 /* ZXRGBLuminanceSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF0A1ED40AB300A9F224 /* ZXRGBLuminanceSource.m */; }; + 11F7B08C1ED40AB300A9F224 /* ZXDataMatrixBitMatrixParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF0F1ED40AB300A9F224 /* ZXDataMatrixBitMatrixParser.m */; }; + 11F7B08D1ED40AB300A9F224 /* ZXDataMatrixDataBlock.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF111ED40AB300A9F224 /* ZXDataMatrixDataBlock.m */; }; + 11F7B08E1ED40AB300A9F224 /* ZXDataMatrixDecodedBitStreamParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF131ED40AB300A9F224 /* ZXDataMatrixDecodedBitStreamParser.m */; }; + 11F7B08F1ED40AB300A9F224 /* ZXDataMatrixDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF151ED40AB300A9F224 /* ZXDataMatrixDecoder.m */; }; + 11F7B0901ED40AB300A9F224 /* ZXDataMatrixVersion.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF171ED40AB300A9F224 /* ZXDataMatrixVersion.m */; }; + 11F7B0911ED40AB300A9F224 /* ZXDataMatrixDetector.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF1A1ED40AB300A9F224 /* ZXDataMatrixDetector.m */; }; + 11F7B0921ED40AB300A9F224 /* ZXDataMatrixASCIIEncoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF1D1ED40AB300A9F224 /* ZXDataMatrixASCIIEncoder.m */; }; + 11F7B0931ED40AB300A9F224 /* ZXDataMatrixBase256Encoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF1F1ED40AB300A9F224 /* ZXDataMatrixBase256Encoder.m */; }; + 11F7B0941ED40AB300A9F224 /* ZXDataMatrixC40Encoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF211ED40AB300A9F224 /* ZXDataMatrixC40Encoder.m */; }; + 11F7B0951ED40AB300A9F224 /* ZXDataMatrixDefaultPlacement.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF231ED40AB300A9F224 /* ZXDataMatrixDefaultPlacement.m */; }; + 11F7B0961ED40AB300A9F224 /* ZXDataMatrixEdifactEncoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF251ED40AB300A9F224 /* ZXDataMatrixEdifactEncoder.m */; }; + 11F7B0971ED40AB300A9F224 /* ZXDataMatrixEncoderContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF281ED40AB300A9F224 /* ZXDataMatrixEncoderContext.m */; }; + 11F7B0981ED40AB300A9F224 /* ZXDataMatrixErrorCorrection.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF2A1ED40AB300A9F224 /* ZXDataMatrixErrorCorrection.m */; }; + 11F7B0991ED40AB300A9F224 /* ZXDataMatrixHighLevelEncoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF2C1ED40AB300A9F224 /* ZXDataMatrixHighLevelEncoder.m */; }; + 11F7B09A1ED40AB300A9F224 /* ZXDataMatrixSymbolInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF2E1ED40AB300A9F224 /* ZXDataMatrixSymbolInfo.m */; }; + 11F7B09B1ED40AB300A9F224 /* ZXDataMatrixSymbolInfo144.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF301ED40AB300A9F224 /* ZXDataMatrixSymbolInfo144.m */; }; + 11F7B09C1ED40AB300A9F224 /* ZXDataMatrixTextEncoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF321ED40AB300A9F224 /* ZXDataMatrixTextEncoder.m */; }; + 11F7B09D1ED40AB300A9F224 /* ZXDataMatrixX12Encoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF341ED40AB300A9F224 /* ZXDataMatrixX12Encoder.m */; }; + 11F7B09E1ED40AB300A9F224 /* ZXDataMatrixReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF361ED40AB300A9F224 /* ZXDataMatrixReader.m */; }; + 11F7B09F1ED40AB300A9F224 /* ZXDataMatrixWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF381ED40AB300A9F224 /* ZXDataMatrixWriter.m */; }; + 11F7B0A01ED40AB300A9F224 /* ZXMaxiCodeBitMatrixParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF3D1ED40AB300A9F224 /* ZXMaxiCodeBitMatrixParser.m */; }; + 11F7B0A11ED40AB300A9F224 /* ZXMaxiCodeDecodedBitStreamParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF3F1ED40AB300A9F224 /* ZXMaxiCodeDecodedBitStreamParser.m */; }; + 11F7B0A21ED40AB300A9F224 /* ZXMaxiCodeDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF411ED40AB300A9F224 /* ZXMaxiCodeDecoder.m */; }; + 11F7B0A31ED40AB300A9F224 /* ZXMaxiCodeReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF441ED40AB300A9F224 /* ZXMaxiCodeReader.m */; }; + 11F7B0A41ED40AB300A9F224 /* ZXByQuadrantReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF471ED40AB300A9F224 /* ZXByQuadrantReader.m */; }; + 11F7B0A51ED40AB300A9F224 /* ZXGenericMultipleBarcodeReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF491ED40AB300A9F224 /* ZXGenericMultipleBarcodeReader.m */; }; + 11F7B0A61ED40AB300A9F224 /* ZXAbstractExpandedDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF501ED40AB300A9F224 /* ZXAbstractExpandedDecoder.m */; }; + 11F7B0A71ED40AB300A9F224 /* ZXAI013103decoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF521ED40AB300A9F224 /* ZXAI013103decoder.m */; }; + 11F7B0A81ED40AB300A9F224 /* ZXAI01320xDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF541ED40AB300A9F224 /* ZXAI01320xDecoder.m */; }; + 11F7B0A91ED40AB300A9F224 /* ZXAI01392xDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF561ED40AB300A9F224 /* ZXAI01392xDecoder.m */; }; + 11F7B0AA1ED40AB300A9F224 /* ZXAI01393xDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF581ED40AB300A9F224 /* ZXAI01393xDecoder.m */; }; + 11F7B0AB1ED40AB300A9F224 /* ZXAI013x0x1xDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF5A1ED40AB300A9F224 /* ZXAI013x0x1xDecoder.m */; }; + 11F7B0AC1ED40AB300A9F224 /* ZXAI013x0xDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF5C1ED40AB300A9F224 /* ZXAI013x0xDecoder.m */; }; + 11F7B0AD1ED40AB300A9F224 /* ZXAI01AndOtherAIs.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF5E1ED40AB300A9F224 /* ZXAI01AndOtherAIs.m */; }; + 11F7B0AE1ED40AB300A9F224 /* ZXAI01decoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF601ED40AB300A9F224 /* ZXAI01decoder.m */; }; + 11F7B0AF1ED40AB300A9F224 /* ZXAI01weightDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF621ED40AB300A9F224 /* ZXAI01weightDecoder.m */; }; + 11F7B0B01ED40AB300A9F224 /* ZXAnyAIDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF641ED40AB300A9F224 /* ZXAnyAIDecoder.m */; }; + 11F7B0B11ED40AB300A9F224 /* ZXRSSExpandedBlockParsedResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF661ED40AB300A9F224 /* ZXRSSExpandedBlockParsedResult.m */; }; + 11F7B0B21ED40AB300A9F224 /* ZXRSSExpandedCurrentParsingState.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF681ED40AB300A9F224 /* ZXRSSExpandedCurrentParsingState.m */; }; + 11F7B0B31ED40AB300A9F224 /* ZXRSSExpandedDecodedChar.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF6A1ED40AB300A9F224 /* ZXRSSExpandedDecodedChar.m */; }; + 11F7B0B41ED40AB300A9F224 /* ZXRSSExpandedDecodedInformation.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF6C1ED40AB300A9F224 /* ZXRSSExpandedDecodedInformation.m */; }; + 11F7B0B51ED40AB300A9F224 /* ZXRSSExpandedDecodedNumeric.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF6E1ED40AB300A9F224 /* ZXRSSExpandedDecodedNumeric.m */; }; + 11F7B0B61ED40AB300A9F224 /* ZXRSSExpandedDecodedObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF701ED40AB300A9F224 /* ZXRSSExpandedDecodedObject.m */; }; + 11F7B0B71ED40AB300A9F224 /* ZXRSSExpandedFieldParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF721ED40AB300A9F224 /* ZXRSSExpandedFieldParser.m */; }; + 11F7B0B81ED40AB300A9F224 /* ZXRSSExpandedGeneralAppIdDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF741ED40AB300A9F224 /* ZXRSSExpandedGeneralAppIdDecoder.m */; }; + 11F7B0B91ED40AB300A9F224 /* ZXBitArrayBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF761ED40AB300A9F224 /* ZXBitArrayBuilder.m */; }; + 11F7B0BA1ED40AB300A9F224 /* ZXRSSExpandedPair.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF781ED40AB300A9F224 /* ZXRSSExpandedPair.m */; }; + 11F7B0BB1ED40AB300A9F224 /* ZXRSSExpandedReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF7A1ED40AB300A9F224 /* ZXRSSExpandedReader.m */; }; + 11F7B0BC1ED40AB300A9F224 /* ZXRSSExpandedRow.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF7C1ED40AB300A9F224 /* ZXRSSExpandedRow.m */; }; + 11F7B0BD1ED40AB300A9F224 /* ZXAbstractRSSReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF7E1ED40AB300A9F224 /* ZXAbstractRSSReader.m */; }; + 11F7B0BE1ED40AB300A9F224 /* ZXRSS14Reader.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF801ED40AB300A9F224 /* ZXRSS14Reader.m */; }; + 11F7B0BF1ED40AB300A9F224 /* ZXRSSDataCharacter.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF821ED40AB300A9F224 /* ZXRSSDataCharacter.m */; }; + 11F7B0C01ED40AB300A9F224 /* ZXRSSFinderPattern.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF841ED40AB300A9F224 /* ZXRSSFinderPattern.m */; }; + 11F7B0C11ED40AB300A9F224 /* ZXRSSPair.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF861ED40AB300A9F224 /* ZXRSSPair.m */; }; + 11F7B0C21ED40AB300A9F224 /* ZXRSSUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF881ED40AB300A9F224 /* ZXRSSUtils.m */; }; + 11F7B0C31ED40AB300A9F224 /* ZXCodaBarReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF8A1ED40AB300A9F224 /* ZXCodaBarReader.m */; }; + 11F7B0C41ED40AB300A9F224 /* ZXCodaBarWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF8C1ED40AB300A9F224 /* ZXCodaBarWriter.m */; }; + 11F7B0C51ED40AB300A9F224 /* ZXCode128Reader.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF8E1ED40AB300A9F224 /* ZXCode128Reader.m */; }; + 11F7B0C61ED40AB300A9F224 /* ZXCode128Writer.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF901ED40AB300A9F224 /* ZXCode128Writer.m */; }; + 11F7B0C71ED40AB300A9F224 /* ZXCode39Reader.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF921ED40AB300A9F224 /* ZXCode39Reader.m */; }; + 11F7B0C81ED40AB300A9F224 /* ZXCode39Writer.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF941ED40AB300A9F224 /* ZXCode39Writer.m */; }; + 11F7B0C91ED40AB300A9F224 /* ZXCode93Reader.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF961ED40AB300A9F224 /* ZXCode93Reader.m */; }; + 11F7B0CA1ED40AB300A9F224 /* ZXEAN13Reader.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF981ED40AB300A9F224 /* ZXEAN13Reader.m */; }; + 11F7B0CB1ED40AB300A9F224 /* ZXEAN13Writer.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF9A1ED40AB300A9F224 /* ZXEAN13Writer.m */; }; + 11F7B0CC1ED40AB300A9F224 /* ZXEAN8Reader.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF9C1ED40AB300A9F224 /* ZXEAN8Reader.m */; }; + 11F7B0CD1ED40AB300A9F224 /* ZXEAN8Writer.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AF9E1ED40AB300A9F224 /* ZXEAN8Writer.m */; }; + 11F7B0CE1ED40AB300A9F224 /* ZXEANManufacturerOrgSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFA01ED40AB300A9F224 /* ZXEANManufacturerOrgSupport.m */; }; + 11F7B0CF1ED40AB300A9F224 /* ZXITFReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFA31ED40AB300A9F224 /* ZXITFReader.m */; }; + 11F7B0D01ED40AB300A9F224 /* ZXITFWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFA51ED40AB300A9F224 /* ZXITFWriter.m */; }; + 11F7B0D11ED40AB300A9F224 /* ZXMultiFormatOneDReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFA71ED40AB300A9F224 /* ZXMultiFormatOneDReader.m */; }; + 11F7B0D21ED40AB300A9F224 /* ZXMultiFormatUPCEANReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFA91ED40AB300A9F224 /* ZXMultiFormatUPCEANReader.m */; }; + 11F7B0D31ED40AB300A9F224 /* ZXOneDimensionalCodeWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFAB1ED40AB300A9F224 /* ZXOneDimensionalCodeWriter.m */; }; + 11F7B0D41ED40AB300A9F224 /* ZXOneDReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFAD1ED40AB300A9F224 /* ZXOneDReader.m */; }; + 11F7B0D51ED40AB300A9F224 /* ZXUPCAReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFAF1ED40AB300A9F224 /* ZXUPCAReader.m */; }; + 11F7B0D61ED40AB300A9F224 /* ZXUPCAWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFB11ED40AB300A9F224 /* ZXUPCAWriter.m */; }; + 11F7B0D71ED40AB300A9F224 /* ZXUPCEANExtension2Support.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFB31ED40AB300A9F224 /* ZXUPCEANExtension2Support.m */; }; + 11F7B0D81ED40AB300A9F224 /* ZXUPCEANExtension5Support.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFB51ED40AB300A9F224 /* ZXUPCEANExtension5Support.m */; }; + 11F7B0D91ED40AB300A9F224 /* ZXUPCEANExtensionSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFB71ED40AB300A9F224 /* ZXUPCEANExtensionSupport.m */; }; + 11F7B0DA1ED40AB300A9F224 /* ZXUPCEANReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFB91ED40AB300A9F224 /* ZXUPCEANReader.m */; }; + 11F7B0DB1ED40AB300A9F224 /* ZXUPCEANWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFBB1ED40AB300A9F224 /* ZXUPCEANWriter.m */; }; + 11F7B0DC1ED40AB300A9F224 /* ZXUPCEReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFBD1ED40AB300A9F224 /* ZXUPCEReader.m */; }; + 11F7B0DD1ED40AB300A9F224 /* ZXModulusGF.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFC21ED40AB300A9F224 /* ZXModulusGF.m */; }; + 11F7B0DE1ED40AB300A9F224 /* ZXModulusPoly.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFC41ED40AB300A9F224 /* ZXModulusPoly.m */; }; + 11F7B0DF1ED40AB300A9F224 /* ZXPDF417ECErrorCorrection.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFC61ED40AB300A9F224 /* ZXPDF417ECErrorCorrection.m */; }; + 11F7B0E01ED40AB300A9F224 /* ZXPDF417BarcodeMetadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFC81ED40AB300A9F224 /* ZXPDF417BarcodeMetadata.m */; }; + 11F7B0E11ED40AB300A9F224 /* ZXPDF417BarcodeValue.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFCA1ED40AB300A9F224 /* ZXPDF417BarcodeValue.m */; }; + 11F7B0E21ED40AB300A9F224 /* ZXPDF417BoundingBox.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFCC1ED40AB300A9F224 /* ZXPDF417BoundingBox.m */; }; + 11F7B0E31ED40AB300A9F224 /* ZXPDF417Codeword.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFCE1ED40AB300A9F224 /* ZXPDF417Codeword.m */; }; + 11F7B0E41ED40AB300A9F224 /* ZXPDF417CodewordDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFD01ED40AB300A9F224 /* ZXPDF417CodewordDecoder.m */; }; + 11F7B0E51ED40AB300A9F224 /* ZXPDF417DecodedBitStreamParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFD21ED40AB300A9F224 /* ZXPDF417DecodedBitStreamParser.m */; }; + 11F7B0E61ED40AB300A9F224 /* ZXPDF417DetectionResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFD41ED40AB300A9F224 /* ZXPDF417DetectionResult.m */; }; + 11F7B0E71ED40AB300A9F224 /* ZXPDF417DetectionResultColumn.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFD61ED40AB300A9F224 /* ZXPDF417DetectionResultColumn.m */; }; + 11F7B0E81ED40AB300A9F224 /* ZXPDF417DetectionResultRowIndicatorColumn.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFD81ED40AB300A9F224 /* ZXPDF417DetectionResultRowIndicatorColumn.m */; }; + 11F7B0E91ED40AB300A9F224 /* ZXPDF417ScanningDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFDA1ED40AB300A9F224 /* ZXPDF417ScanningDecoder.m */; }; + 11F7B0EA1ED40AB300A9F224 /* ZXPDF417Detector.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFDD1ED40AB300A9F224 /* ZXPDF417Detector.m */; }; + 11F7B0EB1ED40AB300A9F224 /* ZXPDF417DetectorResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFDF1ED40AB300A9F224 /* ZXPDF417DetectorResult.m */; }; + 11F7B0EC1ED40AB300A9F224 /* ZXPDF417.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFE21ED40AB300A9F224 /* ZXPDF417.m */; }; + 11F7B0ED1ED40AB300A9F224 /* ZXPDF417BarcodeMatrix.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFE41ED40AB300A9F224 /* ZXPDF417BarcodeMatrix.m */; }; + 11F7B0EE1ED40AB300A9F224 /* ZXPDF417BarcodeRow.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFE61ED40AB300A9F224 /* ZXPDF417BarcodeRow.m */; }; + 11F7B0EF1ED40AB300A9F224 /* ZXPDF417Dimensions.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFE81ED40AB300A9F224 /* ZXPDF417Dimensions.m */; }; + 11F7B0F01ED40AB300A9F224 /* ZXPDF417ErrorCorrection.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFEA1ED40AB300A9F224 /* ZXPDF417ErrorCorrection.m */; }; + 11F7B0F11ED40AB300A9F224 /* ZXPDF417HighLevelEncoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFEC1ED40AB300A9F224 /* ZXPDF417HighLevelEncoder.m */; }; + 11F7B0F21ED40AB300A9F224 /* ZXPDF417Common.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFEF1ED40AB300A9F224 /* ZXPDF417Common.m */; }; + 11F7B0F31ED40AB300A9F224 /* ZXPDF417Reader.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFF11ED40AB300A9F224 /* ZXPDF417Reader.m */; }; + 11F7B0F41ED40AB300A9F224 /* ZXPDF417ResultMetadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFF31ED40AB300A9F224 /* ZXPDF417ResultMetadata.m */; }; + 11F7B0F51ED40AB300A9F224 /* ZXPDF417Writer.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFF51ED40AB300A9F224 /* ZXPDF417Writer.m */; }; + 11F7B0F61ED40AB300A9F224 /* ZXQRCodeBitMatrixParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFF91ED40AB300A9F224 /* ZXQRCodeBitMatrixParser.m */; }; + 11F7B0F71ED40AB300A9F224 /* ZXQRCodeDataBlock.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFFB1ED40AB300A9F224 /* ZXQRCodeDataBlock.m */; }; + 11F7B0F81ED40AB300A9F224 /* ZXQRCodeDataMask.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFFD1ED40AB300A9F224 /* ZXQRCodeDataMask.m */; }; + 11F7B0F91ED40AB300A9F224 /* ZXQRCodeDecodedBitStreamParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7AFFF1ED40AB300A9F224 /* ZXQRCodeDecodedBitStreamParser.m */; }; + 11F7B0FA1ED40AB300A9F224 /* ZXQRCodeDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7B0011ED40AB300A9F224 /* ZXQRCodeDecoder.m */; }; + 11F7B0FB1ED40AB300A9F224 /* ZXQRCodeDecoderMetaData.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7B0031ED40AB300A9F224 /* ZXQRCodeDecoderMetaData.m */; }; + 11F7B0FC1ED40AB300A9F224 /* ZXQRCodeErrorCorrectionLevel.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7B0051ED40AB300A9F224 /* ZXQRCodeErrorCorrectionLevel.m */; }; + 11F7B0FD1ED40AB300A9F224 /* ZXQRCodeFormatInformation.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7B0071ED40AB300A9F224 /* ZXQRCodeFormatInformation.m */; }; + 11F7B0FE1ED40AB300A9F224 /* ZXQRCodeMode.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7B0091ED40AB300A9F224 /* ZXQRCodeMode.m */; }; + 11F7B0FF1ED40AB300A9F224 /* ZXQRCodeVersion.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7B00B1ED40AB300A9F224 /* ZXQRCodeVersion.m */; }; + 11F7B1001ED40AB300A9F224 /* ZXQRCodeAlignmentPattern.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7B00E1ED40AB300A9F224 /* ZXQRCodeAlignmentPattern.m */; }; + 11F7B1011ED40AB300A9F224 /* ZXQRCodeAlignmentPatternFinder.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7B0101ED40AB300A9F224 /* ZXQRCodeAlignmentPatternFinder.m */; }; + 11F7B1021ED40AB300A9F224 /* ZXQRCodeDetector.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7B0121ED40AB300A9F224 /* ZXQRCodeDetector.m */; }; + 11F7B1031ED40AB300A9F224 /* ZXQRCodeFinderPattern.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7B0141ED40AB300A9F224 /* ZXQRCodeFinderPattern.m */; }; + 11F7B1041ED40AB300A9F224 /* ZXQRCodeFinderPatternFinder.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7B0161ED40AB300A9F224 /* ZXQRCodeFinderPatternFinder.m */; }; + 11F7B1051ED40AB300A9F224 /* ZXQRCodeFinderPatternInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7B0181ED40AB300A9F224 /* ZXQRCodeFinderPatternInfo.m */; }; + 11F7B1061ED40AB300A9F224 /* ZXQRCode.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7B01B1ED40AB300A9F224 /* ZXQRCode.m */; }; + 11F7B1071ED40AB300A9F224 /* ZXQRCodeBlockPair.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7B01D1ED40AB300A9F224 /* ZXQRCodeBlockPair.m */; }; + 11F7B1081ED40AB300A9F224 /* ZXQRCodeEncoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7B01F1ED40AB300A9F224 /* ZXQRCodeEncoder.m */; }; + 11F7B1091ED40AB400A9F224 /* ZXQRCodeMaskUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7B0211ED40AB300A9F224 /* ZXQRCodeMaskUtil.m */; }; + 11F7B10A1ED40AB400A9F224 /* ZXQRCodeMatrixUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7B0231ED40AB300A9F224 /* ZXQRCodeMatrixUtil.m */; }; + 11F7B10B1ED40AB400A9F224 /* ZXMultiDetector.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7B0271ED40AB300A9F224 /* ZXMultiDetector.m */; }; + 11F7B10C1ED40AB400A9F224 /* ZXMultiFinderPatternFinder.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7B0291ED40AB300A9F224 /* ZXMultiFinderPatternFinder.m */; }; + 11F7B10D1ED40AB400A9F224 /* ZXQRCodeMultiReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7B02B1ED40AB300A9F224 /* ZXQRCodeMultiReader.m */; }; + 11F7B10E1ED40AB400A9F224 /* ZXQRCodeReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7B02E1ED40AB300A9F224 /* ZXQRCodeReader.m */; }; + 11F7B10F1ED40AB400A9F224 /* ZXQRCodeWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7B0301ED40AB300A9F224 /* ZXQRCodeWriter.m */; }; + 11F7B1101ED40AB400A9F224 /* ZXMultiFormatReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7B0331ED40AB300A9F224 /* ZXMultiFormatReader.m */; }; + 11F7B1111ED40AB400A9F224 /* ZXMultiFormatWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7B0351ED40AB300A9F224 /* ZXMultiFormatWriter.m */; }; + 11F7B1141ED416C900A9F224 /* QRCodeResultVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7B1131ED416C900A9F224 /* QRCodeResultVC.m */; }; + 11F7B1191ED4174D00A9F224 /* QRCodeResultView.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7B1181ED4174D00A9F224 /* QRCodeResultView.m */; }; + 11F7B11C1ED4356B00A9F224 /* PreloadViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 11F7B11B1ED4356B00A9F224 /* PreloadViewController.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -168,10 +432,28 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 110B9BE01ED281D700EC58DB /* BaseTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BaseTableViewCell.h; sourceTree = ""; }; + 110B9BE11ED281D700EC58DB /* BaseTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BaseTableViewCell.m; sourceTree = ""; }; + 110B9BE31ED2845500EC58DB /* BaseModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BaseModel.h; sourceTree = ""; }; + 110B9BE41ED2845500EC58DB /* BaseModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BaseModel.m; sourceTree = ""; }; + 110B9BE61ED2906700EC58DB /* PrereloadCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PrereloadCell.h; sourceTree = ""; }; + 110B9BE71ED2906700EC58DB /* PrereloadCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PrereloadCell.m; sourceTree = ""; }; + 110B9BE91ED2908C00EC58DB /* PrereloadCellModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PrereloadCellModel.h; sourceTree = ""; }; + 110B9BEA1ED2908C00EC58DB /* PrereloadCellModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PrereloadCellModel.m; sourceTree = ""; }; + 110B9BEC1ED291C100EC58DB /* PreloadViewModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PreloadViewModel.h; sourceTree = ""; }; + 110B9BED1ED291C100EC58DB /* PreloadViewModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PreloadViewModel.m; sourceTree = ""; }; + 110B9BEF1ED2932F00EC58DB /* PreloadDetailVC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PreloadDetailVC.h; sourceTree = ""; }; + 110B9BF01ED2932F00EC58DB /* PreloadDetailVC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PreloadDetailVC.m; sourceTree = ""; }; + 110B9BF51ED2B96200EC58DB /* PickDetailModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PickDetailModel.h; sourceTree = ""; }; + 110B9BF61ED2B96200EC58DB /* PickDetailModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PickDetailModel.m; sourceTree = ""; }; + 110B9BF81ED2BEEC00EC58DB /* PickDetailView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PickDetailView.h; sourceTree = ""; }; + 110B9BF91ED2BEEC00EC58DB /* PickDetailView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PickDetailView.m; sourceTree = ""; }; + 110B9BFB1ED2BF0700EC58DB /* PickDetailFootView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PickDetailFootView.h; sourceTree = ""; }; + 110B9BFC1ED2BF0700EC58DB /* PickDetailFootView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PickDetailFootView.m; sourceTree = ""; }; 1121BFC01EC990BD0002D73C /* iDearQRCode.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iDearQRCode.app; sourceTree = BUILT_PRODUCTS_DIR; }; 1121BFC41EC990BD0002D73C /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - 1121BFC61EC990BD0002D73C /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; - 1121BFC71EC990BD0002D73C /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 1121BFC61EC990BD0002D73C /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = iDearQRCode/AppDelegate.h; sourceTree = SOURCE_ROOT; }; + 1121BFC71EC990BD0002D73C /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = iDearQRCode/AppDelegate.m; sourceTree = SOURCE_ROOT; }; 1121BFC91EC990BD0002D73C /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 1121BFCA1EC990BD0002D73C /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 1121BFCD1EC990BD0002D73C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; @@ -227,6 +509,8 @@ 11346AB11ECED3ED00BFDD69 /* UIView+SDAutoLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+SDAutoLayout.m"; sourceTree = ""; }; 11346AB41ECEE02D00BFDD69 /* PickAlert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PickAlert.h; sourceTree = ""; }; 11346AB51ECEE02D00BFDD69 /* PickAlert.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PickAlert.m; sourceTree = ""; }; + 113580D91ED7BEB80069E21E /* PartSearchView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PartSearchView.h; path = ../Controller/PartSearchView.h; sourceTree = ""; }; + 113580DA1ED7BEB80069E21E /* PartSearchView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PartSearchView.m; path = ../Controller/PartSearchView.m; sourceTree = ""; }; 114828E31ECBDD6100BBCBF3 /* MKAnnotationView+WebCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MKAnnotationView+WebCache.h"; sourceTree = ""; }; 114828E41ECBDD6100BBCBF3 /* MKAnnotationView+WebCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MKAnnotationView+WebCache.m"; sourceTree = ""; }; 114828E51ECBDD6100BBCBF3 /* NSData+ImageContentType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+ImageContentType.h"; sourceTree = ""; }; @@ -274,6 +558,28 @@ 114829281ECC1E0000BBCBF3 /* PickingModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PickingModel.m; sourceTree = ""; }; 1148292A1ECC222F00BBCBF3 /* PickingHeadView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PickingHeadView.h; sourceTree = ""; }; 1148292B1ECC222F00BBCBF3 /* PickingHeadView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PickingHeadView.m; sourceTree = ""; }; + 1179FBE51ED56E5D0071ED45 /* PreloadDetailView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PreloadDetailView.h; sourceTree = ""; }; + 1179FBE61ED56E5D0071ED45 /* PreloadDetailView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PreloadDetailView.m; sourceTree = ""; }; + 1179FBE81ED577570071ED45 /* PreloadDetailCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PreloadDetailCell.h; sourceTree = ""; }; + 1179FBE91ED577570071ED45 /* PreloadDetailCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PreloadDetailCell.m; sourceTree = ""; }; + 118E68ED1ED92C9300B62015 /* YQNetworking+RequestManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "YQNetworking+RequestManager.h"; sourceTree = ""; }; + 118E68EE1ED92C9300B62015 /* YQNetworking+RequestManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "YQNetworking+RequestManager.m"; sourceTree = ""; }; + 118E68F11ED92C9900B62015 /* YQCacheManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YQCacheManager.h; sourceTree = ""; }; + 118E68F21ED92C9900B62015 /* YQCacheManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YQCacheManager.m; sourceTree = ""; }; + 118E68F31ED92C9900B62015 /* YQDiskCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YQDiskCache.h; sourceTree = ""; }; + 118E68F41ED92C9900B62015 /* YQDiskCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YQDiskCache.m; sourceTree = ""; }; + 118E68F51ED92C9900B62015 /* YQLRUManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YQLRUManager.h; sourceTree = ""; }; + 118E68F61ED92C9900B62015 /* YQLRUManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YQLRUManager.m; sourceTree = ""; }; + 118E68F71ED92C9900B62015 /* YQMemoryCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YQMemoryCache.h; sourceTree = ""; }; + 118E68F81ED92C9900B62015 /* YQMemoryCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YQMemoryCache.m; sourceTree = ""; }; + 118E68FD1ED92CA000B62015 /* YQNetworking.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YQNetworking.h; sourceTree = ""; }; + 118E68FE1ED92CA000B62015 /* YQNetworking.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YQNetworking.m; sourceTree = ""; }; + 118E69021ED94D5600B62015 /* UserModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UserModel.h; sourceTree = ""; }; + 118E69031ED94D5600B62015 /* UserModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UserModel.m; sourceTree = ""; }; + 118E69051ED94DC900B62015 /* UserManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UserManager.h; sourceTree = ""; }; + 118E69061ED94DC900B62015 /* UserManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UserManager.m; sourceTree = ""; }; + 118E69081ED951BF00B62015 /* KeyManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KeyManager.h; sourceTree = ""; }; + 118E69091ED951BF00B62015 /* KeyManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KeyManager.m; sourceTree = ""; }; 119AB2911ED15E87003DBF5A /* AFHTTPSessionManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFHTTPSessionManager.h; sourceTree = ""; }; 119AB2921ED15E87003DBF5A /* AFHTTPSessionManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFHTTPSessionManager.m; sourceTree = ""; }; 119AB2931ED15E87003DBF5A /* AFNetworking.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFNetworking.h; sourceTree = ""; }; @@ -312,14 +618,14 @@ 119AB2B61ED15E87003DBF5A /* YYClassInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYClassInfo.h; sourceTree = ""; }; 119AB2B71ED15E87003DBF5A /* YYClassInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YYClassInfo.m; sourceTree = ""; }; 119AB2B81ED15E87003DBF5A /* YYModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YYModel.h; sourceTree = ""; }; - 119AB2CA1ED15EB3003DBF5A /* RTNetworking.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RTNetworking.h; sourceTree = ""; }; - 119AB2CB1ED15EB3003DBF5A /* RTNetworking.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RTNetworking.m; sourceTree = ""; }; - 119AB2CD1ED16163003DBF5A /* ViewModelClass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewModelClass.h; sourceTree = ""; }; - 119AB2CE1ED16163003DBF5A /* ViewModelClass.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewModelClass.m; sourceTree = ""; }; + 119AB2CA1ED15EB3003DBF5A /* RTNetworking.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RTNetworking.h; path = ../../../Tools/Lib/RTNetworking.h; sourceTree = ""; }; + 119AB2CB1ED15EB3003DBF5A /* RTNetworking.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RTNetworking.m; path = ../../../Tools/Lib/RTNetworking.m; sourceTree = ""; }; + 119AB2CD1ED16163003DBF5A /* ViewModelClass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ViewModelClass.h; path = ../../../Tools/Lib/ViewModelClass.h; sourceTree = ""; }; + 119AB2CE1ED16163003DBF5A /* ViewModelClass.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ViewModelClass.m; path = ../../../Tools/Lib/ViewModelClass.m; sourceTree = ""; }; 119AB2D01ED161EB003DBF5A /* PickingViewModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PickingViewModel.h; sourceTree = ""; }; 119AB2D11ED161EB003DBF5A /* PickingViewModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PickingViewModel.m; sourceTree = ""; }; - 119AB2D31ED16F2C003DBF5A /* ZYThirdPartService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZYThirdPartService.h; sourceTree = ""; }; - 119AB2D41ED16F2C003DBF5A /* ZYThirdPartService.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZYThirdPartService.m; sourceTree = ""; }; + 119AB2D31ED16F2C003DBF5A /* ZYThirdPartService.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ZYThirdPartService.h; path = ../Tools/Lib/ZYThirdPartService.h; sourceTree = ""; }; + 119AB2D41ED16F2C003DBF5A /* ZYThirdPartService.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ZYThirdPartService.m; path = ../Tools/Lib/ZYThirdPartService.m; sourceTree = ""; }; 119AB2D81ED16FD6003DBF5A /* IQNSArray+Sort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "IQNSArray+Sort.h"; sourceTree = ""; }; 119AB2D91ED16FD6003DBF5A /* IQNSArray+Sort.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "IQNSArray+Sort.m"; sourceTree = ""; }; 119AB2DA1ED16FD6003DBF5A /* IQUIScrollView+Additions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "IQUIScrollView+Additions.h"; sourceTree = ""; }; @@ -363,8 +669,16 @@ 11C243591ED045C7007F69C6 /* PickDetailVc.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PickDetailVc.m; sourceTree = ""; }; 11C6C66A1ECDB47E00C2A9E8 /* PickingFootView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PickingFootView.h; sourceTree = ""; }; 11C6C66B1ECDB47E00C2A9E8 /* PickingFootView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PickingFootView.m; sourceTree = ""; }; - 11E3E95A1ECA879B00D72EE1 /* iDearQRCode.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iDearQRCode.pch; sourceTree = ""; }; - 11E3E95B1ECA890200D72EE1 /* iDear_Public.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = iDear_Public.h; sourceTree = ""; }; + 11DE26F11ED685D300DCDE78 /* NewPreloadVC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NewPreloadVC.h; sourceTree = ""; }; + 11DE26F21ED685D300DCDE78 /* NewPreloadVC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NewPreloadVC.m; sourceTree = ""; }; + 11DE26F41ED6A69000DCDE78 /* PreloadNewView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PreloadNewView.h; sourceTree = ""; }; + 11DE26F51ED6A69000DCDE78 /* PreloadNewView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PreloadNewView.m; sourceTree = ""; }; + 11DE26F71ED6B66800DCDE78 /* NewPartCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NewPartCell.h; sourceTree = ""; }; + 11DE26F81ED6B66800DCDE78 /* NewPartCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NewPartCell.m; sourceTree = ""; }; + 11DE26FA1ED6DBDF00DCDE78 /* NewPartNumberView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NewPartNumberView.h; sourceTree = ""; }; + 11DE26FB1ED6DBDF00DCDE78 /* NewPartNumberView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NewPartNumberView.m; sourceTree = ""; }; + 11E3E95A1ECA879B00D72EE1 /* iDearQRCode.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = iDearQRCode.pch; path = ../iDearQRCode.pch; sourceTree = ""; }; + 11E3E95B1ECA890200D72EE1 /* iDear_Public.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = iDear_Public.h; path = ../iDear_Public.h; sourceTree = ""; }; 11E3E95E1ECA8CEF00D72EE1 /* SheetView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SheetView.h; sourceTree = ""; }; 11E3E95F1ECA8CEF00D72EE1 /* SheetView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SheetView.m; sourceTree = ""; }; 11E3E9631ECA9A3400D72EE1 /* SheetViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SheetViewCell.h; sourceTree = ""; }; @@ -454,8 +768,6 @@ 11E3E9EB1ECAC90D00D72EE1 /* UIBarButtonItem+Item.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIBarButtonItem+Item.m"; sourceTree = ""; }; 11E3E9ED1ECAC90D00D72EE1 /* UIImage+Common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+Common.h"; sourceTree = ""; }; 11E3E9EE1ECAC90D00D72EE1 /* UIImage+Common.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+Common.m"; sourceTree = ""; }; - 11E3E9EF1ECAC90D00D72EE1 /* UIImage+Normalimage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+Normalimage.h"; sourceTree = ""; }; - 11E3E9F01ECAC90D00D72EE1 /* UIImage+Normalimage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+Normalimage.m"; sourceTree = ""; }; 11E3E9F21ECAC90D00D72EE1 /* UIView+Common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+Common.h"; sourceTree = ""; }; 11E3E9F31ECAC90D00D72EE1 /* UIView+Common.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+Common.m"; sourceTree = ""; }; 11E3E9F51ECAC90D00D72EE1 /* UIViewController+Common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIViewController+Common.h"; sourceTree = ""; }; @@ -464,6 +776,503 @@ 11E3EA051ECAEDAD00D72EE1 /* PersonTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PersonTableViewCell.m; sourceTree = ""; }; 11E3EA071ECAF71B00D72EE1 /* PersonHeadView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PersonHeadView.h; sourceTree = ""; }; 11E3EA081ECAF71B00D72EE1 /* PersonHeadView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PersonHeadView.m; sourceTree = ""; }; + 11F7AE171ED4043F00A9F224 /* CodeScan.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = CodeScan.bundle; sourceTree = ""; }; + 11F7AE1A1ED4043F00A9F224 /* UIActionSheet+LBXAlertAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIActionSheet+LBXAlertAction.h"; sourceTree = ""; }; + 11F7AE1B1ED4043F00A9F224 /* UIActionSheet+LBXAlertAction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIActionSheet+LBXAlertAction.m"; sourceTree = ""; }; + 11F7AE1C1ED4043F00A9F224 /* UIAlertController+supportedInterfaceOrientations.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIAlertController+supportedInterfaceOrientations.h"; sourceTree = ""; }; + 11F7AE1D1ED4043F00A9F224 /* UIAlertController+supportedInterfaceOrientations.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIAlertController+supportedInterfaceOrientations.m"; sourceTree = ""; }; + 11F7AE1E1ED4043F00A9F224 /* UIAlertView+LBXAlertAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIAlertView+LBXAlertAction.h"; sourceTree = ""; }; + 11F7AE1F1ED4043F00A9F224 /* UIAlertView+LBXAlertAction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIAlertView+LBXAlertAction.m"; sourceTree = ""; }; + 11F7AE201ED4043F00A9F224 /* LBXAlertAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LBXAlertAction.h; sourceTree = ""; }; + 11F7AE211ED4043F00A9F224 /* LBXAlertAction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LBXAlertAction.m; sourceTree = ""; }; + 11F7AE221ED4043F00A9F224 /* LBXScanLineAnimation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LBXScanLineAnimation.h; sourceTree = ""; }; + 11F7AE231ED4043F00A9F224 /* LBXScanLineAnimation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LBXScanLineAnimation.m; sourceTree = ""; }; + 11F7AE241ED4043F00A9F224 /* LBXScanNative.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LBXScanNative.h; sourceTree = ""; }; + 11F7AE251ED4043F00A9F224 /* LBXScanNative.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LBXScanNative.m; sourceTree = ""; }; + 11F7AE261ED4043F00A9F224 /* LBXScanNetAnimation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LBXScanNetAnimation.h; sourceTree = ""; }; + 11F7AE271ED4043F00A9F224 /* LBXScanNetAnimation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LBXScanNetAnimation.m; sourceTree = ""; }; + 11F7AE281ED4043F00A9F224 /* LBXScanResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LBXScanResult.h; sourceTree = ""; }; + 11F7AE291ED4043F00A9F224 /* LBXScanResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LBXScanResult.m; sourceTree = ""; }; + 11F7AE2A1ED4043F00A9F224 /* LBXScanVideoZoomView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LBXScanVideoZoomView.h; sourceTree = ""; }; + 11F7AE2B1ED4043F00A9F224 /* LBXScanVideoZoomView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LBXScanVideoZoomView.m; sourceTree = ""; }; + 11F7AE2C1ED4043F00A9F224 /* LBXScanView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LBXScanView.h; sourceTree = ""; }; + 11F7AE2D1ED4043F00A9F224 /* LBXScanView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LBXScanView.m; sourceTree = ""; }; + 11F7AE2E1ED4043F00A9F224 /* LBXScanViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LBXScanViewController.h; sourceTree = ""; }; + 11F7AE2F1ED4043F00A9F224 /* LBXScanViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LBXScanViewController.m; sourceTree = ""; }; + 11F7AE301ED4043F00A9F224 /* LBXScanViewStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LBXScanViewStyle.h; sourceTree = ""; }; + 11F7AE311ED4043F00A9F224 /* LBXScanViewStyle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LBXScanViewStyle.m; sourceTree = ""; }; + 11F7AE321ED4043F00A9F224 /* LBXScanWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LBXScanWrapper.h; sourceTree = ""; }; + 11F7AE331ED4043F00A9F224 /* LBXScanWrapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LBXScanWrapper.m; sourceTree = ""; }; + 11F7AE341ED4043F00A9F224 /* LBXZXCapture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LBXZXCapture.h; sourceTree = ""; }; + 11F7AE351ED4043F00A9F224 /* LBXZXCapture.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LBXZXCapture.m; sourceTree = ""; }; + 11F7AE361ED4043F00A9F224 /* LBXZXCaptureDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LBXZXCaptureDelegate.h; sourceTree = ""; }; + 11F7AE371ED4043F00A9F224 /* ZXingWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXingWrapper.h; sourceTree = ""; }; + 11F7AE381ED4043F00A9F224 /* ZXingWrapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXingWrapper.m; sourceTree = ""; }; + 11F7AE491ED404E800A9F224 /* QRCodeVC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = QRCodeVC.h; path = ../QRCodeVC.h; sourceTree = ""; }; + 11F7AE4A1ED404E800A9F224 /* QRCodeVC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = QRCodeVC.m; path = ../QRCodeVC.m; sourceTree = ""; }; + 11F7AE4F1ED40AB300A9F224 /* ZXAztecDecoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXAztecDecoder.h; sourceTree = ""; }; + 11F7AE501ED40AB300A9F224 /* ZXAztecDecoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXAztecDecoder.m; sourceTree = ""; }; + 11F7AE521ED40AB300A9F224 /* ZXAztecDetector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXAztecDetector.h; sourceTree = ""; }; + 11F7AE531ED40AB300A9F224 /* ZXAztecDetector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXAztecDetector.m; sourceTree = ""; }; + 11F7AE551ED40AB300A9F224 /* ZXAztecBinaryShiftToken.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXAztecBinaryShiftToken.h; sourceTree = ""; }; + 11F7AE561ED40AB300A9F224 /* ZXAztecBinaryShiftToken.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXAztecBinaryShiftToken.m; sourceTree = ""; }; + 11F7AE571ED40AB300A9F224 /* ZXAztecCode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXAztecCode.h; sourceTree = ""; }; + 11F7AE581ED40AB300A9F224 /* ZXAztecCode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXAztecCode.m; sourceTree = ""; }; + 11F7AE591ED40AB300A9F224 /* ZXAztecEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXAztecEncoder.h; sourceTree = ""; }; + 11F7AE5A1ED40AB300A9F224 /* ZXAztecEncoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXAztecEncoder.m; sourceTree = ""; }; + 11F7AE5B1ED40AB300A9F224 /* ZXAztecHighLevelEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXAztecHighLevelEncoder.h; sourceTree = ""; }; + 11F7AE5C1ED40AB300A9F224 /* ZXAztecHighLevelEncoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXAztecHighLevelEncoder.m; sourceTree = ""; }; + 11F7AE5D1ED40AB300A9F224 /* ZXAztecSimpleToken.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXAztecSimpleToken.h; sourceTree = ""; }; + 11F7AE5E1ED40AB300A9F224 /* ZXAztecSimpleToken.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXAztecSimpleToken.m; sourceTree = ""; }; + 11F7AE5F1ED40AB300A9F224 /* ZXAztecState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXAztecState.h; sourceTree = ""; }; + 11F7AE601ED40AB300A9F224 /* ZXAztecState.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXAztecState.m; sourceTree = ""; }; + 11F7AE611ED40AB300A9F224 /* ZXAztecToken.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXAztecToken.h; sourceTree = ""; }; + 11F7AE621ED40AB300A9F224 /* ZXAztecToken.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXAztecToken.m; sourceTree = ""; }; + 11F7AE631ED40AB300A9F224 /* ZXAztecDetectorResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXAztecDetectorResult.h; sourceTree = ""; }; + 11F7AE641ED40AB300A9F224 /* ZXAztecDetectorResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXAztecDetectorResult.m; sourceTree = ""; }; + 11F7AE651ED40AB300A9F224 /* ZXAztecReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXAztecReader.h; sourceTree = ""; }; + 11F7AE661ED40AB300A9F224 /* ZXAztecReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXAztecReader.m; sourceTree = ""; }; + 11F7AE671ED40AB300A9F224 /* ZXAztecWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXAztecWriter.h; sourceTree = ""; }; + 11F7AE681ED40AB300A9F224 /* ZXAztecWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXAztecWriter.m; sourceTree = ""; }; + 11F7AE691ED40AB300A9F224 /* ZXingObjCAztec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXingObjCAztec.h; sourceTree = ""; }; + 11F7AE6C1ED40AB300A9F224 /* ZXAbstractDoCoMoResultParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXAbstractDoCoMoResultParser.h; sourceTree = ""; }; + 11F7AE6D1ED40AB300A9F224 /* ZXAbstractDoCoMoResultParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXAbstractDoCoMoResultParser.m; sourceTree = ""; }; + 11F7AE6E1ED40AB300A9F224 /* ZXAddressBookAUResultParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXAddressBookAUResultParser.h; sourceTree = ""; }; + 11F7AE6F1ED40AB300A9F224 /* ZXAddressBookAUResultParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXAddressBookAUResultParser.m; sourceTree = ""; }; + 11F7AE701ED40AB300A9F224 /* ZXAddressBookDoCoMoResultParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXAddressBookDoCoMoResultParser.h; sourceTree = ""; }; + 11F7AE711ED40AB300A9F224 /* ZXAddressBookDoCoMoResultParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXAddressBookDoCoMoResultParser.m; sourceTree = ""; }; + 11F7AE721ED40AB300A9F224 /* ZXAddressBookParsedResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXAddressBookParsedResult.h; sourceTree = ""; }; + 11F7AE731ED40AB300A9F224 /* ZXAddressBookParsedResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXAddressBookParsedResult.m; sourceTree = ""; }; + 11F7AE741ED40AB300A9F224 /* ZXBizcardResultParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXBizcardResultParser.h; sourceTree = ""; }; + 11F7AE751ED40AB300A9F224 /* ZXBizcardResultParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXBizcardResultParser.m; sourceTree = ""; }; + 11F7AE761ED40AB300A9F224 /* ZXBookmarkDoCoMoResultParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXBookmarkDoCoMoResultParser.h; sourceTree = ""; }; + 11F7AE771ED40AB300A9F224 /* ZXBookmarkDoCoMoResultParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXBookmarkDoCoMoResultParser.m; sourceTree = ""; }; + 11F7AE781ED40AB300A9F224 /* ZXCalendarParsedResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXCalendarParsedResult.h; sourceTree = ""; }; + 11F7AE791ED40AB300A9F224 /* ZXCalendarParsedResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXCalendarParsedResult.m; sourceTree = ""; }; + 11F7AE7A1ED40AB300A9F224 /* ZXEmailAddressParsedResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXEmailAddressParsedResult.h; sourceTree = ""; }; + 11F7AE7B1ED40AB300A9F224 /* ZXEmailAddressParsedResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXEmailAddressParsedResult.m; sourceTree = ""; }; + 11F7AE7C1ED40AB300A9F224 /* ZXEmailAddressResultParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXEmailAddressResultParser.h; sourceTree = ""; }; + 11F7AE7D1ED40AB300A9F224 /* ZXEmailAddressResultParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXEmailAddressResultParser.m; sourceTree = ""; }; + 11F7AE7E1ED40AB300A9F224 /* ZXEmailDoCoMoResultParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXEmailDoCoMoResultParser.h; sourceTree = ""; }; + 11F7AE7F1ED40AB300A9F224 /* ZXEmailDoCoMoResultParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXEmailDoCoMoResultParser.m; sourceTree = ""; }; + 11F7AE801ED40AB300A9F224 /* ZXExpandedProductParsedResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXExpandedProductParsedResult.h; sourceTree = ""; }; + 11F7AE811ED40AB300A9F224 /* ZXExpandedProductParsedResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXExpandedProductParsedResult.m; sourceTree = ""; }; + 11F7AE821ED40AB300A9F224 /* ZXExpandedProductResultParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXExpandedProductResultParser.h; sourceTree = ""; }; + 11F7AE831ED40AB300A9F224 /* ZXExpandedProductResultParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXExpandedProductResultParser.m; sourceTree = ""; }; + 11F7AE841ED40AB300A9F224 /* ZXGeoParsedResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXGeoParsedResult.h; sourceTree = ""; }; + 11F7AE851ED40AB300A9F224 /* ZXGeoParsedResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXGeoParsedResult.m; sourceTree = ""; }; + 11F7AE861ED40AB300A9F224 /* ZXGeoResultParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXGeoResultParser.h; sourceTree = ""; }; + 11F7AE871ED40AB300A9F224 /* ZXGeoResultParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXGeoResultParser.m; sourceTree = ""; }; + 11F7AE881ED40AB300A9F224 /* ZXISBNParsedResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXISBNParsedResult.h; sourceTree = ""; }; + 11F7AE891ED40AB300A9F224 /* ZXISBNParsedResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXISBNParsedResult.m; sourceTree = ""; }; + 11F7AE8A1ED40AB300A9F224 /* ZXISBNResultParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXISBNResultParser.h; sourceTree = ""; }; + 11F7AE8B1ED40AB300A9F224 /* ZXISBNResultParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXISBNResultParser.m; sourceTree = ""; }; + 11F7AE8C1ED40AB300A9F224 /* ZXParsedResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXParsedResult.h; sourceTree = ""; }; + 11F7AE8D1ED40AB300A9F224 /* ZXParsedResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXParsedResult.m; sourceTree = ""; }; + 11F7AE8E1ED40AB300A9F224 /* ZXParsedResultType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXParsedResultType.h; sourceTree = ""; }; + 11F7AE8F1ED40AB300A9F224 /* ZXProductParsedResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXProductParsedResult.h; sourceTree = ""; }; + 11F7AE901ED40AB300A9F224 /* ZXProductParsedResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXProductParsedResult.m; sourceTree = ""; }; + 11F7AE911ED40AB300A9F224 /* ZXProductResultParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXProductResultParser.h; sourceTree = ""; }; + 11F7AE921ED40AB300A9F224 /* ZXProductResultParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXProductResultParser.m; sourceTree = ""; }; + 11F7AE931ED40AB300A9F224 /* ZXResultParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXResultParser.h; sourceTree = ""; }; + 11F7AE941ED40AB300A9F224 /* ZXResultParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXResultParser.m; sourceTree = ""; }; + 11F7AE951ED40AB300A9F224 /* ZXSMSMMSResultParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXSMSMMSResultParser.h; sourceTree = ""; }; + 11F7AE961ED40AB300A9F224 /* ZXSMSMMSResultParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXSMSMMSResultParser.m; sourceTree = ""; }; + 11F7AE971ED40AB300A9F224 /* ZXSMSParsedResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXSMSParsedResult.h; sourceTree = ""; }; + 11F7AE981ED40AB300A9F224 /* ZXSMSParsedResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXSMSParsedResult.m; sourceTree = ""; }; + 11F7AE991ED40AB300A9F224 /* ZXSMSTOMMSTOResultParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXSMSTOMMSTOResultParser.h; sourceTree = ""; }; + 11F7AE9A1ED40AB300A9F224 /* ZXSMSTOMMSTOResultParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXSMSTOMMSTOResultParser.m; sourceTree = ""; }; + 11F7AE9B1ED40AB300A9F224 /* ZXSMTPResultParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXSMTPResultParser.h; sourceTree = ""; }; + 11F7AE9C1ED40AB300A9F224 /* ZXSMTPResultParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXSMTPResultParser.m; sourceTree = ""; }; + 11F7AE9D1ED40AB300A9F224 /* ZXTelParsedResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXTelParsedResult.h; sourceTree = ""; }; + 11F7AE9E1ED40AB300A9F224 /* ZXTelParsedResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXTelParsedResult.m; sourceTree = ""; }; + 11F7AE9F1ED40AB300A9F224 /* ZXTelResultParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXTelResultParser.h; sourceTree = ""; }; + 11F7AEA01ED40AB300A9F224 /* ZXTelResultParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXTelResultParser.m; sourceTree = ""; }; + 11F7AEA11ED40AB300A9F224 /* ZXTextParsedResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXTextParsedResult.h; sourceTree = ""; }; + 11F7AEA21ED40AB300A9F224 /* ZXTextParsedResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXTextParsedResult.m; sourceTree = ""; }; + 11F7AEA31ED40AB300A9F224 /* ZXURIParsedResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXURIParsedResult.h; sourceTree = ""; }; + 11F7AEA41ED40AB300A9F224 /* ZXURIParsedResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXURIParsedResult.m; sourceTree = ""; }; + 11F7AEA51ED40AB300A9F224 /* ZXURIResultParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXURIResultParser.h; sourceTree = ""; }; + 11F7AEA61ED40AB300A9F224 /* ZXURIResultParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXURIResultParser.m; sourceTree = ""; }; + 11F7AEA71ED40AB300A9F224 /* ZXURLTOResultParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXURLTOResultParser.h; sourceTree = ""; }; + 11F7AEA81ED40AB300A9F224 /* ZXURLTOResultParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXURLTOResultParser.m; sourceTree = ""; }; + 11F7AEA91ED40AB300A9F224 /* ZXVCardResultParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXVCardResultParser.h; sourceTree = ""; }; + 11F7AEAA1ED40AB300A9F224 /* ZXVCardResultParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXVCardResultParser.m; sourceTree = ""; }; + 11F7AEAB1ED40AB300A9F224 /* ZXVEventResultParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXVEventResultParser.h; sourceTree = ""; }; + 11F7AEAC1ED40AB300A9F224 /* ZXVEventResultParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXVEventResultParser.m; sourceTree = ""; }; + 11F7AEAD1ED40AB300A9F224 /* ZXVINParsedResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXVINParsedResult.h; sourceTree = ""; }; + 11F7AEAE1ED40AB300A9F224 /* ZXVINParsedResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXVINParsedResult.m; sourceTree = ""; }; + 11F7AEAF1ED40AB300A9F224 /* ZXVINResultParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXVINResultParser.h; sourceTree = ""; }; + 11F7AEB01ED40AB300A9F224 /* ZXVINResultParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXVINResultParser.m; sourceTree = ""; }; + 11F7AEB11ED40AB300A9F224 /* ZXWifiParsedResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXWifiParsedResult.h; sourceTree = ""; }; + 11F7AEB21ED40AB300A9F224 /* ZXWifiParsedResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXWifiParsedResult.m; sourceTree = ""; }; + 11F7AEB31ED40AB300A9F224 /* ZXWifiResultParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXWifiResultParser.h; sourceTree = ""; }; + 11F7AEB41ED40AB300A9F224 /* ZXWifiResultParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXWifiResultParser.m; sourceTree = ""; }; + 11F7AEB51ED40AB300A9F224 /* ZXCapture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXCapture.h; sourceTree = ""; }; + 11F7AEB61ED40AB300A9F224 /* ZXCapture.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXCapture.m; sourceTree = ""; }; + 11F7AEB71ED40AB300A9F224 /* ZXCaptureDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXCaptureDelegate.h; sourceTree = ""; }; + 11F7AEB81ED40AB300A9F224 /* ZXCGImageLuminanceSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXCGImageLuminanceSource.h; sourceTree = ""; }; + 11F7AEB91ED40AB300A9F224 /* ZXCGImageLuminanceSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXCGImageLuminanceSource.m; sourceTree = ""; }; + 11F7AEBA1ED40AB300A9F224 /* ZXImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXImage.h; sourceTree = ""; }; + 11F7AEBB1ED40AB300A9F224 /* ZXImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXImage.m; sourceTree = ""; }; + 11F7AEBE1ED40AB300A9F224 /* ZXMathUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXMathUtils.h; sourceTree = ""; }; + 11F7AEBF1ED40AB300A9F224 /* ZXMathUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXMathUtils.m; sourceTree = ""; }; + 11F7AEC01ED40AB300A9F224 /* ZXMonochromeRectangleDetector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXMonochromeRectangleDetector.h; sourceTree = ""; }; + 11F7AEC11ED40AB300A9F224 /* ZXMonochromeRectangleDetector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXMonochromeRectangleDetector.m; sourceTree = ""; }; + 11F7AEC21ED40AB300A9F224 /* ZXWhiteRectangleDetector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXWhiteRectangleDetector.h; sourceTree = ""; }; + 11F7AEC31ED40AB300A9F224 /* ZXWhiteRectangleDetector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXWhiteRectangleDetector.m; sourceTree = ""; }; + 11F7AEC51ED40AB300A9F224 /* ZXGenericGF.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXGenericGF.h; sourceTree = ""; }; + 11F7AEC61ED40AB300A9F224 /* ZXGenericGF.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXGenericGF.m; sourceTree = ""; }; + 11F7AEC71ED40AB300A9F224 /* ZXGenericGFPoly.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXGenericGFPoly.h; sourceTree = ""; }; + 11F7AEC81ED40AB300A9F224 /* ZXGenericGFPoly.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXGenericGFPoly.m; sourceTree = ""; }; + 11F7AEC91ED40AB300A9F224 /* ZXReedSolomonDecoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXReedSolomonDecoder.h; sourceTree = ""; }; + 11F7AECA1ED40AB300A9F224 /* ZXReedSolomonDecoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXReedSolomonDecoder.m; sourceTree = ""; }; + 11F7AECB1ED40AB300A9F224 /* ZXReedSolomonEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXReedSolomonEncoder.h; sourceTree = ""; }; + 11F7AECC1ED40AB300A9F224 /* ZXReedSolomonEncoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXReedSolomonEncoder.m; sourceTree = ""; }; + 11F7AECD1ED40AB300A9F224 /* ZXBitArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXBitArray.h; sourceTree = ""; }; + 11F7AECE1ED40AB300A9F224 /* ZXBitArray.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXBitArray.m; sourceTree = ""; }; + 11F7AECF1ED40AB300A9F224 /* ZXBitMatrix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXBitMatrix.h; sourceTree = ""; }; + 11F7AED01ED40AB300A9F224 /* ZXBitMatrix.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXBitMatrix.m; sourceTree = ""; }; + 11F7AED11ED40AB300A9F224 /* ZXBitSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXBitSource.h; sourceTree = ""; }; + 11F7AED21ED40AB300A9F224 /* ZXBitSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXBitSource.m; sourceTree = ""; }; + 11F7AED31ED40AB300A9F224 /* ZXBoolArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXBoolArray.h; sourceTree = ""; }; + 11F7AED41ED40AB300A9F224 /* ZXBoolArray.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXBoolArray.m; sourceTree = ""; }; + 11F7AED51ED40AB300A9F224 /* ZXByteArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXByteArray.h; sourceTree = ""; }; + 11F7AED61ED40AB300A9F224 /* ZXByteArray.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXByteArray.m; sourceTree = ""; }; + 11F7AED71ED40AB300A9F224 /* ZXCharacterSetECI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXCharacterSetECI.h; sourceTree = ""; }; + 11F7AED81ED40AB300A9F224 /* ZXCharacterSetECI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXCharacterSetECI.m; sourceTree = ""; }; + 11F7AED91ED40AB300A9F224 /* ZXDecoderResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXDecoderResult.h; sourceTree = ""; }; + 11F7AEDA1ED40AB300A9F224 /* ZXDecoderResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXDecoderResult.m; sourceTree = ""; }; + 11F7AEDB1ED40AB300A9F224 /* ZXDefaultGridSampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXDefaultGridSampler.h; sourceTree = ""; }; + 11F7AEDC1ED40AB300A9F224 /* ZXDefaultGridSampler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXDefaultGridSampler.m; sourceTree = ""; }; + 11F7AEDD1ED40AB300A9F224 /* ZXDetectorResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXDetectorResult.h; sourceTree = ""; }; + 11F7AEDE1ED40AB300A9F224 /* ZXDetectorResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXDetectorResult.m; sourceTree = ""; }; + 11F7AEDF1ED40AB300A9F224 /* ZXGlobalHistogramBinarizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXGlobalHistogramBinarizer.h; sourceTree = ""; }; + 11F7AEE01ED40AB300A9F224 /* ZXGlobalHistogramBinarizer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXGlobalHistogramBinarizer.m; sourceTree = ""; }; + 11F7AEE11ED40AB300A9F224 /* ZXGridSampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXGridSampler.h; sourceTree = ""; }; + 11F7AEE21ED40AB300A9F224 /* ZXGridSampler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXGridSampler.m; sourceTree = ""; }; + 11F7AEE31ED40AB300A9F224 /* ZXHybridBinarizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXHybridBinarizer.h; sourceTree = ""; }; + 11F7AEE41ED40AB300A9F224 /* ZXHybridBinarizer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXHybridBinarizer.m; sourceTree = ""; }; + 11F7AEE51ED40AB300A9F224 /* ZXIntArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXIntArray.h; sourceTree = ""; }; + 11F7AEE61ED40AB300A9F224 /* ZXIntArray.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXIntArray.m; sourceTree = ""; }; + 11F7AEE71ED40AB300A9F224 /* ZXPerspectiveTransform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXPerspectiveTransform.h; sourceTree = ""; }; + 11F7AEE81ED40AB300A9F224 /* ZXPerspectiveTransform.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXPerspectiveTransform.m; sourceTree = ""; }; + 11F7AEE91ED40AB300A9F224 /* ZXStringUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXStringUtils.h; sourceTree = ""; }; + 11F7AEEA1ED40AB300A9F224 /* ZXStringUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXStringUtils.m; sourceTree = ""; }; + 11F7AEEC1ED40AB300A9F224 /* ZXBarcodeFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXBarcodeFormat.h; sourceTree = ""; }; + 11F7AEED1ED40AB300A9F224 /* ZXBinarizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXBinarizer.h; sourceTree = ""; }; + 11F7AEEE1ED40AB300A9F224 /* ZXBinarizer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXBinarizer.m; sourceTree = ""; }; + 11F7AEEF1ED40AB300A9F224 /* ZXBinaryBitmap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXBinaryBitmap.h; sourceTree = ""; }; + 11F7AEF01ED40AB300A9F224 /* ZXBinaryBitmap.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXBinaryBitmap.m; sourceTree = ""; }; + 11F7AEF11ED40AB300A9F224 /* ZXByteMatrix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXByteMatrix.h; sourceTree = ""; }; + 11F7AEF21ED40AB300A9F224 /* ZXByteMatrix.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXByteMatrix.m; sourceTree = ""; }; + 11F7AEF31ED40AB300A9F224 /* ZXDecodeHints.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXDecodeHints.h; sourceTree = ""; }; + 11F7AEF41ED40AB300A9F224 /* ZXDecodeHints.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXDecodeHints.m; sourceTree = ""; }; + 11F7AEF51ED40AB300A9F224 /* ZXDimension.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXDimension.h; sourceTree = ""; }; + 11F7AEF61ED40AB300A9F224 /* ZXDimension.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXDimension.m; sourceTree = ""; }; + 11F7AEF71ED40AB300A9F224 /* ZXEncodeHints.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXEncodeHints.h; sourceTree = ""; }; + 11F7AEF81ED40AB300A9F224 /* ZXEncodeHints.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXEncodeHints.m; sourceTree = ""; }; + 11F7AEF91ED40AB300A9F224 /* ZXErrors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXErrors.h; sourceTree = ""; }; + 11F7AEFA1ED40AB300A9F224 /* ZXErrors.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXErrors.m; sourceTree = ""; }; + 11F7AEFB1ED40AB300A9F224 /* ZXingObjCCore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXingObjCCore.h; sourceTree = ""; }; + 11F7AEFC1ED40AB300A9F224 /* ZXInvertedLuminanceSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXInvertedLuminanceSource.h; sourceTree = ""; }; + 11F7AEFD1ED40AB300A9F224 /* ZXInvertedLuminanceSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXInvertedLuminanceSource.m; sourceTree = ""; }; + 11F7AEFE1ED40AB300A9F224 /* ZXLuminanceSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXLuminanceSource.h; sourceTree = ""; }; + 11F7AEFF1ED40AB300A9F224 /* ZXLuminanceSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXLuminanceSource.m; sourceTree = ""; }; + 11F7AF001ED40AB300A9F224 /* ZXPlanarYUVLuminanceSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXPlanarYUVLuminanceSource.h; sourceTree = ""; }; + 11F7AF011ED40AB300A9F224 /* ZXPlanarYUVLuminanceSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXPlanarYUVLuminanceSource.m; sourceTree = ""; }; + 11F7AF021ED40AB300A9F224 /* ZXReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXReader.h; sourceTree = ""; }; + 11F7AF031ED40AB300A9F224 /* ZXResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXResult.h; sourceTree = ""; }; + 11F7AF041ED40AB300A9F224 /* ZXResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXResult.m; sourceTree = ""; }; + 11F7AF051ED40AB300A9F224 /* ZXResultMetadataType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXResultMetadataType.h; sourceTree = ""; }; + 11F7AF061ED40AB300A9F224 /* ZXResultPoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXResultPoint.h; sourceTree = ""; }; + 11F7AF071ED40AB300A9F224 /* ZXResultPoint.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXResultPoint.m; sourceTree = ""; }; + 11F7AF081ED40AB300A9F224 /* ZXResultPointCallback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXResultPointCallback.h; sourceTree = ""; }; + 11F7AF091ED40AB300A9F224 /* ZXRGBLuminanceSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXRGBLuminanceSource.h; sourceTree = ""; }; + 11F7AF0A1ED40AB300A9F224 /* ZXRGBLuminanceSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXRGBLuminanceSource.m; sourceTree = ""; }; + 11F7AF0B1ED40AB300A9F224 /* ZXWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXWriter.h; sourceTree = ""; }; + 11F7AF0E1ED40AB300A9F224 /* ZXDataMatrixBitMatrixParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXDataMatrixBitMatrixParser.h; sourceTree = ""; }; + 11F7AF0F1ED40AB300A9F224 /* ZXDataMatrixBitMatrixParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXDataMatrixBitMatrixParser.m; sourceTree = ""; }; + 11F7AF101ED40AB300A9F224 /* ZXDataMatrixDataBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXDataMatrixDataBlock.h; sourceTree = ""; }; + 11F7AF111ED40AB300A9F224 /* ZXDataMatrixDataBlock.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXDataMatrixDataBlock.m; sourceTree = ""; }; + 11F7AF121ED40AB300A9F224 /* ZXDataMatrixDecodedBitStreamParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXDataMatrixDecodedBitStreamParser.h; sourceTree = ""; }; + 11F7AF131ED40AB300A9F224 /* ZXDataMatrixDecodedBitStreamParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXDataMatrixDecodedBitStreamParser.m; sourceTree = ""; }; + 11F7AF141ED40AB300A9F224 /* ZXDataMatrixDecoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXDataMatrixDecoder.h; sourceTree = ""; }; + 11F7AF151ED40AB300A9F224 /* ZXDataMatrixDecoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXDataMatrixDecoder.m; sourceTree = ""; }; + 11F7AF161ED40AB300A9F224 /* ZXDataMatrixVersion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXDataMatrixVersion.h; sourceTree = ""; }; + 11F7AF171ED40AB300A9F224 /* ZXDataMatrixVersion.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXDataMatrixVersion.m; sourceTree = ""; }; + 11F7AF191ED40AB300A9F224 /* ZXDataMatrixDetector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXDataMatrixDetector.h; sourceTree = ""; }; + 11F7AF1A1ED40AB300A9F224 /* ZXDataMatrixDetector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXDataMatrixDetector.m; sourceTree = ""; }; + 11F7AF1C1ED40AB300A9F224 /* ZXDataMatrixASCIIEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXDataMatrixASCIIEncoder.h; sourceTree = ""; }; + 11F7AF1D1ED40AB300A9F224 /* ZXDataMatrixASCIIEncoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXDataMatrixASCIIEncoder.m; sourceTree = ""; }; + 11F7AF1E1ED40AB300A9F224 /* ZXDataMatrixBase256Encoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXDataMatrixBase256Encoder.h; sourceTree = ""; }; + 11F7AF1F1ED40AB300A9F224 /* ZXDataMatrixBase256Encoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXDataMatrixBase256Encoder.m; sourceTree = ""; }; + 11F7AF201ED40AB300A9F224 /* ZXDataMatrixC40Encoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXDataMatrixC40Encoder.h; sourceTree = ""; }; + 11F7AF211ED40AB300A9F224 /* ZXDataMatrixC40Encoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXDataMatrixC40Encoder.m; sourceTree = ""; }; + 11F7AF221ED40AB300A9F224 /* ZXDataMatrixDefaultPlacement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXDataMatrixDefaultPlacement.h; sourceTree = ""; }; + 11F7AF231ED40AB300A9F224 /* ZXDataMatrixDefaultPlacement.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXDataMatrixDefaultPlacement.m; sourceTree = ""; }; + 11F7AF241ED40AB300A9F224 /* ZXDataMatrixEdifactEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXDataMatrixEdifactEncoder.h; sourceTree = ""; }; + 11F7AF251ED40AB300A9F224 /* ZXDataMatrixEdifactEncoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXDataMatrixEdifactEncoder.m; sourceTree = ""; }; + 11F7AF261ED40AB300A9F224 /* ZXDataMatrixEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXDataMatrixEncoder.h; sourceTree = ""; }; + 11F7AF271ED40AB300A9F224 /* ZXDataMatrixEncoderContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXDataMatrixEncoderContext.h; sourceTree = ""; }; + 11F7AF281ED40AB300A9F224 /* ZXDataMatrixEncoderContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXDataMatrixEncoderContext.m; sourceTree = ""; }; + 11F7AF291ED40AB300A9F224 /* ZXDataMatrixErrorCorrection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXDataMatrixErrorCorrection.h; sourceTree = ""; }; + 11F7AF2A1ED40AB300A9F224 /* ZXDataMatrixErrorCorrection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXDataMatrixErrorCorrection.m; sourceTree = ""; }; + 11F7AF2B1ED40AB300A9F224 /* ZXDataMatrixHighLevelEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXDataMatrixHighLevelEncoder.h; sourceTree = ""; }; + 11F7AF2C1ED40AB300A9F224 /* ZXDataMatrixHighLevelEncoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXDataMatrixHighLevelEncoder.m; sourceTree = ""; }; + 11F7AF2D1ED40AB300A9F224 /* ZXDataMatrixSymbolInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXDataMatrixSymbolInfo.h; sourceTree = ""; }; + 11F7AF2E1ED40AB300A9F224 /* ZXDataMatrixSymbolInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXDataMatrixSymbolInfo.m; sourceTree = ""; }; + 11F7AF2F1ED40AB300A9F224 /* ZXDataMatrixSymbolInfo144.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXDataMatrixSymbolInfo144.h; sourceTree = ""; }; + 11F7AF301ED40AB300A9F224 /* ZXDataMatrixSymbolInfo144.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXDataMatrixSymbolInfo144.m; sourceTree = ""; }; + 11F7AF311ED40AB300A9F224 /* ZXDataMatrixTextEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXDataMatrixTextEncoder.h; sourceTree = ""; }; + 11F7AF321ED40AB300A9F224 /* ZXDataMatrixTextEncoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXDataMatrixTextEncoder.m; sourceTree = ""; }; + 11F7AF331ED40AB300A9F224 /* ZXDataMatrixX12Encoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXDataMatrixX12Encoder.h; sourceTree = ""; }; + 11F7AF341ED40AB300A9F224 /* ZXDataMatrixX12Encoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXDataMatrixX12Encoder.m; sourceTree = ""; }; + 11F7AF351ED40AB300A9F224 /* ZXDataMatrixReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXDataMatrixReader.h; sourceTree = ""; }; + 11F7AF361ED40AB300A9F224 /* ZXDataMatrixReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXDataMatrixReader.m; sourceTree = ""; }; + 11F7AF371ED40AB300A9F224 /* ZXDataMatrixWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXDataMatrixWriter.h; sourceTree = ""; }; + 11F7AF381ED40AB300A9F224 /* ZXDataMatrixWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXDataMatrixWriter.m; sourceTree = ""; }; + 11F7AF391ED40AB300A9F224 /* ZXingObjCDataMatrix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXingObjCDataMatrix.h; sourceTree = ""; }; + 11F7AF3C1ED40AB300A9F224 /* ZXMaxiCodeBitMatrixParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXMaxiCodeBitMatrixParser.h; sourceTree = ""; }; + 11F7AF3D1ED40AB300A9F224 /* ZXMaxiCodeBitMatrixParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXMaxiCodeBitMatrixParser.m; sourceTree = ""; }; + 11F7AF3E1ED40AB300A9F224 /* ZXMaxiCodeDecodedBitStreamParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXMaxiCodeDecodedBitStreamParser.h; sourceTree = ""; }; + 11F7AF3F1ED40AB300A9F224 /* ZXMaxiCodeDecodedBitStreamParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXMaxiCodeDecodedBitStreamParser.m; sourceTree = ""; }; + 11F7AF401ED40AB300A9F224 /* ZXMaxiCodeDecoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXMaxiCodeDecoder.h; sourceTree = ""; }; + 11F7AF411ED40AB300A9F224 /* ZXMaxiCodeDecoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXMaxiCodeDecoder.m; sourceTree = ""; }; + 11F7AF421ED40AB300A9F224 /* ZXingObjCMaxiCode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXingObjCMaxiCode.h; sourceTree = ""; }; + 11F7AF431ED40AB300A9F224 /* ZXMaxiCodeReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXMaxiCodeReader.h; sourceTree = ""; }; + 11F7AF441ED40AB300A9F224 /* ZXMaxiCodeReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXMaxiCodeReader.m; sourceTree = ""; }; + 11F7AF461ED40AB300A9F224 /* ZXByQuadrantReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXByQuadrantReader.h; sourceTree = ""; }; + 11F7AF471ED40AB300A9F224 /* ZXByQuadrantReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXByQuadrantReader.m; sourceTree = ""; }; + 11F7AF481ED40AB300A9F224 /* ZXGenericMultipleBarcodeReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXGenericMultipleBarcodeReader.h; sourceTree = ""; }; + 11F7AF491ED40AB300A9F224 /* ZXGenericMultipleBarcodeReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXGenericMultipleBarcodeReader.m; sourceTree = ""; }; + 11F7AF4A1ED40AB300A9F224 /* ZXMultipleBarcodeReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXMultipleBarcodeReader.h; sourceTree = ""; }; + 11F7AF4F1ED40AB300A9F224 /* ZXAbstractExpandedDecoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXAbstractExpandedDecoder.h; sourceTree = ""; }; + 11F7AF501ED40AB300A9F224 /* ZXAbstractExpandedDecoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXAbstractExpandedDecoder.m; sourceTree = ""; }; + 11F7AF511ED40AB300A9F224 /* ZXAI013103decoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXAI013103decoder.h; sourceTree = ""; }; + 11F7AF521ED40AB300A9F224 /* ZXAI013103decoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXAI013103decoder.m; sourceTree = ""; }; + 11F7AF531ED40AB300A9F224 /* ZXAI01320xDecoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXAI01320xDecoder.h; sourceTree = ""; }; + 11F7AF541ED40AB300A9F224 /* ZXAI01320xDecoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXAI01320xDecoder.m; sourceTree = ""; }; + 11F7AF551ED40AB300A9F224 /* ZXAI01392xDecoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXAI01392xDecoder.h; sourceTree = ""; }; + 11F7AF561ED40AB300A9F224 /* ZXAI01392xDecoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXAI01392xDecoder.m; sourceTree = ""; }; + 11F7AF571ED40AB300A9F224 /* ZXAI01393xDecoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXAI01393xDecoder.h; sourceTree = ""; }; + 11F7AF581ED40AB300A9F224 /* ZXAI01393xDecoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXAI01393xDecoder.m; sourceTree = ""; }; + 11F7AF591ED40AB300A9F224 /* ZXAI013x0x1xDecoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXAI013x0x1xDecoder.h; sourceTree = ""; }; + 11F7AF5A1ED40AB300A9F224 /* ZXAI013x0x1xDecoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXAI013x0x1xDecoder.m; sourceTree = ""; }; + 11F7AF5B1ED40AB300A9F224 /* ZXAI013x0xDecoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXAI013x0xDecoder.h; sourceTree = ""; }; + 11F7AF5C1ED40AB300A9F224 /* ZXAI013x0xDecoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXAI013x0xDecoder.m; sourceTree = ""; }; + 11F7AF5D1ED40AB300A9F224 /* ZXAI01AndOtherAIs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXAI01AndOtherAIs.h; sourceTree = ""; }; + 11F7AF5E1ED40AB300A9F224 /* ZXAI01AndOtherAIs.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXAI01AndOtherAIs.m; sourceTree = ""; }; + 11F7AF5F1ED40AB300A9F224 /* ZXAI01decoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXAI01decoder.h; sourceTree = ""; }; + 11F7AF601ED40AB300A9F224 /* ZXAI01decoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXAI01decoder.m; sourceTree = ""; }; + 11F7AF611ED40AB300A9F224 /* ZXAI01weightDecoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXAI01weightDecoder.h; sourceTree = ""; }; + 11F7AF621ED40AB300A9F224 /* ZXAI01weightDecoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXAI01weightDecoder.m; sourceTree = ""; }; + 11F7AF631ED40AB300A9F224 /* ZXAnyAIDecoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXAnyAIDecoder.h; sourceTree = ""; }; + 11F7AF641ED40AB300A9F224 /* ZXAnyAIDecoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXAnyAIDecoder.m; sourceTree = ""; }; + 11F7AF651ED40AB300A9F224 /* ZXRSSExpandedBlockParsedResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXRSSExpandedBlockParsedResult.h; sourceTree = ""; }; + 11F7AF661ED40AB300A9F224 /* ZXRSSExpandedBlockParsedResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXRSSExpandedBlockParsedResult.m; sourceTree = ""; }; + 11F7AF671ED40AB300A9F224 /* ZXRSSExpandedCurrentParsingState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXRSSExpandedCurrentParsingState.h; sourceTree = ""; }; + 11F7AF681ED40AB300A9F224 /* ZXRSSExpandedCurrentParsingState.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXRSSExpandedCurrentParsingState.m; sourceTree = ""; }; + 11F7AF691ED40AB300A9F224 /* ZXRSSExpandedDecodedChar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXRSSExpandedDecodedChar.h; sourceTree = ""; }; + 11F7AF6A1ED40AB300A9F224 /* ZXRSSExpandedDecodedChar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXRSSExpandedDecodedChar.m; sourceTree = ""; }; + 11F7AF6B1ED40AB300A9F224 /* ZXRSSExpandedDecodedInformation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXRSSExpandedDecodedInformation.h; sourceTree = ""; }; + 11F7AF6C1ED40AB300A9F224 /* ZXRSSExpandedDecodedInformation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXRSSExpandedDecodedInformation.m; sourceTree = ""; }; + 11F7AF6D1ED40AB300A9F224 /* ZXRSSExpandedDecodedNumeric.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXRSSExpandedDecodedNumeric.h; sourceTree = ""; }; + 11F7AF6E1ED40AB300A9F224 /* ZXRSSExpandedDecodedNumeric.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXRSSExpandedDecodedNumeric.m; sourceTree = ""; }; + 11F7AF6F1ED40AB300A9F224 /* ZXRSSExpandedDecodedObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXRSSExpandedDecodedObject.h; sourceTree = ""; }; + 11F7AF701ED40AB300A9F224 /* ZXRSSExpandedDecodedObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXRSSExpandedDecodedObject.m; sourceTree = ""; }; + 11F7AF711ED40AB300A9F224 /* ZXRSSExpandedFieldParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXRSSExpandedFieldParser.h; sourceTree = ""; }; + 11F7AF721ED40AB300A9F224 /* ZXRSSExpandedFieldParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXRSSExpandedFieldParser.m; sourceTree = ""; }; + 11F7AF731ED40AB300A9F224 /* ZXRSSExpandedGeneralAppIdDecoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXRSSExpandedGeneralAppIdDecoder.h; sourceTree = ""; }; + 11F7AF741ED40AB300A9F224 /* ZXRSSExpandedGeneralAppIdDecoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXRSSExpandedGeneralAppIdDecoder.m; sourceTree = ""; }; + 11F7AF751ED40AB300A9F224 /* ZXBitArrayBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXBitArrayBuilder.h; sourceTree = ""; }; + 11F7AF761ED40AB300A9F224 /* ZXBitArrayBuilder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXBitArrayBuilder.m; sourceTree = ""; }; + 11F7AF771ED40AB300A9F224 /* ZXRSSExpandedPair.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXRSSExpandedPair.h; sourceTree = ""; }; + 11F7AF781ED40AB300A9F224 /* ZXRSSExpandedPair.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXRSSExpandedPair.m; sourceTree = ""; }; + 11F7AF791ED40AB300A9F224 /* ZXRSSExpandedReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXRSSExpandedReader.h; sourceTree = ""; }; + 11F7AF7A1ED40AB300A9F224 /* ZXRSSExpandedReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXRSSExpandedReader.m; sourceTree = ""; }; + 11F7AF7B1ED40AB300A9F224 /* ZXRSSExpandedRow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXRSSExpandedRow.h; sourceTree = ""; }; + 11F7AF7C1ED40AB300A9F224 /* ZXRSSExpandedRow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXRSSExpandedRow.m; sourceTree = ""; }; + 11F7AF7D1ED40AB300A9F224 /* ZXAbstractRSSReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXAbstractRSSReader.h; sourceTree = ""; }; + 11F7AF7E1ED40AB300A9F224 /* ZXAbstractRSSReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXAbstractRSSReader.m; sourceTree = ""; }; + 11F7AF7F1ED40AB300A9F224 /* ZXRSS14Reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXRSS14Reader.h; sourceTree = ""; }; + 11F7AF801ED40AB300A9F224 /* ZXRSS14Reader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXRSS14Reader.m; sourceTree = ""; }; + 11F7AF811ED40AB300A9F224 /* ZXRSSDataCharacter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXRSSDataCharacter.h; sourceTree = ""; }; + 11F7AF821ED40AB300A9F224 /* ZXRSSDataCharacter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXRSSDataCharacter.m; sourceTree = ""; }; + 11F7AF831ED40AB300A9F224 /* ZXRSSFinderPattern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXRSSFinderPattern.h; sourceTree = ""; }; + 11F7AF841ED40AB300A9F224 /* ZXRSSFinderPattern.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXRSSFinderPattern.m; sourceTree = ""; }; + 11F7AF851ED40AB300A9F224 /* ZXRSSPair.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXRSSPair.h; sourceTree = ""; }; + 11F7AF861ED40AB300A9F224 /* ZXRSSPair.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXRSSPair.m; sourceTree = ""; }; + 11F7AF871ED40AB300A9F224 /* ZXRSSUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXRSSUtils.h; sourceTree = ""; }; + 11F7AF881ED40AB300A9F224 /* ZXRSSUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXRSSUtils.m; sourceTree = ""; }; + 11F7AF891ED40AB300A9F224 /* ZXCodaBarReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXCodaBarReader.h; sourceTree = ""; }; + 11F7AF8A1ED40AB300A9F224 /* ZXCodaBarReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXCodaBarReader.m; sourceTree = ""; }; + 11F7AF8B1ED40AB300A9F224 /* ZXCodaBarWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXCodaBarWriter.h; sourceTree = ""; }; + 11F7AF8C1ED40AB300A9F224 /* ZXCodaBarWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXCodaBarWriter.m; sourceTree = ""; }; + 11F7AF8D1ED40AB300A9F224 /* ZXCode128Reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXCode128Reader.h; sourceTree = ""; }; + 11F7AF8E1ED40AB300A9F224 /* ZXCode128Reader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXCode128Reader.m; sourceTree = ""; }; + 11F7AF8F1ED40AB300A9F224 /* ZXCode128Writer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXCode128Writer.h; sourceTree = ""; }; + 11F7AF901ED40AB300A9F224 /* ZXCode128Writer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXCode128Writer.m; sourceTree = ""; }; + 11F7AF911ED40AB300A9F224 /* ZXCode39Reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXCode39Reader.h; sourceTree = ""; }; + 11F7AF921ED40AB300A9F224 /* ZXCode39Reader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXCode39Reader.m; sourceTree = ""; }; + 11F7AF931ED40AB300A9F224 /* ZXCode39Writer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXCode39Writer.h; sourceTree = ""; }; + 11F7AF941ED40AB300A9F224 /* ZXCode39Writer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXCode39Writer.m; sourceTree = ""; }; + 11F7AF951ED40AB300A9F224 /* ZXCode93Reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXCode93Reader.h; sourceTree = ""; }; + 11F7AF961ED40AB300A9F224 /* ZXCode93Reader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXCode93Reader.m; sourceTree = ""; }; + 11F7AF971ED40AB300A9F224 /* ZXEAN13Reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXEAN13Reader.h; sourceTree = ""; }; + 11F7AF981ED40AB300A9F224 /* ZXEAN13Reader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXEAN13Reader.m; sourceTree = ""; }; + 11F7AF991ED40AB300A9F224 /* ZXEAN13Writer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXEAN13Writer.h; sourceTree = ""; }; + 11F7AF9A1ED40AB300A9F224 /* ZXEAN13Writer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXEAN13Writer.m; sourceTree = ""; }; + 11F7AF9B1ED40AB300A9F224 /* ZXEAN8Reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXEAN8Reader.h; sourceTree = ""; }; + 11F7AF9C1ED40AB300A9F224 /* ZXEAN8Reader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXEAN8Reader.m; sourceTree = ""; }; + 11F7AF9D1ED40AB300A9F224 /* ZXEAN8Writer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXEAN8Writer.h; sourceTree = ""; }; + 11F7AF9E1ED40AB300A9F224 /* ZXEAN8Writer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXEAN8Writer.m; sourceTree = ""; }; + 11F7AF9F1ED40AB300A9F224 /* ZXEANManufacturerOrgSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXEANManufacturerOrgSupport.h; sourceTree = ""; }; + 11F7AFA01ED40AB300A9F224 /* ZXEANManufacturerOrgSupport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXEANManufacturerOrgSupport.m; sourceTree = ""; }; + 11F7AFA11ED40AB300A9F224 /* ZXingObjCOneD.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXingObjCOneD.h; sourceTree = ""; }; + 11F7AFA21ED40AB300A9F224 /* ZXITFReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXITFReader.h; sourceTree = ""; }; + 11F7AFA31ED40AB300A9F224 /* ZXITFReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXITFReader.m; sourceTree = ""; }; + 11F7AFA41ED40AB300A9F224 /* ZXITFWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXITFWriter.h; sourceTree = ""; }; + 11F7AFA51ED40AB300A9F224 /* ZXITFWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXITFWriter.m; sourceTree = ""; }; + 11F7AFA61ED40AB300A9F224 /* ZXMultiFormatOneDReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXMultiFormatOneDReader.h; sourceTree = ""; }; + 11F7AFA71ED40AB300A9F224 /* ZXMultiFormatOneDReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXMultiFormatOneDReader.m; sourceTree = ""; }; + 11F7AFA81ED40AB300A9F224 /* ZXMultiFormatUPCEANReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXMultiFormatUPCEANReader.h; sourceTree = ""; }; + 11F7AFA91ED40AB300A9F224 /* ZXMultiFormatUPCEANReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXMultiFormatUPCEANReader.m; sourceTree = ""; }; + 11F7AFAA1ED40AB300A9F224 /* ZXOneDimensionalCodeWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXOneDimensionalCodeWriter.h; sourceTree = ""; }; + 11F7AFAB1ED40AB300A9F224 /* ZXOneDimensionalCodeWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXOneDimensionalCodeWriter.m; sourceTree = ""; }; + 11F7AFAC1ED40AB300A9F224 /* ZXOneDReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXOneDReader.h; sourceTree = ""; }; + 11F7AFAD1ED40AB300A9F224 /* ZXOneDReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXOneDReader.m; sourceTree = ""; }; + 11F7AFAE1ED40AB300A9F224 /* ZXUPCAReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXUPCAReader.h; sourceTree = ""; }; + 11F7AFAF1ED40AB300A9F224 /* ZXUPCAReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXUPCAReader.m; sourceTree = ""; }; + 11F7AFB01ED40AB300A9F224 /* ZXUPCAWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXUPCAWriter.h; sourceTree = ""; }; + 11F7AFB11ED40AB300A9F224 /* ZXUPCAWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXUPCAWriter.m; sourceTree = ""; }; + 11F7AFB21ED40AB300A9F224 /* ZXUPCEANExtension2Support.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXUPCEANExtension2Support.h; sourceTree = ""; }; + 11F7AFB31ED40AB300A9F224 /* ZXUPCEANExtension2Support.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXUPCEANExtension2Support.m; sourceTree = ""; }; + 11F7AFB41ED40AB300A9F224 /* ZXUPCEANExtension5Support.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXUPCEANExtension5Support.h; sourceTree = ""; }; + 11F7AFB51ED40AB300A9F224 /* ZXUPCEANExtension5Support.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXUPCEANExtension5Support.m; sourceTree = ""; }; + 11F7AFB61ED40AB300A9F224 /* ZXUPCEANExtensionSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXUPCEANExtensionSupport.h; sourceTree = ""; }; + 11F7AFB71ED40AB300A9F224 /* ZXUPCEANExtensionSupport.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXUPCEANExtensionSupport.m; sourceTree = ""; }; + 11F7AFB81ED40AB300A9F224 /* ZXUPCEANReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXUPCEANReader.h; sourceTree = ""; }; + 11F7AFB91ED40AB300A9F224 /* ZXUPCEANReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXUPCEANReader.m; sourceTree = ""; }; + 11F7AFBA1ED40AB300A9F224 /* ZXUPCEANWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXUPCEANWriter.h; sourceTree = ""; }; + 11F7AFBB1ED40AB300A9F224 /* ZXUPCEANWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXUPCEANWriter.m; sourceTree = ""; }; + 11F7AFBC1ED40AB300A9F224 /* ZXUPCEReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXUPCEReader.h; sourceTree = ""; }; + 11F7AFBD1ED40AB300A9F224 /* ZXUPCEReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXUPCEReader.m; sourceTree = ""; }; + 11F7AFC11ED40AB300A9F224 /* ZXModulusGF.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXModulusGF.h; sourceTree = ""; }; + 11F7AFC21ED40AB300A9F224 /* ZXModulusGF.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXModulusGF.m; sourceTree = ""; }; + 11F7AFC31ED40AB300A9F224 /* ZXModulusPoly.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXModulusPoly.h; sourceTree = ""; }; + 11F7AFC41ED40AB300A9F224 /* ZXModulusPoly.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXModulusPoly.m; sourceTree = ""; }; + 11F7AFC51ED40AB300A9F224 /* ZXPDF417ECErrorCorrection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXPDF417ECErrorCorrection.h; sourceTree = ""; }; + 11F7AFC61ED40AB300A9F224 /* ZXPDF417ECErrorCorrection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXPDF417ECErrorCorrection.m; sourceTree = ""; }; + 11F7AFC71ED40AB300A9F224 /* ZXPDF417BarcodeMetadata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXPDF417BarcodeMetadata.h; sourceTree = ""; }; + 11F7AFC81ED40AB300A9F224 /* ZXPDF417BarcodeMetadata.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXPDF417BarcodeMetadata.m; sourceTree = ""; }; + 11F7AFC91ED40AB300A9F224 /* ZXPDF417BarcodeValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXPDF417BarcodeValue.h; sourceTree = ""; }; + 11F7AFCA1ED40AB300A9F224 /* ZXPDF417BarcodeValue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXPDF417BarcodeValue.m; sourceTree = ""; }; + 11F7AFCB1ED40AB300A9F224 /* ZXPDF417BoundingBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXPDF417BoundingBox.h; sourceTree = ""; }; + 11F7AFCC1ED40AB300A9F224 /* ZXPDF417BoundingBox.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXPDF417BoundingBox.m; sourceTree = ""; }; + 11F7AFCD1ED40AB300A9F224 /* ZXPDF417Codeword.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXPDF417Codeword.h; sourceTree = ""; }; + 11F7AFCE1ED40AB300A9F224 /* ZXPDF417Codeword.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXPDF417Codeword.m; sourceTree = ""; }; + 11F7AFCF1ED40AB300A9F224 /* ZXPDF417CodewordDecoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXPDF417CodewordDecoder.h; sourceTree = ""; }; + 11F7AFD01ED40AB300A9F224 /* ZXPDF417CodewordDecoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXPDF417CodewordDecoder.m; sourceTree = ""; }; + 11F7AFD11ED40AB300A9F224 /* ZXPDF417DecodedBitStreamParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXPDF417DecodedBitStreamParser.h; sourceTree = ""; }; + 11F7AFD21ED40AB300A9F224 /* ZXPDF417DecodedBitStreamParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXPDF417DecodedBitStreamParser.m; sourceTree = ""; }; + 11F7AFD31ED40AB300A9F224 /* ZXPDF417DetectionResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXPDF417DetectionResult.h; sourceTree = ""; }; + 11F7AFD41ED40AB300A9F224 /* ZXPDF417DetectionResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXPDF417DetectionResult.m; sourceTree = ""; }; + 11F7AFD51ED40AB300A9F224 /* ZXPDF417DetectionResultColumn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXPDF417DetectionResultColumn.h; sourceTree = ""; }; + 11F7AFD61ED40AB300A9F224 /* ZXPDF417DetectionResultColumn.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXPDF417DetectionResultColumn.m; sourceTree = ""; }; + 11F7AFD71ED40AB300A9F224 /* ZXPDF417DetectionResultRowIndicatorColumn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXPDF417DetectionResultRowIndicatorColumn.h; sourceTree = ""; }; + 11F7AFD81ED40AB300A9F224 /* ZXPDF417DetectionResultRowIndicatorColumn.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXPDF417DetectionResultRowIndicatorColumn.m; sourceTree = ""; }; + 11F7AFD91ED40AB300A9F224 /* ZXPDF417ScanningDecoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXPDF417ScanningDecoder.h; sourceTree = ""; }; + 11F7AFDA1ED40AB300A9F224 /* ZXPDF417ScanningDecoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXPDF417ScanningDecoder.m; sourceTree = ""; }; + 11F7AFDC1ED40AB300A9F224 /* ZXPDF417Detector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXPDF417Detector.h; sourceTree = ""; }; + 11F7AFDD1ED40AB300A9F224 /* ZXPDF417Detector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXPDF417Detector.m; sourceTree = ""; }; + 11F7AFDE1ED40AB300A9F224 /* ZXPDF417DetectorResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXPDF417DetectorResult.h; sourceTree = ""; }; + 11F7AFDF1ED40AB300A9F224 /* ZXPDF417DetectorResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXPDF417DetectorResult.m; sourceTree = ""; }; + 11F7AFE11ED40AB300A9F224 /* ZXPDF417.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXPDF417.h; sourceTree = ""; }; + 11F7AFE21ED40AB300A9F224 /* ZXPDF417.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXPDF417.m; sourceTree = ""; }; + 11F7AFE31ED40AB300A9F224 /* ZXPDF417BarcodeMatrix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXPDF417BarcodeMatrix.h; sourceTree = ""; }; + 11F7AFE41ED40AB300A9F224 /* ZXPDF417BarcodeMatrix.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXPDF417BarcodeMatrix.m; sourceTree = ""; }; + 11F7AFE51ED40AB300A9F224 /* ZXPDF417BarcodeRow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXPDF417BarcodeRow.h; sourceTree = ""; }; + 11F7AFE61ED40AB300A9F224 /* ZXPDF417BarcodeRow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXPDF417BarcodeRow.m; sourceTree = ""; }; + 11F7AFE71ED40AB300A9F224 /* ZXPDF417Dimensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXPDF417Dimensions.h; sourceTree = ""; }; + 11F7AFE81ED40AB300A9F224 /* ZXPDF417Dimensions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXPDF417Dimensions.m; sourceTree = ""; }; + 11F7AFE91ED40AB300A9F224 /* ZXPDF417ErrorCorrection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXPDF417ErrorCorrection.h; sourceTree = ""; }; + 11F7AFEA1ED40AB300A9F224 /* ZXPDF417ErrorCorrection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXPDF417ErrorCorrection.m; sourceTree = ""; }; + 11F7AFEB1ED40AB300A9F224 /* ZXPDF417HighLevelEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXPDF417HighLevelEncoder.h; sourceTree = ""; }; + 11F7AFEC1ED40AB300A9F224 /* ZXPDF417HighLevelEncoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXPDF417HighLevelEncoder.m; sourceTree = ""; }; + 11F7AFED1ED40AB300A9F224 /* ZXingObjCPDF417.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXingObjCPDF417.h; sourceTree = ""; }; + 11F7AFEE1ED40AB300A9F224 /* ZXPDF417Common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXPDF417Common.h; sourceTree = ""; }; + 11F7AFEF1ED40AB300A9F224 /* ZXPDF417Common.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXPDF417Common.m; sourceTree = ""; }; + 11F7AFF01ED40AB300A9F224 /* ZXPDF417Reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXPDF417Reader.h; sourceTree = ""; }; + 11F7AFF11ED40AB300A9F224 /* ZXPDF417Reader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXPDF417Reader.m; sourceTree = ""; }; + 11F7AFF21ED40AB300A9F224 /* ZXPDF417ResultMetadata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXPDF417ResultMetadata.h; sourceTree = ""; }; + 11F7AFF31ED40AB300A9F224 /* ZXPDF417ResultMetadata.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXPDF417ResultMetadata.m; sourceTree = ""; }; + 11F7AFF41ED40AB300A9F224 /* ZXPDF417Writer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXPDF417Writer.h; sourceTree = ""; }; + 11F7AFF51ED40AB300A9F224 /* ZXPDF417Writer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXPDF417Writer.m; sourceTree = ""; }; + 11F7AFF81ED40AB300A9F224 /* ZXQRCodeBitMatrixParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXQRCodeBitMatrixParser.h; sourceTree = ""; }; + 11F7AFF91ED40AB300A9F224 /* ZXQRCodeBitMatrixParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXQRCodeBitMatrixParser.m; sourceTree = ""; }; + 11F7AFFA1ED40AB300A9F224 /* ZXQRCodeDataBlock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXQRCodeDataBlock.h; sourceTree = ""; }; + 11F7AFFB1ED40AB300A9F224 /* ZXQRCodeDataBlock.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXQRCodeDataBlock.m; sourceTree = ""; }; + 11F7AFFC1ED40AB300A9F224 /* ZXQRCodeDataMask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXQRCodeDataMask.h; sourceTree = ""; }; + 11F7AFFD1ED40AB300A9F224 /* ZXQRCodeDataMask.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXQRCodeDataMask.m; sourceTree = ""; }; + 11F7AFFE1ED40AB300A9F224 /* ZXQRCodeDecodedBitStreamParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXQRCodeDecodedBitStreamParser.h; sourceTree = ""; }; + 11F7AFFF1ED40AB300A9F224 /* ZXQRCodeDecodedBitStreamParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXQRCodeDecodedBitStreamParser.m; sourceTree = ""; }; + 11F7B0001ED40AB300A9F224 /* ZXQRCodeDecoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXQRCodeDecoder.h; sourceTree = ""; }; + 11F7B0011ED40AB300A9F224 /* ZXQRCodeDecoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXQRCodeDecoder.m; sourceTree = ""; }; + 11F7B0021ED40AB300A9F224 /* ZXQRCodeDecoderMetaData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXQRCodeDecoderMetaData.h; sourceTree = ""; }; + 11F7B0031ED40AB300A9F224 /* ZXQRCodeDecoderMetaData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXQRCodeDecoderMetaData.m; sourceTree = ""; }; + 11F7B0041ED40AB300A9F224 /* ZXQRCodeErrorCorrectionLevel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXQRCodeErrorCorrectionLevel.h; sourceTree = ""; }; + 11F7B0051ED40AB300A9F224 /* ZXQRCodeErrorCorrectionLevel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXQRCodeErrorCorrectionLevel.m; sourceTree = ""; }; + 11F7B0061ED40AB300A9F224 /* ZXQRCodeFormatInformation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXQRCodeFormatInformation.h; sourceTree = ""; }; + 11F7B0071ED40AB300A9F224 /* ZXQRCodeFormatInformation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXQRCodeFormatInformation.m; sourceTree = ""; }; + 11F7B0081ED40AB300A9F224 /* ZXQRCodeMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXQRCodeMode.h; sourceTree = ""; }; + 11F7B0091ED40AB300A9F224 /* ZXQRCodeMode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXQRCodeMode.m; sourceTree = ""; }; + 11F7B00A1ED40AB300A9F224 /* ZXQRCodeVersion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXQRCodeVersion.h; sourceTree = ""; }; + 11F7B00B1ED40AB300A9F224 /* ZXQRCodeVersion.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXQRCodeVersion.m; sourceTree = ""; }; + 11F7B00D1ED40AB300A9F224 /* ZXQRCodeAlignmentPattern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXQRCodeAlignmentPattern.h; sourceTree = ""; }; + 11F7B00E1ED40AB300A9F224 /* ZXQRCodeAlignmentPattern.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXQRCodeAlignmentPattern.m; sourceTree = ""; }; + 11F7B00F1ED40AB300A9F224 /* ZXQRCodeAlignmentPatternFinder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXQRCodeAlignmentPatternFinder.h; sourceTree = ""; }; + 11F7B0101ED40AB300A9F224 /* ZXQRCodeAlignmentPatternFinder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXQRCodeAlignmentPatternFinder.m; sourceTree = ""; }; + 11F7B0111ED40AB300A9F224 /* ZXQRCodeDetector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXQRCodeDetector.h; sourceTree = ""; }; + 11F7B0121ED40AB300A9F224 /* ZXQRCodeDetector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXQRCodeDetector.m; sourceTree = ""; }; + 11F7B0131ED40AB300A9F224 /* ZXQRCodeFinderPattern.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXQRCodeFinderPattern.h; sourceTree = ""; }; + 11F7B0141ED40AB300A9F224 /* ZXQRCodeFinderPattern.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXQRCodeFinderPattern.m; sourceTree = ""; }; + 11F7B0151ED40AB300A9F224 /* ZXQRCodeFinderPatternFinder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXQRCodeFinderPatternFinder.h; sourceTree = ""; }; + 11F7B0161ED40AB300A9F224 /* ZXQRCodeFinderPatternFinder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXQRCodeFinderPatternFinder.m; sourceTree = ""; }; + 11F7B0171ED40AB300A9F224 /* ZXQRCodeFinderPatternInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXQRCodeFinderPatternInfo.h; sourceTree = ""; }; + 11F7B0181ED40AB300A9F224 /* ZXQRCodeFinderPatternInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXQRCodeFinderPatternInfo.m; sourceTree = ""; }; + 11F7B01A1ED40AB300A9F224 /* ZXQRCode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXQRCode.h; sourceTree = ""; }; + 11F7B01B1ED40AB300A9F224 /* ZXQRCode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXQRCode.m; sourceTree = ""; }; + 11F7B01C1ED40AB300A9F224 /* ZXQRCodeBlockPair.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXQRCodeBlockPair.h; sourceTree = ""; }; + 11F7B01D1ED40AB300A9F224 /* ZXQRCodeBlockPair.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXQRCodeBlockPair.m; sourceTree = ""; }; + 11F7B01E1ED40AB300A9F224 /* ZXQRCodeEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXQRCodeEncoder.h; sourceTree = ""; }; + 11F7B01F1ED40AB300A9F224 /* ZXQRCodeEncoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXQRCodeEncoder.m; sourceTree = ""; }; + 11F7B0201ED40AB300A9F224 /* ZXQRCodeMaskUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXQRCodeMaskUtil.h; sourceTree = ""; }; + 11F7B0211ED40AB300A9F224 /* ZXQRCodeMaskUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXQRCodeMaskUtil.m; sourceTree = ""; }; + 11F7B0221ED40AB300A9F224 /* ZXQRCodeMatrixUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXQRCodeMatrixUtil.h; sourceTree = ""; }; + 11F7B0231ED40AB300A9F224 /* ZXQRCodeMatrixUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXQRCodeMatrixUtil.m; sourceTree = ""; }; + 11F7B0261ED40AB300A9F224 /* ZXMultiDetector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXMultiDetector.h; sourceTree = ""; }; + 11F7B0271ED40AB300A9F224 /* ZXMultiDetector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXMultiDetector.m; sourceTree = ""; }; + 11F7B0281ED40AB300A9F224 /* ZXMultiFinderPatternFinder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXMultiFinderPatternFinder.h; sourceTree = ""; }; + 11F7B0291ED40AB300A9F224 /* ZXMultiFinderPatternFinder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXMultiFinderPatternFinder.m; sourceTree = ""; }; + 11F7B02A1ED40AB300A9F224 /* ZXQRCodeMultiReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXQRCodeMultiReader.h; sourceTree = ""; }; + 11F7B02B1ED40AB300A9F224 /* ZXQRCodeMultiReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXQRCodeMultiReader.m; sourceTree = ""; }; + 11F7B02C1ED40AB300A9F224 /* ZXingObjCQRCode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXingObjCQRCode.h; sourceTree = ""; }; + 11F7B02D1ED40AB300A9F224 /* ZXQRCodeReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXQRCodeReader.h; sourceTree = ""; }; + 11F7B02E1ED40AB300A9F224 /* ZXQRCodeReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXQRCodeReader.m; sourceTree = ""; }; + 11F7B02F1ED40AB300A9F224 /* ZXQRCodeWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXQRCodeWriter.h; sourceTree = ""; }; + 11F7B0301ED40AB300A9F224 /* ZXQRCodeWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXQRCodeWriter.m; sourceTree = ""; }; + 11F7B0311ED40AB300A9F224 /* ZXingObjC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXingObjC.h; sourceTree = ""; }; + 11F7B0321ED40AB300A9F224 /* ZXMultiFormatReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXMultiFormatReader.h; sourceTree = ""; }; + 11F7B0331ED40AB300A9F224 /* ZXMultiFormatReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXMultiFormatReader.m; sourceTree = ""; }; + 11F7B0341ED40AB300A9F224 /* ZXMultiFormatWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZXMultiFormatWriter.h; sourceTree = ""; }; + 11F7B0351ED40AB300A9F224 /* ZXMultiFormatWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZXMultiFormatWriter.m; sourceTree = ""; }; + 11F7B1121ED416C900A9F224 /* QRCodeResultVC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = QRCodeResultVC.h; path = ../QRCodeResultVC.h; sourceTree = ""; }; + 11F7B1131ED416C900A9F224 /* QRCodeResultVC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = QRCodeResultVC.m; path = ../QRCodeResultVC.m; sourceTree = ""; }; + 11F7B1171ED4174D00A9F224 /* QRCodeResultView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QRCodeResultView.h; sourceTree = ""; }; + 11F7B1181ED4174D00A9F224 /* QRCodeResultView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QRCodeResultView.m; sourceTree = ""; }; + 11F7B11A1ED4356B00A9F224 /* PreloadViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PreloadViewController.h; sourceTree = ""; }; + 11F7B11B1ED4356B00A9F224 /* PreloadViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PreloadViewController.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -491,6 +1300,68 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 110B9BD21ED275E800EC58DB /* Model */ = { + isa = PBXGroup; + children = ( + ); + path = Model; + sourceTree = ""; + }; + 110B9BD31ED2764B00EC58DB /* PreloadVC */ = { + isa = PBXGroup; + children = ( + 110B9BD61ED276C100EC58DB /* Model */, + 110B9BD51ED2769A00EC58DB /* View */, + 110B9BD41ED2768E00EC58DB /* Controller */, + ); + path = PreloadVC; + sourceTree = ""; + }; + 110B9BD41ED2768E00EC58DB /* Controller */ = { + isa = PBXGroup; + children = ( + 11F7B11A1ED4356B00A9F224 /* PreloadViewController.h */, + 11F7B11B1ED4356B00A9F224 /* PreloadViewController.m */, + 110B9BEF1ED2932F00EC58DB /* PreloadDetailVC.h */, + 110B9BF01ED2932F00EC58DB /* PreloadDetailVC.m */, + 11DE26F11ED685D300DCDE78 /* NewPreloadVC.h */, + 11DE26F21ED685D300DCDE78 /* NewPreloadVC.m */, + ); + path = Controller; + sourceTree = ""; + }; + 110B9BD51ED2769A00EC58DB /* View */ = { + isa = PBXGroup; + children = ( + 110B9BE61ED2906700EC58DB /* PrereloadCell.h */, + 110B9BE71ED2906700EC58DB /* PrereloadCell.m */, + 1179FBE51ED56E5D0071ED45 /* PreloadDetailView.h */, + 1179FBE61ED56E5D0071ED45 /* PreloadDetailView.m */, + 1179FBE81ED577570071ED45 /* PreloadDetailCell.h */, + 1179FBE91ED577570071ED45 /* PreloadDetailCell.m */, + 11DE26F41ED6A69000DCDE78 /* PreloadNewView.h */, + 11DE26F51ED6A69000DCDE78 /* PreloadNewView.m */, + 11DE26F71ED6B66800DCDE78 /* NewPartCell.h */, + 11DE26F81ED6B66800DCDE78 /* NewPartCell.m */, + 11DE26FA1ED6DBDF00DCDE78 /* NewPartNumberView.h */, + 11DE26FB1ED6DBDF00DCDE78 /* NewPartNumberView.m */, + 113580D91ED7BEB80069E21E /* PartSearchView.h */, + 113580DA1ED7BEB80069E21E /* PartSearchView.m */, + ); + path = View; + sourceTree = ""; + }; + 110B9BD61ED276C100EC58DB /* Model */ = { + isa = PBXGroup; + children = ( + 110B9BE91ED2908C00EC58DB /* PrereloadCellModel.h */, + 110B9BEA1ED2908C00EC58DB /* PrereloadCellModel.m */, + 110B9BEC1ED291C100EC58DB /* PreloadViewModel.h */, + 110B9BED1ED291C100EC58DB /* PreloadViewModel.m */, + ); + path = Model; + sourceTree = ""; + }; 1121BFB71EC990BD0002D73C = { isa = PBXGroup; children = ( @@ -514,21 +1385,15 @@ 1121BFC21EC990BD0002D73C /* iDearQRCode */ = { isa = PBXGroup; children = ( + 118E68E61ED92A5E00B62015 /* Manager */, + 118E68E51ED92A5000B62015 /* Utils */, + 118E68E41ED92A3E00B62015 /* ThridParty */, + 118E68E31ED92A2100B62015 /* Resource */, + 118E68E11ED929BB00B62015 /* Base */, + 118E68E01ED9298200B62015 /* Modules */, + 118E68DF1ED9295800B62015 /* AppDelegate */, 1121C0101EC9B7080002D73C /* Tools */, - 1121BFF61EC9942A0002D73C /* BaseQRCode */, - 1121C0041EC9A0990002D73C /* MainVC */, - 11E3E9B91ECAAFAF00D72EE1 /* Me */, - 1148291D1ECC1C2C00BBCBF3 /* OtherVC */, - 1121BFC61EC990BD0002D73C /* AppDelegate.h */, - 1121BFC71EC990BD0002D73C /* AppDelegate.m */, - 1121BFC91EC990BD0002D73C /* ViewController.h */, - 1121BFCA1EC990BD0002D73C /* ViewController.m */, - 1121BFCC1EC990BD0002D73C /* Main.storyboard */, - 1121BFCF1EC990BD0002D73C /* Assets.xcassets */, - 1121BFD11EC990BD0002D73C /* LaunchScreen.storyboard */, - 1121BFD41EC990BD0002D73C /* Info.plist */, - 11E3E95A1ECA879B00D72EE1 /* iDearQRCode.pch */, - 11E3E95B1ECA890200D72EE1 /* iDear_Public.h */, + 118E68E21ED929EB00B62015 /* Define */, 1121BFC31EC990BD0002D73C /* Supporting Files */, ); path = iDearQRCode; @@ -537,6 +1402,12 @@ 1121BFC31EC990BD0002D73C /* Supporting Files */ = { isa = PBXGroup; children = ( + 1121BFCF1EC990BD0002D73C /* Assets.xcassets */, + 1121BFC91EC990BD0002D73C /* ViewController.h */, + 1121BFCA1EC990BD0002D73C /* ViewController.m */, + 1121BFD11EC990BD0002D73C /* LaunchScreen.storyboard */, + 1121BFCC1EC990BD0002D73C /* Main.storyboard */, + 1121BFD41EC990BD0002D73C /* Info.plist */, 1121BFC41EC990BD0002D73C /* main.m */, ); name = "Supporting Files"; @@ -567,9 +1438,14 @@ 1121BFF81EC994820002D73C /* BaseViewController.m */, 1121BFFD1EC995A40002D73C /* QRCNavigationController.h */, 1121BFFE1EC995A40002D73C /* QRCNavigationController.m */, + 110B9BE01ED281D700EC58DB /* BaseTableViewCell.h */, + 110B9BE11ED281D700EC58DB /* BaseTableViewCell.m */, + 110B9BE31ED2845500EC58DB /* BaseModel.h */, + 110B9BE41ED2845500EC58DB /* BaseModel.m */, ); - path = BaseQRCode; - sourceTree = ""; + name = BaseQRCode; + path = iDearQRCode/BaseQRCode; + sourceTree = SOURCE_ROOT; }; 1121C0001EC99F420002D73C /* FDFullscreenPopGesture */ = { isa = PBXGroup; @@ -587,25 +1463,18 @@ 11E3E95D1ECA8CBF00D72EE1 /* Controller */, 11E3E95C1ECA8CB300D72EE1 /* View */, ); - path = MainVC; + name = MainVC; + path = ../MainVC; sourceTree = ""; }; 1121C0101EC9B7080002D73C /* Tools */ = { isa = PBXGroup; children = ( - 119AB30A1ED17335003DBF5A /* DZNEmptyDataSet */, - 119AB2D61ED16FD6003DBF5A /* IQKeyboardManager */, 119AB28F1ED15E87003DBF5A /* Lib */, 11E3E9D81ECAC90D00D72EE1 /* Category */, 11E3E9C51ECAC85E00D72EE1 /* UIViewUtils */, 11E3E9C11ECAC84900D72EE1 /* Toast */, 11E3E9BD1ECAC82600D72EE1 /* AlertManager */, - 11E3E9A91ECAA72600D72EE1 /* SDRefeshView */, - 11346AAC1ECED3ED00BFDD69 /* SDAutoLayout */, - 11E3E9661ECAA6F600D72EE1 /* MJRefresh */, - 1121C0001EC99F420002D73C /* FDFullscreenPopGesture */, - 1121C0141EC9C1300002D73C /* Masonry */, - 114828E21ECBDD6100BBCBF3 /* SDWebImage */, 1121C0111EC9B70D0002D73C /* UIColor+HexString.h */, 1121C0121EC9B70D0002D73C /* UIColor+HexString.m */, 11E3E9D51ECAC8F400D72EE1 /* Tools.h */, @@ -644,7 +1513,8 @@ 1121C02D1EC9C1300002D73C /* ViewController+MASAdditions.h */, 1121C02E1EC9C1300002D73C /* ViewController+MASAdditions.m */, ); - path = Masonry; + name = Masonry; + path = ../Tools/Masonry; sourceTree = ""; }; 11346AAC1ECED3ED00BFDD69 /* SDAutoLayout */ = { @@ -656,7 +1526,8 @@ 11346AB01ECED3ED00BFDD69 /* UIView+SDAutoLayout.h */, 11346AB11ECED3ED00BFDD69 /* UIView+SDAutoLayout.m */, ); - path = SDAutoLayout; + name = SDAutoLayout; + path = ../Tools/SDAutoLayout; sourceTree = ""; }; 114828E21ECBDD6100BBCBF3 /* SDWebImage */ = { @@ -702,17 +1573,19 @@ 114829081ECBDD6100BBCBF3 /* UIView+WebCacheOperation.h */, 114829091ECBDD6100BBCBF3 /* UIView+WebCacheOperation.m */, ); - path = SDWebImage; + name = SDWebImage; + path = ../Tools/SDWebImage; sourceTree = ""; }; 1148291D1ECC1C2C00BBCBF3 /* OtherVC */ = { isa = PBXGroup; children = ( - 114829201ECC1C5000BBCBF3 /* Model */, - 1148291F1ECC1C4500BBCBF3 /* View */, - 1148291E1ECC1C3B00BBCBF3 /* Controller */, + 118E68E81ED92B6F00B62015 /* PickVC */, + 11F7AE151ED3E7A900A9F224 /* QRCodeVC */, + 110B9BD31ED2764B00EC58DB /* PreloadVC */, ); - path = OtherVC; + name = OtherVC; + path = ../OtherVC; sourceTree = ""; }; 1148291E1ECC1C3B00BBCBF3 /* Controller */ = { @@ -725,7 +1598,8 @@ 11C243581ED045C7007F69C6 /* PickDetailVc.h */, 11C243591ED045C7007F69C6 /* PickDetailVc.m */, ); - path = Controller; + name = Controller; + path = ../Controller; sourceTree = ""; }; 1148291F1ECC1C4500BBCBF3 /* View */ = { @@ -741,8 +1615,13 @@ 11346AB51ECEE02D00BFDD69 /* PickAlert.m */, 11C2434F1ED01986007F69C6 /* PickDateView.h */, 11C243501ED01986007F69C6 /* PickDateView.m */, + 110B9BF81ED2BEEC00EC58DB /* PickDetailView.h */, + 110B9BF91ED2BEEC00EC58DB /* PickDetailView.m */, + 110B9BFB1ED2BF0700EC58DB /* PickDetailFootView.h */, + 110B9BFC1ED2BF0700EC58DB /* PickDetailFootView.m */, ); - path = View; + name = View; + path = ../View; sourceTree = ""; }; 114829201ECC1C5000BBCBF3 /* Model */ = { @@ -750,24 +1629,198 @@ children = ( 114829271ECC1E0000BBCBF3 /* PickingModel.h */, 114829281ECC1E0000BBCBF3 /* PickingModel.m */, + 110B9BF51ED2B96200EC58DB /* PickDetailModel.h */, + 110B9BF61ED2B96200EC58DB /* PickDetailModel.m */, 119AB2D01ED161EB003DBF5A /* PickingViewModel.h */, 119AB2D11ED161EB003DBF5A /* PickingViewModel.m */, ); - path = Model; + name = Model; + path = ../Model; sourceTree = ""; }; - 119AB28F1ED15E87003DBF5A /* Lib */ = { + 118E68DF1ED9295800B62015 /* AppDelegate */ = { + isa = PBXGroup; + children = ( + 1121BFC61EC990BD0002D73C /* AppDelegate.h */, + 1121BFC71EC990BD0002D73C /* AppDelegate.m */, + ); + path = AppDelegate; + sourceTree = ""; + }; + 118E68E01ED9298200B62015 /* Modules */ = { + isa = PBXGroup; + children = ( + 1148291D1ECC1C2C00BBCBF3 /* OtherVC */, + 1121C0041EC9A0990002D73C /* MainVC */, + 11E3E9B91ECAAFAF00D72EE1 /* Me */, + ); + path = Modules; + sourceTree = ""; + }; + 118E68E11ED929BB00B62015 /* Base */ = { + isa = PBXGroup; + children = ( + 1121BFF61EC9942A0002D73C /* BaseQRCode */, + ); + path = Base; + sourceTree = ""; + }; + 118E68E21ED929EB00B62015 /* Define */ = { + isa = PBXGroup; + children = ( + 11E3E95A1ECA879B00D72EE1 /* iDearQRCode.pch */, + 11E3E95B1ECA890200D72EE1 /* iDear_Public.h */, + ); + path = Define; + sourceTree = ""; + }; + 118E68E31ED92A2100B62015 /* Resource */ = { + isa = PBXGroup; + children = ( + ); + path = Resource; + sourceTree = ""; + }; + 118E68E41ED92A3E00B62015 /* ThridParty */ = { isa = PBXGroup; children = ( - 119AB2CA1ED15EB3003DBF5A /* RTNetworking.h */, - 119AB2CB1ED15EB3003DBF5A /* RTNetworking.m */, - 119AB2CD1ED16163003DBF5A /* ViewModelClass.h */, - 119AB2CE1ED16163003DBF5A /* ViewModelClass.m */, 119AB2D31ED16F2C003DBF5A /* ZYThirdPartService.h */, 119AB2D41ED16F2C003DBF5A /* ZYThirdPartService.m */, + 11E3E9A91ECAA72600D72EE1 /* SDRefeshView */, + 11346AAC1ECED3ED00BFDD69 /* SDAutoLayout */, + 11E3E9661ECAA6F600D72EE1 /* MJRefresh */, + 1121C0001EC99F420002D73C /* FDFullscreenPopGesture */, + 1121C0141EC9C1300002D73C /* Masonry */, + 114828E21ECBDD6100BBCBF3 /* SDWebImage */, 119AB2901ED15E87003DBF5A /* AFNetworking */, 119AB29E1ED15E87003DBF5A /* UIKit+AFNetworking */, 119AB2B31ED15E87003DBF5A /* YYModel */, + 119AB2D61ED16FD6003DBF5A /* IQKeyboardManager */, + 119AB30A1ED17335003DBF5A /* DZNEmptyDataSet */, + 11F7AE161ED4043F00A9F224 /* LBXScan */, + 11F7AE4C1ED40AB300A9F224 /* ZXingObjC */, + ); + path = ThridParty; + sourceTree = ""; + }; + 118E68E51ED92A5000B62015 /* Utils */ = { + isa = PBXGroup; + children = ( + 11E3E9EC1ECAC90D00D72EE1 /* UIImage+Common */, + 11E3E9DD1ECAC90D00D72EE1 /* NSString */, + ); + path = Utils; + sourceTree = ""; + }; + 118E68E61ED92A5E00B62015 /* Manager */ = { + isa = PBXGroup; + children = ( + 118E69001ED94D1500B62015 /* UserManager */, + 118E68E91ED92BB900B62015 /* NetManager */, + ); + path = Manager; + sourceTree = ""; + }; + 118E68E71ED92B4100B62015 /* ViewController */ = { + isa = PBXGroup; + children = ( + 11F7AE491ED404E800A9F224 /* QRCodeVC.h */, + 11F7AE4A1ED404E800A9F224 /* QRCodeVC.m */, + 11F7B1121ED416C900A9F224 /* QRCodeResultVC.h */, + 11F7B1131ED416C900A9F224 /* QRCodeResultVC.m */, + ); + path = ViewController; + sourceTree = ""; + }; + 118E68E81ED92B6F00B62015 /* PickVC */ = { + isa = PBXGroup; + children = ( + 114829201ECC1C5000BBCBF3 /* Model */, + 1148291F1ECC1C4500BBCBF3 /* View */, + 1148291E1ECC1C3B00BBCBF3 /* Controller */, + ); + path = PickVC; + sourceTree = ""; + }; + 118E68E91ED92BB900B62015 /* NetManager */ = { + isa = PBXGroup; + children = ( + 118E68EB1ED92C7900B62015 /* YQNetworking */, + 118E68EA1ED92C5000B62015 /* RTNetworking */, + ); + path = NetManager; + sourceTree = ""; + }; + 118E68EA1ED92C5000B62015 /* RTNetworking */ = { + isa = PBXGroup; + children = ( + 119AB2CA1ED15EB3003DBF5A /* RTNetworking.h */, + 119AB2CB1ED15EB3003DBF5A /* RTNetworking.m */, + 119AB2CD1ED16163003DBF5A /* ViewModelClass.h */, + 119AB2CE1ED16163003DBF5A /* ViewModelClass.m */, + ); + path = RTNetworking; + sourceTree = ""; + }; + 118E68EB1ED92C7900B62015 /* YQNetworking */ = { + isa = PBXGroup; + children = ( + 118E68FD1ED92CA000B62015 /* YQNetworking.h */, + 118E68FE1ED92CA000B62015 /* YQNetworking.m */, + 118E68F01ED92C9900B62015 /* Cache */, + 118E68EC1ED92C9300B62015 /* RequestManager */, + ); + path = YQNetworking; + sourceTree = ""; + }; + 118E68EC1ED92C9300B62015 /* RequestManager */ = { + isa = PBXGroup; + children = ( + 118E68ED1ED92C9300B62015 /* YQNetworking+RequestManager.h */, + 118E68EE1ED92C9300B62015 /* YQNetworking+RequestManager.m */, + ); + path = RequestManager; + sourceTree = ""; + }; + 118E68F01ED92C9900B62015 /* Cache */ = { + isa = PBXGroup; + children = ( + 118E68F11ED92C9900B62015 /* YQCacheManager.h */, + 118E68F21ED92C9900B62015 /* YQCacheManager.m */, + 118E68F31ED92C9900B62015 /* YQDiskCache.h */, + 118E68F41ED92C9900B62015 /* YQDiskCache.m */, + 118E68F51ED92C9900B62015 /* YQLRUManager.h */, + 118E68F61ED92C9900B62015 /* YQLRUManager.m */, + 118E68F71ED92C9900B62015 /* YQMemoryCache.h */, + 118E68F81ED92C9900B62015 /* YQMemoryCache.m */, + ); + path = Cache; + sourceTree = ""; + }; + 118E69001ED94D1500B62015 /* UserManager */ = { + isa = PBXGroup; + children = ( + 118E69011ED94D2900B62015 /* UserModel */, + 118E69051ED94DC900B62015 /* UserManager.h */, + 118E69061ED94DC900B62015 /* UserManager.m */, + 118E69081ED951BF00B62015 /* KeyManager.h */, + 118E69091ED951BF00B62015 /* KeyManager.m */, + ); + path = UserManager; + sourceTree = ""; + }; + 118E69011ED94D2900B62015 /* UserModel */ = { + isa = PBXGroup; + children = ( + 118E69021ED94D5600B62015 /* UserModel.h */, + 118E69031ED94D5600B62015 /* UserModel.m */, + ); + path = UserModel; + sourceTree = ""; + }; + 119AB28F1ED15E87003DBF5A /* Lib */ = { + isa = PBXGroup; + children = ( ); path = Lib; sourceTree = ""; @@ -789,7 +1842,8 @@ 119AB29C1ED15E87003DBF5A /* AFURLSessionManager.h */, 119AB29D1ED15E87003DBF5A /* AFURLSessionManager.m */, ); - path = AFNetworking; + name = AFNetworking; + path = ../Tools/Lib/AFNetworking; sourceTree = ""; }; 119AB29E1ED15E87003DBF5A /* UIKit+AFNetworking */ = { @@ -816,7 +1870,8 @@ 119AB2B11ED15E87003DBF5A /* UIWebView+AFNetworking.h */, 119AB2B21ED15E87003DBF5A /* UIWebView+AFNetworking.m */, ); - path = "UIKit+AFNetworking"; + name = "UIKit+AFNetworking"; + path = "../Tools/Lib/UIKit+AFNetworking"; sourceTree = ""; }; 119AB2B31ED15E87003DBF5A /* YYModel */ = { @@ -828,7 +1883,8 @@ 119AB2B71ED15E87003DBF5A /* YYClassInfo.m */, 119AB2B81ED15E87003DBF5A /* YYModel.h */, ); - path = YYModel; + name = YYModel; + path = ../Tools/Lib/YYModel; sourceTree = ""; }; 119AB2D61ED16FD6003DBF5A /* IQKeyboardManager */ = { @@ -844,7 +1900,8 @@ 119AB2EE1ED16FD6003DBF5A /* IQToolbar */, 119AB2F91ED16FD6003DBF5A /* Resources */, ); - path = IQKeyboardManager; + name = IQKeyboardManager; + path = ../Tools/IQKeyboardManager; sourceTree = ""; }; 119AB2D71ED16FD6003DBF5A /* Categories */ = { @@ -915,7 +1972,8 @@ 119AB30B1ED17359003DBF5A /* UIScrollView+EmptyDataSet.h */, 119AB30C1ED17359003DBF5A /* UIScrollView+EmptyDataSet.m */, ); - path = DZNEmptyDataSet; + name = DZNEmptyDataSet; + path = ../Tools/DZNEmptyDataSet; sourceTree = ""; }; 11E3E95C1ECA8CB300D72EE1 /* View */ = { @@ -956,7 +2014,8 @@ 11E3E9931ECAA6F600D72EE1 /* UIView+MJExtension.h */, 11E3E9941ECAA6F600D72EE1 /* UIView+MJExtension.m */, ); - path = MJRefresh; + name = MJRefresh; + path = ../Tools/MJRefresh; sourceTree = ""; }; 11E3E9671ECAA6F600D72EE1 /* Base */ = { @@ -1047,16 +2106,19 @@ 11E3E9B21ECAA72600D72EE1 /* UIView+SDExtension.h */, 11E3E9B31ECAA72600D72EE1 /* UIView+SDExtension.m */, ); - path = SDRefeshView; + name = SDRefeshView; + path = ../Tools/SDRefeshView; sourceTree = ""; }; 11E3E9B91ECAAFAF00D72EE1 /* Me */ = { isa = PBXGroup; children = ( + 110B9BD21ED275E800EC58DB /* Model */, 11E3EA031ECAED5F00D72EE1 /* View */, 11E3EA021ECAED5200D72EE1 /* Controller */, ); - path = Me; + name = Me; + path = ../Me; sourceTree = ""; }; 11E3E9BD1ECAC82600D72EE1 /* AlertManager */ = { @@ -1101,12 +2163,8 @@ 11E3E9DA1ECAC90D00D72EE1 /* ColorUtil.m */, 11E3E9DB1ECAC90D00D72EE1 /* NSDictionary+Propery.h */, 11E3E9DC1ECAC90D00D72EE1 /* NSDictionary+Propery.m */, - 11E3E9DD1ECAC90D00D72EE1 /* NSString */, 11E3E9EA1ECAC90D00D72EE1 /* UIBarButtonItem+Item.h */, 11E3E9EB1ECAC90D00D72EE1 /* UIBarButtonItem+Item.m */, - 11E3E9EC1ECAC90D00D72EE1 /* UIImage+Common */, - 11E3E9EF1ECAC90D00D72EE1 /* UIImage+Normalimage.h */, - 11E3E9F01ECAC90D00D72EE1 /* UIImage+Normalimage.m */, 11E3E9F11ECAC90D00D72EE1 /* UIView+Common */, 11E3E9F41ECAC90D00D72EE1 /* UIViewController+Common */, ); @@ -1120,7 +2178,8 @@ 11E3E9E41ECAC90D00D72EE1 /* NSString+dateString */, 11E3E9E71ECAC90D00D72EE1 /* NSString+Validate */, ); - path = NSString; + name = NSString; + path = ../Tools/Category/NSString; sourceTree = ""; }; 11E3E9DE1ECAC90D00D72EE1 /* NSString+Crypt */ = { @@ -1161,7 +2220,8 @@ 11E3E9ED1ECAC90D00D72EE1 /* UIImage+Common.h */, 11E3E9EE1ECAC90D00D72EE1 /* UIImage+Common.m */, ); - path = "UIImage+Common"; + name = "UIImage+Common"; + path = "../Tools/Category/UIImage+Common"; sourceTree = ""; }; 11E3E9F11ECAC90D00D72EE1 /* UIView+Common */ = { @@ -1202,6 +2262,809 @@ path = View; sourceTree = ""; }; + 11F7AE151ED3E7A900A9F224 /* QRCodeVC */ = { + isa = PBXGroup; + children = ( + 118E68E71ED92B4100B62015 /* ViewController */, + 11F7B1161ED4172000A9F224 /* Model */, + 11F7B1151ED4171100A9F224 /* View */, + ); + path = QRCodeVC; + sourceTree = ""; + }; + 11F7AE161ED4043F00A9F224 /* LBXScan */ = { + isa = PBXGroup; + children = ( + 11F7AE171ED4043F00A9F224 /* CodeScan.bundle */, + 11F7AE181ED4043F00A9F224 /* LBXAlertAction */, + 11F7AE221ED4043F00A9F224 /* LBXScanLineAnimation.h */, + 11F7AE231ED4043F00A9F224 /* LBXScanLineAnimation.m */, + 11F7AE241ED4043F00A9F224 /* LBXScanNative.h */, + 11F7AE251ED4043F00A9F224 /* LBXScanNative.m */, + 11F7AE261ED4043F00A9F224 /* LBXScanNetAnimation.h */, + 11F7AE271ED4043F00A9F224 /* LBXScanNetAnimation.m */, + 11F7AE281ED4043F00A9F224 /* LBXScanResult.h */, + 11F7AE291ED4043F00A9F224 /* LBXScanResult.m */, + 11F7AE2A1ED4043F00A9F224 /* LBXScanVideoZoomView.h */, + 11F7AE2B1ED4043F00A9F224 /* LBXScanVideoZoomView.m */, + 11F7AE2C1ED4043F00A9F224 /* LBXScanView.h */, + 11F7AE2D1ED4043F00A9F224 /* LBXScanView.m */, + 11F7AE2E1ED4043F00A9F224 /* LBXScanViewController.h */, + 11F7AE2F1ED4043F00A9F224 /* LBXScanViewController.m */, + 11F7AE301ED4043F00A9F224 /* LBXScanViewStyle.h */, + 11F7AE311ED4043F00A9F224 /* LBXScanViewStyle.m */, + 11F7AE321ED4043F00A9F224 /* LBXScanWrapper.h */, + 11F7AE331ED4043F00A9F224 /* LBXScanWrapper.m */, + 11F7AE341ED4043F00A9F224 /* LBXZXCapture.h */, + 11F7AE351ED4043F00A9F224 /* LBXZXCapture.m */, + 11F7AE361ED4043F00A9F224 /* LBXZXCaptureDelegate.h */, + 11F7AE371ED4043F00A9F224 /* ZXingWrapper.h */, + 11F7AE381ED4043F00A9F224 /* ZXingWrapper.m */, + ); + name = LBXScan; + path = ../Tools/LBXScan; + sourceTree = ""; + }; + 11F7AE181ED4043F00A9F224 /* LBXAlertAction */ = { + isa = PBXGroup; + children = ( + 11F7AE191ED4043F00A9F224 /* Class */, + 11F7AE201ED4043F00A9F224 /* LBXAlertAction.h */, + 11F7AE211ED4043F00A9F224 /* LBXAlertAction.m */, + ); + path = LBXAlertAction; + sourceTree = ""; + }; + 11F7AE191ED4043F00A9F224 /* Class */ = { + isa = PBXGroup; + children = ( + 11F7AE1A1ED4043F00A9F224 /* UIActionSheet+LBXAlertAction.h */, + 11F7AE1B1ED4043F00A9F224 /* UIActionSheet+LBXAlertAction.m */, + 11F7AE1C1ED4043F00A9F224 /* UIAlertController+supportedInterfaceOrientations.h */, + 11F7AE1D1ED4043F00A9F224 /* UIAlertController+supportedInterfaceOrientations.m */, + 11F7AE1E1ED4043F00A9F224 /* UIAlertView+LBXAlertAction.h */, + 11F7AE1F1ED4043F00A9F224 /* UIAlertView+LBXAlertAction.m */, + ); + path = Class; + sourceTree = ""; + }; + 11F7AE4C1ED40AB300A9F224 /* ZXingObjC */ = { + isa = PBXGroup; + children = ( + 11F7AE4D1ED40AB300A9F224 /* aztec */, + 11F7AE6A1ED40AB300A9F224 /* client */, + 11F7AEBC1ED40AB300A9F224 /* common */, + 11F7AEEB1ED40AB300A9F224 /* core */, + 11F7AF0C1ED40AB300A9F224 /* datamatrix */, + 11F7AF3A1ED40AB300A9F224 /* maxicode */, + 11F7AF451ED40AB300A9F224 /* multi */, + 11F7AF4B1ED40AB300A9F224 /* oned */, + 11F7AFBE1ED40AB300A9F224 /* pdf417 */, + 11F7AFF61ED40AB300A9F224 /* qrcode */, + 11F7B0311ED40AB300A9F224 /* ZXingObjC.h */, + 11F7B0321ED40AB300A9F224 /* ZXMultiFormatReader.h */, + 11F7B0331ED40AB300A9F224 /* ZXMultiFormatReader.m */, + 11F7B0341ED40AB300A9F224 /* ZXMultiFormatWriter.h */, + 11F7B0351ED40AB300A9F224 /* ZXMultiFormatWriter.m */, + ); + name = ZXingObjC; + path = ../Tools/ZXingObjC; + sourceTree = ""; + }; + 11F7AE4D1ED40AB300A9F224 /* aztec */ = { + isa = PBXGroup; + children = ( + 11F7AE4E1ED40AB300A9F224 /* decoder */, + 11F7AE511ED40AB300A9F224 /* detector */, + 11F7AE541ED40AB300A9F224 /* encoder */, + 11F7AE631ED40AB300A9F224 /* ZXAztecDetectorResult.h */, + 11F7AE641ED40AB300A9F224 /* ZXAztecDetectorResult.m */, + 11F7AE651ED40AB300A9F224 /* ZXAztecReader.h */, + 11F7AE661ED40AB300A9F224 /* ZXAztecReader.m */, + 11F7AE671ED40AB300A9F224 /* ZXAztecWriter.h */, + 11F7AE681ED40AB300A9F224 /* ZXAztecWriter.m */, + 11F7AE691ED40AB300A9F224 /* ZXingObjCAztec.h */, + ); + path = aztec; + sourceTree = ""; + }; + 11F7AE4E1ED40AB300A9F224 /* decoder */ = { + isa = PBXGroup; + children = ( + 11F7AE4F1ED40AB300A9F224 /* ZXAztecDecoder.h */, + 11F7AE501ED40AB300A9F224 /* ZXAztecDecoder.m */, + ); + path = decoder; + sourceTree = ""; + }; + 11F7AE511ED40AB300A9F224 /* detector */ = { + isa = PBXGroup; + children = ( + 11F7AE521ED40AB300A9F224 /* ZXAztecDetector.h */, + 11F7AE531ED40AB300A9F224 /* ZXAztecDetector.m */, + ); + path = detector; + sourceTree = ""; + }; + 11F7AE541ED40AB300A9F224 /* encoder */ = { + isa = PBXGroup; + children = ( + 11F7AE551ED40AB300A9F224 /* ZXAztecBinaryShiftToken.h */, + 11F7AE561ED40AB300A9F224 /* ZXAztecBinaryShiftToken.m */, + 11F7AE571ED40AB300A9F224 /* ZXAztecCode.h */, + 11F7AE581ED40AB300A9F224 /* ZXAztecCode.m */, + 11F7AE591ED40AB300A9F224 /* ZXAztecEncoder.h */, + 11F7AE5A1ED40AB300A9F224 /* ZXAztecEncoder.m */, + 11F7AE5B1ED40AB300A9F224 /* ZXAztecHighLevelEncoder.h */, + 11F7AE5C1ED40AB300A9F224 /* ZXAztecHighLevelEncoder.m */, + 11F7AE5D1ED40AB300A9F224 /* ZXAztecSimpleToken.h */, + 11F7AE5E1ED40AB300A9F224 /* ZXAztecSimpleToken.m */, + 11F7AE5F1ED40AB300A9F224 /* ZXAztecState.h */, + 11F7AE601ED40AB300A9F224 /* ZXAztecState.m */, + 11F7AE611ED40AB300A9F224 /* ZXAztecToken.h */, + 11F7AE621ED40AB300A9F224 /* ZXAztecToken.m */, + ); + path = encoder; + sourceTree = ""; + }; + 11F7AE6A1ED40AB300A9F224 /* client */ = { + isa = PBXGroup; + children = ( + 11F7AE6B1ED40AB300A9F224 /* result */, + 11F7AEB51ED40AB300A9F224 /* ZXCapture.h */, + 11F7AEB61ED40AB300A9F224 /* ZXCapture.m */, + 11F7AEB71ED40AB300A9F224 /* ZXCaptureDelegate.h */, + 11F7AEB81ED40AB300A9F224 /* ZXCGImageLuminanceSource.h */, + 11F7AEB91ED40AB300A9F224 /* ZXCGImageLuminanceSource.m */, + 11F7AEBA1ED40AB300A9F224 /* ZXImage.h */, + 11F7AEBB1ED40AB300A9F224 /* ZXImage.m */, + ); + path = client; + sourceTree = ""; + }; + 11F7AE6B1ED40AB300A9F224 /* result */ = { + isa = PBXGroup; + children = ( + 11F7AE6C1ED40AB300A9F224 /* ZXAbstractDoCoMoResultParser.h */, + 11F7AE6D1ED40AB300A9F224 /* ZXAbstractDoCoMoResultParser.m */, + 11F7AE6E1ED40AB300A9F224 /* ZXAddressBookAUResultParser.h */, + 11F7AE6F1ED40AB300A9F224 /* ZXAddressBookAUResultParser.m */, + 11F7AE701ED40AB300A9F224 /* ZXAddressBookDoCoMoResultParser.h */, + 11F7AE711ED40AB300A9F224 /* ZXAddressBookDoCoMoResultParser.m */, + 11F7AE721ED40AB300A9F224 /* ZXAddressBookParsedResult.h */, + 11F7AE731ED40AB300A9F224 /* ZXAddressBookParsedResult.m */, + 11F7AE741ED40AB300A9F224 /* ZXBizcardResultParser.h */, + 11F7AE751ED40AB300A9F224 /* ZXBizcardResultParser.m */, + 11F7AE761ED40AB300A9F224 /* ZXBookmarkDoCoMoResultParser.h */, + 11F7AE771ED40AB300A9F224 /* ZXBookmarkDoCoMoResultParser.m */, + 11F7AE781ED40AB300A9F224 /* ZXCalendarParsedResult.h */, + 11F7AE791ED40AB300A9F224 /* ZXCalendarParsedResult.m */, + 11F7AE7A1ED40AB300A9F224 /* ZXEmailAddressParsedResult.h */, + 11F7AE7B1ED40AB300A9F224 /* ZXEmailAddressParsedResult.m */, + 11F7AE7C1ED40AB300A9F224 /* ZXEmailAddressResultParser.h */, + 11F7AE7D1ED40AB300A9F224 /* ZXEmailAddressResultParser.m */, + 11F7AE7E1ED40AB300A9F224 /* ZXEmailDoCoMoResultParser.h */, + 11F7AE7F1ED40AB300A9F224 /* ZXEmailDoCoMoResultParser.m */, + 11F7AE801ED40AB300A9F224 /* ZXExpandedProductParsedResult.h */, + 11F7AE811ED40AB300A9F224 /* ZXExpandedProductParsedResult.m */, + 11F7AE821ED40AB300A9F224 /* ZXExpandedProductResultParser.h */, + 11F7AE831ED40AB300A9F224 /* ZXExpandedProductResultParser.m */, + 11F7AE841ED40AB300A9F224 /* ZXGeoParsedResult.h */, + 11F7AE851ED40AB300A9F224 /* ZXGeoParsedResult.m */, + 11F7AE861ED40AB300A9F224 /* ZXGeoResultParser.h */, + 11F7AE871ED40AB300A9F224 /* ZXGeoResultParser.m */, + 11F7AE881ED40AB300A9F224 /* ZXISBNParsedResult.h */, + 11F7AE891ED40AB300A9F224 /* ZXISBNParsedResult.m */, + 11F7AE8A1ED40AB300A9F224 /* ZXISBNResultParser.h */, + 11F7AE8B1ED40AB300A9F224 /* ZXISBNResultParser.m */, + 11F7AE8C1ED40AB300A9F224 /* ZXParsedResult.h */, + 11F7AE8D1ED40AB300A9F224 /* ZXParsedResult.m */, + 11F7AE8E1ED40AB300A9F224 /* ZXParsedResultType.h */, + 11F7AE8F1ED40AB300A9F224 /* ZXProductParsedResult.h */, + 11F7AE901ED40AB300A9F224 /* ZXProductParsedResult.m */, + 11F7AE911ED40AB300A9F224 /* ZXProductResultParser.h */, + 11F7AE921ED40AB300A9F224 /* ZXProductResultParser.m */, + 11F7AE931ED40AB300A9F224 /* ZXResultParser.h */, + 11F7AE941ED40AB300A9F224 /* ZXResultParser.m */, + 11F7AE951ED40AB300A9F224 /* ZXSMSMMSResultParser.h */, + 11F7AE961ED40AB300A9F224 /* ZXSMSMMSResultParser.m */, + 11F7AE971ED40AB300A9F224 /* ZXSMSParsedResult.h */, + 11F7AE981ED40AB300A9F224 /* ZXSMSParsedResult.m */, + 11F7AE991ED40AB300A9F224 /* ZXSMSTOMMSTOResultParser.h */, + 11F7AE9A1ED40AB300A9F224 /* ZXSMSTOMMSTOResultParser.m */, + 11F7AE9B1ED40AB300A9F224 /* ZXSMTPResultParser.h */, + 11F7AE9C1ED40AB300A9F224 /* ZXSMTPResultParser.m */, + 11F7AE9D1ED40AB300A9F224 /* ZXTelParsedResult.h */, + 11F7AE9E1ED40AB300A9F224 /* ZXTelParsedResult.m */, + 11F7AE9F1ED40AB300A9F224 /* ZXTelResultParser.h */, + 11F7AEA01ED40AB300A9F224 /* ZXTelResultParser.m */, + 11F7AEA11ED40AB300A9F224 /* ZXTextParsedResult.h */, + 11F7AEA21ED40AB300A9F224 /* ZXTextParsedResult.m */, + 11F7AEA31ED40AB300A9F224 /* ZXURIParsedResult.h */, + 11F7AEA41ED40AB300A9F224 /* ZXURIParsedResult.m */, + 11F7AEA51ED40AB300A9F224 /* ZXURIResultParser.h */, + 11F7AEA61ED40AB300A9F224 /* ZXURIResultParser.m */, + 11F7AEA71ED40AB300A9F224 /* ZXURLTOResultParser.h */, + 11F7AEA81ED40AB300A9F224 /* ZXURLTOResultParser.m */, + 11F7AEA91ED40AB300A9F224 /* ZXVCardResultParser.h */, + 11F7AEAA1ED40AB300A9F224 /* ZXVCardResultParser.m */, + 11F7AEAB1ED40AB300A9F224 /* ZXVEventResultParser.h */, + 11F7AEAC1ED40AB300A9F224 /* ZXVEventResultParser.m */, + 11F7AEAD1ED40AB300A9F224 /* ZXVINParsedResult.h */, + 11F7AEAE1ED40AB300A9F224 /* ZXVINParsedResult.m */, + 11F7AEAF1ED40AB300A9F224 /* ZXVINResultParser.h */, + 11F7AEB01ED40AB300A9F224 /* ZXVINResultParser.m */, + 11F7AEB11ED40AB300A9F224 /* ZXWifiParsedResult.h */, + 11F7AEB21ED40AB300A9F224 /* ZXWifiParsedResult.m */, + 11F7AEB31ED40AB300A9F224 /* ZXWifiResultParser.h */, + 11F7AEB41ED40AB300A9F224 /* ZXWifiResultParser.m */, + ); + path = result; + sourceTree = ""; + }; + 11F7AEBC1ED40AB300A9F224 /* common */ = { + isa = PBXGroup; + children = ( + 11F7AEBD1ED40AB300A9F224 /* detector */, + 11F7AEC41ED40AB300A9F224 /* reedsolomon */, + 11F7AECD1ED40AB300A9F224 /* ZXBitArray.h */, + 11F7AECE1ED40AB300A9F224 /* ZXBitArray.m */, + 11F7AECF1ED40AB300A9F224 /* ZXBitMatrix.h */, + 11F7AED01ED40AB300A9F224 /* ZXBitMatrix.m */, + 11F7AED11ED40AB300A9F224 /* ZXBitSource.h */, + 11F7AED21ED40AB300A9F224 /* ZXBitSource.m */, + 11F7AED31ED40AB300A9F224 /* ZXBoolArray.h */, + 11F7AED41ED40AB300A9F224 /* ZXBoolArray.m */, + 11F7AED51ED40AB300A9F224 /* ZXByteArray.h */, + 11F7AED61ED40AB300A9F224 /* ZXByteArray.m */, + 11F7AED71ED40AB300A9F224 /* ZXCharacterSetECI.h */, + 11F7AED81ED40AB300A9F224 /* ZXCharacterSetECI.m */, + 11F7AED91ED40AB300A9F224 /* ZXDecoderResult.h */, + 11F7AEDA1ED40AB300A9F224 /* ZXDecoderResult.m */, + 11F7AEDB1ED40AB300A9F224 /* ZXDefaultGridSampler.h */, + 11F7AEDC1ED40AB300A9F224 /* ZXDefaultGridSampler.m */, + 11F7AEDD1ED40AB300A9F224 /* ZXDetectorResult.h */, + 11F7AEDE1ED40AB300A9F224 /* ZXDetectorResult.m */, + 11F7AEDF1ED40AB300A9F224 /* ZXGlobalHistogramBinarizer.h */, + 11F7AEE01ED40AB300A9F224 /* ZXGlobalHistogramBinarizer.m */, + 11F7AEE11ED40AB300A9F224 /* ZXGridSampler.h */, + 11F7AEE21ED40AB300A9F224 /* ZXGridSampler.m */, + 11F7AEE31ED40AB300A9F224 /* ZXHybridBinarizer.h */, + 11F7AEE41ED40AB300A9F224 /* ZXHybridBinarizer.m */, + 11F7AEE51ED40AB300A9F224 /* ZXIntArray.h */, + 11F7AEE61ED40AB300A9F224 /* ZXIntArray.m */, + 11F7AEE71ED40AB300A9F224 /* ZXPerspectiveTransform.h */, + 11F7AEE81ED40AB300A9F224 /* ZXPerspectiveTransform.m */, + 11F7AEE91ED40AB300A9F224 /* ZXStringUtils.h */, + 11F7AEEA1ED40AB300A9F224 /* ZXStringUtils.m */, + ); + path = common; + sourceTree = ""; + }; + 11F7AEBD1ED40AB300A9F224 /* detector */ = { + isa = PBXGroup; + children = ( + 11F7AEBE1ED40AB300A9F224 /* ZXMathUtils.h */, + 11F7AEBF1ED40AB300A9F224 /* ZXMathUtils.m */, + 11F7AEC01ED40AB300A9F224 /* ZXMonochromeRectangleDetector.h */, + 11F7AEC11ED40AB300A9F224 /* ZXMonochromeRectangleDetector.m */, + 11F7AEC21ED40AB300A9F224 /* ZXWhiteRectangleDetector.h */, + 11F7AEC31ED40AB300A9F224 /* ZXWhiteRectangleDetector.m */, + ); + path = detector; + sourceTree = ""; + }; + 11F7AEC41ED40AB300A9F224 /* reedsolomon */ = { + isa = PBXGroup; + children = ( + 11F7AEC51ED40AB300A9F224 /* ZXGenericGF.h */, + 11F7AEC61ED40AB300A9F224 /* ZXGenericGF.m */, + 11F7AEC71ED40AB300A9F224 /* ZXGenericGFPoly.h */, + 11F7AEC81ED40AB300A9F224 /* ZXGenericGFPoly.m */, + 11F7AEC91ED40AB300A9F224 /* ZXReedSolomonDecoder.h */, + 11F7AECA1ED40AB300A9F224 /* ZXReedSolomonDecoder.m */, + 11F7AECB1ED40AB300A9F224 /* ZXReedSolomonEncoder.h */, + 11F7AECC1ED40AB300A9F224 /* ZXReedSolomonEncoder.m */, + ); + path = reedsolomon; + sourceTree = ""; + }; + 11F7AEEB1ED40AB300A9F224 /* core */ = { + isa = PBXGroup; + children = ( + 11F7AEEC1ED40AB300A9F224 /* ZXBarcodeFormat.h */, + 11F7AEED1ED40AB300A9F224 /* ZXBinarizer.h */, + 11F7AEEE1ED40AB300A9F224 /* ZXBinarizer.m */, + 11F7AEEF1ED40AB300A9F224 /* ZXBinaryBitmap.h */, + 11F7AEF01ED40AB300A9F224 /* ZXBinaryBitmap.m */, + 11F7AEF11ED40AB300A9F224 /* ZXByteMatrix.h */, + 11F7AEF21ED40AB300A9F224 /* ZXByteMatrix.m */, + 11F7AEF31ED40AB300A9F224 /* ZXDecodeHints.h */, + 11F7AEF41ED40AB300A9F224 /* ZXDecodeHints.m */, + 11F7AEF51ED40AB300A9F224 /* ZXDimension.h */, + 11F7AEF61ED40AB300A9F224 /* ZXDimension.m */, + 11F7AEF71ED40AB300A9F224 /* ZXEncodeHints.h */, + 11F7AEF81ED40AB300A9F224 /* ZXEncodeHints.m */, + 11F7AEF91ED40AB300A9F224 /* ZXErrors.h */, + 11F7AEFA1ED40AB300A9F224 /* ZXErrors.m */, + 11F7AEFB1ED40AB300A9F224 /* ZXingObjCCore.h */, + 11F7AEFC1ED40AB300A9F224 /* ZXInvertedLuminanceSource.h */, + 11F7AEFD1ED40AB300A9F224 /* ZXInvertedLuminanceSource.m */, + 11F7AEFE1ED40AB300A9F224 /* ZXLuminanceSource.h */, + 11F7AEFF1ED40AB300A9F224 /* ZXLuminanceSource.m */, + 11F7AF001ED40AB300A9F224 /* ZXPlanarYUVLuminanceSource.h */, + 11F7AF011ED40AB300A9F224 /* ZXPlanarYUVLuminanceSource.m */, + 11F7AF021ED40AB300A9F224 /* ZXReader.h */, + 11F7AF031ED40AB300A9F224 /* ZXResult.h */, + 11F7AF041ED40AB300A9F224 /* ZXResult.m */, + 11F7AF051ED40AB300A9F224 /* ZXResultMetadataType.h */, + 11F7AF061ED40AB300A9F224 /* ZXResultPoint.h */, + 11F7AF071ED40AB300A9F224 /* ZXResultPoint.m */, + 11F7AF081ED40AB300A9F224 /* ZXResultPointCallback.h */, + 11F7AF091ED40AB300A9F224 /* ZXRGBLuminanceSource.h */, + 11F7AF0A1ED40AB300A9F224 /* ZXRGBLuminanceSource.m */, + 11F7AF0B1ED40AB300A9F224 /* ZXWriter.h */, + ); + path = core; + sourceTree = ""; + }; + 11F7AF0C1ED40AB300A9F224 /* datamatrix */ = { + isa = PBXGroup; + children = ( + 11F7AF0D1ED40AB300A9F224 /* decoder */, + 11F7AF181ED40AB300A9F224 /* detector */, + 11F7AF1B1ED40AB300A9F224 /* encoder */, + 11F7AF351ED40AB300A9F224 /* ZXDataMatrixReader.h */, + 11F7AF361ED40AB300A9F224 /* ZXDataMatrixReader.m */, + 11F7AF371ED40AB300A9F224 /* ZXDataMatrixWriter.h */, + 11F7AF381ED40AB300A9F224 /* ZXDataMatrixWriter.m */, + 11F7AF391ED40AB300A9F224 /* ZXingObjCDataMatrix.h */, + ); + path = datamatrix; + sourceTree = ""; + }; + 11F7AF0D1ED40AB300A9F224 /* decoder */ = { + isa = PBXGroup; + children = ( + 11F7AF0E1ED40AB300A9F224 /* ZXDataMatrixBitMatrixParser.h */, + 11F7AF0F1ED40AB300A9F224 /* ZXDataMatrixBitMatrixParser.m */, + 11F7AF101ED40AB300A9F224 /* ZXDataMatrixDataBlock.h */, + 11F7AF111ED40AB300A9F224 /* ZXDataMatrixDataBlock.m */, + 11F7AF121ED40AB300A9F224 /* ZXDataMatrixDecodedBitStreamParser.h */, + 11F7AF131ED40AB300A9F224 /* ZXDataMatrixDecodedBitStreamParser.m */, + 11F7AF141ED40AB300A9F224 /* ZXDataMatrixDecoder.h */, + 11F7AF151ED40AB300A9F224 /* ZXDataMatrixDecoder.m */, + 11F7AF161ED40AB300A9F224 /* ZXDataMatrixVersion.h */, + 11F7AF171ED40AB300A9F224 /* ZXDataMatrixVersion.m */, + ); + path = decoder; + sourceTree = ""; + }; + 11F7AF181ED40AB300A9F224 /* detector */ = { + isa = PBXGroup; + children = ( + 11F7AF191ED40AB300A9F224 /* ZXDataMatrixDetector.h */, + 11F7AF1A1ED40AB300A9F224 /* ZXDataMatrixDetector.m */, + ); + path = detector; + sourceTree = ""; + }; + 11F7AF1B1ED40AB300A9F224 /* encoder */ = { + isa = PBXGroup; + children = ( + 11F7AF1C1ED40AB300A9F224 /* ZXDataMatrixASCIIEncoder.h */, + 11F7AF1D1ED40AB300A9F224 /* ZXDataMatrixASCIIEncoder.m */, + 11F7AF1E1ED40AB300A9F224 /* ZXDataMatrixBase256Encoder.h */, + 11F7AF1F1ED40AB300A9F224 /* ZXDataMatrixBase256Encoder.m */, + 11F7AF201ED40AB300A9F224 /* ZXDataMatrixC40Encoder.h */, + 11F7AF211ED40AB300A9F224 /* ZXDataMatrixC40Encoder.m */, + 11F7AF221ED40AB300A9F224 /* ZXDataMatrixDefaultPlacement.h */, + 11F7AF231ED40AB300A9F224 /* ZXDataMatrixDefaultPlacement.m */, + 11F7AF241ED40AB300A9F224 /* ZXDataMatrixEdifactEncoder.h */, + 11F7AF251ED40AB300A9F224 /* ZXDataMatrixEdifactEncoder.m */, + 11F7AF261ED40AB300A9F224 /* ZXDataMatrixEncoder.h */, + 11F7AF271ED40AB300A9F224 /* ZXDataMatrixEncoderContext.h */, + 11F7AF281ED40AB300A9F224 /* ZXDataMatrixEncoderContext.m */, + 11F7AF291ED40AB300A9F224 /* ZXDataMatrixErrorCorrection.h */, + 11F7AF2A1ED40AB300A9F224 /* ZXDataMatrixErrorCorrection.m */, + 11F7AF2B1ED40AB300A9F224 /* ZXDataMatrixHighLevelEncoder.h */, + 11F7AF2C1ED40AB300A9F224 /* ZXDataMatrixHighLevelEncoder.m */, + 11F7AF2D1ED40AB300A9F224 /* ZXDataMatrixSymbolInfo.h */, + 11F7AF2E1ED40AB300A9F224 /* ZXDataMatrixSymbolInfo.m */, + 11F7AF2F1ED40AB300A9F224 /* ZXDataMatrixSymbolInfo144.h */, + 11F7AF301ED40AB300A9F224 /* ZXDataMatrixSymbolInfo144.m */, + 11F7AF311ED40AB300A9F224 /* ZXDataMatrixTextEncoder.h */, + 11F7AF321ED40AB300A9F224 /* ZXDataMatrixTextEncoder.m */, + 11F7AF331ED40AB300A9F224 /* ZXDataMatrixX12Encoder.h */, + 11F7AF341ED40AB300A9F224 /* ZXDataMatrixX12Encoder.m */, + ); + path = encoder; + sourceTree = ""; + }; + 11F7AF3A1ED40AB300A9F224 /* maxicode */ = { + isa = PBXGroup; + children = ( + 11F7AF3B1ED40AB300A9F224 /* decoder */, + 11F7AF421ED40AB300A9F224 /* ZXingObjCMaxiCode.h */, + 11F7AF431ED40AB300A9F224 /* ZXMaxiCodeReader.h */, + 11F7AF441ED40AB300A9F224 /* ZXMaxiCodeReader.m */, + ); + path = maxicode; + sourceTree = ""; + }; + 11F7AF3B1ED40AB300A9F224 /* decoder */ = { + isa = PBXGroup; + children = ( + 11F7AF3C1ED40AB300A9F224 /* ZXMaxiCodeBitMatrixParser.h */, + 11F7AF3D1ED40AB300A9F224 /* ZXMaxiCodeBitMatrixParser.m */, + 11F7AF3E1ED40AB300A9F224 /* ZXMaxiCodeDecodedBitStreamParser.h */, + 11F7AF3F1ED40AB300A9F224 /* ZXMaxiCodeDecodedBitStreamParser.m */, + 11F7AF401ED40AB300A9F224 /* ZXMaxiCodeDecoder.h */, + 11F7AF411ED40AB300A9F224 /* ZXMaxiCodeDecoder.m */, + ); + path = decoder; + sourceTree = ""; + }; + 11F7AF451ED40AB300A9F224 /* multi */ = { + isa = PBXGroup; + children = ( + 11F7AF461ED40AB300A9F224 /* ZXByQuadrantReader.h */, + 11F7AF471ED40AB300A9F224 /* ZXByQuadrantReader.m */, + 11F7AF481ED40AB300A9F224 /* ZXGenericMultipleBarcodeReader.h */, + 11F7AF491ED40AB300A9F224 /* ZXGenericMultipleBarcodeReader.m */, + 11F7AF4A1ED40AB300A9F224 /* ZXMultipleBarcodeReader.h */, + ); + path = multi; + sourceTree = ""; + }; + 11F7AF4B1ED40AB300A9F224 /* oned */ = { + isa = PBXGroup; + children = ( + 11F7AF4C1ED40AB300A9F224 /* rss */, + 11F7AF891ED40AB300A9F224 /* ZXCodaBarReader.h */, + 11F7AF8A1ED40AB300A9F224 /* ZXCodaBarReader.m */, + 11F7AF8B1ED40AB300A9F224 /* ZXCodaBarWriter.h */, + 11F7AF8C1ED40AB300A9F224 /* ZXCodaBarWriter.m */, + 11F7AF8D1ED40AB300A9F224 /* ZXCode128Reader.h */, + 11F7AF8E1ED40AB300A9F224 /* ZXCode128Reader.m */, + 11F7AF8F1ED40AB300A9F224 /* ZXCode128Writer.h */, + 11F7AF901ED40AB300A9F224 /* ZXCode128Writer.m */, + 11F7AF911ED40AB300A9F224 /* ZXCode39Reader.h */, + 11F7AF921ED40AB300A9F224 /* ZXCode39Reader.m */, + 11F7AF931ED40AB300A9F224 /* ZXCode39Writer.h */, + 11F7AF941ED40AB300A9F224 /* ZXCode39Writer.m */, + 11F7AF951ED40AB300A9F224 /* ZXCode93Reader.h */, + 11F7AF961ED40AB300A9F224 /* ZXCode93Reader.m */, + 11F7AF971ED40AB300A9F224 /* ZXEAN13Reader.h */, + 11F7AF981ED40AB300A9F224 /* ZXEAN13Reader.m */, + 11F7AF991ED40AB300A9F224 /* ZXEAN13Writer.h */, + 11F7AF9A1ED40AB300A9F224 /* ZXEAN13Writer.m */, + 11F7AF9B1ED40AB300A9F224 /* ZXEAN8Reader.h */, + 11F7AF9C1ED40AB300A9F224 /* ZXEAN8Reader.m */, + 11F7AF9D1ED40AB300A9F224 /* ZXEAN8Writer.h */, + 11F7AF9E1ED40AB300A9F224 /* ZXEAN8Writer.m */, + 11F7AF9F1ED40AB300A9F224 /* ZXEANManufacturerOrgSupport.h */, + 11F7AFA01ED40AB300A9F224 /* ZXEANManufacturerOrgSupport.m */, + 11F7AFA11ED40AB300A9F224 /* ZXingObjCOneD.h */, + 11F7AFA21ED40AB300A9F224 /* ZXITFReader.h */, + 11F7AFA31ED40AB300A9F224 /* ZXITFReader.m */, + 11F7AFA41ED40AB300A9F224 /* ZXITFWriter.h */, + 11F7AFA51ED40AB300A9F224 /* ZXITFWriter.m */, + 11F7AFA61ED40AB300A9F224 /* ZXMultiFormatOneDReader.h */, + 11F7AFA71ED40AB300A9F224 /* ZXMultiFormatOneDReader.m */, + 11F7AFA81ED40AB300A9F224 /* ZXMultiFormatUPCEANReader.h */, + 11F7AFA91ED40AB300A9F224 /* ZXMultiFormatUPCEANReader.m */, + 11F7AFAA1ED40AB300A9F224 /* ZXOneDimensionalCodeWriter.h */, + 11F7AFAB1ED40AB300A9F224 /* ZXOneDimensionalCodeWriter.m */, + 11F7AFAC1ED40AB300A9F224 /* ZXOneDReader.h */, + 11F7AFAD1ED40AB300A9F224 /* ZXOneDReader.m */, + 11F7AFAE1ED40AB300A9F224 /* ZXUPCAReader.h */, + 11F7AFAF1ED40AB300A9F224 /* ZXUPCAReader.m */, + 11F7AFB01ED40AB300A9F224 /* ZXUPCAWriter.h */, + 11F7AFB11ED40AB300A9F224 /* ZXUPCAWriter.m */, + 11F7AFB21ED40AB300A9F224 /* ZXUPCEANExtension2Support.h */, + 11F7AFB31ED40AB300A9F224 /* ZXUPCEANExtension2Support.m */, + 11F7AFB41ED40AB300A9F224 /* ZXUPCEANExtension5Support.h */, + 11F7AFB51ED40AB300A9F224 /* ZXUPCEANExtension5Support.m */, + 11F7AFB61ED40AB300A9F224 /* ZXUPCEANExtensionSupport.h */, + 11F7AFB71ED40AB300A9F224 /* ZXUPCEANExtensionSupport.m */, + 11F7AFB81ED40AB300A9F224 /* ZXUPCEANReader.h */, + 11F7AFB91ED40AB300A9F224 /* ZXUPCEANReader.m */, + 11F7AFBA1ED40AB300A9F224 /* ZXUPCEANWriter.h */, + 11F7AFBB1ED40AB300A9F224 /* ZXUPCEANWriter.m */, + 11F7AFBC1ED40AB300A9F224 /* ZXUPCEReader.h */, + 11F7AFBD1ED40AB300A9F224 /* ZXUPCEReader.m */, + ); + path = oned; + sourceTree = ""; + }; + 11F7AF4C1ED40AB300A9F224 /* rss */ = { + isa = PBXGroup; + children = ( + 11F7AF4D1ED40AB300A9F224 /* expanded */, + 11F7AF7D1ED40AB300A9F224 /* ZXAbstractRSSReader.h */, + 11F7AF7E1ED40AB300A9F224 /* ZXAbstractRSSReader.m */, + 11F7AF7F1ED40AB300A9F224 /* ZXRSS14Reader.h */, + 11F7AF801ED40AB300A9F224 /* ZXRSS14Reader.m */, + 11F7AF811ED40AB300A9F224 /* ZXRSSDataCharacter.h */, + 11F7AF821ED40AB300A9F224 /* ZXRSSDataCharacter.m */, + 11F7AF831ED40AB300A9F224 /* ZXRSSFinderPattern.h */, + 11F7AF841ED40AB300A9F224 /* ZXRSSFinderPattern.m */, + 11F7AF851ED40AB300A9F224 /* ZXRSSPair.h */, + 11F7AF861ED40AB300A9F224 /* ZXRSSPair.m */, + 11F7AF871ED40AB300A9F224 /* ZXRSSUtils.h */, + 11F7AF881ED40AB300A9F224 /* ZXRSSUtils.m */, + ); + path = rss; + sourceTree = ""; + }; + 11F7AF4D1ED40AB300A9F224 /* expanded */ = { + isa = PBXGroup; + children = ( + 11F7AF4E1ED40AB300A9F224 /* decoders */, + 11F7AF751ED40AB300A9F224 /* ZXBitArrayBuilder.h */, + 11F7AF761ED40AB300A9F224 /* ZXBitArrayBuilder.m */, + 11F7AF771ED40AB300A9F224 /* ZXRSSExpandedPair.h */, + 11F7AF781ED40AB300A9F224 /* ZXRSSExpandedPair.m */, + 11F7AF791ED40AB300A9F224 /* ZXRSSExpandedReader.h */, + 11F7AF7A1ED40AB300A9F224 /* ZXRSSExpandedReader.m */, + 11F7AF7B1ED40AB300A9F224 /* ZXRSSExpandedRow.h */, + 11F7AF7C1ED40AB300A9F224 /* ZXRSSExpandedRow.m */, + ); + path = expanded; + sourceTree = ""; + }; + 11F7AF4E1ED40AB300A9F224 /* decoders */ = { + isa = PBXGroup; + children = ( + 11F7AF4F1ED40AB300A9F224 /* ZXAbstractExpandedDecoder.h */, + 11F7AF501ED40AB300A9F224 /* ZXAbstractExpandedDecoder.m */, + 11F7AF511ED40AB300A9F224 /* ZXAI013103decoder.h */, + 11F7AF521ED40AB300A9F224 /* ZXAI013103decoder.m */, + 11F7AF531ED40AB300A9F224 /* ZXAI01320xDecoder.h */, + 11F7AF541ED40AB300A9F224 /* ZXAI01320xDecoder.m */, + 11F7AF551ED40AB300A9F224 /* ZXAI01392xDecoder.h */, + 11F7AF561ED40AB300A9F224 /* ZXAI01392xDecoder.m */, + 11F7AF571ED40AB300A9F224 /* ZXAI01393xDecoder.h */, + 11F7AF581ED40AB300A9F224 /* ZXAI01393xDecoder.m */, + 11F7AF591ED40AB300A9F224 /* ZXAI013x0x1xDecoder.h */, + 11F7AF5A1ED40AB300A9F224 /* ZXAI013x0x1xDecoder.m */, + 11F7AF5B1ED40AB300A9F224 /* ZXAI013x0xDecoder.h */, + 11F7AF5C1ED40AB300A9F224 /* ZXAI013x0xDecoder.m */, + 11F7AF5D1ED40AB300A9F224 /* ZXAI01AndOtherAIs.h */, + 11F7AF5E1ED40AB300A9F224 /* ZXAI01AndOtherAIs.m */, + 11F7AF5F1ED40AB300A9F224 /* ZXAI01decoder.h */, + 11F7AF601ED40AB300A9F224 /* ZXAI01decoder.m */, + 11F7AF611ED40AB300A9F224 /* ZXAI01weightDecoder.h */, + 11F7AF621ED40AB300A9F224 /* ZXAI01weightDecoder.m */, + 11F7AF631ED40AB300A9F224 /* ZXAnyAIDecoder.h */, + 11F7AF641ED40AB300A9F224 /* ZXAnyAIDecoder.m */, + 11F7AF651ED40AB300A9F224 /* ZXRSSExpandedBlockParsedResult.h */, + 11F7AF661ED40AB300A9F224 /* ZXRSSExpandedBlockParsedResult.m */, + 11F7AF671ED40AB300A9F224 /* ZXRSSExpandedCurrentParsingState.h */, + 11F7AF681ED40AB300A9F224 /* ZXRSSExpandedCurrentParsingState.m */, + 11F7AF691ED40AB300A9F224 /* ZXRSSExpandedDecodedChar.h */, + 11F7AF6A1ED40AB300A9F224 /* ZXRSSExpandedDecodedChar.m */, + 11F7AF6B1ED40AB300A9F224 /* ZXRSSExpandedDecodedInformation.h */, + 11F7AF6C1ED40AB300A9F224 /* ZXRSSExpandedDecodedInformation.m */, + 11F7AF6D1ED40AB300A9F224 /* ZXRSSExpandedDecodedNumeric.h */, + 11F7AF6E1ED40AB300A9F224 /* ZXRSSExpandedDecodedNumeric.m */, + 11F7AF6F1ED40AB300A9F224 /* ZXRSSExpandedDecodedObject.h */, + 11F7AF701ED40AB300A9F224 /* ZXRSSExpandedDecodedObject.m */, + 11F7AF711ED40AB300A9F224 /* ZXRSSExpandedFieldParser.h */, + 11F7AF721ED40AB300A9F224 /* ZXRSSExpandedFieldParser.m */, + 11F7AF731ED40AB300A9F224 /* ZXRSSExpandedGeneralAppIdDecoder.h */, + 11F7AF741ED40AB300A9F224 /* ZXRSSExpandedGeneralAppIdDecoder.m */, + ); + path = decoders; + sourceTree = ""; + }; + 11F7AFBE1ED40AB300A9F224 /* pdf417 */ = { + isa = PBXGroup; + children = ( + 11F7AFBF1ED40AB300A9F224 /* decoder */, + 11F7AFDB1ED40AB300A9F224 /* detector */, + 11F7AFE01ED40AB300A9F224 /* encoder */, + 11F7AFED1ED40AB300A9F224 /* ZXingObjCPDF417.h */, + 11F7AFEE1ED40AB300A9F224 /* ZXPDF417Common.h */, + 11F7AFEF1ED40AB300A9F224 /* ZXPDF417Common.m */, + 11F7AFF01ED40AB300A9F224 /* ZXPDF417Reader.h */, + 11F7AFF11ED40AB300A9F224 /* ZXPDF417Reader.m */, + 11F7AFF21ED40AB300A9F224 /* ZXPDF417ResultMetadata.h */, + 11F7AFF31ED40AB300A9F224 /* ZXPDF417ResultMetadata.m */, + 11F7AFF41ED40AB300A9F224 /* ZXPDF417Writer.h */, + 11F7AFF51ED40AB300A9F224 /* ZXPDF417Writer.m */, + ); + path = pdf417; + sourceTree = ""; + }; + 11F7AFBF1ED40AB300A9F224 /* decoder */ = { + isa = PBXGroup; + children = ( + 11F7AFC01ED40AB300A9F224 /* ec */, + 11F7AFC71ED40AB300A9F224 /* ZXPDF417BarcodeMetadata.h */, + 11F7AFC81ED40AB300A9F224 /* ZXPDF417BarcodeMetadata.m */, + 11F7AFC91ED40AB300A9F224 /* ZXPDF417BarcodeValue.h */, + 11F7AFCA1ED40AB300A9F224 /* ZXPDF417BarcodeValue.m */, + 11F7AFCB1ED40AB300A9F224 /* ZXPDF417BoundingBox.h */, + 11F7AFCC1ED40AB300A9F224 /* ZXPDF417BoundingBox.m */, + 11F7AFCD1ED40AB300A9F224 /* ZXPDF417Codeword.h */, + 11F7AFCE1ED40AB300A9F224 /* ZXPDF417Codeword.m */, + 11F7AFCF1ED40AB300A9F224 /* ZXPDF417CodewordDecoder.h */, + 11F7AFD01ED40AB300A9F224 /* ZXPDF417CodewordDecoder.m */, + 11F7AFD11ED40AB300A9F224 /* ZXPDF417DecodedBitStreamParser.h */, + 11F7AFD21ED40AB300A9F224 /* ZXPDF417DecodedBitStreamParser.m */, + 11F7AFD31ED40AB300A9F224 /* ZXPDF417DetectionResult.h */, + 11F7AFD41ED40AB300A9F224 /* ZXPDF417DetectionResult.m */, + 11F7AFD51ED40AB300A9F224 /* ZXPDF417DetectionResultColumn.h */, + 11F7AFD61ED40AB300A9F224 /* ZXPDF417DetectionResultColumn.m */, + 11F7AFD71ED40AB300A9F224 /* ZXPDF417DetectionResultRowIndicatorColumn.h */, + 11F7AFD81ED40AB300A9F224 /* ZXPDF417DetectionResultRowIndicatorColumn.m */, + 11F7AFD91ED40AB300A9F224 /* ZXPDF417ScanningDecoder.h */, + 11F7AFDA1ED40AB300A9F224 /* ZXPDF417ScanningDecoder.m */, + ); + path = decoder; + sourceTree = ""; + }; + 11F7AFC01ED40AB300A9F224 /* ec */ = { + isa = PBXGroup; + children = ( + 11F7AFC11ED40AB300A9F224 /* ZXModulusGF.h */, + 11F7AFC21ED40AB300A9F224 /* ZXModulusGF.m */, + 11F7AFC31ED40AB300A9F224 /* ZXModulusPoly.h */, + 11F7AFC41ED40AB300A9F224 /* ZXModulusPoly.m */, + 11F7AFC51ED40AB300A9F224 /* ZXPDF417ECErrorCorrection.h */, + 11F7AFC61ED40AB300A9F224 /* ZXPDF417ECErrorCorrection.m */, + ); + path = ec; + sourceTree = ""; + }; + 11F7AFDB1ED40AB300A9F224 /* detector */ = { + isa = PBXGroup; + children = ( + 11F7AFDC1ED40AB300A9F224 /* ZXPDF417Detector.h */, + 11F7AFDD1ED40AB300A9F224 /* ZXPDF417Detector.m */, + 11F7AFDE1ED40AB300A9F224 /* ZXPDF417DetectorResult.h */, + 11F7AFDF1ED40AB300A9F224 /* ZXPDF417DetectorResult.m */, + ); + path = detector; + sourceTree = ""; + }; + 11F7AFE01ED40AB300A9F224 /* encoder */ = { + isa = PBXGroup; + children = ( + 11F7AFE11ED40AB300A9F224 /* ZXPDF417.h */, + 11F7AFE21ED40AB300A9F224 /* ZXPDF417.m */, + 11F7AFE31ED40AB300A9F224 /* ZXPDF417BarcodeMatrix.h */, + 11F7AFE41ED40AB300A9F224 /* ZXPDF417BarcodeMatrix.m */, + 11F7AFE51ED40AB300A9F224 /* ZXPDF417BarcodeRow.h */, + 11F7AFE61ED40AB300A9F224 /* ZXPDF417BarcodeRow.m */, + 11F7AFE71ED40AB300A9F224 /* ZXPDF417Dimensions.h */, + 11F7AFE81ED40AB300A9F224 /* ZXPDF417Dimensions.m */, + 11F7AFE91ED40AB300A9F224 /* ZXPDF417ErrorCorrection.h */, + 11F7AFEA1ED40AB300A9F224 /* ZXPDF417ErrorCorrection.m */, + 11F7AFEB1ED40AB300A9F224 /* ZXPDF417HighLevelEncoder.h */, + 11F7AFEC1ED40AB300A9F224 /* ZXPDF417HighLevelEncoder.m */, + ); + path = encoder; + sourceTree = ""; + }; + 11F7AFF61ED40AB300A9F224 /* qrcode */ = { + isa = PBXGroup; + children = ( + 11F7AFF71ED40AB300A9F224 /* decoder */, + 11F7B00C1ED40AB300A9F224 /* detector */, + 11F7B0191ED40AB300A9F224 /* encoder */, + 11F7B0241ED40AB300A9F224 /* multi */, + 11F7B02C1ED40AB300A9F224 /* ZXingObjCQRCode.h */, + 11F7B02D1ED40AB300A9F224 /* ZXQRCodeReader.h */, + 11F7B02E1ED40AB300A9F224 /* ZXQRCodeReader.m */, + 11F7B02F1ED40AB300A9F224 /* ZXQRCodeWriter.h */, + 11F7B0301ED40AB300A9F224 /* ZXQRCodeWriter.m */, + ); + path = qrcode; + sourceTree = ""; + }; + 11F7AFF71ED40AB300A9F224 /* decoder */ = { + isa = PBXGroup; + children = ( + 11F7AFF81ED40AB300A9F224 /* ZXQRCodeBitMatrixParser.h */, + 11F7AFF91ED40AB300A9F224 /* ZXQRCodeBitMatrixParser.m */, + 11F7AFFA1ED40AB300A9F224 /* ZXQRCodeDataBlock.h */, + 11F7AFFB1ED40AB300A9F224 /* ZXQRCodeDataBlock.m */, + 11F7AFFC1ED40AB300A9F224 /* ZXQRCodeDataMask.h */, + 11F7AFFD1ED40AB300A9F224 /* ZXQRCodeDataMask.m */, + 11F7AFFE1ED40AB300A9F224 /* ZXQRCodeDecodedBitStreamParser.h */, + 11F7AFFF1ED40AB300A9F224 /* ZXQRCodeDecodedBitStreamParser.m */, + 11F7B0001ED40AB300A9F224 /* ZXQRCodeDecoder.h */, + 11F7B0011ED40AB300A9F224 /* ZXQRCodeDecoder.m */, + 11F7B0021ED40AB300A9F224 /* ZXQRCodeDecoderMetaData.h */, + 11F7B0031ED40AB300A9F224 /* ZXQRCodeDecoderMetaData.m */, + 11F7B0041ED40AB300A9F224 /* ZXQRCodeErrorCorrectionLevel.h */, + 11F7B0051ED40AB300A9F224 /* ZXQRCodeErrorCorrectionLevel.m */, + 11F7B0061ED40AB300A9F224 /* ZXQRCodeFormatInformation.h */, + 11F7B0071ED40AB300A9F224 /* ZXQRCodeFormatInformation.m */, + 11F7B0081ED40AB300A9F224 /* ZXQRCodeMode.h */, + 11F7B0091ED40AB300A9F224 /* ZXQRCodeMode.m */, + 11F7B00A1ED40AB300A9F224 /* ZXQRCodeVersion.h */, + 11F7B00B1ED40AB300A9F224 /* ZXQRCodeVersion.m */, + ); + path = decoder; + sourceTree = ""; + }; + 11F7B00C1ED40AB300A9F224 /* detector */ = { + isa = PBXGroup; + children = ( + 11F7B00D1ED40AB300A9F224 /* ZXQRCodeAlignmentPattern.h */, + 11F7B00E1ED40AB300A9F224 /* ZXQRCodeAlignmentPattern.m */, + 11F7B00F1ED40AB300A9F224 /* ZXQRCodeAlignmentPatternFinder.h */, + 11F7B0101ED40AB300A9F224 /* ZXQRCodeAlignmentPatternFinder.m */, + 11F7B0111ED40AB300A9F224 /* ZXQRCodeDetector.h */, + 11F7B0121ED40AB300A9F224 /* ZXQRCodeDetector.m */, + 11F7B0131ED40AB300A9F224 /* ZXQRCodeFinderPattern.h */, + 11F7B0141ED40AB300A9F224 /* ZXQRCodeFinderPattern.m */, + 11F7B0151ED40AB300A9F224 /* ZXQRCodeFinderPatternFinder.h */, + 11F7B0161ED40AB300A9F224 /* ZXQRCodeFinderPatternFinder.m */, + 11F7B0171ED40AB300A9F224 /* ZXQRCodeFinderPatternInfo.h */, + 11F7B0181ED40AB300A9F224 /* ZXQRCodeFinderPatternInfo.m */, + ); + path = detector; + sourceTree = ""; + }; + 11F7B0191ED40AB300A9F224 /* encoder */ = { + isa = PBXGroup; + children = ( + 11F7B01A1ED40AB300A9F224 /* ZXQRCode.h */, + 11F7B01B1ED40AB300A9F224 /* ZXQRCode.m */, + 11F7B01C1ED40AB300A9F224 /* ZXQRCodeBlockPair.h */, + 11F7B01D1ED40AB300A9F224 /* ZXQRCodeBlockPair.m */, + 11F7B01E1ED40AB300A9F224 /* ZXQRCodeEncoder.h */, + 11F7B01F1ED40AB300A9F224 /* ZXQRCodeEncoder.m */, + 11F7B0201ED40AB300A9F224 /* ZXQRCodeMaskUtil.h */, + 11F7B0211ED40AB300A9F224 /* ZXQRCodeMaskUtil.m */, + 11F7B0221ED40AB300A9F224 /* ZXQRCodeMatrixUtil.h */, + 11F7B0231ED40AB300A9F224 /* ZXQRCodeMatrixUtil.m */, + ); + path = encoder; + sourceTree = ""; + }; + 11F7B0241ED40AB300A9F224 /* multi */ = { + isa = PBXGroup; + children = ( + 11F7B0251ED40AB300A9F224 /* detector */, + 11F7B02A1ED40AB300A9F224 /* ZXQRCodeMultiReader.h */, + 11F7B02B1ED40AB300A9F224 /* ZXQRCodeMultiReader.m */, + ); + path = multi; + sourceTree = ""; + }; + 11F7B0251ED40AB300A9F224 /* detector */ = { + isa = PBXGroup; + children = ( + 11F7B0261ED40AB300A9F224 /* ZXMultiDetector.h */, + 11F7B0271ED40AB300A9F224 /* ZXMultiDetector.m */, + 11F7B0281ED40AB300A9F224 /* ZXMultiFinderPatternFinder.h */, + 11F7B0291ED40AB300A9F224 /* ZXMultiFinderPatternFinder.m */, + ); + path = detector; + sourceTree = ""; + }; + 11F7B1151ED4171100A9F224 /* View */ = { + isa = PBXGroup; + children = ( + 11F7B1171ED4174D00A9F224 /* QRCodeResultView.h */, + 11F7B1181ED4174D00A9F224 /* QRCodeResultView.m */, + ); + path = View; + sourceTree = ""; + }; + 11F7B1161ED4172000A9F224 /* Model */ = { + isa = PBXGroup; + children = ( + ); + path = Model; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -1318,6 +3181,7 @@ 119AB3091ED16FD7003DBF5A /* IQKeyboardManager.bundle in Resources */, 11E3E9A31ECAA6F600D72EE1 /* MJRefresh.bundle in Resources */, 1121BFCE1EC990BD0002D73C /* Main.storyboard in Resources */, + 11F7AE391ED4043F00A9F224 /* CodeScan.bundle in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1342,137 +3206,400 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 11F7B0841ED40AB300A9F224 /* ZXEncodeHints.m in Sources */, 119AB2C11ED15E87003DBF5A /* AFNetworkActivityIndicatorManager.m in Sources */, + 11F7B1031ED40AB300A9F224 /* ZXQRCodeFinderPattern.m in Sources */, + 11F7B0D71ED40AB300A9F224 /* ZXUPCEANExtension2Support.m in Sources */, + 11F7B0671ED40AB300A9F224 /* ZXCGImageLuminanceSource.m in Sources */, 119AB2D51ED16F2C003DBF5A /* ZYThirdPartService.m in Sources */, + 110B9BE51ED2845500EC58DB /* BaseModel.m in Sources */, 119AB2C41ED15E87003DBF5A /* UIImageView+AFNetworking.m in Sources */, + 11F7B0EA1ED40AB300A9F224 /* ZXPDF417Detector.m in Sources */, + 11F7B0F01ED40AB300A9F224 /* ZXPDF417ErrorCorrection.m in Sources */, + 11F7B0B81ED40AB300A9F224 /* ZXRSSExpandedGeneralAppIdDecoder.m in Sources */, + 11F7B0861ED40AB300A9F224 /* ZXInvertedLuminanceSource.m in Sources */, + 11F7B0771ED40AB300A9F224 /* ZXDefaultGridSampler.m in Sources */, 1148291C1ECBDD6100BBCBF3 /* UIView+WebCacheOperation.m in Sources */, 119AB2C31ED15E87003DBF5A /* UIButton+AFNetworking.m in Sources */, + 11F7B0471ED40AB300A9F224 /* ZXBookmarkDoCoMoResultParser.m in Sources */, + 11F7B04A1ED40AB300A9F224 /* ZXEmailAddressResultParser.m in Sources */, + 11F7B0651ED40AB300A9F224 /* ZXWifiResultParser.m in Sources */, + 11F7B0DD1ED40AB300A9F224 /* ZXModulusGF.m in Sources */, + 11F7B08A1ED40AB300A9F224 /* ZXResultPoint.m in Sources */, 119AB3021ED16FD7003DBF5A /* IQKeyboardReturnKeyHandler.m in Sources */, 11E3E9A01ECAA6F600D72EE1 /* MJRefreshGifHeader.m in Sources */, + 11F7B0F11ED40AB300A9F224 /* ZXPDF417HighLevelEncoder.m in Sources */, + 11F7B0631ED40AB300A9F224 /* ZXVINResultParser.m in Sources */, + 118E68F91ED92C9900B62015 /* YQCacheManager.m in Sources */, + 11F7B0691ED40AB300A9F224 /* ZXMathUtils.m in Sources */, + 11F7B0981ED40AB300A9F224 /* ZXDataMatrixErrorCorrection.m in Sources */, 119AB3081ED16FD7003DBF5A /* IQUIView+IQKeyboardToolbar.m in Sources */, + 11F7AE3F1ED4043F00A9F224 /* LBXScanNative.m in Sources */, + 11F7B0371ED40AB300A9F224 /* ZXAztecDetector.m in Sources */, + 11F7B0451ED40AB300A9F224 /* ZXAddressBookParsedResult.m in Sources */, + 11F7B0D11ED40AB300A9F224 /* ZXMultiFormatOneDReader.m in Sources */, + 11F7B0441ED40AB300A9F224 /* ZXAddressBookDoCoMoResultParser.m in Sources */, 114829131ECBDD6100BBCBF3 /* SDWebImageManager.m in Sources */, + 11F7B0A61ED40AB300A9F224 /* ZXAbstractExpandedDecoder.m in Sources */, + 11F7B0C41ED40AB300A9F224 /* ZXCodaBarWriter.m in Sources */, + 11F7B0681ED40AB300A9F224 /* ZXImage.m in Sources */, 11E3E9F91ECAC90D00D72EE1 /* GTMBase64.m in Sources */, 119AB3011ED16FD7003DBF5A /* IQKeyboardManager.m in Sources */, + 11F7B0FC1ED40AB300A9F224 /* ZXQRCodeErrorCorrectionLevel.m in Sources */, + 11F7B09C1ED40AB300A9F224 /* ZXDataMatrixTextEncoder.m in Sources */, + 11F7B0AC1ED40AB300A9F224 /* ZXAI013x0xDecoder.m in Sources */, 114829141ECBDD6100BBCBF3 /* SDWebImagePrefetcher.m in Sources */, + 11F7B0F71ED40AB300A9F224 /* ZXQRCodeDataBlock.m in Sources */, + 11F7AE431ED4043F00A9F224 /* LBXScanView.m in Sources */, 11E3E9B61ECAA72600D72EE1 /* SDRefreshHeaderView.m in Sources */, + 11F7AE481ED4043F00A9F224 /* ZXingWrapper.m in Sources */, 11E3E9D11ECAC85E00D72EE1 /* UIView+Extension.m in Sources */, + 11F7B1101ED40AB400A9F224 /* ZXMultiFormatReader.m in Sources */, 11C243511ED01986007F69C6 /* PickDateView.m in Sources */, 119AB2FF1ED16FD7003DBF5A /* IQUIViewController+Additions.m in Sources */, + 11F7AE3D1ED4043F00A9F224 /* LBXAlertAction.m in Sources */, + 11F7B06D1ED40AB300A9F224 /* ZXGenericGFPoly.m in Sources */, 11E3E9D71ECAC8F400D72EE1 /* Tools.m in Sources */, 119AB2CC1ED15EB3003DBF5A /* RTNetworking.m in Sources */, 114829171ECBDD6100BBCBF3 /* UIImage+MultiFormat.m in Sources */, + 11F7B0AE1ED40AB300A9F224 /* ZXAI01decoder.m in Sources */, + 11F7B0711ED40AB300A9F224 /* ZXBitMatrix.m in Sources */, 119AB2D21ED161EB003DBF5A /* PickingViewModel.m in Sources */, 11E3E9A51ECAA6F600D72EE1 /* NSBundle+MJRefresh.m in Sources */, 11E3EA091ECAF71B00D72EE1 /* PersonHeadView.m in Sources */, + 11F7B0A41ED40AB300A9F224 /* ZXByQuadrantReader.m in Sources */, 119AB30D1ED17359003DBF5A /* UIScrollView+EmptyDataSet.m in Sources */, + 11F7B0BA1ED40AB300A9F224 /* ZXRSSExpandedPair.m in Sources */, + 11F7B0FA1ED40AB300A9F224 /* ZXQRCodeDecoder.m in Sources */, + 11F7B0E61ED40AB300A9F224 /* ZXPDF417DetectionResult.m in Sources */, + 11F7B0811ED40AB300A9F224 /* ZXByteMatrix.m in Sources */, + 11F7B0D51ED40AB300A9F224 /* ZXUPCAReader.m in Sources */, + 11F7B0D81ED40AB300A9F224 /* ZXUPCEANExtension5Support.m in Sources */, + 11F7B1001ED40AB300A9F224 /* ZXQRCodeAlignmentPattern.m in Sources */, + 11F7B04B1ED40AB300A9F224 /* ZXEmailDoCoMoResultParser.m in Sources */, 11E3E9CF1ECAC85E00D72EE1 /* UIView+Alert.m in Sources */, + 11F7B0751ED40AB300A9F224 /* ZXCharacterSetECI.m in Sources */, + 11F7B0DC1ED40AB300A9F224 /* ZXUPCEReader.m in Sources */, + 11F7B0421ED40AB300A9F224 /* ZXAbstractDoCoMoResultParser.m in Sources */, + 11F7B06B1ED40AB300A9F224 /* ZXWhiteRectangleDetector.m in Sources */, 11E3E9D01ECAC85E00D72EE1 /* UIView+Controller.m in Sources */, + 11F7B0F21ED40AB300A9F224 /* ZXPDF417Common.m in Sources */, + 11F7B09A1ED40AB300A9F224 /* ZXDataMatrixSymbolInfo.m in Sources */, 11E3EA061ECAEDAD00D72EE1 /* PersonTableViewCell.m in Sources */, 1148290F1ECBDD6100BBCBF3 /* SDWebImageCompat.m in Sources */, + 11F7B08B1ED40AB300A9F224 /* ZXRGBLuminanceSource.m in Sources */, + 11F7B0B01ED40AB300A9F224 /* ZXAnyAIDecoder.m in Sources */, 1121C0381EC9C1300002D73C /* View+MASAdditions.m in Sources */, + 11F7B0761ED40AB300A9F224 /* ZXDecoderResult.m in Sources */, 1121C0131EC9B70D0002D73C /* UIColor+HexString.m in Sources */, 11E3E99C1ECAA6F600D72EE1 /* MJRefreshAutoStateFooter.m in Sources */, + 11F7B0C51ED40AB300A9F224 /* ZXCode128Reader.m in Sources */, + 11F7AE4B1ED404E800A9F224 /* QRCodeVC.m in Sources */, + 11F7B0D31ED40AB300A9F224 /* ZXOneDimensionalCodeWriter.m in Sources */, + 11F7AE411ED4043F00A9F224 /* LBXScanResult.m in Sources */, + 11F7B0851ED40AB300A9F224 /* ZXErrors.m in Sources */, + 118E69041ED94D5600B62015 /* UserModel.m in Sources */, + 11F7B0F51ED40AB300A9F224 /* ZXPDF417Writer.m in Sources */, + 110B9BFD1ED2BF0700EC58DB /* PickDetailFootView.m in Sources */, + 11F7B0971ED40AB300A9F224 /* ZXDataMatrixEncoderContext.m in Sources */, + 11F7B0C71ED40AB300A9F224 /* ZXCode39Reader.m in Sources */, + 11F7B0EE1ED40AB300A9F224 /* ZXPDF417BarcodeRow.m in Sources */, + 11F7B0561ED40AB300A9F224 /* ZXSMSMMSResultParser.m in Sources */, + 11F7B0C91ED40AB300A9F224 /* ZXCode93Reader.m in Sources */, + 110B9BE81ED2906700EC58DB /* PrereloadCell.m in Sources */, 114829101ECBDD6100BBCBF3 /* SDWebImageDecoder.m in Sources */, + 11F7B0361ED40AB300A9F224 /* ZXAztecDecoder.m in Sources */, + 11F7B0461ED40AB300A9F224 /* ZXBizcardResultParser.m in Sources */, + 11F7B10F1ED40AB400A9F224 /* ZXQRCodeWriter.m in Sources */, + 11F7B0831ED40AB300A9F224 /* ZXDimension.m in Sources */, 119AB2C51ED15E87003DBF5A /* UIProgressView+AFNetworking.m in Sources */, 1121C0031EC99F420002D73C /* UINavigationController+FDFullscreenPopGesture.m in Sources */, + 11F7B0551ED40AB300A9F224 /* ZXResultParser.m in Sources */, 1121C0071EC9A0DF0002D73C /* QRCViewController.m in Sources */, + 11F7B11C1ED4356B00A9F224 /* PreloadViewController.m in Sources */, + 11F7AE3C1ED4043F00A9F224 /* UIAlertView+LBXAlertAction.m in Sources */, + 11F7B0871ED40AB300A9F224 /* ZXLuminanceSource.m in Sources */, 11E3E99E1ECAA6F600D72EE1 /* MJRefreshBackNormalFooter.m in Sources */, 1148290B1ECBDD6100BBCBF3 /* NSData+ImageContentType.m in Sources */, 11C2434E1ECFF0E8007F69C6 /* ResultDisplayController.m in Sources */, + 113580DB1ED7BEB80069E21E /* PartSearchView.m in Sources */, + 118E68FF1ED92CA000B62015 /* YQNetworking.m in Sources */, 119AB3071ED16FD7003DBF5A /* IQToolbar.m in Sources */, 114829231ECC1DC900BBCBF3 /* PickingVC.m in Sources */, + 11F7AE451ED4043F00A9F224 /* LBXScanViewStyle.m in Sources */, + 11F7B09F1ED40AB300A9F224 /* ZXDataMatrixWriter.m in Sources */, 1121BFCB1EC990BD0002D73C /* ViewController.m in Sources */, 1148290E1ECBDD6100BBCBF3 /* SDImageCacheConfig.m in Sources */, + 11F7B0951ED40AB300A9F224 /* ZXDataMatrixDefaultPlacement.m in Sources */, + 1179FBEA1ED577570071ED45 /* PreloadDetailCell.m in Sources */, + 11DE26F61ED6A69000DCDE78 /* PreloadNewView.m in Sources */, + 11F7B08F1ED40AB300A9F224 /* ZXDataMatrixDecoder.m in Sources */, + 11F7B0741ED40AB300A9F224 /* ZXByteArray.m in Sources */, + 11F7B0DA1ED40AB300A9F224 /* ZXUPCEANReader.m in Sources */, + 11F7B0731ED40AB300A9F224 /* ZXBoolArray.m in Sources */, 114829121ECBDD6100BBCBF3 /* SDWebImageDownloaderOperation.m in Sources */, 11E3E9FA1ECAC90D00D72EE1 /* NSString+Crypt.m in Sources */, + 11F7B0B31ED40AB300A9F224 /* ZXRSSExpandedDecodedChar.m in Sources */, 11E3E9961ECAA6F600D72EE1 /* MJRefreshBackFooter.m in Sources */, 119AB2C01ED15E87003DBF5A /* AFImageDownloader.m in Sources */, 1121C0391EC9C1300002D73C /* ViewController+MASAdditions.m in Sources */, + 11F7B03F1ED40AB300A9F224 /* ZXAztecDetectorResult.m in Sources */, 11E3E9B81ECAA72600D72EE1 /* UIView+SDExtension.m in Sources */, + 11F7B0BE1ED40AB300A9F224 /* ZXRSS14Reader.m in Sources */, + 11F7B0DF1ED40AB300A9F224 /* ZXPDF417ECErrorCorrection.m in Sources */, 119AB3001ED16FD7003DBF5A /* IQUIWindow+Hierarchy.m in Sources */, + 11F7B0901ED40AB300A9F224 /* ZXDataMatrixVersion.m in Sources */, + 11F7B1071ED40AB300A9F224 /* ZXQRCodeBlockPair.m in Sources */, 11E3E9B51ECAA72600D72EE1 /* SDRefreshFooterView.m in Sources */, 11E3E9A81ECAA6F600D72EE1 /* UIView+MJExtension.m in Sources */, - 11E3E9FF1ECAC90D00D72EE1 /* UIImage+Normalimage.m in Sources */, + 11F7B0571ED40AB300A9F224 /* ZXSMSParsedResult.m in Sources */, + 11F7B0CC1ED40AB300A9F224 /* ZXEAN8Reader.m in Sources */, + 11F7AE3B1ED4043F00A9F224 /* UIAlertController+supportedInterfaceOrientations.m in Sources */, + 11F7B1081ED40AB300A9F224 /* ZXQRCodeEncoder.m in Sources */, + 11F7B07A1ED40AB300A9F224 /* ZXGridSampler.m in Sources */, + 11F7B0521ED40AB300A9F224 /* ZXParsedResult.m in Sources */, + 11F7B0821ED40AB300A9F224 /* ZXDecodeHints.m in Sources */, + 11DE26F91ED6B66800DCDE78 /* NewPartCell.m in Sources */, 11346AB21ECED3ED00BFDD69 /* UITableView+SDAutoTableViewCellHeight.m in Sources */, 114829181ECBDD6100BBCBF3 /* UIImage+WebP.m in Sources */, + 11F7B0E31ED40AB300A9F224 /* ZXPDF417Codeword.m in Sources */, 119AB2C61ED15E87003DBF5A /* UIRefreshControl+AFNetworking.m in Sources */, 11346AB31ECED3ED00BFDD69 /* UIView+SDAutoLayout.m in Sources */, + 11F7B0CE1ED40AB300A9F224 /* ZXEANManufacturerOrgSupport.m in Sources */, + 11F7B0DE1ED40AB300A9F224 /* ZXModulusPoly.m in Sources */, + 11F7B0BB1ED40AB300A9F224 /* ZXRSSExpandedReader.m in Sources */, + 11F7B0E91ED40AB300A9F224 /* ZXPDF417ScanningDecoder.m in Sources */, 11E3E9FE1ECAC90D00D72EE1 /* UIImage+Common.m in Sources */, + 11F7B03A1ED40AB300A9F224 /* ZXAztecEncoder.m in Sources */, 11E3E9B71ECAA72600D72EE1 /* SDRefreshView.m in Sources */, + 11DE26FC1ED6DBDF00DCDE78 /* NewPartNumberView.m in Sources */, 11E3E99D1ECAA6F600D72EE1 /* MJRefreshBackGifFooter.m in Sources */, + 11F7B0FD1ED40AB300A9F224 /* ZXQRCodeFormatInformation.m in Sources */, + 11F7B0CF1ED40AB300A9F224 /* ZXITFReader.m in Sources */, 1121C0341EC9C1300002D73C /* MASViewAttribute.m in Sources */, + 11F7B0BC1ED40AB300A9F224 /* ZXRSSExpandedRow.m in Sources */, 11E3E9BC1ECAAFC500D72EE1 /* personViewController.m in Sources */, + 110B9BFA1ED2BEEC00EC58DB /* PickDetailView.m in Sources */, 11E3E9A21ECAA6F600D72EE1 /* MJRefreshStateHeader.m in Sources */, + 1179FBE71ED56E5D0071ED45 /* PreloadDetailView.m in Sources */, + 11F7B0591ED40AB300A9F224 /* ZXSMTPResultParser.m in Sources */, 119AB2FD1ED16FD7003DBF5A /* IQUITextFieldView+Additions.m in Sources */, + 11F7B0BD1ED40AB300A9F224 /* ZXAbstractRSSReader.m in Sources */, 119AB2C71ED15E87003DBF5A /* UIWebView+AFNetworking.m in Sources */, + 11F7B07E1ED40AB300A9F224 /* ZXStringUtils.m in Sources */, + 11F7B04E1ED40AB300A9F224 /* ZXGeoParsedResult.m in Sources */, + 11F7B0431ED40AB300A9F224 /* ZXAddressBookAUResultParser.m in Sources */, + 11F7AE3A1ED4043F00A9F224 /* UIActionSheet+LBXAlertAction.m in Sources */, + 11DE26F31ED685D300DCDE78 /* NewPreloadVC.m in Sources */, 119AB2BD1ED15E87003DBF5A /* AFURLResponseSerialization.m in Sources */, + 11F7B0E21ED40AB300A9F224 /* ZXPDF417BoundingBox.m in Sources */, 119AB3061ED16FD7003DBF5A /* IQTitleBarButtonItem.m in Sources */, + 11F7B04F1ED40AB300A9F224 /* ZXGeoResultParser.m in Sources */, + 11F7B0CD1ED40AB300A9F224 /* ZXEAN8Writer.m in Sources */, 119AB2C81ED15E87003DBF5A /* NSObject+YYModel.m in Sources */, + 11F7B0781ED40AB300A9F224 /* ZXDetectorResult.m in Sources */, + 11F7B10A1ED40AB400A9F224 /* ZXQRCodeMatrixUtil.m in Sources */, + 11F7AE471ED4043F00A9F224 /* LBXZXCapture.m in Sources */, 119AB2BF1ED15E87003DBF5A /* AFAutoPurgingImageCache.m in Sources */, + 110B9BF11ED2932F00EC58DB /* PreloadDetailVC.m in Sources */, 11E3E9D41ECAC8BE00D72EE1 /* MBProgressHUD.m in Sources */, 11E3E9C01ECAC82600D72EE1 /* AlertManager.m in Sources */, 1121C0301EC9C1300002D73C /* MASCompositeConstraint.m in Sources */, 11E3E9F81ECAC90D00D72EE1 /* NSDictionary+Propery.m in Sources */, + 11F7B0EF1ED40AB300A9F224 /* ZXPDF417Dimensions.m in Sources */, + 11F7B0381ED40AB300A9F224 /* ZXAztecBinaryShiftToken.m in Sources */, + 11F7B0391ED40AB300A9F224 /* ZXAztecCode.m in Sources */, 1148292C1ECC222F00BBCBF3 /* PickingHeadView.m in Sources */, + 11F7B08E1ED40AB300A9F224 /* ZXDataMatrixDecodedBitStreamParser.m in Sources */, + 11F7B0531ED40AB300A9F224 /* ZXProductParsedResult.m in Sources */, + 11F7B0581ED40AB300A9F224 /* ZXSMSTOMMSTOResultParser.m in Sources */, + 11F7B0E01ED40AB300A9F224 /* ZXPDF417BarcodeMetadata.m in Sources */, 1148290D1ECBDD6100BBCBF3 /* SDImageCache.m in Sources */, + 11F7B0F81ED40AB300A9F224 /* ZXQRCodeDataMask.m in Sources */, + 11F7B0991ED40AB300A9F224 /* ZXDataMatrixHighLevelEncoder.m in Sources */, + 110B9BEE1ED291C100EC58DB /* PreloadViewModel.m in Sources */, + 11F7B0801ED40AB300A9F224 /* ZXBinaryBitmap.m in Sources */, + 11F7B0A31ED40AB300A9F224 /* ZXMaxiCodeReader.m in Sources */, 119AB2FB1ED16FD7003DBF5A /* IQNSArray+Sort.m in Sources */, + 11F7B0701ED40AB300A9F224 /* ZXBitArray.m in Sources */, + 11F7B0AA1ED40AB300A9F224 /* ZXAI01393xDecoder.m in Sources */, 119AB2FC1ED16FD7003DBF5A /* IQUIScrollView+Additions.m in Sources */, 1121BFF91EC994820002D73C /* BaseViewController.m in Sources */, + 11F7B05F1ED40AB300A9F224 /* ZXURLTOResultParser.m in Sources */, 11E3E9C41ECAC84900D72EE1 /* UIView+Toast.m in Sources */, + 11F7B10D1ED40AB400A9F224 /* ZXQRCodeMultiReader.m in Sources */, + 11F7B05D1ED40AB300A9F224 /* ZXURIParsedResult.m in Sources */, 119AB2BE1ED15E87003DBF5A /* AFURLSessionManager.m in Sources */, 11C6C66C1ECDB47E00C2A9E8 /* PickingFootView.m in Sources */, + 11F7B0891ED40AB300A9F224 /* ZXResult.m in Sources */, + 11F7B0C61ED40AB300A9F224 /* ZXCode128Writer.m in Sources */, 11E3E9971ECAA6F600D72EE1 /* MJRefreshComponent.m in Sources */, 119AB2BB1ED15E87003DBF5A /* AFSecurityPolicy.m in Sources */, + 118E690A1ED951BF00B62015 /* KeyManager.m in Sources */, 11E3E9991ECAA6F600D72EE1 /* MJRefreshHeader.m in Sources */, 11E3EA011ECAC90D00D72EE1 /* UIViewController+Common.m in Sources */, + 11F7B0621ED40AB300A9F224 /* ZXVINParsedResult.m in Sources */, + 11F7B04C1ED40AB300A9F224 /* ZXExpandedProductParsedResult.m in Sources */, 119AB2C91ED15E87003DBF5A /* YYClassInfo.m in Sources */, + 118E68FC1ED92C9900B62015 /* YQMemoryCache.m in Sources */, 1121C0321EC9C1300002D73C /* MASConstraintMaker.m in Sources */, 11E3E99A1ECAA6F600D72EE1 /* MJRefreshAutoGifFooter.m in Sources */, + 11F7B1051ED40AB300A9F224 /* ZXQRCodeFinderPatternInfo.m in Sources */, 11E3E9FB1ECAC90D00D72EE1 /* NSString+dateString.m in Sources */, + 11F7B09B1ED40AB300A9F224 /* ZXDataMatrixSymbolInfo144.m in Sources */, + 118E68EF1ED92C9300B62015 /* YQNetworking+RequestManager.m in Sources */, + 11F7B0FE1ED40AB300A9F224 /* ZXQRCodeMode.m in Sources */, + 11F7B07C1ED40AB300A9F224 /* ZXIntArray.m in Sources */, + 11F7B10B1ED40AB400A9F224 /* ZXMultiDetector.m in Sources */, + 11F7B0D01ED40AB300A9F224 /* ZXITFWriter.m in Sources */, + 11F7B0A01ED40AB300A9F224 /* ZXMaxiCodeBitMatrixParser.m in Sources */, + 11F7B0AB1ED40AB300A9F224 /* ZXAI013x0x1xDecoder.m in Sources */, + 11F7B0A91ED40AB300A9F224 /* ZXAI01392xDecoder.m in Sources */, + 11F7B0721ED40AB300A9F224 /* ZXBitSource.m in Sources */, + 118E68FB1ED92C9900B62015 /* YQLRUManager.m in Sources */, + 11F7B0B41ED40AB300A9F224 /* ZXRSSExpandedDecodedInformation.m in Sources */, + 11F7B1091ED40AB400A9F224 /* ZXQRCodeMaskUtil.m in Sources */, + 11F7B0E51ED40AB300A9F224 /* ZXPDF417DecodedBitStreamParser.m in Sources */, + 11F7B0E71ED40AB300A9F224 /* ZXPDF417DetectionResultColumn.m in Sources */, + 11F7AE401ED4043F00A9F224 /* LBXScanNetAnimation.m in Sources */, 1121C0311EC9C1300002D73C /* MASConstraint.m in Sources */, + 11F7AE3E1ED4043F00A9F224 /* LBXScanLineAnimation.m in Sources */, + 11F7B0931ED40AB300A9F224 /* ZXDataMatrixBase256Encoder.m in Sources */, + 11F7B0D41ED40AB300A9F224 /* ZXOneDReader.m in Sources */, + 110B9BE21ED281D700EC58DB /* BaseTableViewCell.m in Sources */, + 11F7B0881ED40AB300A9F224 /* ZXPlanarYUVLuminanceSource.m in Sources */, + 11F7B0AF1ED40AB300A9F224 /* ZXAI01weightDecoder.m in Sources */, + 11F7B0A81ED40AB300A9F224 /* ZXAI01320xDecoder.m in Sources */, + 11F7B04D1ED40AB300A9F224 /* ZXExpandedProductResultParser.m in Sources */, + 11F7B0661ED40AB300A9F224 /* ZXCapture.m in Sources */, 1121C0371EC9C1300002D73C /* NSLayoutConstraint+MASDebugAdditions.m in Sources */, 11E3E9CE1ECAC85E00D72EE1 /* UIResponder+Router.m in Sources */, 119AB3041ED16FD7003DBF5A /* IQBarButtonItem.m in Sources */, 119AB2BA1ED15E87003DBF5A /* AFNetworkReachabilityManager.m in Sources */, 114829151ECBDD6100BBCBF3 /* UIButton+WebCache.m in Sources */, + 11F7B0B61ED40AB300A9F224 /* ZXRSSExpandedDecodedObject.m in Sources */, + 11F7B0C31ED40AB300A9F224 /* ZXCodaBarReader.m in Sources */, + 11F7B0911ED40AB300A9F224 /* ZXDataMatrixDetector.m in Sources */, + 11F7B09E1ED40AB300A9F224 /* ZXDataMatrixReader.m in Sources */, + 11F7B0DB1ED40AB300A9F224 /* ZXUPCEANWriter.m in Sources */, + 11F7B03D1ED40AB300A9F224 /* ZXAztecState.m in Sources */, + 11F7B0B71ED40AB300A9F224 /* ZXRSSExpandedFieldParser.m in Sources */, + 11F7B0791ED40AB300A9F224 /* ZXGlobalHistogramBinarizer.m in Sources */, 1121C0331EC9C1300002D73C /* MASLayoutConstraint.m in Sources */, + 11F7B0EC1ED40AB300A9F224 /* ZXPDF417.m in Sources */, + 11F7B0481ED40AB300A9F224 /* ZXCalendarParsedResult.m in Sources */, + 11F7B0AD1ED40AB300A9F224 /* ZXAI01AndOtherAIs.m in Sources */, + 11F7B10C1ED40AB400A9F224 /* ZXMultiFinderPatternFinder.m in Sources */, 114829291ECC1E0000BBCBF3 /* PickingModel.m in Sources */, 114829261ECC1DEC00BBCBF3 /* PickingCell.m in Sources */, + 11F7B06A1ED40AB300A9F224 /* ZXMonochromeRectangleDetector.m in Sources */, 11E3E9601ECA8CEF00D72EE1 /* SheetView.m in Sources */, + 11F7B0E11ED40AB300A9F224 /* ZXPDF417BarcodeValue.m in Sources */, 114829161ECBDD6100BBCBF3 /* UIImage+GIF.m in Sources */, + 11F7B05E1ED40AB300A9F224 /* ZXURIResultParser.m in Sources */, + 11F7B0F61ED40AB300A9F224 /* ZXQRCodeBitMatrixParser.m in Sources */, + 11F7B0C81ED40AB300A9F224 /* ZXCode39Writer.m in Sources */, + 11F7B0601ED40AB300A9F224 /* ZXVCardResultParser.m in Sources */, 1148291B1ECBDD6100BBCBF3 /* UIView+WebCache.m in Sources */, + 11F7B0BF1ED40AB300A9F224 /* ZXRSSDataCharacter.m in Sources */, + 11F7B0E41ED40AB300A9F224 /* ZXPDF417CodewordDecoder.m in Sources */, 11E3E99F1ECAA6F600D72EE1 /* MJRefreshBackStateFooter.m in Sources */, + 11F7B0411ED40AB300A9F224 /* ZXAztecWriter.m in Sources */, + 11F7B0B21ED40AB300A9F224 /* ZXRSSExpandedCurrentParsingState.m in Sources */, + 11F7B03B1ED40AB300A9F224 /* ZXAztecHighLevelEncoder.m in Sources */, + 11F7B0511ED40AB300A9F224 /* ZXISBNResultParser.m in Sources */, + 11F7AE441ED4043F00A9F224 /* LBXScanViewController.m in Sources */, + 11F7B0CB1ED40AB300A9F224 /* ZXEAN13Writer.m in Sources */, 119AB3051ED16FD7003DBF5A /* IQPreviousNextView.m in Sources */, + 11F7B0ED1ED40AB300A9F224 /* ZXPDF417BarcodeMatrix.m in Sources */, 11E3E9A61ECAA6F600D72EE1 /* UIScrollView+MJExtension.m in Sources */, + 11F7B0D21ED40AB300A9F224 /* ZXMultiFormatUPCEANReader.m in Sources */, + 11F7B0961ED40AB300A9F224 /* ZXDataMatrixEdifactEncoder.m in Sources */, + 11F7B0F31ED40AB300A9F224 /* ZXPDF417Reader.m in Sources */, + 11F7B0501ED40AB300A9F224 /* ZXISBNParsedResult.m in Sources */, + 11F7B0921ED40AB300A9F224 /* ZXDataMatrixASCIIEncoder.m in Sources */, 11E3E9A71ECAA6F600D72EE1 /* UIScrollView+MJRefresh.m in Sources */, + 11F7B0EB1ED40AB300A9F224 /* ZXPDF417DetectorResult.m in Sources */, + 11F7B1061ED40AB300A9F224 /* ZXQRCode.m in Sources */, + 11F7B0C01ED40AB300A9F224 /* ZXRSSFinderPattern.m in Sources */, + 11F7B0A11ED40AB300A9F224 /* ZXMaxiCodeDecodedBitStreamParser.m in Sources */, + 11F7B0D61ED40AB300A9F224 /* ZXUPCAWriter.m in Sources */, + 11F7B06C1ED40AB300A9F224 /* ZXGenericGF.m in Sources */, 119AB3031ED16FD7003DBF5A /* IQTextView.m in Sources */, 119AB2CF1ED16163003DBF5A /* ViewModelClass.m in Sources */, 11E3E99B1ECAA6F600D72EE1 /* MJRefreshAutoNormalFooter.m in Sources */, + 11F7B07D1ED40AB300A9F224 /* ZXPerspectiveTransform.m in Sources */, 114829191ECBDD6100BBCBF3 /* UIImageView+HighlightedWebCache.m in Sources */, + 11F7B06E1ED40AB300A9F224 /* ZXReedSolomonDecoder.m in Sources */, + 11F7B0FB1ED40AB300A9F224 /* ZXQRCodeDecoderMetaData.m in Sources */, 119AB2C21ED15E87003DBF5A /* UIActivityIndicatorView+AFNetworking.m in Sources */, 11E3E9651ECA9A3400D72EE1 /* SheetViewCell.m in Sources */, 1121C0361EC9C1300002D73C /* NSArray+MASAdditions.m in Sources */, 11E3E9951ECAA6F600D72EE1 /* MJRefreshAutoFooter.m in Sources */, + 11F7AE461ED4043F00A9F224 /* LBXScanWrapper.m in Sources */, + 11F7B0541ED40AB300A9F224 /* ZXProductResultParser.m in Sources */, + 11F7B07B1ED40AB300A9F224 /* ZXHybridBinarizer.m in Sources */, + 11F7B1111ED40AB400A9F224 /* ZXMultiFormatWriter.m in Sources */, + 11F7B0C11ED40AB300A9F224 /* ZXRSSPair.m in Sources */, 11E3E9FC1ECAC90D00D72EE1 /* NSString+Validate.m in Sources */, + 11F7B0401ED40AB300A9F224 /* ZXAztecReader.m in Sources */, + 11F7B07F1ED40AB300A9F224 /* ZXBinarizer.m in Sources */, 11E3E9A41ECAA6F600D72EE1 /* MJRefreshConst.m in Sources */, + 11F7B0F91ED40AB300A9F224 /* ZXQRCodeDecodedBitStreamParser.m in Sources */, + 11F7B0A21ED40AB300A9F224 /* ZXMaxiCodeDecoder.m in Sources */, + 11F7B0641ED40AB300A9F224 /* ZXWifiParsedResult.m in Sources */, + 11F7B0CA1ED40AB300A9F224 /* ZXEAN13Reader.m in Sources */, 119AB2FE1ED16FD7003DBF5A /* IQUIView+Hierarchy.m in Sources */, + 11F7AE421ED4043F00A9F224 /* LBXScanVideoZoomView.m in Sources */, + 11F7B0C21ED40AB300A9F224 /* ZXRSSUtils.m in Sources */, 11E3EA001ECAC90D00D72EE1 /* UIView+Common.m in Sources */, 114829111ECBDD6100BBCBF3 /* SDWebImageDownloader.m in Sources */, + 110B9BF71ED2B96200EC58DB /* PickDetailModel.m in Sources */, + 11F7B1141ED416C900A9F224 /* QRCodeResultVC.m in Sources */, + 11F7B05A1ED40AB300A9F224 /* ZXTelParsedResult.m in Sources */, 11E3E9F71ECAC90D00D72EE1 /* ColorUtil.m in Sources */, + 11F7B0FF1ED40AB300A9F224 /* ZXQRCodeVersion.m in Sources */, + 11F7B08C1ED40AB300A9F224 /* ZXDataMatrixBitMatrixParser.m in Sources */, 1148291A1ECBDD6100BBCBF3 /* UIImageView+WebCache.m in Sources */, + 11F7B0A51ED40AB300A9F224 /* ZXGenericMultipleBarcodeReader.m in Sources */, 11E3E9981ECAA6F600D72EE1 /* MJRefreshFooter.m in Sources */, + 11F7B1021ED40AB300A9F224 /* ZXQRCodeDetector.m in Sources */, 1121BFC81EC990BD0002D73C /* AppDelegate.m in Sources */, + 11F7B0D91ED40AB300A9F224 /* ZXUPCEANExtensionSupport.m in Sources */, + 11F7B1011ED40AB300A9F224 /* ZXQRCodeAlignmentPatternFinder.m in Sources */, + 11F7B0F41ED40AB300A9F224 /* ZXPDF417ResultMetadata.m in Sources */, + 11F7B1191ED4174D00A9F224 /* QRCodeResultView.m in Sources */, 11C243541ED022F1007F69C6 /* NSDate+Extension.m in Sources */, + 11F7B0B91ED40AB300A9F224 /* ZXBitArrayBuilder.m in Sources */, 11E3E9A11ECAA6F600D72EE1 /* MJRefreshNormalHeader.m in Sources */, + 11F7B03E1ED40AB300A9F224 /* ZXAztecToken.m in Sources */, + 11F7B10E1ED40AB400A9F224 /* ZXQRCodeReader.m in Sources */, 119AB2B91ED15E87003DBF5A /* AFHTTPSessionManager.m in Sources */, 1148290C1ECBDD6100BBCBF3 /* NSImage+WebCache.m in Sources */, 1121BFFF1EC995A40002D73C /* QRCNavigationController.m in Sources */, + 11F7B0B51ED40AB300A9F224 /* ZXRSSExpandedDecodedNumeric.m in Sources */, 1121BFC51EC990BD0002D73C /* main.m in Sources */, + 11F7B06F1ED40AB300A9F224 /* ZXReedSolomonEncoder.m in Sources */, + 11F7B0611ED40AB300A9F224 /* ZXVEventResultParser.m in Sources */, 1148290A1ECBDD6100BBCBF3 /* MKAnnotationView+WebCache.m in Sources */, 11C2435A1ED045C7007F69C6 /* PickDetailVc.m in Sources */, 11346AB61ECEE02D00BFDD69 /* PickAlert.m in Sources */, + 11F7B03C1ED40AB300A9F224 /* ZXAztecSimpleToken.m in Sources */, + 118E68FA1ED92C9900B62015 /* YQDiskCache.m in Sources */, + 11F7B0A71ED40AB300A9F224 /* ZXAI013103decoder.m in Sources */, + 11F7B05B1ED40AB300A9F224 /* ZXTelResultParser.m in Sources */, + 11F7B05C1ED40AB300A9F224 /* ZXTextParsedResult.m in Sources */, + 118E69071ED94DC900B62015 /* UserManager.m in Sources */, + 11F7B0B11ED40AB300A9F224 /* ZXRSSExpandedBlockParsedResult.m in Sources */, + 11F7B0E81ED40AB300A9F224 /* ZXPDF417DetectionResultRowIndicatorColumn.m in Sources */, + 110B9BEB1ED2908C00EC58DB /* PrereloadCellModel.m in Sources */, 11E3E9FD1ECAC90D00D72EE1 /* UIBarButtonItem+Item.m in Sources */, 119AB2BC1ED15E87003DBF5A /* AFURLRequestSerialization.m in Sources */, + 11F7B0491ED40AB300A9F224 /* ZXEmailAddressParsedResult.m in Sources */, + 11F7B09D1ED40AB300A9F224 /* ZXDataMatrixX12Encoder.m in Sources */, + 11F7B1041ED40AB300A9F224 /* ZXQRCodeFinderPatternFinder.m in Sources */, + 11F7B0941ED40AB300A9F224 /* ZXDataMatrixC40Encoder.m in Sources */, + 11F7B08D1ED40AB300A9F224 /* ZXDataMatrixDataBlock.m in Sources */, 1121C0351EC9C1300002D73C /* MASViewConstraint.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git "a/iDearQRCode/Assets.xcassets/@3x/btn_\346\267\273\345\212\240.imageset/Contents.json" b/iDearQRCode/Assets.xcassets/@3x/btn_addCell.imageset/Contents.json similarity index 100% rename from "iDearQRCode/Assets.xcassets/@3x/btn_\346\267\273\345\212\240.imageset/Contents.json" rename to iDearQRCode/Assets.xcassets/@3x/btn_addCell.imageset/Contents.json diff --git "a/iDearQRCode/Assets.xcassets/@3x/btn_\346\267\273\345\212\240.imageset/btn_\346\267\273\345\212\240@2x.png" "b/iDearQRCode/Assets.xcassets/@3x/btn_addCell.imageset/btn_\346\267\273\345\212\240@2x.png" similarity index 100% rename from "iDearQRCode/Assets.xcassets/@3x/btn_\346\267\273\345\212\240.imageset/btn_\346\267\273\345\212\240@2x.png" rename to "iDearQRCode/Assets.xcassets/@3x/btn_addCell.imageset/btn_\346\267\273\345\212\240@2x.png" diff --git "a/iDearQRCode/Assets.xcassets/@3x/btn_\346\267\273\345\212\240.imageset/btn_\346\267\273\345\212\240@3x.png" "b/iDearQRCode/Assets.xcassets/@3x/btn_addCell.imageset/btn_\346\267\273\345\212\240@3x.png" similarity index 100% rename from "iDearQRCode/Assets.xcassets/@3x/btn_\346\267\273\345\212\240.imageset/btn_\346\267\273\345\212\240@3x.png" rename to "iDearQRCode/Assets.xcassets/@3x/btn_addCell.imageset/btn_\346\267\273\345\212\240@3x.png" diff --git "a/iDearQRCode/Assets.xcassets/@3x/icon_\345\210\240\351\231\244(2).imageset/Contents.json" b/iDearQRCode/Assets.xcassets/@3x/icon_delete).imageset/Contents.json similarity index 100% rename from "iDearQRCode/Assets.xcassets/@3x/icon_\345\210\240\351\231\244(2).imageset/Contents.json" rename to iDearQRCode/Assets.xcassets/@3x/icon_delete).imageset/Contents.json diff --git "a/iDearQRCode/Assets.xcassets/@3x/icon_\345\210\240\351\231\244(2).imageset/icon_\345\210\240\351\231\244(2)@2x.png" "b/iDearQRCode/Assets.xcassets/@3x/icon_delete).imageset/icon_\345\210\240\351\231\244(2)@2x.png" similarity index 100% rename from "iDearQRCode/Assets.xcassets/@3x/icon_\345\210\240\351\231\244(2).imageset/icon_\345\210\240\351\231\244(2)@2x.png" rename to "iDearQRCode/Assets.xcassets/@3x/icon_delete).imageset/icon_\345\210\240\351\231\244(2)@2x.png" diff --git "a/iDearQRCode/Assets.xcassets/@3x/icon_\345\210\240\351\231\244(2).imageset/icon_\345\210\240\351\231\244(2)@3x.png" "b/iDearQRCode/Assets.xcassets/@3x/icon_delete).imageset/icon_\345\210\240\351\231\244(2)@3x.png" similarity index 100% rename from "iDearQRCode/Assets.xcassets/@3x/icon_\345\210\240\351\231\244(2).imageset/icon_\345\210\240\351\231\244(2)@3x.png" rename to "iDearQRCode/Assets.xcassets/@3x/icon_delete).imageset/icon_\345\210\240\351\231\244(2)@3x.png" diff --git a/iDearQRCode/BaseQRCode/BaseModel.h b/iDearQRCode/BaseQRCode/BaseModel.h new file mode 100644 index 0000000..b3ad960 --- /dev/null +++ b/iDearQRCode/BaseQRCode/BaseModel.h @@ -0,0 +1,22 @@ +// +// BaseModel.h +// iDearQRCode +// +// Created by Mortimer on 17/5/22. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import + +@interface BaseModel : NSObject + +@property (nonatomic , copy) NSString * URL; +@property (nonatomic , copy) NSString * name; +@property (nonatomic , copy) NSString * doSometing; +@property (nonatomic , copy) NSString * join_time; + +@property (nonatomic , assign) NSInteger count; +@property (nonatomic , assign) CGFloat height; +@property (nonatomic , copy) NSString * pickId; + +@end diff --git a/iDearQRCode/BaseQRCode/BaseModel.m b/iDearQRCode/BaseQRCode/BaseModel.m new file mode 100644 index 0000000..a0de010 --- /dev/null +++ b/iDearQRCode/BaseQRCode/BaseModel.m @@ -0,0 +1,13 @@ +// +// BaseModel.m +// iDearQRCode +// +// Created by Mortimer on 17/5/22. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import "BaseModel.h" + +@implementation BaseModel + +@end diff --git a/iDearQRCode/BaseQRCode/BaseTableViewCell.h b/iDearQRCode/BaseQRCode/BaseTableViewCell.h new file mode 100644 index 0000000..684ac20 --- /dev/null +++ b/iDearQRCode/BaseQRCode/BaseTableViewCell.h @@ -0,0 +1,23 @@ +// +// BaseTableViewCell.h +// iDearQRCode +// +// Created by Mortimer on 17/5/22. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import + +typedef enum { + selectCellNormal = 0, + selectCellDelete, + selectCellCombine, + selectCellError +} selectCellType; +@interface BaseTableViewCell : UITableViewCell + + + + + +@end diff --git a/iDearQRCode/BaseQRCode/BaseTableViewCell.m b/iDearQRCode/BaseQRCode/BaseTableViewCell.m new file mode 100644 index 0000000..db36496 --- /dev/null +++ b/iDearQRCode/BaseQRCode/BaseTableViewCell.m @@ -0,0 +1,43 @@ +// +// BaseTableViewCell.m +// iDearQRCode +// +// Created by Mortimer on 17/5/22. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import "BaseTableViewCell.h" + + +@implementation BaseTableViewCell + + +-(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{ + if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) { + self.backgroundColor = back_Color; + [self setupDefaultCell]; + } + return self; +} + +-(void)setupDefaultCell{ + +} + + + + + + +- (void)awakeFromNib { + [super awakeFromNib]; + // Initialization code +} + +- (void)setSelected:(BOOL)selected animated:(BOOL)animated { + [super setSelected:selected animated:animated]; + + // Configure the view for the selected state +} + +@end diff --git a/iDearQRCode/BaseQRCode/BaseViewController.h b/iDearQRCode/BaseQRCode/BaseViewController.h index 29b07dd..7169421 100644 --- a/iDearQRCode/BaseQRCode/BaseViewController.h +++ b/iDearQRCode/BaseQRCode/BaseViewController.h @@ -53,4 +53,10 @@ titleFont:(UIFont*)titleFont leftBarButtonItem:(UIBarButtonItem*)leftItem rightBarButtonItem:(UIBarButtonItem*)rightItem; + + +/** + 刷新ResultVC的数据 + */ +-(void)upResultViewData; @end diff --git a/iDearQRCode/BaseQRCode/BaseViewController.m b/iDearQRCode/BaseQRCode/BaseViewController.m index 3f3c9c1..a5201fe 100644 --- a/iDearQRCode/BaseQRCode/BaseViewController.m +++ b/iDearQRCode/BaseQRCode/BaseViewController.m @@ -7,11 +7,16 @@ // #import "BaseViewController.h" - -@interface BaseViewController () +#import "ResultDisplayController.h" +#import "UIScrollView+EmptyDataSet.h" +#import "PickDetailVc.h" +#import "PreloadDetailVC.h" +@interface BaseViewController () @property (nonatomic, assign) BOOL statusBarStyle; @property (nonatomic, assign) BOOL statusBarHidden; +@property (nonatomic , strong) ResultDisplayController * resultVC; + @end @implementation BaseViewController @@ -19,12 +24,17 @@ @implementation BaseViewController - (void)viewDidLoad { [super viewDidLoad]; - [self setIsExtendLayout:NO]; - - [self yd_removeNavgationBarLine]; -// [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent; + [self setIsExtendLayout:NO]; - self.view.backgroundColor = [UIColor colorWithHexString:@"#eff4f4"]; + [self yd_removeNavgationBarLine]; + + + if ([self isKindOfClass:NSClassFromString(@"PickingVC")] || [self isKindOfClass:NSClassFromString(@"PreloadViewController")]) { + [self setupSearchView]; + } + + + self.view.backgroundColor = [UIColor colorWithHexString:@"#eff4f4"]; // Do any additional setup after loading the view. } @@ -33,6 +43,47 @@ - (void)didReceiveMemoryWarning { // Dispose of any resources that can be recreated. } + +-(void)setupSearchView{ + ResultDisplayController * result = [[ResultDisplayController alloc] init]; + result.delegate = self; +// result.Classtitle = title; + _resultVC = result; + WeakObj(self); + result.upPickStatusStytle=^{ + __strong typeof(self) strongSelf = selfWeak; + [strongSelf changeStatusBarStyle:NO statusBarHidden:NO changeStatusBarAnimated:NO]; + }; + self.searchView = [[UISearchController alloc] initWithSearchResultsController:result]; + self.searchView.searchResultsUpdater = result; + result.datas = [self.dataSource mutableCopy]; + + self.searchView.hidesNavigationBarDuringPresentation = NO; + self.searchView.searchBar.placeholder = @"搜索"; + + self.searchView.searchBar.tintColor = text_Color1; + self.searchView.searchBar.barTintColor = [UIColor whiteColor]; + + UIView *searchTextField = nil; + + if (iOS7) { + searchTextField = [[[self.searchView.searchBar.subviews firstObject] subviews] lastObject]; + }else{ + for (UIView * subView in self.searchView.searchBar.subviews) { + if ([subView isKindOfClass:NSClassFromString(@"UISearchBarTextField")]) { + searchTextField = subView; + } + } + } + searchTextField.backgroundColor = back_Color; + +} + +-(void)upResultViewData{ + [_resultVC.datas removeAllObjects]; + _resultVC.datas = [self.dataSource mutableCopy]; +} + #pragma mark UITableViewDataSource - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section @@ -54,6 +105,13 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N } +-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{ + return 0.01; +} + +-(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{ + return 0.01; +} -(void)setupRightItem:(NSString *)title{ [self removeRightItem]; UIButton *rightBtn = [UIButton buttonWithType:UIButtonTypeCustom]; @@ -79,6 +137,42 @@ -(void)change{ } +#pragma mark ResultDisplayDelegate +-(void)didSelectRow:(NSIndexPath *)indexPath{ + + [self dismissViewControllerAnimated:NO completion:nil]; + if ([self isKindOfClass:NSClassFromString(@"PickingVC")] ) { + + PickDetailVc * detail = [[PickDetailVc alloc] init]; + [self.navigationController pushViewController:detail animated:YES]; + }else if ([self isKindOfClass:NSClassFromString(@"PreloadViewController")]){ + PreloadDetailVC * detail = [[PreloadDetailVC alloc] init]; + [self.navigationController pushViewController:detail animated:YES]; + } + +} + +#pragma mark DZNEmptyDataSetSource +//返回图片 +//-(UIImage *)imageForEmptyDataSet:(UIScrollView *)scrollView{ +// +//} +//返回标题文字 +-(NSAttributedString *)titleForEmptyDataSet:(UIScrollView *)scrollView{ + NSString *text = @"没有数据"; + NSDictionary *attribute = @{NSFontAttributeName: [UIFont systemFontOfSize:18.0], NSForegroundColorAttributeName: text_Color1}; + return [[NSAttributedString alloc] initWithString:text attributes:attribute]; +} +//空白区域点击事件 +-(void)emptyDataSet:(UIScrollView *)scrollView didTapView:(UIView *)view{ + +} + +-(UIColor *)backgroundColorForEmptyDataSet:(UIScrollView *)scrollView{ + + return back_Color; +} + #pragma mark - private /** * 去除nav 上的line @@ -193,7 +287,7 @@ - (void)layoutNavigationBar:(UIImage*)backGroundImage - (UITableView * )tableView{ if (!_tableView){ - _tableView = [[UITableView alloc] init]; + _tableView = [[UITableView alloc] init];//WithFrame:[UIScreen mainScreen].bounds style:UITableViewStyleGrouped _tableView.delegate = self; _tableView.dataSource = self; _tableView.tableFooterView = [UIView new]; @@ -201,6 +295,10 @@ - (UITableView * )tableView{ // self.tableView.separatorColor = [UIColor clearColor]; [_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:identifier]; _tableView.backgroundColor = [UIColor colorWithHexString:@"#eff4f4"]; + _tableView.emptyDataSetSource = self; + _tableView.emptyDataSetDelegate = self; +// self.tableView.sectionFooterHeight = 0.01f; + _tableView.showsVerticalScrollIndicator = NO; // 5.设置分割线样式 _tableView.separatorStyle = UITableViewCellSeparatorStyleNone; } @@ -228,6 +326,11 @@ - (BOOL)prefersStatusBarHidden { return self.statusBarHidden; } + +-(void)dealloc{ + _resultVC.delegate = nil; + NSLog(@"%@",[self class]); +} //-(UIStatusBarStyle)preferredStatusBarStyle{ // return UIStatusBarStyleLightContent; //} diff --git a/iDearQRCode/MainVC/QRCViewController.m b/iDearQRCode/MainVC/QRCViewController.m index f4c0034..d849a21 100644 --- a/iDearQRCode/MainVC/QRCViewController.m +++ b/iDearQRCode/MainVC/QRCViewController.m @@ -9,9 +9,10 @@ #import "QRCViewController.h" #import "SheetView.h" #import "personViewController.h" -#import "UIImage+Normalimage.h" +#import "UIImage+Common.h" #import "PickingVC.h" +#import "PreloadViewController.h" @interface QRCViewController () { UIView *_autoMarginViews; @@ -112,7 +113,9 @@ -(void)clickAction:(UIButton *)sender{ break; case 1: { - NSLog(@"1"); + PreloadViewController * preload = [[PreloadViewController alloc] init]; + [self.navigationController pushViewController:preload animated:YES]; + } break; case 2: diff --git a/iDearQRCode/Manager/NetManager/YQNetworking/Cache/YQCacheManager.h b/iDearQRCode/Manager/NetManager/YQNetworking/Cache/YQCacheManager.h new file mode 100755 index 0000000..e8a49ac --- /dev/null +++ b/iDearQRCode/Manager/NetManager/YQNetworking/Cache/YQCacheManager.h @@ -0,0 +1,107 @@ +// +// YQCacheManager.h +// YQNetworking +// +// Created by yingqiu huang on 2017/2/10. +// Copyright © 2017年 yingqiu huang. All rights reserved. +// + +#import + +@interface YQCacheManager : NSObject +/** + * 默认的磁盘空间是40MB,缓存有效期是7天 + * + * @return manager + */ ++ (YQCacheManager *)shareManager; + +/** + * 设置缓存时间和缓存的磁盘空间 + * + * @param time 缓存时间 + * @param capacity 磁盘空间 + */ +- (void)setCacheTime:(NSTimeInterval) time diskCapacity:(NSUInteger) capacity; + +/** + * 缓存响应数据 + * + * @param responseObject 响应数据 + * @param requestUrl 请求url + * @param params 请求参数 + */ +- (void)cacheResponseObject:(id)responseObject requestUrl:(NSString *)requestUrl params:(NSDictionary *)params; + +/** + * 获取响应数据 + * + * @param requestUrl 请求url + * @param params 请求参数 + * + * @return 响应数据 + */ +- (id)getCacheResponseObjectWithRequestUrl:(NSString *)requestUrl params:(NSDictionary *)params; + +/** + * 存储下载文件 + * + * @param data 文件数据 + * @param requestUrl 请求url + * + */ +- (void)storeDownloadData:(NSData *)data + requestUrl:(NSString *)requestUrl; + +/** + * 获取磁盘中的下载文件 + * + * @param requestUrl 请求url + * + * @return 文件本地存储路径 + */ +- (NSURL *)getDownloadDataFromCacheWithRequestUrl:(NSString *)requestUrl; + +/** + * 获取缓存目录路径 + * + * @return 缓存目录路径 + */ +- (NSString *)getCacheDiretoryPath; + +/** + * 获取下载目录路径 + * + * @return 下载目录路径 + */ +- (NSString *)getDownDirectoryPath; + +/** + * 获取缓存大小 + * + * @return 缓存大小 + */ +- (NSUInteger)totalCacheSize; + +/** + * 清除所有缓存 + */ +- (void)clearTotalCache; + +/** + * 清除最近最少使用的缓存,用LRU算法实现 + */ +- (void)clearLRUCache; + +/** + * 获取所有下载数据大小 + * + * @return 下载数据大小 + */ +- (NSUInteger)totalDownloadDataSize; + +/** + * 清除下载数据 + */ +- (void)clearDownloadData; +@end diff --git a/iDearQRCode/Manager/NetManager/YQNetworking/Cache/YQCacheManager.m b/iDearQRCode/Manager/NetManager/YQNetworking/Cache/YQCacheManager.m new file mode 100755 index 0000000..cc0443d --- /dev/null +++ b/iDearQRCode/Manager/NetManager/YQNetworking/Cache/YQCacheManager.m @@ -0,0 +1,241 @@ +// +// YQCacheManager.m +// YQNetworking +// +// Created by yingqiu huang on 2017/2/10. +// Copyright © 2017年 yingqiu huang. All rights reserved. +// + +#import "YQCacheManager.h" +#import "YQMemoryCache.h" +#import "YQDiskCache.h" +#import "YQLRUManager.h" +#import + +static NSString *const cacheDirKey = @"cacheDirKey"; + +static NSString *const downloadDirKey = @"downloadDirKey"; + +static NSUInteger diskCapacity = 40 * 1024 * 1024; + +static NSTimeInterval cacheTime = 7 * 24 * 60 * 60; + +@implementation YQCacheManager + ++ (YQCacheManager *)shareManager { + static YQCacheManager *_YQCacheManager = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _YQCacheManager = [[YQCacheManager alloc] init]; + }); + return _YQCacheManager; +} + +- (void)setCacheTime:(NSTimeInterval)time diskCapacity:(NSUInteger)capacity { + diskCapacity = capacity; + cacheTime = time; +} + +- (void)cacheResponseObject:(id)responseObject + requestUrl:(NSString *)requestUrl + params:(NSDictionary *)params { + assert(responseObject); + + assert(requestUrl); + + if (!params) params = @{}; + NSString *originString = [NSString stringWithFormat:@"%@%@",requestUrl,params]; + NSString *hash = [self md5:originString]; + + NSData *data = nil; + NSError *error = nil; + if ([responseObject isKindOfClass:[NSData class]]) { + data = responseObject; + }else if ([responseObject isKindOfClass:[NSDictionary class]]){ + data = [NSJSONSerialization dataWithJSONObject:responseObject options:NSJSONWritingPrettyPrinted error:&error]; + } + + if (error == nil) { + //缓存到内存中 + [YQMemoryCache writeData:responseObject forKey:hash]; + + //缓存到磁盘中 + //磁盘路径 + NSString *directoryPath = nil; + directoryPath = [[NSUserDefaults standardUserDefaults] objectForKey:cacheDirKey]; + if (!directoryPath) { + directoryPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:@"YQNetworking"] stringByAppendingPathComponent:@"networkCache"]; + [[NSUserDefaults standardUserDefaults] setObject:directoryPath forKey:cacheDirKey]; + [[NSUserDefaults standardUserDefaults] synchronize]; + } + [YQDiskCache writeData:data toDir:directoryPath filename:hash]; + + [[YQLRUManager shareManager] addFileNode:hash]; + } + +} + +- (id)getCacheResponseObjectWithRequestUrl:(NSString *)requestUrl + params:(NSDictionary *)params { + assert(requestUrl); + + id cacheData = nil; + + if (!params) params = @{}; + NSString *originString = [NSString stringWithFormat:@"%@%@",requestUrl,params]; + NSString *hash = [self md5:originString]; + + //先从内存中查找 + cacheData = [YQMemoryCache readDataWithKey:hash]; + + if (!cacheData) { + NSString *directoryPath = [[NSUserDefaults standardUserDefaults] objectForKey:cacheDirKey]; + + if (directoryPath) { + cacheData = [YQDiskCache readDataFromDir:directoryPath filename:hash]; + + if (cacheData) [[YQLRUManager shareManager] refreshIndexOfFileNode:hash]; + } + } + + return cacheData; +} + +- (void)storeDownloadData:(NSData *)data + requestUrl:(NSString *)requestUrl { + assert(data); + + assert(requestUrl); + + NSString *fileName = nil; + NSString *type = nil; + NSArray *strArray = nil; + + strArray = [requestUrl componentsSeparatedByString:@"."]; + if (strArray.count > 0) { + type = strArray[strArray.count - 1]; + } + + if (type) { + fileName = [NSString stringWithFormat:@"%@.%@",[self md5:requestUrl],type]; + }else { + fileName = [NSString stringWithFormat:@"%@",[self md5:requestUrl]]; + } + + NSString *directoryPath = nil; + directoryPath = [[NSUserDefaults standardUserDefaults] objectForKey:downloadDirKey]; + if (!directoryPath) { + directoryPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0] stringByAppendingPathComponent:@"YQNetworking"] stringByAppendingPathComponent:@"download"]; + + [[NSUserDefaults standardUserDefaults] setObject:directoryPath forKey:downloadDirKey]; + [[NSUserDefaults standardUserDefaults] synchronize]; + } + + + [YQDiskCache writeData:data toDir:directoryPath filename:fileName]; + +} + +- (NSURL *)getDownloadDataFromCacheWithRequestUrl:(NSString *)requestUrl { + assert(requestUrl); + + NSData *data = nil; + NSString *fileName = nil; + NSString *type = nil; + NSArray *strArray = nil; + NSURL *fileUrl = nil; + + + strArray = [requestUrl componentsSeparatedByString:@"."]; + if (strArray.count > 0) { + type = strArray[strArray.count - 1]; + } + + if (type) { + fileName = [NSString stringWithFormat:@"%@.%@",[self md5:requestUrl],type]; + }else { + fileName = [NSString stringWithFormat:@"%@",[self md5:requestUrl]]; + } + + + NSString *directoryPath = [[NSUserDefaults standardUserDefaults] objectForKey:downloadDirKey]; + + if (directoryPath) data = [YQDiskCache readDataFromDir:directoryPath filename:fileName]; + + if (data) { + NSString *path = [directoryPath stringByAppendingPathComponent:fileName]; + fileUrl = [NSURL fileURLWithPath:path]; + } + + return fileUrl; +} + +- (NSUInteger)totalCacheSize { + NSString *diretoryPath = [[NSUserDefaults standardUserDefaults] objectForKey: cacheDirKey]; + + return [YQDiskCache dataSizeInDir:diretoryPath]; +} + +- (NSUInteger)totalDownloadDataSize { + NSString *diretoryPath = [[NSUserDefaults standardUserDefaults] objectForKey: downloadDirKey]; + + return [YQDiskCache dataSizeInDir:diretoryPath]; +} + +- (void)clearDownloadData { + NSString *diretoryPath = [[NSUserDefaults standardUserDefaults] objectForKey:downloadDirKey]; + + [YQDiskCache clearDataIinDir:diretoryPath]; +} + +- (NSString *)getDownDirectoryPath { + NSString *diretoryPath = [[NSUserDefaults standardUserDefaults] objectForKey:downloadDirKey]; + return diretoryPath; +} + +- (NSString *)getCacheDiretoryPath { + NSString *diretoryPath = [[NSUserDefaults standardUserDefaults] objectForKey:cacheDirKey]; + return diretoryPath; +} + +- (void)clearTotalCache { + NSString *directoryPath = [[NSUserDefaults standardUserDefaults] objectForKey:cacheDirKey]; + + [YQDiskCache clearDataIinDir:directoryPath]; +} + +- (void)clearLRUCache { + if ([self totalCacheSize] > diskCapacity) { + NSArray *deleteFiles = [[YQLRUManager shareManager] removeLRUFileNodeWithCacheTime:cacheTime]; + NSString *directoryPath = [[NSUserDefaults standardUserDefaults] objectForKey:cacheDirKey]; + if (directoryPath && deleteFiles.count > 0) { + [deleteFiles enumerateObjectsUsingBlock:^(NSString *obj, NSUInteger idx, BOOL * _Nonnull stop) { + NSString *filePath = [directoryPath stringByAppendingPathComponent:obj]; + [YQDiskCache deleteCache:filePath]; + }]; + + } + } +} + +#pragma mark - 散列值 +- (NSString *)md5:(NSString *)string { + if (string == nil || string.length == 0) { + return nil; + } + + unsigned char digest[CC_MD5_DIGEST_LENGTH],i; + + CC_MD5([string UTF8String],(int)[string lengthOfBytesUsingEncoding:NSUTF8StringEncoding],digest); + + NSMutableString *ms = [NSMutableString string]; + + for (i = 0; i < CC_MD5_DIGEST_LENGTH; i++) { + [ms appendFormat:@"%02x",(int)(digest[i])]; + } + + return [ms copy]; +} + + +@end diff --git a/iDearQRCode/Manager/NetManager/YQNetworking/Cache/YQDiskCache.h b/iDearQRCode/Manager/NetManager/YQNetworking/Cache/YQDiskCache.h new file mode 100755 index 0000000..6e31ed0 --- /dev/null +++ b/iDearQRCode/Manager/NetManager/YQNetworking/Cache/YQDiskCache.h @@ -0,0 +1,57 @@ +// +// YQDiskCache.h +// YQNetworking +// +// Created by yingqiu huang on 2017/2/10. +// Copyright © 2017年 yingqiu huang. All rights reserved. +// + +#import + +@interface YQDiskCache : NSObject +/** + * 将数据写入磁盘 + * + * @param data 数据 + * @param directory 目录 + * @param filename 文件名 + */ ++ (void)writeData:(id)data + toDir:(NSString *)directory + filename:(NSString *)filename; + +/** + * 从磁盘读取数据 + * + * @param directory 目录 + * @param filename 文件名 + * + * @return 数据 + */ ++ (id)readDataFromDir:(NSString *)directory + filename:(NSString *)filename; + +/** + * 获取目录中文件总大小 + * + * @param directory 目录名 + * + * @return 文件总大小 + */ ++ (NSUInteger)dataSizeInDir:(NSString *)directory; + +/** + * 清理目录中的文件 + * + * @param directory 目录名 + */ ++ (void)clearDataIinDir:(NSString *)directory; + +/** + * 删除某文件 + * + * @param fileUrl 文件路径 + */ ++ (void)deleteCache:(NSString *)fileUrl; + +@end diff --git a/iDearQRCode/Manager/NetManager/YQNetworking/Cache/YQDiskCache.m b/iDearQRCode/Manager/NetManager/YQNetworking/Cache/YQDiskCache.m new file mode 100755 index 0000000..0511fc9 --- /dev/null +++ b/iDearQRCode/Manager/NetManager/YQNetworking/Cache/YQDiskCache.m @@ -0,0 +1,109 @@ +// +// YQDiskCache.m +// YQNetworking +// +// Created by yingqiu huang on 2017/2/10. +// Copyright © 2017年 yingqiu huang. All rights reserved. +// + +#import "YQDiskCache.h" + +@implementation YQDiskCache + ++ (void)writeData:(id)data + toDir:(NSString *)directory + filename:(NSString *)filename{ + assert(data); + + assert(directory); + + assert(filename); + + NSError *error = nil; + + if (![[NSFileManager defaultManager] fileExistsAtPath:directory isDirectory:nil]) { + [[NSFileManager defaultManager] createDirectoryAtPath:directory withIntermediateDirectories:YES attributes:nil error:&error]; + } + + if (error) { + NSLog(@"createDirectory error is %@",error.localizedDescription); + return; + } + + NSString *filePath = [directory stringByAppendingPathComponent:filename]; + + [[NSFileManager defaultManager] createFileAtPath:filePath contents:data attributes:nil]; + +} + ++ (id)readDataFromDir:(NSString *)directory + filename:(NSString *)filename { + assert(directory); + + assert(filename); + + NSData *data = nil; + + NSString *filePath = [directory stringByAppendingPathComponent:filename]; + + data = [[NSFileManager defaultManager] contentsAtPath:filePath]; + + return data; +} + ++ (NSUInteger)dataSizeInDir:(NSString *)directory { + + if (!directory) { + return 0; + } + + BOOL isDir = NO; + NSUInteger total = 0; + if ([[NSFileManager defaultManager] fileExistsAtPath:directory isDirectory:&isDir]) { + if (isDir) { + NSError *error = nil; + NSArray *array = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:directory error:&error]; + if (!error) { + for (NSString *subFile in array) { + NSString *filePath = [directory stringByAppendingPathComponent:subFile]; + NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:&error]; + + if (!error) { + total += [attributes[NSFileSize] unsignedIntegerValue]; + } + } + } + } + } + + return total; +} + ++ (void)clearDataIinDir:(NSString *)directory { + if (directory) { + if ([[NSFileManager defaultManager] fileExistsAtPath:directory isDirectory:nil]) { + NSError *error = nil; + [[NSFileManager defaultManager] removeItemAtPath:directory error:&error]; + if (error) { + NSLog(@"清理缓存是出现错误:%@",error.localizedDescription); + } + } + } +} + ++ (void)deleteCache:(NSString *)fileUrl { + if (fileUrl) { + if ([[NSFileManager defaultManager] fileExistsAtPath:fileUrl]) { + NSError *error = nil; + [[NSFileManager defaultManager] removeItemAtPath:fileUrl error:&error]; + if (error) { + NSLog(@"删除文件出现错误出现错误:%@",error.localizedDescription); + } + }else { + NSLog(@"不存在文件"); + } + } +} + + +@end diff --git a/iDearQRCode/Manager/NetManager/YQNetworking/Cache/YQLRUManager.h b/iDearQRCode/Manager/NetManager/YQNetworking/Cache/YQLRUManager.h new file mode 100755 index 0000000..46ad93e --- /dev/null +++ b/iDearQRCode/Manager/NetManager/YQNetworking/Cache/YQLRUManager.h @@ -0,0 +1,46 @@ +// +// YQLRUManager.h +// YQNetworking +// +// Created by yingqiu huang on 2017/2/10. +// Copyright © 2017年 yingqiu huang. All rights reserved. +// + +#import + +/** + * 最近最少使用淘汰算法,创建一个队列,新加的结点添加在队列的尾部;命中缓存时,调整结点的位置,将其放在队列的尾部;要淘汰缓存时,删除队列的头部节点 + */ +@interface YQLRUManager : NSObject + +/** + * 当前队列的情况 + */ +@property (nonatomic, copy, readonly)NSArray *currentQueue; + ++ (YQLRUManager *)shareManager; + +/** + * 添加新的结点 + * + * @param filename 文件名字 + */ +- (void)addFileNode:(NSString *)filename; + +/** + * 调整结点位置,一般用于命中缓存时 + * + * @param filename 文件名字 + */ +- (void)refreshIndexOfFileNode:(NSString *)filename; + +/** + * 删除最近最久未使用的缓存 + * + * @param time 缓存时间 + * + * @return 删除结点的文件名列表 + */ +- (NSArray *)removeLRUFileNodeWithCacheTime:(NSTimeInterval) time; + +@end diff --git a/iDearQRCode/Manager/NetManager/YQNetworking/Cache/YQLRUManager.m b/iDearQRCode/Manager/NetManager/YQNetworking/Cache/YQLRUManager.m new file mode 100755 index 0000000..2b97bea --- /dev/null +++ b/iDearQRCode/Manager/NetManager/YQNetworking/Cache/YQLRUManager.m @@ -0,0 +1,93 @@ +// +// YQLRUManager.m +// YQNetworking +// +// Created by yingqiu huang on 2017/2/10. +// Copyright © 2017年 yingqiu huang. All rights reserved. +// + +#import "YQLRUManager.h" + +static YQLRUManager *manager = nil; + +static NSMutableArray *operationQueue = nil; + +static NSString *const YQLRUManagerName = @"YQLRUManagerName"; + +@implementation YQLRUManager + ++ (YQLRUManager *)shareManager { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + manager = [[YQLRUManager alloc] init]; + if ([[NSUserDefaults standardUserDefaults] objectForKey:YQLRUManagerName]) { + operationQueue = [NSMutableArray arrayWithArray:(NSArray *)[[NSUserDefaults standardUserDefaults] objectForKey:YQLRUManagerName]]; + }else { + operationQueue = [NSMutableArray array]; + } + }); + return manager; +} +- (void)addFileNode:(NSString *)filename { + NSArray *array = [operationQueue copy]; + + //优化遍历 + NSArray *reverseArray = [[array reverseObjectEnumerator] allObjects]; + + [reverseArray enumerateObjectsUsingBlock:^(NSDictionary *obj, NSUInteger idx, BOOL * _Nonnull stop) { + if ([obj[@"fileName"] isEqualToString:filename]) { + [operationQueue removeObjectAtIndex:idx]; + *stop = YES; + } + + }]; + + NSDate *date = [NSDate date]; + + NSDictionary *newDic = @{@"fileName":filename,@"date":date}; + + [operationQueue addObject:newDic]; + + [[NSUserDefaults standardUserDefaults] setObject:[operationQueue copy] forKey:YQLRUManagerName]; + [[NSUserDefaults standardUserDefaults] synchronize]; +} + +- (void)refreshIndexOfFileNode:(NSString *)filename { + [self addFileNode:filename]; +} + +- (NSArray *)removeLRUFileNodeWithCacheTime:(NSTimeInterval)time { + NSMutableArray *result = [NSMutableArray array]; + + if (operationQueue.count > 0) { + + NSArray *tmpArray = [operationQueue copy]; + + [tmpArray enumerateObjectsUsingBlock:^(NSDictionary *obj, NSUInteger idx, BOOL * _Nonnull stop) { + NSDate *date = obj[@"date"]; + NSDate *newDate = [date dateByAddingTimeInterval:time]; + if ([[NSDate date] compare:newDate] == NSOrderedDescending) { + [result addObject:obj[@"fileName"]]; + [operationQueue removeObjectAtIndex:idx]; + } + }]; + + if (result.count == 0) { + NSString *removeFileName = [operationQueue firstObject][@"fileName"]; + [result addObject:removeFileName]; + [operationQueue removeObjectAtIndex:0]; + } + + [[NSUserDefaults standardUserDefaults] setObject:[operationQueue copy] forKey:YQLRUManagerName]; + [[NSUserDefaults standardUserDefaults] synchronize]; + } + return [result copy]; + +} + +- (NSArray *)currentQueue { + return [operationQueue copy]; +} + + +@end diff --git a/iDearQRCode/Manager/NetManager/YQNetworking/Cache/YQMemoryCache.h b/iDearQRCode/Manager/NetManager/YQNetworking/Cache/YQMemoryCache.h new file mode 100755 index 0000000..6c36afc --- /dev/null +++ b/iDearQRCode/Manager/NetManager/YQNetworking/Cache/YQMemoryCache.h @@ -0,0 +1,32 @@ +// +// YQMemoryCache.h +// YQNetworking +// +// Created by yingqiu huang on 2017/2/10. +// Copyright © 2017年 yingqiu huang. All rights reserved. +// + +#import + +/** + * 可拓展的内存缓存策略 + */ +@interface YQMemoryCache : NSObject +/** + * 将数据写入内存 + * + * @param data 数据 + * @param key 键值 + */ ++ (void)writeData:(id) data forKey:(NSString *)key; + +/** + * 从内存中读取数据 + * + * @param key 键值 + * + * @return 数据 + */ ++ (id)readDataWithKey:(NSString *)key; + +@end diff --git a/iDearQRCode/Manager/NetManager/YQNetworking/Cache/YQMemoryCache.m b/iDearQRCode/Manager/NetManager/YQNetworking/Cache/YQMemoryCache.m new file mode 100755 index 0000000..4fdc123 --- /dev/null +++ b/iDearQRCode/Manager/NetManager/YQNetworking/Cache/YQMemoryCache.m @@ -0,0 +1,59 @@ +// +// YQMemoryCache.m +// YQNetworking +// +// Created by yingqiu huang on 2017/2/10. +// Copyright © 2017年 yingqiu huang. All rights reserved. +// + +#import "YQMemoryCache.h" +#import + +static NSCache *shareCache; + +@implementation YQMemoryCache + ++ (NSCache *)shareCache { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + if (shareCache == nil) shareCache = [[NSCache alloc] init]; + }); + + //当收到内存警报时,清空内存缓存 + [[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidReceiveMemoryWarningNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) { + [shareCache removeAllObjects]; + }]; + + return shareCache; +} + ++ (void)writeData:(id)data forKey:(NSString *)key { + assert(data); + + assert(key); + + NSCache *cache = [YQMemoryCache shareCache]; + + [cache setObject:data forKey:key]; + +} + ++ (id)readDataWithKey:(NSString *)key { + assert(key); + + id data = nil; + + NSCache *cache = [YQMemoryCache shareCache]; + + data = [cache objectForKey:key]; + + + return data; +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; +} + + +@end diff --git a/iDearQRCode/Manager/NetManager/YQNetworking/RequestManager/YQNetworking+RequestManager.h b/iDearQRCode/Manager/NetManager/YQNetworking/RequestManager/YQNetworking+RequestManager.h new file mode 100755 index 0000000..0eca665 --- /dev/null +++ b/iDearQRCode/Manager/NetManager/YQNetworking/RequestManager/YQNetworking+RequestManager.h @@ -0,0 +1,30 @@ +// +// YQNetworking+RequestManager.h +// YQNetworking +// +// Created by yingqiu huang on 2017/2/10. +// Copyright © 2017年 yingqiu huang. All rights reserved. +// + +#import "YQNetworking.h" + +@interface YQNetworking (RequestManager) +/** + * 判断网络请求池中是否有相同的请求 + * + * @param task 网络请求任务 + * + * @return bool + */ ++ (BOOL)haveSameRequestInTasksPool:(YQURLSessionTask *)task; + +/** + * 如果有旧请求则取消旧请求 + * + * @param task 新请求 + * + * @return 旧请求 + */ ++ (YQURLSessionTask *)cancleSameRequestInTasksPool:(YQURLSessionTask *)task; + +@end diff --git a/iDearQRCode/Manager/NetManager/YQNetworking/RequestManager/YQNetworking+RequestManager.m b/iDearQRCode/Manager/NetManager/YQNetworking/RequestManager/YQNetworking+RequestManager.m new file mode 100755 index 0000000..35113ff --- /dev/null +++ b/iDearQRCode/Manager/NetManager/YQNetworking/RequestManager/YQNetworking+RequestManager.m @@ -0,0 +1,64 @@ +// +// YQNetworking+RequestManager.m +// YQNetworking +// +// Created by yingqiu huang on 2017/2/10. +// Copyright © 2017年 yingqiu huang. All rights reserved. +// + +#import "YQNetworking+RequestManager.h" + +@interface NSURLRequest (decide) + +//判断是否是同一个请求(依据是请求url和参数是否相同) +- (BOOL)isTheSameRequest:(NSURLRequest *)request; + +@end + +@implementation NSURLRequest (decide) + +- (BOOL)isTheSameRequest:(NSURLRequest *)request { + if ([self.HTTPMethod isEqualToString:request.HTTPMethod]) { + if ([self.URL.absoluteString isEqualToString:request.URL.absoluteString]) { + if ([self.HTTPMethod isEqualToString:@"GET"]||[self.HTTPBody isEqualToData:request.HTTPBody]) { + return YES; + } + } + } + return NO; +} + +@end + +@implementation YQNetworking (RequestManager) + ++ (BOOL)haveSameRequestInTasksPool:(YQURLSessionTask *)task { + __block BOOL isSame = NO; + [[self currentRunningTasks] enumerateObjectsUsingBlock:^(YQURLSessionTask *obj, NSUInteger idx, BOOL * _Nonnull stop) { + if ([task.originalRequest isTheSameRequest:obj.originalRequest]) { + isSame = YES; + *stop = YES; + } + }]; + return isSame; +} + ++ (YQURLSessionTask *)cancleSameRequestInTasksPool:(YQURLSessionTask *)task { + __block YQURLSessionTask *oldTask = nil; + + [[self currentRunningTasks] enumerateObjectsUsingBlock:^(YQURLSessionTask *obj, NSUInteger idx, BOOL * _Nonnull stop) { + if ([task.originalRequest isTheSameRequest:obj.originalRequest]) { + if (obj.state == NSURLSessionTaskStateRunning) { + [obj cancel]; + oldTask = obj; + } + *stop = YES; + } + }]; + + return oldTask; +} + + + +@end diff --git a/iDearQRCode/Manager/NetManager/YQNetworking/YQNetworking.h b/iDearQRCode/Manager/NetManager/YQNetworking/YQNetworking.h new file mode 100755 index 0000000..44052cf --- /dev/null +++ b/iDearQRCode/Manager/NetManager/YQNetworking/YQNetworking.h @@ -0,0 +1,285 @@ +// +// YQNetworking.h +// YQNetworking +// +// Created by yingqiu huang on 2017/2/10. +// Copyright © 2017年 yingqiu huang. All rights reserved. +// + +#import + +/** + * 网络状态 + */ +typedef NS_ENUM(NSInteger, YQNetworkStatus) { + /** + * 未知网络 + */ + YQNetworkStatusUnknown = 1 << 0, + /** + * 无法连接 + */ + YQNetworkStatusNotReachable = 1 << 1, + /** + * WWAN网络 + */ + YQNetworkStatusReachableViaWWAN = 1 << 2, + /** + * WiFi网络 + */ + YQNetworkStatusReachableViaWiFi = 1 << 3 +}; + +/** + * 请求任务 + */ +typedef NSURLSessionTask YQURLSessionTask; + +/** + * 成功回调 + * + * @param response 成功后返回的数据 + */ +typedef void(^YQResponseSuccessBlock)(id response); + +/** + * 失败回调 + * + * @param error 失败后返回的错误信息 + */ +typedef void(^YQResponseFailBlock)(NSError *error); + +/** + * 下载进度 + * + * @param bytesRead 已下载的大小 + * @param totalBytes 总下载大小 + */ +typedef void (^YQDownloadProgress)(int64_t bytesRead, +int64_t totalBytes); + +/** + * 下载成功回调 + * + * @param url 下载存放的路径 + */ +typedef void(^YQDownloadSuccessBlock)(NSURL *url); + + +/** + * 上传进度 + * + * @param bytesWritten 已上传的大小 + * @param totalBytes 总上传大小 + */ +typedef void(^YQUploadProgressBlock)(int64_t bytesWritten, +int64_t totalBytes); +/** + * 多文件上传成功回调 + * + * @param responses 成功后返回的数据 + */ +typedef void(^YQMultUploadSuccessBlock)(NSArray *responses); + +/** + * 多文件上传失败回调 + * + * @param errors 失败后返回的错误信息 + */ +typedef void(^YQMultUploadFailBlock)(NSArray *errors); + +typedef YQDownloadProgress YQGetProgress; + +typedef YQDownloadProgress YQPostProgress; + +typedef YQResponseFailBlock YQDownloadFailBlock; + +@interface YQNetworking : NSObject + +/** + * 正在运行的网络任务 + * + * @return task + */ ++ (NSArray *)currentRunningTasks; + + +/** + * 配置请求头 + * + * @param httpHeader 请求头 + */ ++ (void)configHttpHeader:(NSDictionary *)httpHeader; + +/** + * 取消GET请求 + */ ++ (void)cancelRequestWithURL:(NSString *)url; + +/** + * 取消所有请求 + */ ++ (void)cancleAllRequest; + +/** + * 设置超时时间 + * + * @param timeout 超时时间 + */ ++ (void)setupTimeout:(NSTimeInterval)timeout; + +/** + * GET请求 + * + * @param url 请求路径 + * @param cache 是否缓存 + * @param refresh 是否刷新请求(遇到重复请求,若为YES,则会取消旧的请求,用新的请求,若为NO,则忽略新请求,用旧请求) + * @param params 拼接参数 + * @param progressBlock 进度回调 + * @param successBlock 成功回调 + * @param failBlock 失败回调 + * + * @return 返回的对象中可取消请求 + */ ++ (YQURLSessionTask *)getWithUrl:(NSString *)url + refreshRequest:(BOOL)refresh + cache:(BOOL)cache + params:(NSDictionary *)params + progressBlock:(YQGetProgress)progressBlock + successBlock:(YQResponseSuccessBlock)successBlock + failBlock:(YQResponseFailBlock)failBlock; + + + + +/** + * POST请求 + * + * @param url 请求路径 + * @param cache 是否缓存 + * @param refresh 解释同上 + * @param params 拼接参数 + * @param progressBlock 进度回调 + * @param successBlock 成功回调 + * @param failBlock 失败回调 + * + * @return 返回的对象中可取消请求 + */ ++ (YQURLSessionTask *)postWithUrl:(NSString *)url + refreshRequest:(BOOL)refresh + cache:(BOOL)cache + params:(NSDictionary *)params + progressBlock:(YQPostProgress)progressBlock + successBlock:(YQResponseSuccessBlock)successBlock + failBlock:(YQResponseFailBlock)failBlock; + + + + +/** + * 文件上传 + * + * @param url 上传文件接口地址 + * @param data 上传文件数据 + * @param type 上传文件类型 + * @param name 上传文件服务器文件夹名 + * @param mimeType mimeType + * @param progressBlock 上传文件路径 + * @param successBlock 成功回调 + * @param failBlock 失败回调 + * + * @return 返回的对象中可取消请求 + */ ++ (YQURLSessionTask *)uploadFileWithUrl:(NSString *)url + fileData:(NSData *)data + type:(NSString *)type + name:(NSString *)name + mimeType:(NSString *)mimeType + progressBlock:(YQUploadProgressBlock)progressBlock + successBlock:(YQResponseSuccessBlock)successBlock + failBlock:(YQResponseFailBlock)failBlock; + + +/** + * 多文件上传 + * + * @param url 上传文件地址 + * @param datas 数据集合 + * @param type 类型 + * @param name 服务器文件夹名 + * @param mimeTypes mimeTypes + * @param progressBlock 上传进度 + * @param successBlock 成功回调 + * @param failBlock 失败回调 + * + * @return 任务集合 + */ ++ (NSArray *)uploadMultFileWithUrl:(NSString *)url + fileDatas:(NSArray *)datas + type:(NSString *)type + name:(NSString *)name + mimeType:(NSString *)mimeTypes + progressBlock:(YQUploadProgressBlock)progressBlock + successBlock:(YQMultUploadSuccessBlock)successBlock + failBlock:(YQMultUploadFailBlock)failBlock; + +/** + * 文件下载 + * + * @param url 下载文件接口地址 + * @param progressBlock 下载进度 + * @param successBlock 成功回调 + * @param failBlock 下载回调 + * + * @return 返回的对象可取消请求 + */ ++ (YQURLSessionTask *)downloadWithUrl:(NSString *)url + progressBlock:(YQDownloadProgress)progressBlock + successBlock:(YQDownloadSuccessBlock)successBlock + failBlock:(YQDownloadFailBlock)failBlock; + +@end + + + +@interface YQNetworking (cache) + +/** + * 获取缓存目录路径 + * + * @return 缓存目录路径 + */ ++ (NSString *)getCacheDiretoryPath; + +/** + * 获取下载目录路径 + * + * @return 下载目录路径 + */ ++ (NSString *)getDownDirectoryPath; + +/** + * 获取缓存大小 + * + * @return 缓存大小 + */ ++ (NSUInteger)totalCacheSize; + +/** + * 清除所有缓存 + */ ++ (void)clearTotalCache; + +/** + * 获取所有下载数据大小 + * + * @return 下载数据大小 + */ ++ (NSUInteger)totalDownloadDataSize; + +/** + * 清除下载数据 + */ ++ (void)clearDownloadData; + +@end diff --git a/iDearQRCode/Manager/NetManager/YQNetworking/YQNetworking.m b/iDearQRCode/Manager/NetManager/YQNetworking/YQNetworking.m new file mode 100755 index 0000000..417bb8b --- /dev/null +++ b/iDearQRCode/Manager/NetManager/YQNetworking/YQNetworking.m @@ -0,0 +1,483 @@ +// +// YQNetworking.m +// YQNetworking +// +// Created by yingqiu huang on 2017/2/10. +// Copyright © 2017年 yingqiu huang. All rights reserved. +// + +#import "YQNetworking.h" +#import "AFNetworking.h" +#import "AFNetworkActivityIndicatorManager.h" +#import "YQNetworking+RequestManager.h" +#import "YQCacheManager.h" + +#define YQ_ERROR_IMFORMATION @"网络出现错误,请检查网络连接" + +#define YQ_ERROR [NSError errorWithDomain:@"com.hyq.YQNetworking.ErrorDomain" code:-999 userInfo:@{ NSLocalizedDescriptionKey:YQ_ERROR_IMFORMATION}] + +static NSMutableArray *requestTasksPool; + +static NSDictionary *headers; + +static YQNetworkStatus networkStatus; + +static NSTimeInterval requestTimeout = 20.f; + +@implementation YQNetworking +#pragma mark - manager ++ (AFHTTPSessionManager *)manager { + [AFNetworkActivityIndicatorManager sharedManager].enabled = YES; + + AFHTTPSessionManager *manager = [AFHTTPSessionManager manager]; + + //默认解析模式 + manager.requestSerializer = [AFHTTPRequestSerializer serializer]; + manager.responseSerializer = [AFJSONResponseSerializer serializer]; + + //配置请求序列化 + AFJSONResponseSerializer *serializer = [AFJSONResponseSerializer serializer]; + + [serializer setRemovesKeysWithNullValues:YES]; + + manager.requestSerializer.stringEncoding = NSUTF8StringEncoding; + + manager.requestSerializer.timeoutInterval = requestTimeout; + + for (NSString *key in headers.allKeys) { + if (headers[key] != nil) { + [manager.requestSerializer setValue:headers[key] forHTTPHeaderField:key]; + } + } + + //配置响应序列化 + manager.responseSerializer.acceptableContentTypes = [NSSet setWithArray:@[@"application/json", + @"text/html", + @"text/json", + @"text/plain", + @"text/javascript", + @"text/xml", + @"image/*", + @"application/octet-stream", + @"application/zip"]]; + + [self checkNetworkStatus]; + + //每次网络请求的时候,检查此时磁盘中的缓存大小,阈值默认是40MB,如果超过阈值,则清理LRU缓存,同时也会清理过期缓存,缓存默认SSL是7天,磁盘缓存的大小和SSL的设置可以通过该方法[YQCacheManager shareManager] setCacheTime: diskCapacity:]设置 + [[YQCacheManager shareManager] clearLRUCache]; + + return manager; +} + +#pragma mark - 检查网络 ++ (void)checkNetworkStatus { + AFNetworkReachabilityManager *manager = [AFNetworkReachabilityManager sharedManager]; + + [manager startMonitoring]; + + [manager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) { + + switch (status) { + case AFNetworkReachabilityStatusNotReachable: + networkStatus = YQNetworkStatusNotReachable; + break; + case AFNetworkReachabilityStatusUnknown: + networkStatus = YQNetworkStatusUnknown; + break; + case AFNetworkReachabilityStatusReachableViaWWAN: + networkStatus = YQNetworkStatusReachableViaWWAN; + break; + case AFNetworkReachabilityStatusReachableViaWiFi: + networkStatus = YQNetworkStatusReachableViaWiFi; + break; + default: + networkStatus = YQNetworkStatusUnknown; + break; + } + + }]; +} + ++ (NSMutableArray *)allTasks { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + if (requestTasksPool == nil) requestTasksPool = [NSMutableArray array]; + }); + + return requestTasksPool; +} + +#pragma mark - get ++ (YQURLSessionTask *)getWithUrl:(NSString *)url + refreshRequest:(BOOL)refresh + cache:(BOOL)cache + params:(NSDictionary *)params + progressBlock:(YQGetProgress)progressBlock + successBlock:(YQResponseSuccessBlock)successBlock + failBlock:(YQResponseFailBlock)failBlock { + //将session拷贝到堆中,block内部才可以获取得到session + __block YQURLSessionTask *session = nil; + + AFHTTPSessionManager *manager = [self manager]; + + if (networkStatus == YQNetworkStatusNotReachable) { + if (failBlock) failBlock(YQ_ERROR); + return session; + } + + id responseObj = [[YQCacheManager shareManager] getCacheResponseObjectWithRequestUrl:url params:params]; + + if (responseObj && cache) { + if (successBlock) successBlock(responseObj); + } + + session = [manager GET:url + parameters:params + progress:^(NSProgress * _Nonnull downloadProgress) { + if (progressBlock) progressBlock(downloadProgress.completedUnitCount, + downloadProgress.totalUnitCount); + + } success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { + if (successBlock) successBlock(responseObject); + + if (cache) [[YQCacheManager shareManager] cacheResponseObject:responseObject requestUrl:url params:params]; + + [[self allTasks] removeObject:session]; + + } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { + if (failBlock) failBlock(error); + [[self allTasks] removeObject:session]; + + }]; + + if ([self haveSameRequestInTasksPool:session] && !refresh) { + //取消新请求 + [session cancel]; + return session; + }else { + //无论是否有旧请求,先执行取消旧请求,反正都需要刷新请求 + YQURLSessionTask *oldTask = [self cancleSameRequestInTasksPool:session]; + if (oldTask) [[self allTasks] removeObject:oldTask]; + if (session) [[self allTasks] addObject:session]; + [session resume]; + return session; + } +} + +#pragma mark - post ++ (YQURLSessionTask *)postWithUrl:(NSString *)url + refreshRequest:(BOOL)refresh + cache:(BOOL)cache + params:(NSDictionary *)params + progressBlock:(YQPostProgress)progressBlock + successBlock:(YQResponseSuccessBlock)successBlock + failBlock:(YQResponseFailBlock)failBlock { + __block YQURLSessionTask *session = nil; + + AFHTTPSessionManager *manager = [self manager]; + + if (networkStatus == YQNetworkStatusNotReachable) { + if (failBlock) failBlock(YQ_ERROR); + return session; + } + + id responseObj = [[YQCacheManager shareManager] getCacheResponseObjectWithRequestUrl:url params:params]; + + if (responseObj && cache) { + if (successBlock) successBlock(responseObj); + } + + session = [manager POST:url + parameters:params + progress:^(NSProgress * _Nonnull uploadProgress) { + if (progressBlock) progressBlock(uploadProgress.completedUnitCount, + uploadProgress.totalUnitCount); + + } success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { + if (successBlock) successBlock(responseObject); + + if (cache) [[YQCacheManager shareManager] cacheResponseObject:responseObject requestUrl:url params:params]; + + if ([[self allTasks] containsObject:session]) { + [[self allTasks] removeObject:session]; + } + + } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { + if (failBlock) failBlock(error); + [[self allTasks] removeObject:session]; + + }]; + + + if ([self haveSameRequestInTasksPool:session] && !refresh) { + [session cancel]; + return session; + }else { + YQURLSessionTask *oldTask = [self cancleSameRequestInTasksPool:session]; + if (oldTask) [[self allTasks] removeObject:oldTask]; + if (session) [[self allTasks] addObject:session]; + [session resume]; + return session; + } +} + +#pragma mark - 文件上传 ++ (YQURLSessionTask *)uploadFileWithUrl:(NSString *)url + fileData:(NSData *)data + type:(NSString *)type + name:(NSString *)name + mimeType:(NSString *)mimeType + progressBlock:(YQUploadProgressBlock)progressBlock + successBlock:(YQResponseSuccessBlock)successBlock + failBlock:(YQResponseFailBlock)failBlock { + __block YQURLSessionTask *session = nil; + + AFHTTPSessionManager *manager = [self manager]; + + if (networkStatus == YQNetworkStatusNotReachable) { + if (failBlock) failBlock(YQ_ERROR); + return session; + } + + session = [manager POST:url + parameters:nil + constructingBodyWithBlock:^(id _Nonnull formData) { + NSString *fileName = nil; + + NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; + formatter.dateFormat = @"yyyyMMddHHmmss"; + + NSString *day = [formatter stringFromDate:[NSDate date]]; + + fileName = [NSString stringWithFormat:@"%@.%@",day,type]; + + [formData appendPartWithFileData:data name:name fileName:fileName mimeType:mimeType]; + + } progress:^(NSProgress * _Nonnull uploadProgress) { + if (progressBlock) progressBlock (uploadProgress.completedUnitCount,uploadProgress.totalUnitCount); + + } success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { + if (successBlock) successBlock(responseObject); + [[self allTasks] removeObject:session]; + + } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { + if (failBlock) failBlock(error); + [[self allTasks] removeObject:session]; + + }]; + + + [session resume]; + + if (session) [[self allTasks] addObject:session]; + + return session; +} + +#pragma mark - 多文件上传 ++ (NSArray *)uploadMultFileWithUrl:(NSString *)url + fileDatas:(NSArray *)datas + type:(NSString *)type + name:(NSString *)name + mimeType:(NSString *)mimeTypes + progressBlock:(YQUploadProgressBlock)progressBlock + successBlock:(YQMultUploadSuccessBlock)successBlock + failBlock:(YQMultUploadFailBlock)failBlock { + + if (networkStatus == YQNetworkStatusNotReachable) { + if (failBlock) failBlock(@[YQ_ERROR]); + return nil; + } + + __block NSMutableArray *sessions = [NSMutableArray array]; + __block NSMutableArray *responses = [NSMutableArray array]; + __block NSMutableArray *failResponse = [NSMutableArray array]; + + dispatch_group_t uploadGroup = dispatch_group_create(); + + NSInteger count = datas.count; + for (int i = 0; i < count; i++) { + __block YQURLSessionTask *session = nil; + + dispatch_group_enter(uploadGroup); + + session = [self uploadFileWithUrl:url + fileData:datas[i] + type:type name:name + mimeType:mimeTypes + progressBlock:^(int64_t bytesWritten, int64_t totalBytes) { + if (progressBlock) progressBlock(bytesWritten, + totalBytes); + + } successBlock:^(id response) { + [responses addObject:response]; + + dispatch_group_leave(uploadGroup); + + [sessions removeObject:session]; + + } failBlock:^(NSError *error) { + NSError *Error = [NSError errorWithDomain:url code:-999 userInfo:@{NSLocalizedDescriptionKey:[NSString stringWithFormat:@"第%d次上传失败",i]}]; + + [failResponse addObject:Error]; + + dispatch_group_leave(uploadGroup); + + [sessions removeObject:session]; + }]; + + [session resume]; + + if (session) [sessions addObject:session]; + } + + [[self allTasks] addObjectsFromArray:sessions]; + + dispatch_group_notify(uploadGroup, dispatch_get_main_queue(), ^{ + if (responses.count > 0) { + if (successBlock) { + successBlock([responses copy]); + if (sessions.count > 0) { + [[self allTasks] removeObjectsInArray:sessions]; + } + } + } + + if (failResponse.count > 0) { + if (failBlock) { + failBlock([failResponse copy]); + if (sessions.count > 0) { + [[self allTasks] removeObjectsInArray:sessions]; + } + } + } + + }); + + return [sessions copy]; +} + +#pragma mark - 下载 ++ (YQURLSessionTask *)downloadWithUrl:(NSString *)url + progressBlock:(YQDownloadProgress)progressBlock + successBlock:(YQDownloadSuccessBlock)successBlock + failBlock:(YQDownloadFailBlock)failBlock { + NSString *type = nil; + NSArray *subStringArr = nil; + __block YQURLSessionTask *session = nil; + + NSURL *fileUrl = [[YQCacheManager shareManager] getDownloadDataFromCacheWithRequestUrl:url]; + + if (fileUrl) { + if (successBlock) successBlock(fileUrl); + return nil; + } + + if (url) { + subStringArr = [url componentsSeparatedByString:@"."]; + if (subStringArr.count > 0) { + type = subStringArr[subStringArr.count - 1]; + } + } + + AFHTTPSessionManager *manager = [self manager]; + //响应内容序列化为二进制 + manager.responseSerializer = [AFHTTPResponseSerializer serializer]; + + session = [manager GET:url + parameters:nil + progress:^(NSProgress * _Nonnull downloadProgress) { + if (progressBlock) progressBlock(downloadProgress.completedUnitCount, downloadProgress.totalUnitCount); + + } success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { + if (successBlock) { + NSData *dataObj = (NSData *)responseObject; + + [[YQCacheManager shareManager] storeDownloadData:dataObj requestUrl:url]; + + NSURL *downFileUrl = [[YQCacheManager shareManager] getDownloadDataFromCacheWithRequestUrl:url]; + + successBlock(downFileUrl); + } + + } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { + if (failBlock) { + failBlock (error); + } + }]; + + [session resume]; + + if (session) [[self allTasks] addObject:session]; + + return session; + +} + +#pragma mark - other method ++ (void)setupTimeout:(NSTimeInterval)timeout { + requestTimeout = timeout; +} + ++ (void)cancleAllRequest { + @synchronized (self) { + [[self allTasks] enumerateObjectsUsingBlock:^(YQURLSessionTask *_Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { + if ([obj isKindOfClass:[YQURLSessionTask class]]) { + [obj cancel]; + } + }]; + [[self allTasks] removeAllObjects]; + } +} + ++ (void)cancelRequestWithURL:(NSString *)url { + if (!url) return; + @synchronized (self) { + [[self allTasks] enumerateObjectsUsingBlock:^(YQURLSessionTask * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { + if ([obj isKindOfClass:[YQURLSessionTask class]]) { + if ([obj.currentRequest.URL.absoluteString hasSuffix:url]) { + [obj cancel]; + *stop = YES; + } + } + }]; + } +} + ++ (void)configHttpHeader:(NSDictionary *)httpHeader { + headers = httpHeader; +} + ++ (NSArray *)currentRunningTasks { + return [[self allTasks] copy]; +} + +@end + +@implementation YQNetworking (cache) ++ (NSUInteger)totalCacheSize { + return [[YQCacheManager shareManager] totalCacheSize]; +} + ++ (NSUInteger)totalDownloadDataSize { + return [[YQCacheManager shareManager] totalDownloadDataSize]; +} + ++ (void)clearDownloadData { + [[YQCacheManager shareManager] clearDownloadData]; +} + ++ (NSString *)getDownDirectoryPath { + return [[YQCacheManager shareManager] getDownDirectoryPath]; +} + ++ (NSString *)getCacheDiretoryPath { + + return [[YQCacheManager shareManager] getCacheDiretoryPath]; +} + ++ (void)clearTotalCache { + [[YQCacheManager shareManager] clearTotalCache]; +} + +@end diff --git a/iDearQRCode/Manager/UserManager/KeyManager.h b/iDearQRCode/Manager/UserManager/KeyManager.h new file mode 100644 index 0000000..f43d43e --- /dev/null +++ b/iDearQRCode/Manager/UserManager/KeyManager.h @@ -0,0 +1,19 @@ +// +// KeyManager.h +// iDearQRCode +// +// Created by Mortimer on 17/5/27. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import + +static NSString * const kKeyPassword = @"kPassword"; + +@interface KeyManager : NSObject + ++ (void)saveData:(NSString *)service data:(id)data; ++ (id)loadData:(NSString *)service; ++ (void)deleteData:(NSString *)service; + +@end diff --git a/iDearQRCode/Manager/UserManager/KeyManager.m b/iDearQRCode/Manager/UserManager/KeyManager.m new file mode 100644 index 0000000..7687410 --- /dev/null +++ b/iDearQRCode/Manager/UserManager/KeyManager.m @@ -0,0 +1,59 @@ +// +// KeyManager.m +// iDearQRCode +// +// Created by Mortimer on 17/5/27. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import "KeyManager.h" + +@implementation KeyManager + ++(void)deleteData:(NSString *)service{ + NSMutableDictionary *keychainQuery = [self getKeychainQuery:service]; + SecItemDelete((CFDictionaryRef)keychainQuery); +} + ++ (id)loadData:(NSString *)service { + id ret = nil; + NSMutableDictionary *keychainQuery = [self getKeychainQuery:service]; + //Configure the search setting + //Since in our simple case we are expecting only a single attribute to be returned (the password) we can set the attribute kSecReturnData to kCFBooleanTrue + [keychainQuery setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData]; + [keychainQuery setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit]; + CFDataRef keyData = NULL; + if (SecItemCopyMatching((CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr) { + @try { + ret = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge NSData *)keyData]; + } @catch (NSException *e) { + NSLog(@"Unarchive of %@ failed: %@", service, e); + } @finally { + } + } + if (keyData) + CFRelease(keyData); + return ret; +} + ++ (void)saveData:(NSString *)service data:(id)data { + //Get search dictionary + NSMutableDictionary *keychainQuery = [self getKeychainQuery:service]; + //Delete old item before add new item + SecItemDelete((CFDictionaryRef)keychainQuery); + //Add new object to search dictionary(Attention:the data format) + [keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(id)kSecValueData]; + //Add item to keychain with the search dictionary + SecItemAdd((CFDictionaryRef)keychainQuery, NULL); +} + ++ (NSMutableDictionary *)getKeychainQuery:(NSString *)service { + return [NSMutableDictionary dictionaryWithObjectsAndKeys: + (id)kSecClassGenericPassword,(id)kSecClass, + service, (id)kSecAttrService, + service, (id)kSecAttrAccount, + (id)kSecAttrAccessibleAfterFirstUnlock,(id)kSecAttrAccessible, + nil]; +} + +@end diff --git a/iDearQRCode/Manager/UserManager/UserManager.h b/iDearQRCode/Manager/UserManager/UserManager.h new file mode 100644 index 0000000..2d48fd2 --- /dev/null +++ b/iDearQRCode/Manager/UserManager/UserManager.h @@ -0,0 +1,33 @@ +// +// UserManager.h +// iDearQRCode +// +// Created by Mortimer on 17/5/27. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import +@class UserModel; +@interface UserManager : NSObject + ++ (instancetype)sharedInstance; + ++ (BOOL)isLogin; + ++ (void)saveLocalUserLoginInfo; + ++ (void)removeLocalUserLoginInfo; + + + +-(void)updatePassword:(NSString *)password; + +@property (nonatomic , strong) UserModel * userData; + +@property (nonatomic , copy) NSString * password; +@property (nonatomic , copy) NSString * userId; +@property (nonatomic , copy) NSString * avater; +@property (nonatomic , copy) NSString * username; + + +@end diff --git a/iDearQRCode/Manager/UserManager/UserManager.m b/iDearQRCode/Manager/UserManager/UserManager.m new file mode 100644 index 0000000..0e7602c --- /dev/null +++ b/iDearQRCode/Manager/UserManager/UserManager.m @@ -0,0 +1,76 @@ +// +// UserManager.m +// iDearQRCode +// +// Created by Mortimer on 17/5/27. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import "UserManager.h" +#import "UserModel.h" +#import "KeyManager.h" +#define USER_Data @"User_Data" +@implementation UserManager + + ++(instancetype)sharedInstance{ + static UserManager * sharedInstance; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[self alloc] init]; + }); + return sharedInstance; +} + + +-(instancetype)init{ + if (self = [super init]) { + NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; + _userData = [NSKeyedUnarchiver unarchiveObjectWithData:[userDefaults objectForKey:USER_Data]]; + _userId = _userData.userId; + _username = _userData.username; + _avater = _userData.avatar; + } + return self; +} + + +-(void)updatePassword:(NSString *)password{ + if (!password.length) { + return; + } + + [KeyManager saveData:kKeyPassword data:password]; +} + ++(void)saveLocalUserLoginInfo{ + NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; + NSData *data = [NSKeyedArchiver archivedDataWithRootObject:[UserManager sharedInstance].userData]; + [userDefaults setObject:data forKey:USER_Data]; + [userDefaults synchronize]; +} + ++ (void)removeLocalUserLoginInfo { + NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; + [userDefaults removeObjectForKey:USER_Data]; + [userDefaults synchronize]; +} + +-(UserModel *)loadLocalUserLoginInfo { + NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; + return [NSKeyedUnarchiver unarchiveObjectWithData:[userDefaults objectForKey:USER_Data]]; +} + ++(BOOL)isLogin{ + return [UserManager sharedInstance].userData.userId.length > 0; +} + +- (NSString *)password { + return safeString([KeyManager loadData:kKeyPassword]); +} + +NSString* safeString(id obj) { + return [obj isKindOfClass:[NSObject class]]?[NSString stringWithFormat:@"%@",obj]:@""; +} + +@end diff --git a/iDearQRCode/Manager/UserManager/UserModel/UserModel.h b/iDearQRCode/Manager/UserManager/UserModel/UserModel.h new file mode 100644 index 0000000..a7cb068 --- /dev/null +++ b/iDearQRCode/Manager/UserManager/UserModel/UserModel.h @@ -0,0 +1,20 @@ +// +// UserModel.h +// iDearQRCode +// +// Created by Mortimer on 17/5/27. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import + +@interface UserModel : NSObject + +@property (nonatomic , copy) NSString * username; +@property (nonatomic , copy) NSString * password; +@property (nonatomic , copy) NSString * userId; +@property (nonatomic , copy) NSString * avatar; //头像 +@property (nonatomic , copy) NSString * creattime; +@property (nonatomic , copy) NSString * nickname; + +@end diff --git a/iDearQRCode/Manager/UserManager/UserModel/UserModel.m b/iDearQRCode/Manager/UserManager/UserModel/UserModel.m new file mode 100644 index 0000000..cb1f34b --- /dev/null +++ b/iDearQRCode/Manager/UserManager/UserModel/UserModel.m @@ -0,0 +1,46 @@ +// +// UserModel.m +// iDearQRCode +// +// Created by Mortimer on 17/5/27. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import "UserModel.h" +#import "YYModel.h" +@implementation UserModel + +-(id)copyWithZone:(NSZone *)zone{ + return [self yy_modelCopy]; +} + +-(instancetype)init{ + if (self = [super init]) { + _username = @""; + _password = @""; + + _userId = @""; + _avatar = @""; + _creattime = @""; + _nickname = @""; + } + return self; +} + ++(NSDictionary *)modelCustomPropertyMapper { + return @{@"userId" : @"id"}; +} + +-(void)encodeWithCoder:(NSCoder *)aCoder{ + [self yy_modelEncodeWithCoder:aCoder]; +} + +-(instancetype)initWithCoder:(NSCoder *)aDecoder{ + if (self = [super init]) { + [self yy_modelInitWithCoder:aDecoder]; + } + + return self; +} + +@end diff --git a/iDearQRCode/Me/View/PersonHeadView.h b/iDearQRCode/Me/View/PersonHeadView.h index db3ec62..01c4ce9 100644 --- a/iDearQRCode/Me/View/PersonHeadView.h +++ b/iDearQRCode/Me/View/PersonHeadView.h @@ -7,11 +7,9 @@ // #import - +@class UserModel; @interface PersonHeadView : UIView -@property (nonatomic , copy) NSString * URL; -@property (nonatomic , copy) NSString * name; -@property (nonatomic , copy) NSString * doing; +@property (nonatomic , strong) UserModel * userModel; @end diff --git a/iDearQRCode/Me/View/PersonHeadView.m b/iDearQRCode/Me/View/PersonHeadView.m index 261e115..dcc4bc7 100644 --- a/iDearQRCode/Me/View/PersonHeadView.m +++ b/iDearQRCode/Me/View/PersonHeadView.m @@ -7,6 +7,7 @@ // #import "PersonHeadView.h" +#import "UserModel.h" @interface PersonHeadView () @property (nonatomic , strong) UIImageView * backView; @@ -47,20 +48,14 @@ -(void)setupHeadUI{ [self.backView addSubview:_do_label]; } --(void)setName:(NSString *)name{ - _name = name; - _name_label.text = name; -} --(void)setURL:(NSString *)URL{ - _URL = URL; - [_headView sd_setImageWithURL:[NSURL URLWithString:URL] placeholderImage:[UIImage imageNamed:@""]]; +-(void)setUserModel:(UserModel *)userModel{ + _userModel = userModel; + _name_label.text = userModel.username; + [_headView sd_setImageWithURL:[NSURL URLWithString:userModel.avatar] placeholderImage:[UIImage imageNamed:@""]]; + _do_label.text = userModel.userId; } --(void)setDoing:(NSString *)doing{ - _doing = doing; - _do_label.text = doing; -} -(void)layoutSubviews{ [super layoutSubviews]; diff --git a/iDearQRCode/Me/personViewController.m b/iDearQRCode/Me/personViewController.m index 28fed4f..26b28eb 100644 --- a/iDearQRCode/Me/personViewController.m +++ b/iDearQRCode/Me/personViewController.m @@ -11,11 +11,17 @@ #import "PersonHeadView.h" #import "AlertManager.h" #import "UIView+Toast.h" - +#import "UserManager.h" +#import "UserModel.h" @interface personViewController () { UIView * alphaView; + CGFloat _alpha; } + +@property (nonatomic , strong) UITableView * personView; +//@property (nonatomic , strong) UserModel * user; + @end @implementation personViewController @@ -28,16 +34,15 @@ - (void)viewDidLoad { [self setupRightItem:@"更换头像"]; [self setupTableView]; +// self.user = [UserManager sharedInstance].userData; + } -(void)setupTableView{ - [self.view addSubview:self.tableView]; - [self.tableView mas_makeConstraints:^(MASConstraintMaker *make) { + [self.view addSubview:self.personView]; + [self.personView mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(self.view).with.insets(UIEdgeInsetsMake(-64, 0, 0, 0)); }]; -// self.tableView.sd_layout.topSpaceToView(self.view,-64).leftEqualToView(self.view).rightEqualToView(self.view).bottomEqualToView(self.view); - self.tableView.sectionFooterHeight = 0.01f; - self.tableView.scrollEnabled = NO; self.dataSource = [NSMutableArray arrayWithArray:@[@[@"部门",@"职位",@"入职时间"],@[@"生产二部",@"组长",@"2014-06-12"]]]; } @@ -68,8 +73,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N -(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{ PersonHeadView * head = [[PersonHeadView alloc] initWithFrame:CGRectMake(0, 0, kScreen_width, 300)]; head.backgroundColor = [UIColor grayColor]; - head.name = @"Mortimer"; - head.doing = @"Martin"; + head.userModel = [UserManager sharedInstance].userData; return head; } @@ -211,6 +215,33 @@ -(void)imagePickerControllerDidCancel:(UIImagePickerController *)picker // } // } //} + + +-(void)scrollViewDidScroll:(UIScrollView *)scrollView +{ + CGFloat offsetY = scrollView.contentOffset.y; + _alpha = offsetY / 90 < 1 ? offsetY / 90 : 1; + [self.navigationController.navigationBar.subviews[0] setAlpha:_alpha]; +} + + +- (UITableView * )personView{ + if (!_personView){ + _personView = [[UITableView alloc] initWithFrame:[UIScreen mainScreen].bounds style:UITableViewStyleGrouped]; + _personView.delegate = self; + _personView.dataSource = self; + _personView.tableFooterView = [UIView new]; + + _personView.backgroundColor = [UIColor colorWithHexString:@"#eff4f4"]; + + _personView.showsVerticalScrollIndicator = NO; + // 5.设置分割线样式 + _personView.separatorStyle = UITableViewCellSeparatorStyleNone; + } + + return _personView; + +} /* #pragma mark - Navigation diff --git a/iDearQRCode/OtherVC/Controller/PickDetailVc.m b/iDearQRCode/OtherVC/Controller/PickDetailVc.m index 9a7055f..061b4db 100644 --- a/iDearQRCode/OtherVC/Controller/PickDetailVc.m +++ b/iDearQRCode/OtherVC/Controller/PickDetailVc.m @@ -7,18 +7,210 @@ // #import "PickDetailVc.h" +#import "PickDetailView.h" +#import "PickDetailFootView.h" +#import "QRCodeVC.h" +@interface PickDetailVc () + +@property (nonatomic , strong) PickDetailView * DetailView; +@property (nonatomic , strong) PickDetailFootView * DetailFootView; + + +@property (nonatomic , assign) CGFloat Headheigit;//headView高度 +@property (nonatomic , assign) CGFloat FootHeight; -@interface PickDetailVc () @end @implementation PickDetailVc - + static NSString * identifier = @"UITableViewCell" ; - (void)viewDidLoad { [super viewDidLoad]; + + self.title = @"领料"; + + [self setupRightItem:@"添加"]; + + [self setupDetailView]; + + [self loadDetailData]; + // Do any additional setup after loading the view. } + +-(void)setupDetailView{ + [self.view addSubview:self.tableView]; + [self.tableView mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.top.right.bottom.equalTo(self.view); + }]; +} + +-(void)loadDetailData{ + + NSArray *namesArray = @[@"老板", + @"经理", + @"总裁", + @"董事长", + @"其他"]; + + NSArray *textArray = @[@"生产一组", + @"生产二组", + @"生产三组", + @"生产四组", + @"生产五组" + ]; + + NSArray *commentsArray = @[@"2017-12-21", + @"2017-2-7", + @"2017-12-00", + @"2017-11-00", + @"2017-12-04", + @"2017-7-14", + @"2017-2-05"]; + + NSArray *picImageNamesArray = @[ @"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1495084429317&di=8bf661af0e01924831b035e439500bd6&imgtype=0&src=http%3A%2F%2Ffile06.16sucai.com%2F2016%2F0303%2F7d4ddedc06495605d726459772423d3b.jpg", + @"http://file06.16sucai.com/2016/0303/567565d0e78a7e51b6c38f07e7be06ac.jpg", + @"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1495084429317&di=8bf661af0e01924831b035e439500bd6&imgtype=0&src=http%3A%2F%2Ffile06.16sucai.com%2F2016%2F0303%2F7d4ddedc06495605d726459772423d3b.jpg", + @"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1495084431319&di=6ee6bcce85550898fa42c8e86ace9f79&imgtype=0&src=http%3A%2F%2Ffile06.16sucai.com%2F2016%2F0303%2F6b7f7a3c5ccbe9900094add1d8b5cbc8.jpg", + @"http://file06.16sucai.com/2016/0303/3d9ef7096c8c540064f6c4eb8877a929.jpg", + @"https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=3219125739,1362099777&fm=23&gp=0.jpg" + + ]; + + + NSArray * Array1 = @[@"滤水器内芯(110224244)", + @"滤水器内芯 (33325523434)", + @"滤水器外壳 (33325523434)", + @"滤水器塑胶管 (33325523434)"]; + + NSArray * Array2 = @[@"30000", + @"60000", + @"888", + @"666"]; + + NSArray * Array3 = @[@"领料时间:2017-12-21", + @"领料时间:2017-2-7", + @"领料时间:2017-12-00", + @"领料时间:2017-11-00"]; + + + int count = arc4random_uniform(4); + if (count == 0) { + count = 1; + } + + + self.Headheigit = 20; + self.FootHeight = 30; + for (int i = 0; i +#import "MJRefresh.h" +#import "AFNetworking.h" +@interface PickingVC () @property (nonatomic , assign) UPViewtype type; @property (nonatomic , strong) PickingHeadView * pickHead; @@ -30,6 +31,7 @@ @interface PickingVC ()0) { - PickAlert * alert = [[PickAlert alloc] initWithPickTitle:[NSString stringWithFormat:@"是否确定删除这%ld项",self.selectArray.count] AlertAction:@[@"取消",@"确定"] Complete:^(NSInteger index) { - if (index == 1) { +-(void)setupPickFootView{ + PickingFootView * pickFoot = [[PickingFootView alloc] initWithFrame:CGRectMake(0, kScreen_height, kScreen_width, 60)]; + pickFoot.delegate = self; + [self.view addSubview:pickFoot]; + _pickFoot = pickFoot; +} +#pragma mark PickingFootViewDelegate + +-(void)didHandelAction:(PickModelType)type{ + + switch (type) { + case PickModelNormal: + { + [self.selectArray removeAllObjects]; + [self setCellState:selectCellNormal]; + [self.tableView reloadData]; + } + break; + case PickModelDelete: + { + if (self.selectArray.count>0) { + PickAlert * alert = [[PickAlert alloc] initWithPickTitle:[NSString stringWithFormat:@"是否确定删除这%ld项",self.selectArray.count] AlertAction:@[@"取消",@"确定"] Complete:^(NSInteger index) { + if (index == 1) { - for (int j = 0; j 0) { - PickAlert * alert = [[PickAlert alloc] initWithPickTitle:self.dataSource.count == self.selectArray.count ? [NSString stringWithFormat:@"是否确定合并全部%ld项",self.selectArray.count] : [NSString stringWithFormat:@"是否确定合并这%ld项",self.selectArray.count] AlertAction:@[@"取消",@"确定"] Complete:^(NSInteger index) { - if (index == 1) { - - - for (int j = 0; j 0) { + PickAlert * alert = [[PickAlert alloc] initWithPickTitle:self.dataSource.count == self.selectArray.count ? [NSString stringWithFormat:@"是否确定合并全部%ld项",self.selectArray.count] : [NSString stringWithFormat:@"是否确定合并这%ld项",self.selectArray.count] AlertAction:@[@"取消",@"确定"] Complete:^(NSInteger index) { + if (index == 1) { + + + for (int j = 0; j + +@protocol ResultDisplayControllerDelegate + +@optional +-(void)didSelectRow:(NSIndexPath *)indexPath; + +@end @interface ResultDisplayController : UITableViewController + +@property (nonatomic , weak) id delegate; + + @property (nonatomic , strong) NSMutableArray * datas; @property (nonatomic , copy) void(^upPickStatusStytle)(void); +@property (nonatomic , copy) NSString * Classtitle; @end diff --git a/iDearQRCode/OtherVC/Controller/ResultDisplayController.m b/iDearQRCode/OtherVC/Controller/ResultDisplayController.m index e8f1602..081caa1 100644 --- a/iDearQRCode/OtherVC/Controller/ResultDisplayController.m +++ b/iDearQRCode/OtherVC/Controller/ResultDisplayController.m @@ -9,6 +9,8 @@ #import "ResultDisplayController.h" #import "PickingCell.h" #import "PickingModel.h" +//#import "PickDetailVc.h" +//#import "PreloadDetailVC.h" @interface ResultDisplayController () @property (nonatomic , strong) NSMutableArray * results; @property (nonatomic , assign) BOOL tableViewStatusStytle; @@ -64,7 +66,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N cell.pickModel = self.results[indexPath.row]; - cell.isLastCell = self.results.count - 1 == indexPath.row ? YES : NO; +// cell.isLastCell = self.results.count - 1 == indexPath.row ? YES : NO; return cell; } @@ -79,6 +81,17 @@ -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPat return pick.height; } + +-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ + + if ([_delegate respondsToSelector:@selector(didSelectRow:)]) { + + [_delegate didSelectRow:indexPath]; + } + + +} + #pragma mark UISearchResultsUpdating -(void)updateSearchResultsForSearchController:(UISearchController *)searchController{ diff --git a/iDearQRCode/OtherVC/Model/PickDetailModel.h b/iDearQRCode/OtherVC/Model/PickDetailModel.h new file mode 100644 index 0000000..e4e74dd --- /dev/null +++ b/iDearQRCode/OtherVC/Model/PickDetailModel.h @@ -0,0 +1,13 @@ +// +// PickDetailModel.h +// iDearQRCode +// +// Created by Mortimer on 17/5/22. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import "BaseModel.h" + +@interface PickDetailModel : BaseModel + +@end diff --git a/iDearQRCode/OtherVC/Model/PickDetailModel.m b/iDearQRCode/OtherVC/Model/PickDetailModel.m new file mode 100644 index 0000000..3684ca5 --- /dev/null +++ b/iDearQRCode/OtherVC/Model/PickDetailModel.m @@ -0,0 +1,13 @@ +// +// PickDetailModel.m +// iDearQRCode +// +// Created by Mortimer on 17/5/22. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import "PickDetailModel.h" + +@implementation PickDetailModel + +@end diff --git a/iDearQRCode/OtherVC/Model/PickingViewModel.h b/iDearQRCode/OtherVC/Model/PickingViewModel.h index a1bbe58..f76b742 100644 --- a/iDearQRCode/OtherVC/Model/PickingViewModel.h +++ b/iDearQRCode/OtherVC/Model/PickingViewModel.h @@ -8,10 +8,18 @@ #import "ViewModelClass.h" + +/** 刷新控件的状态 */ +typedef NS_ENUM(NSInteger, PickingRefreshState) { + /** 普通闲置状态 */ + PickingHeadRefresh = 1, + /** 松开就可以进行刷新的状态 */ + PickingFootRefresh +}; @interface PickingViewModel : ViewModelClass // 获取商品列表 -- (void)fetchPickingList; +- (void)fetchPickingList:(NSInteger)page; // 跳转到商品详情页 - (void)pushDetailWithVC:(UIViewController *)vc didSelectRowAtPickId:(NSString *)pickId; diff --git a/iDearQRCode/OtherVC/Model/PickingViewModel.m b/iDearQRCode/OtherVC/Model/PickingViewModel.m index 59eae69..d1d6a35 100644 --- a/iDearQRCode/OtherVC/Model/PickingViewModel.m +++ b/iDearQRCode/OtherVC/Model/PickingViewModel.m @@ -7,23 +7,27 @@ // #import "PickingViewModel.h" -#import "RTNetworking.h" +//#import "RTNetworking.h" +#import "YQNetworking.h" #import "PickDetailVc.h" #import "PickingModel.h" + +@interface PickingViewModel () + +@property(nonatomic , assign) NSInteger page; + +@end @implementation PickingViewModel --(void)fetchPickingList{ -// [RTNetworking getWithUrl:@"v1/Home/all.json" refreshCache:NO success:^(id response) { -// -// [self loadDataWithSuccessDic:response]; -// -// } fail:^(NSError *error) { -// -// self.errorBlock(error); -// -// }]; +-(void)fetchPickingList:(NSInteger)page{ + + [YQNetworking postWithUrl:@"http://image.degjsm.cn/EHome/services/api/mobileManager/" refreshRequest:NO cache:NO params:@{@"type": @(4)} progressBlock:nil successBlock:^(id response) { + [self loadDataWithSuccessDic:response]; + } failBlock:^(NSError *error) { + self.errorBlock(error); + }]; + - [self loadDataWithSuccessDic:nil]; } - (void)loadDataWithSuccessDic:(NSDictionary *)dic{ diff --git a/iDearQRCode/OtherVC/PreloadVC/Controller/NewPreloadVC.h b/iDearQRCode/OtherVC/PreloadVC/Controller/NewPreloadVC.h new file mode 100644 index 0000000..afa57d1 --- /dev/null +++ b/iDearQRCode/OtherVC/PreloadVC/Controller/NewPreloadVC.h @@ -0,0 +1,13 @@ +// +// NewPreloadVC.h +// iDearQRCode +// +// Created by Mortimer on 17/5/25. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import "BaseViewController.h" + +@interface NewPreloadVC : BaseViewController + +@end diff --git a/iDearQRCode/OtherVC/PreloadVC/Controller/NewPreloadVC.m b/iDearQRCode/OtherVC/PreloadVC/Controller/NewPreloadVC.m new file mode 100644 index 0000000..78f450d --- /dev/null +++ b/iDearQRCode/OtherVC/PreloadVC/Controller/NewPreloadVC.m @@ -0,0 +1,257 @@ +// +// NewPreloadVC.m +// iDearQRCode +// +// Created by Mortimer on 17/5/25. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import "NewPreloadVC.h" +#import "PreloadNewView.h" +#import "NewPartCell.h" +#import "NewPartNumberView.h" +#import "PartSearchView.h" +@interface NewPreloadVC () + +@property (nonatomic , strong) NewPartNumberView * partNumber; + +@property (nonatomic , strong) PreloadNewView * preloadView; +@property (nonatomic , strong) UIView * head; +@property (nonatomic , strong) UITableView * partTableView; +@property (nonatomic , strong) NSMutableArray * partdata; +@property (nonatomic , assign) NSInteger indexrow; + + +@end + +@implementation NewPreloadVC + +static NSString * identifier = @"NewPartCell"; +- (void)viewDidLoad { + [super viewDidLoad]; + + self.title = @"新增预装"; + [self setupRightItem:@"保存"]; + [self setupNewPreloadView]; + [self setupTableHeadView]; + [self setupTableView]; + + self.indexrow = 0; + // Do any additional setup after loading the view. +} + + + +-(void)setupTableView{ + _partTableView = [[UITableView alloc] init]; + _partTableView.delegate = self; + _partTableView.dataSource = self; + _partTableView.tableFooterView = [UIView new]; + _partTableView.rowHeight = 50; +// _partTableView.estimatedRowHeight = 50; + _partTableView.backgroundColor = [UIColor colorWithHexString:@"#eff4f4"]; + _partTableView.showsVerticalScrollIndicator = NO; + // 5.设置分割线样式 + _partTableView.separatorStyle = UITableViewCellSeparatorStyleNone; + [self.view addSubview:self.partTableView]; + [self.partTableView mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.bottom.right.equalTo(self.view); + make.top.equalTo(_head.mas_bottom); + }]; + [self.partTableView registerClass:NSClassFromString(identifier) forCellReuseIdentifier:identifier]; +} + +-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ + + return self.partdata.count; +} + +-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ + NewPartCell * cell = [tableView dequeueReusableCellWithIdentifier:identifier]; + if (cell == nil) { + cell = [tableView dequeueReusableCellWithIdentifier:identifier]; + } + cell.selectionStyle = UITableViewCellSelectionStyleNone; + if (self.partdata.count>0) { + cell.partName = [NSString stringWithFormat:@"%@",[self.partdata[indexPath.row] valueForKey:@"partname"]]; + cell.number = [NSString stringWithFormat:@"%ld",[[self.partdata[indexPath.row] valueForKey:@"partnumber"]integerValue]]; + cell.index = indexPath.row; + if (self.partdata.count - 1 == indexPath.row) { + cell.isLastCell = YES; + }else if (self.partdata.count == 1){ + cell.isLastCell = YES; + }else{ + cell.isLastCell = NO; + } + } + + WeakObj(self); + cell.didSelectHandle = ^(NSInteger index , NSInteger row){ + + if (index == 11) { + [selfWeak deleteCell:row]; + }else{ + self.indexrow = row; + [selfWeak selectNumber]; + } + }; + + return cell; +} + + +-(void)setupNewPreloadView{ + PreloadNewView * view = [[PreloadNewView alloc] initWithFrame:CGRectMake(0, 0, kScreen_width, 300)]; +// view.nameText.text = self.partname; +// view.numberText.text = self.partnumber; +// view.countText.text = self.partcount; + [self.view addSubview:view]; + _preloadView = view; + [_preloadView mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.top.right.equalTo(self.view); + make.height.mas_equalTo(200); + }]; +} + + + +-(void)change{ + + NSLog(@"%@\n,%@\n%@\n",self.preloadView.numberText.text,self.preloadView.nameText.text,self.preloadView.countText.text); +} + + + +-(void)setupTableHeadView{ + + UIView * view = [UIView new]; + view.backgroundColor = [UIColor whiteColor]; + [self.view addSubview:view]; + _head = view; + + [view mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.right.equalTo(self.view); + make.height.mas_equalTo(30); + make.top.equalTo(_preloadView.mas_bottom).offset(10); + }]; + + UILabel * head = [UILabel new]; + head.text = @"零件 :"; + head.textColor = topView_Color; + head.font = kFont_14; + [view addSubview:head]; + + [head mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(view).offset(6); + make.centerY.equalTo(view); + }]; + + UIButton * add = [UIButton buttonWithType:UIButtonTypeCustom]; + [add setImage:[UIImage imageNamed:@"btn_addCell"] forState:UIControlStateNormal]; + [add addTarget:self action:@selector(addCell) forControlEvents:UIControlEventTouchUpInside]; + [view addSubview:add]; + + [add mas_makeConstraints:^(MASConstraintMaker *make) { + make.right.equalTo(view).offset(-6); + make.centerY.equalTo(view); + }]; + UIView * line = [UIView new]; + line.backgroundColor = line_Color; + [view addSubview:line]; + [line mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.right.bottom.equalTo(view); + make.height.mas_equalTo(0.6); + }]; +} + + + + +-(void)selectNumber{ + + WeakObj(self); + NewPartNumberView * number = [[NewPartNumberView alloc] initWithComplete:^(NSInteger index) { + + NSMutableArray * newArray = [self.partdata mutableCopy]; + NSString * partname = [self.partdata[self.indexrow] valueForKey:@"partname"]; + [newArray replaceObjectAtIndex:self.indexrow withObject:@{@"partname" : partname, @"partnumber" : @(index)}]; + self.partdata = newArray; + [selfWeak.partTableView reloadData]; + }]; + + [number show]; + _partNumber = number; +} + + +-(void)addCell{ + + + + [self changeStatusBarStyle:YES statusBarHidden:NO changeStatusBarAnimated:NO]; + WeakObj(self); + PartSearchView * search = [[PartSearchView alloc] initWithPartSearchView:^(NSString *part) { + [selfWeak changeStatusBarStyle:NO statusBarHidden:NO changeStatusBarAnimated:NO]; + if (part && ![part isEqualToString:@"-1"]) { + + [selfWeak.partTableView beginUpdates]; + [selfWeak.partdata addObject:@{@"partname" : part ,@"partnumber" : @0}]; + NSIndexPath * indexPath ; + if (selfWeak.partdata.count == 0) { + indexPath = [NSIndexPath indexPathForRow:0 inSection:0]; + [selfWeak.partTableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft]; + }else{ + indexPath = [NSIndexPath indexPathForRow:self.partdata.count - 1 inSection:0]; + [selfWeak.partTableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft]; + } + + [selfWeak.partTableView endUpdates]; + [selfWeak.partTableView reloadData]; + [selfWeak.partTableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES]; + } + + }]; + + [search show]; + + + +} + +-(void)deleteCell:(NSInteger)index{ + [self.partTableView beginUpdates]; + [self.partdata removeObjectAtIndex:index]; + [self.partTableView deleteRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:index inSection:0]] withRowAnimation:UITableViewRowAnimationRight]; + [self.partTableView endUpdates]; + [self.partTableView reloadData]; +} + +-(NSMutableArray *)partdata{ + + if (!_partdata) { + _partdata = [NSMutableArray array]; + } + return _partdata; +} + + +-(void)viewWillDisappear:(BOOL)animated{ + [super viewWillDisappear:animated]; + [_partNumber removeFromSuperview]; +} +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +/* +#pragma mark - Navigation + +// In a storyboard-based application, you will often want to do a little preparation before navigation +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { + // Get the new view controller using [segue destinationViewController]. + // Pass the selected object to the new view controller. +} +*/ + +@end diff --git a/iDearQRCode/OtherVC/PreloadVC/Controller/PartSearchView.h b/iDearQRCode/OtherVC/PreloadVC/Controller/PartSearchView.h new file mode 100644 index 0000000..244389c --- /dev/null +++ b/iDearQRCode/OtherVC/PreloadVC/Controller/PartSearchView.h @@ -0,0 +1,17 @@ +// +// PartSearchView.h +// iDearQRCode +// +// Created by Mortimer on 17/5/26. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import + +@interface PartSearchView : UIView + + +-(instancetype)initWithPartSearchView:(void(^)(NSString * part))complete; + +-(void)show; +@end diff --git a/iDearQRCode/OtherVC/PreloadVC/Controller/PartSearchView.m b/iDearQRCode/OtherVC/PreloadVC/Controller/PartSearchView.m new file mode 100644 index 0000000..c25492f --- /dev/null +++ b/iDearQRCode/OtherVC/PreloadVC/Controller/PartSearchView.m @@ -0,0 +1,236 @@ +// +// PartSearchView.m +// iDearQRCode +// +// Created by Mortimer on 17/5/26. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import "PartSearchView.h" +#import "UIView+MJExtension.h" + +@interface PartSearchView () + +@property (nonatomic , strong) UITextField * searchView; +@property (nonatomic , strong) UIView * topView; +@property (nonatomic , strong) UIPickerView * searchPick; +@property (nonatomic , strong) NSMutableArray * searchData; +@property (nonatomic , strong) NSMutableArray * resultData; + +//@property (nonatomic , assign) NSInteger row; + +@property (nonatomic , copy) void(^didSelectRow)(NSString * partname); + +@end +@implementation PartSearchView + +-(instancetype)initWithPartSearchView:(void (^)(NSString *))complete{ + if (self = [super init]) { + self.frame = [UIScreen mainScreen].bounds; + self.backgroundColor = RGBA(0, 0, 0, 0.4); + [self setupPartSearchView]; + if (complete) { + self.didSelectRow = ^(NSString * partname){ + complete(partname); + }; + } + } + return self; +} + + +-(void)setupPartSearchView{ + + UIView * view = [UIView new]; + view.backgroundColor = [UIColor whiteColor]; + [self addSubview:view]; + _topView = view; + UITextField * textField = [[UITextField alloc] init]; + textField.backgroundColor = back_Color; + textField.borderStyle = UITextBorderStyleNone; + textField.font = kFont_16; + textField.textColor = text_Color1; + _searchView = textField; + [textField addTarget:self action:@selector(searchData:) forControlEvents:UIControlEventEditingChanged]; + [_topView addSubview:textField]; + + UIButton * cancel = [UIButton buttonWithType:UIButtonTypeCustom]; + [cancel setTitle:@"取消" forState:UIControlStateNormal]; + [cancel setTitleColor:text_Color1 forState:UIControlStateNormal]; + [cancel addTarget:self action:@selector(dissMiss) forControlEvents:UIControlEventTouchUpInside]; + [_topView addSubview:cancel]; + + UIView * line = [UIView new]; + line.backgroundColor = line_Color; + [_topView addSubview:line]; + + + self.searchPick = [UIPickerView new]; + [self.topView addSubview:self.searchPick]; + self.searchPick.backgroundColor = [UIColor whiteColor]; + // self.pick.showsSelectionIndicator = YES; + self.searchPick.delegate = self; + self.searchPick.dataSource = self; + [_topView addSubview:self.searchPick]; + + _topView.frame = CGRectMake(0, -64, kScreen_width, 264); +// [_topView mas_makeConstraints:^(MASConstraintMaker *make) { +// make.left.top.right.equalTo(self); +// make.height.mas_offset(264); +// }]; + + [_searchView mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(_topView).offset(6); + make.top.equalTo(self).offset(26); + make.height.mas_equalTo(30); + make.right.equalTo(cancel.mas_left).offset(-8); + }]; + + [cancel mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerY.equalTo(_searchView); + make.right.equalTo(_topView).offset(-6); + make.width.mas_equalTo(50); + }]; + + [line mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.right.equalTo(_topView); + make.height.mas_equalTo(0.6); + make.top.equalTo(_topView).offset(63); + }]; + + [_searchPick mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(line.mas_bottom); + make.left.right.bottom.equalTo(_topView); + }]; + _resultData = [NSMutableArray array]; + +} + + + +#pragma mark UIPickView DataSource Method +//指定pickerview有几个表盘 +-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{ + return 1; +} +//指定每个表盘上有几行数据 +-(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{ + + if(self.resultData.count >0) return self.resultData.count; + + return self.searchData.count; +} + +#pragma mark UIPickerView Delegate Method +//指定每行如何展示数据 +-(NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component{ + + if (self.resultData.count > 0) { + return self.resultData[row]; + } + return self.searchData[row] ; +} + +-(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{ + + + +// self.row = row; + [self dissMiss:row]; +} + +-(void)show{ + [[UIApplication sharedApplication].keyWindow addSubview:self]; + + [UIView animateWithDuration:0.4 animations:^{ + _topView.mj_y = 0; + self.alpha = 1; + } completion:^(BOOL finished) { + [_searchView becomeFirstResponder]; + }]; +} + +-(void)dissMiss:(NSInteger)row{ + + + if (self.didSelectRow) { + if (self.resultData.count>0) { + self.didSelectRow(self.resultData[row]); + }else{ + self.didSelectRow(self.searchData[row]); + } + + } + + + + + [UIView animateWithDuration:0.4 animations:^{ + _topView.mj_y = -64; + self.alpha = 0; + [_searchView resignFirstResponder]; + } completion:^(BOOL finished) { + + [self removeFromSuperview]; + }]; +} + +-(void)dissMiss{ + + + if (self.didSelectRow) { + self.didSelectRow(@"-1"); + } + + [UIView animateWithDuration:0.4 animations:^{ + _topView.mj_y = -64; + self.alpha = 0; + [_searchView resignFirstResponder]; + } completion:^(BOOL finished) { + + [self removeFromSuperview]; + }]; +} + +-(void)upPartView:(NSMutableArray *)data{ + self.searchData = [data mutableCopy]; + [self.searchPick reloadAllComponents]; + +} + +-(void)searchData:(UITextField *)search{ + + if (self.resultData.count>0) { + [self.resultData removeAllObjects]; + } + + for (NSString * part in self.searchData) { + if ([part.lowercaseString rangeOfString:search.text.lowercaseString].location != NSNotFound) { + + [self.resultData addObject:part]; + } + } + + [self.searchPick reloadAllComponents]; + +} + +-(NSMutableArray *)searchData{ + if (!_searchData) { + _searchData = [NSMutableArray array]; + + for (int i = 0; i< 30; i++) { + [_searchData addObject:[NSString stringWithFormat:@"滤水器内芯 (123%d)",i]]; + } + } + return _searchData; +} +/* +// Only override drawRect: if you perform custom drawing. +// An empty implementation adversely affects performance during animation. +- (void)drawRect:(CGRect)rect { + // Drawing code +} +*/ + +@end diff --git a/iDearQRCode/OtherVC/PreloadVC/Controller/PreloadDetailVC.h b/iDearQRCode/OtherVC/PreloadVC/Controller/PreloadDetailVC.h new file mode 100644 index 0000000..984a64e --- /dev/null +++ b/iDearQRCode/OtherVC/PreloadVC/Controller/PreloadDetailVC.h @@ -0,0 +1,15 @@ +// +// PreloadDetailVC.h +// iDearQRCode +// +// Created by Mortimer on 17/5/22. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import "BaseViewController.h" + +@interface PreloadDetailVC : BaseViewController + +@property (nonatomic , copy) NSString * pickId; + +@end diff --git a/iDearQRCode/OtherVC/PreloadVC/Controller/PreloadDetailVC.m b/iDearQRCode/OtherVC/PreloadVC/Controller/PreloadDetailVC.m new file mode 100644 index 0000000..bf79468 --- /dev/null +++ b/iDearQRCode/OtherVC/PreloadVC/Controller/PreloadDetailVC.m @@ -0,0 +1,216 @@ +// +// PreloadDetailVC.m +// iDearQRCode +// +// Created by Mortimer on 17/5/22. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import "PreloadDetailVC.h" +#import "PreloadDetailCell.h" +#import "PreloadDetailView.h" +#import "PrereloadCellModel.h" +#import "NewPreloadVC.h" +#import "UINavigationController+FDFullscreenPopGesture.h" +@interface PreloadDetailVC () + +@property (nonatomic , strong) UIView * backView; +//@property (nonatomic , strong) UITableView * currentView; + +@end + +@implementation PreloadDetailVC + +static NSString * identifier = @"PreloadDetailCell" ; + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.title = @"预装"; + [self setupRightItem:@"添加"]; + [self setupTableView]; + // Do any additional setup after loading the view. +} + +-(void)change{ + +} + +-(void)viewWillAppear:(BOOL)animated{ + [super viewWillAppear:animated]; + self.fd_interactivePopDisabled = YES; +} + +-(void)viewDidDisappear:(BOOL)animated{ + [super viewDidDisappear:animated]; + self.fd_interactivePopDisabled = NO; +} +-(void)setupTableView{ + _backView = [UIView new]; +// _backView.layer.cornerRadius = 5; +// _backView.layer.masksToBounds = YES; + _backView.backgroundColor = [UIColor whiteColor]; + [self.view addSubview:_backView]; + [_backView addSubview:self.tableView]; + + [_backView mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(self.view).offset(10); + make.top.bottom.equalTo(self.view); + make.right.equalTo(self.view).offset(-10);; + }]; + [self.tableView registerClass:NSClassFromString(identifier) forCellReuseIdentifier:identifier]; + [self.tableView mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.top.right.bottom.equalTo(_backView); + + }]; + +// [self.tableView reloadData]; +} + +-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{ + + return 3; +} + +-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ + if (section != 0) { + return 2; + } + return 0; +} + +-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{ + if (section == 0) { + return [UIView new]; + } + PreloadDetailView * view = [[PreloadDetailView alloc] init]; + if (section == 1) { + view.isFirst = YES; + } + [view uploadDetailHeadView:@[@"https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=3219125739,1362099777&fm=23&gp=0.jpg",@"测试",@"九把刀",@"无用"]]; + return view; +} + +-(UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section{ + + if (section == 2) { + UIView * foot = [UIView new]; + // 获取一条曲线。曲线路径为(0,0,96,50).圆角位置为右上和右下,圆角大小为25 + UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, kScreen_width - 20, 20) byRoundingCorners: UIRectCornerBottomLeft | UIRectCornerBottomRight cornerRadii:CGSizeMake(5, 5)]; + + // 初始化一个CAShapeLayer + CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init]; + maskLayer.frame = CGRectMake(0, 0, kScreen_width - 20, 20); + // 将曲线路径设置为layer的路径 + maskLayer.path = path.CGPath; + + // 设置控件的mask为CAShapeLayer + foot.layer.mask = maskLayer; + + foot.backgroundColor = [UIColor whiteColor]; + UIView * line = [UIView new]; + line.frame =CGRectMake(0, 0, _backView.frame.size.width, 0.6); + line.backgroundColor = line_Color; + [foot addSubview:line]; + + UILabel * label = [UILabel new]; + label.frame = CGRectMake(0, 1, kScreen_width-20-6, 20); + label.text = @"共 14 件"; + label.textAlignment = NSTextAlignmentRight; + [foot addSubview:label]; + + return foot; + } + return [UIView new]; +} + +-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ + + PreloadDetailCell * cell = [tableView dequeueReusableCellWithIdentifier:identifier]; + if (cell == nil) { + cell = [tableView dequeueReusableCellWithIdentifier:identifier]; + } + + cell.selectionStyle = UITableViewCellSelectionStyleNone; + cell.shouldMove = indexPath.row == 0 ? YES : NO; + cell.data = @[@[@"滤水器",@"滤水器",@"滤水器"],@[@"1",@"1",@"1"]]; + + WeakObj(self); + cell.didCopyHandle = ^(NSArray * data){ + + NewPreloadVC * new = [[NewPreloadVC alloc] init]; + [selfWeak.navigationController pushViewController:new animated:YES]; + }; + return cell; + +} + +-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ + + return 75; + +} + +-(CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{ + + if (section == 2) { + return 20; + } + return 0.01; +} + +-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{ + if (section == 0) return 10; + if (section == 1) { + return 50; + } + + return 40; +} + + + +//#pragma mark - Getters +// +///** +// * 懒加载 +// * +// */ +// +//- (UITableView * )tableView{ +// if (!_tableView){ +// _tableView = [[UITableView alloc] initWithFrame:[UIScreen mainScreen].bounds style:UITableViewStylePlain]; +// _tableView.delegate = self; +// _tableView.dataSource = self; +// _tableView.tableFooterView = [UIView new]; +// // 4.设置我们分割线颜色(clearColor相当于取消系统分割线) +// // self.tableView.separatorColor = [UIColor clearColor]; +// [_tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:identifier]; +// _tableView.backgroundColor = [UIColor colorWithHexString:@"#eff4f4"]; +// self.tableView.emptyDataSetSource = self; +// self.tableView.emptyDataSetDelegate = self; +// // self.tableView.sectionFooterHeight = 0.01f; +// self.tableView.showsVerticalScrollIndicator = NO; +// // 5.设置分割线样式 +// _tableView.separatorStyle = UITableViewCellSeparatorStyleNone; +// } +// +// return _tableView; +// +//} +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +/* +#pragma mark - Navigation + +// In a storyboard-based application, you will often want to do a little preparation before navigation +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { + // Get the new view controller using [segue destinationViewController]. + // Pass the selected object to the new view controller. +} +*/ + +@end diff --git a/iDearQRCode/OtherVC/PreloadVC/Controller/PreloadViewController.h b/iDearQRCode/OtherVC/PreloadVC/Controller/PreloadViewController.h new file mode 100644 index 0000000..41145a3 --- /dev/null +++ b/iDearQRCode/OtherVC/PreloadVC/Controller/PreloadViewController.h @@ -0,0 +1,13 @@ +// +// PreloadViewController.h +// iDearQRCode +// +// Created by Mortimer on 17/5/23. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import "BaseViewController.h" + +@interface PreloadViewController : BaseViewController + +@end diff --git a/iDearQRCode/OtherVC/PreloadVC/Controller/PreloadViewController.m b/iDearQRCode/OtherVC/PreloadVC/Controller/PreloadViewController.m new file mode 100644 index 0000000..3a7e484 --- /dev/null +++ b/iDearQRCode/OtherVC/PreloadVC/Controller/PreloadViewController.m @@ -0,0 +1,527 @@ +// +// PreloadViewController.m +// iDearQRCode +// +// Created by Mortimer on 17/5/23. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import "PreloadViewController.h" +#import "PrereloadCell.h" +#import "PickingHeadView.h" +#import "PickingModel.h" +#import "PickingFootView.h" +#import "PickAlert.h" +#import "PreloadDetailVC.h" +#import "PickDateView.h" +#import "PrereloadCellModel.h" +#import "PreloadViewModel.h" +#import "MJRefresh.h" + +@interface PreloadViewController () + +@property (nonatomic , assign) UPViewtype type; +@property (nonatomic , strong) PickingHeadView * pickHead; +@property (nonatomic , strong) PickingFootView * pickFoot; + +@property (nonatomic , assign) NSInteger changeRightItem; + +@property (nonatomic , strong) NSMutableArray * tempArray; +@property (nonatomic , strong) NSMutableArray * selectArray; +@property (nonatomic , strong) PickAlert * pickAlert; + + +@property (nonatomic , strong) PreloadViewModel * DataManager; + +@property (nonatomic , assign) NSInteger page; +@end + +@implementation PreloadViewController + +static NSString * identifier = @"PrereloadCell"; +- (void)viewDidLoad { + [super viewDidLoad]; + + self.title = @"预装"; + // self.automaticallyAdjustsScrollViewInsets = NO; + self.type = selectCellNormal; + [self setupRightItem:@"添加"]; + [self setupPickingHeadView]; + [self setupUI]; + [self setupPickFootView]; + [self loadData]; + + // Do any additional setup after loading the view. +} + +-(void)setupUI{ + [self.view addSubview:self.tableView]; + [self.pickHead mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.left.right.equalTo(self.view); + make.height.mas_equalTo(40); + }]; + + [self.tableView mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(self.pickHead.mas_bottom); + make.left.right.bottom.equalTo(self.view); + }]; + + + [self.tableView registerClass:[PrereloadCell class] forCellReuseIdentifier:identifier]; + + self.type = selectCellNormal;//设置选择状态 + + __unsafe_unretained UITableView *tableView = self.tableView; +// __unsafe_unretained typeof(self) weakSelf = self; + //下拉刷新 + PreloadViewModel * model = [[PreloadViewModel alloc] init]; + tableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{ + + + if (self.type == selectCellNormal) { + [model setBlockWithReturnBlock:^(id returnValue) { + + + self.dataSource = returnValue; + [self.tempArray removeAllObjects]; + for (int i = 0; i < self.dataSource.count; i++) { + [self.tempArray addObject:@{@"State" : @0}]; + } + [tableView.mj_header endRefreshing]; + [tableView reloadData]; + } WithErrorBlock:^(id errorCode) { + [tableView.mj_header endRefreshing]; + }]; + + + + [model loadPreViewData:1]; + }else{ + [tableView.mj_header endRefreshing]; + } + + + + }]; + + // 设置自动切换透明度(在导航栏下面自动隐藏) + tableView.mj_header.automaticallyChangeAlpha = YES; + + self.page = 1; + // 上拉刷新 + tableView.mj_footer = [MJRefreshBackNormalFooter footerWithRefreshingBlock:^{ +// PreloadViewModel * model = [[PreloadViewModel alloc] init]; + + if (self.type == selectCellNormal) { + [model setBlockWithReturnBlock:^(id returnValue) { + NSArray * tempArray = returnValue; + [self.dataSource addObjectsFromArray:returnValue]; + for (int i = 0; i < tempArray.count; i++) { + [self.tempArray addObject:@{@"State" : @0}]; + } + // 结束刷新 + [tableView.mj_footer endRefreshing]; + [tableView reloadData]; + } WithErrorBlock:^(id errorCode) { + if (self.page<=1) { + self.page = 1; + }else{ + self.page--; + } + // 结束刷新 + [tableView.mj_footer endRefreshing]; + }]; + + self.page++; + [model loadPreViewData:self.page]; + }else{ + [tableView.mj_footer endRefreshing]; + } + + + + }]; + +} + +//空白区域点击事件 +-(void)emptyDataSet:(UIScrollView *)scrollView didTapView:(UIView *)view{ + [self loadData]; +} + + +-(void)loadData{ + PreloadViewModel * model = [[PreloadViewModel alloc] init]; + + + [model setBlockWithReturnBlock:^(id returnValue) { + + + self.dataSource = returnValue; + [self.tempArray removeAllObjects]; + for (int i = 0; i < self.dataSource.count; i++) { + [self.tempArray addObject:@{@"State" : @0}]; + } + + [self.tableView reloadData]; + } WithErrorBlock:^(id errorCode) { + + }]; + + + + [model loadPreViewData:1]; + +// _DataManager = model; +} + +#pragma mark UITableViewDataSource + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + + + return self.dataSource.count; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + PrereloadCell * cell = [tableView dequeueReusableCellWithIdentifier:identifier]; + if(cell==nil){ + cell = [[PrereloadCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier]; + } + cell.selectionStyle = UITableViewCellSelectionStyleNone; + + + cell.preModel = self.dataSource[indexPath.row]; + + cell.selectType = (selectCellType)[[self.tempArray[indexPath.row] valueForKey:@"state"] integerValue]; + + cell.state = _changeRightItem; + cell.index = indexPath.row; + + WeakObj(self); + cell.selectCellAction = ^(PrereloadCellModel * model,BOOL select,selectCellType type,NSUInteger index){ + NSMutableArray * newArray = [selfWeak.tempArray mutableCopy]; + [newArray replaceObjectAtIndex:index withObject:@{@"state" : @(type)}]; + selfWeak.tempArray = newArray; + if (select == YES) { + [selfWeak.selectArray addObject:model.pickId]; + }else{ + [selfWeak deleteObjc:model.pickId]; + } + + + [selfWeak.tableView reloadData]; + + }; + + + return cell; + +} + + +-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ + if (self.type == selectCellNormal) { + PickingModel * pick = self.dataSource[indexPath.row]; + PreloadViewModel * View =[[PreloadViewModel alloc] init]; + [View pushDetailWithVC:self didSelectRowAtPickId:pick.pickId]; + } + + +} + + +-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ + + PickingModel * pick = self.dataSource[indexPath.row]; + return pick.height; +} + + + + +#pragma mark RightItemAction + +-(void)change{ + switch (self.type) { + case UPViewNormal: + { + + } + break; + + case UPViewDeleteType: + { + [self resetDefaultSeting]; + } + break; + case UPViewCombineType: + { + [self resetDefaultSeting]; + + } + break; + + default: + break; + } + +} +#pragma mark 设置头视图以及各个功能 + +-(void)setupPickingHeadView{ + PickingHeadView * pick = [[PickingHeadView alloc] initWithFrame:CGRectMake(0, 0, kScreen_width, 40)]; + pick.delegate = self; + [self.view addSubview:pick]; + _pickHead = pick; +} + +#pragma mark PickingHeadViewDelegae +-(void)didClick:(UPViewtype)type WithSelect:(BOOL)select{ + switch (type) { + case UPViewSearchType: + { + + if (self.type == UPViewDeleteType || self.type == UPViewCombineType) { + return ; + } + [self upResultViewData]; + [self changeStatusBarStyle:YES statusBarHidden:NO changeStatusBarAnimated:NO]; + [self presentViewController:self.searchView animated:YES completion:nil]; + } + break; + case UPViewScreenType: + { + if (self.type == UPViewDeleteType || self.type == UPViewCombineType) { + return ; + } + + [self changeStatusBarStyle:YES statusBarHidden:NO changeStatusBarAnimated:NO]; + + + PickDateView * date = [[PickDateView alloc] initWithScreenDate:^(NSString * state, NSString * end,NSInteger index) { + switch (index) { + case 0: + { + [self changeStatusBarStyle:NO statusBarHidden:NO changeStatusBarAnimated:YES]; + } + break; + case 1: + { + + } + break; + default: + break; + } + }]; + date.didSelectCell = ^(NSString * pickId){ + PreloadDetailVC * detial = [[PreloadDetailVC alloc] init]; + [self.navigationController pushViewController:detial animated:YES]; + }; + [date show]; + + } + break; + case UPViewDeleteType: + { + if (self.type == UPViewDeleteType || self.type == UPViewCombineType) { + return ; + } + + self.changeRightItem = 1; + self.type = UPViewDeleteType; + [self setupRightItem:@"取消"]; + [self setCellState:selectCellNormal]; + [self.pickFoot show:PickModelDelete]; + [self.tableView reloadData]; + } + break; + case UPViewCombineType: + { + if (self.type == UPViewCombineType || self.type == UPViewDeleteType ) { + return ; + } + + self.type = UPViewCombineType; + [self setupRightItem:@"取消"]; + self.changeRightItem = 2; + [self setCellState:selectCellNormal]; + [self.pickFoot show:PickModelCombine]; + [self.tableView reloadData]; + } + break; + + case UPViewNormal: + { + [self setCellState:selectCellNormal]; + [self.pickFoot dismiss]; + [self.tableView reloadData]; + } + break; + default: + break; + } + +} + +#pragma mark 设置footView及各项功能 + +-(void)setupPickFootView{ + PickingFootView * pickFoot = [[PickingFootView alloc] initWithFrame:CGRectMake(0, kScreen_height, kScreen_width, 60)]; + pickFoot.delegate = self; + [self.view addSubview:pickFoot]; + _pickFoot = pickFoot; +} +#pragma mark PickingFootViewDelegate + +-(void)didHandelAction:(PickModelType)type{ + + switch (type) { + case PickModelNormal: + { + [self.selectArray removeAllObjects]; + [self setCellState:selectCellNormal]; + [self.tableView reloadData]; + } + break; + case PickModelDelete: + { + if (self.selectArray.count>0) { + PickAlert * alert = [[PickAlert alloc] initWithPickTitle:[NSString stringWithFormat:@"是否确定删除这%ld项",self.selectArray.count] AlertAction:@[@"取消",@"确定"] Complete:^(NSInteger index) { + if (index == 1) { + + + for (int j = 0; j 0) { + PickAlert * alert = [[PickAlert alloc] initWithPickTitle:self.dataSource.count == self.selectArray.count ? [NSString stringWithFormat:@"是否确定合并全部%ld项",self.selectArray.count] : [NSString stringWithFormat:@"是否确定合并这%ld项",self.selectArray.count] AlertAction:@[@"取消",@"确定"] Complete:^(NSInteger index) { + if (index == 1) { + + + for (int j = 0; j 1) { + break; + } + + height += 26; + + + for (int k = 0; k1) { + height += 10; + } + + height += 20; + + model.height = height ; + + model.Anyting = sometingArray[doIndex]; + + [arr addObject:model]; + } + + self.returnBlock(arr); + +} + +-(void)pushDetailWithVC:(UIViewController *)vc didSelectRowAtPickId:(NSString *)pickId{ + + PreloadDetailVC * detail = [[PreloadDetailVC alloc] init]; + detail.pickId = pickId; + [vc.navigationController pushViewController:detail animated:YES]; + +} + + + +@end diff --git a/iDearQRCode/OtherVC/PreloadVC/Model/PrereloadCellModel.h b/iDearQRCode/OtherVC/PreloadVC/Model/PrereloadCellModel.h new file mode 100644 index 0000000..af4a291 --- /dev/null +++ b/iDearQRCode/OtherVC/PreloadVC/Model/PrereloadCellModel.h @@ -0,0 +1,20 @@ +// +// PrereloadCellModel.h +// iDearQRCode +// +// Created by Mortimer on 17/5/22. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import "BaseModel.h" + +@interface PrereloadCellModel : BaseModel + +@property (nonatomic , assign) NSInteger numberSometing; + +@property (nonatomic , copy) NSString * Anyting; + + +@end + + diff --git a/iDearQRCode/OtherVC/PreloadVC/Model/PrereloadCellModel.m b/iDearQRCode/OtherVC/PreloadVC/Model/PrereloadCellModel.m new file mode 100644 index 0000000..521bab4 --- /dev/null +++ b/iDearQRCode/OtherVC/PreloadVC/Model/PrereloadCellModel.m @@ -0,0 +1,13 @@ +// +// PrereloadCellModel.m +// iDearQRCode +// +// Created by Mortimer on 17/5/22. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import "PrereloadCellModel.h" + +@implementation PrereloadCellModel + +@end diff --git a/iDearQRCode/OtherVC/PreloadVC/View/NewPartCell.h b/iDearQRCode/OtherVC/PreloadVC/View/NewPartCell.h new file mode 100644 index 0000000..c991bf0 --- /dev/null +++ b/iDearQRCode/OtherVC/PreloadVC/View/NewPartCell.h @@ -0,0 +1,23 @@ +// +// NewPartCell.h +// iDearQRCode +// +// Created by Mortimer on 17/5/25. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import + +@interface NewPartCell : UITableViewCell + +@property (nonatomic , copy) void(^didSelectHandle)(NSInteger select,NSInteger row); + +@property (nonatomic , copy) NSString * number; + +@property (nonatomic , assign) BOOL isLastCell; + +@property (nonatomic , copy) NSString * partName; + +@property (nonatomic , assign) NSInteger index; + +@end diff --git a/iDearQRCode/OtherVC/PreloadVC/View/NewPartCell.m b/iDearQRCode/OtherVC/PreloadVC/View/NewPartCell.m new file mode 100644 index 0000000..16e8329 --- /dev/null +++ b/iDearQRCode/OtherVC/PreloadVC/View/NewPartCell.m @@ -0,0 +1,150 @@ +// +// NewPartCell.m +// iDearQRCode +// +// Created by Mortimer on 17/5/25. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import "NewPartCell.h" +#import "NSString+Validate.h" +@interface NewPartCell () + +@property (nonatomic , strong) UILabel * part; +@property (nonatomic , strong) UIButton * deleteBtn; +@property (nonatomic , strong) UIButton * numberBtn; +@property (nonatomic , strong) UIView * line; + +@end + +@implementation NewPartCell + + + +-(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{ + if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) { + self.backgroundColor = [UIColor whiteColor]; + [self setupDefaultPartView]; + } + return self; +} + +-(void)setupDefaultPartView{ + + UILabel * label = [UILabel new]; + label.textColor = text_Color1; + label.font = kFont_16; + [self.contentView addSubview:label]; + _part = label; + + UILabel * number = [UILabel new]; + number.textColor = text_Color2; + number.font = kFont_12; + number.text = @"数量 :"; + [self.contentView addSubview:number]; + + _deleteBtn = [UIButton buttonWithType:UIButtonTypeCustom]; + _deleteBtn.tag = 11; + [_deleteBtn setImage:[UIImage imageNamed:@"icon_delete)"] forState:UIControlStateNormal]; + [_deleteBtn addTarget:self action:@selector(didSelectNumber:) forControlEvents:UIControlEventTouchUpInside]; + [self.contentView addSubview:_deleteBtn]; + + + _numberBtn = [UIButton buttonWithType:UIButtonTypeCustom]; + _numberBtn.tag = 12; + NSMutableAttributedString * title = [[NSMutableAttributedString alloc] initWithString:@"请选择数量"]; + NSRange titleRange = {0,[title length]}; + [title addAttribute:NSForegroundColorAttributeName value:[UIColor colorWithHexString:@"#9aa9a9"] range:titleRange]; + + [title addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInteger:NSUnderlineStyleSingle] range:titleRange]; + [_numberBtn setAttributedTitle:title forState:UIControlStateNormal]; + _numberBtn.titleLabel.font = kFont_14; + [_numberBtn addTarget:self action:@selector(didSelectNumber:) forControlEvents:UIControlEventTouchUpInside]; +// _numberBtn.backgroundColor = [UIColor redColor]; + [self.contentView addSubview:_numberBtn]; + + _line = [UIView new]; + _line.backgroundColor = line_Color; + [self.contentView addSubview:_line]; + + [_part mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.top.equalTo(self.contentView).offset(6); +// make.width.mas_equalTo(kScreen_width*3/4); + }]; + + [number mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(_part); + make.top.equalTo(_part.mas_bottom).offset(3); + }]; + + [_numberBtn mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(number.mas_right).offset(4); +// make.bottom.equalTo(number); + make.centerY.equalTo(number); + }]; + + [_deleteBtn mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerY.equalTo(self.contentView); + make.right.equalTo(self.contentView).offset(-8); + }]; + + [_line mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(_part); + make.right.equalTo(_deleteBtn); + make.bottom.equalTo(self.contentView); + make.height.mas_equalTo(0.6); + }]; +} + + +-(void)setPartName:(NSString *)partName{ + _partName = partName; + _part.text = partName; +} +-(void)setNumber:(NSString *)number{ + _number = number; + + NSString * cellNumber = number; + if (![cellNumber validateOnlyNumber] || [cellNumber isEqualToString:@"0"]) { + + cellNumber = @"请选择数量"; + } + + NSMutableAttributedString * title = [[NSMutableAttributedString alloc] initWithString:cellNumber]; + NSRange titleRange = {0,[title length]}; + [title addAttribute:NSForegroundColorAttributeName value:topView_Color range:titleRange]; + + [title addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInteger:NSUnderlineStyleSingle] range:titleRange]; + [_numberBtn setAttributedTitle:title forState:UIControlStateNormal]; + +} + +-(void)didSelectNumber:(UIButton *)sender{ + + if (self.didSelectHandle) { + _didSelectHandle(sender.tag,self.index); + } +} + +-(void)setIsLastCell:(BOOL)isLastCell{ + _isLastCell = isLastCell; + if (isLastCell == YES) { + _line.hidden = YES; + }else{ + _line.hidden = NO; + } + +} + +- (void)awakeFromNib { + [super awakeFromNib]; + // Initialization code +} + +- (void)setSelected:(BOOL)selected animated:(BOOL)animated { + [super setSelected:selected animated:animated]; + + // Configure the view for the selected state +} + +@end diff --git a/iDearQRCode/OtherVC/PreloadVC/View/NewPartNumberView.h b/iDearQRCode/OtherVC/PreloadVC/View/NewPartNumberView.h new file mode 100644 index 0000000..499e6b3 --- /dev/null +++ b/iDearQRCode/OtherVC/PreloadVC/View/NewPartNumberView.h @@ -0,0 +1,25 @@ +// +// NewPartNumberView.h +// iDearQRCode +// +// Created by Mortimer on 17/5/25. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import + +@interface NewPartNumberView : UIView + + +/** + 初始化numberView + + @param complete 获取数量的blcok + @return 返回view + */ +-(instancetype)initWithComplete:(void(^)(NSInteger index))complete; + +-(void)show; + +-(void)dissMiss; +@end diff --git a/iDearQRCode/OtherVC/PreloadVC/View/NewPartNumberView.m b/iDearQRCode/OtherVC/PreloadVC/View/NewPartNumberView.m new file mode 100644 index 0000000..346ac00 --- /dev/null +++ b/iDearQRCode/OtherVC/PreloadVC/View/NewPartNumberView.m @@ -0,0 +1,199 @@ +// +// NewPartNumberView.m +// iDearQRCode +// +// Created by Mortimer on 17/5/25. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import "NewPartNumberView.h" +#import "UIView+MJExtension.h" +@interface NewPartNumberView () + +@property (nonatomic ,copy) void(^didClickHandle)(NSInteger number); +@property (nonatomic , strong) UIView * bottomView; +@property (nonatomic , strong) UIPickerView * pick; +@property (nonatomic , strong) NSMutableArray * number; + + +@end +@implementation NewPartNumberView + +-(instancetype)initWithComplete:(void (^)(NSInteger))complete{ + if (self = [super init]) { + self.backgroundColor = RGBA(0, 0, 0, 0.4); + self.frame = CGRectMake(0, 128, kScreen_width, kScreen_height - 64); + [self addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dissMiss)]]; + [self loadData]; + [self setupPartNumberView]; + if (complete) { + self.didClickHandle = ^(NSInteger number){ + complete(number); + }; + } + } + return self; +} + + +-(void)loadData{ + self.number = [NSMutableArray arrayWithCapacity:100]; + for (int i = 1; i< 501; i++) { + [self.number addObject:@(i)]; + } +} + +-(void)setupPartNumberView{ + + _bottomView = [UIView new]; + _bottomView.backgroundColor = [UIColor grayColor]; + [self addSubview:_bottomView]; + + UIButton * (^creatBtn)(NSString *,UIColor *,UIColor *,NSInteger )= ^(NSString * title,UIColor * backColor,UIColor * titleColor,NSInteger tag){ + UIButton * btn = [UIButton buttonWithType:UIButtonTypeCustom]; + [btn setTitle:title forState:UIControlStateNormal]; + if (backColor) { + btn.backgroundColor = backColor; + btn.layer.cornerRadius = 4; + btn.layer.masksToBounds = YES; + } + if (titleColor) { + [btn setTitleColor:titleColor forState:UIControlStateNormal]; + } + btn.tag = tag; + [btn addTarget:self action:@selector(PickNumberClickAction:) forControlEvents:UIControlEventTouchUpInside]; + return btn; + }; + + UIButton * cancel = creatBtn(@"取消",nil,[UIColor blueColor],30); + UIButton * sure = creatBtn(@"确定",nil,[UIColor blueColor],31); + + + [self.bottomView addSubview:cancel ]; + [self.bottomView addSubview:sure ]; + + UILabel * promit = [UILabel new]; + promit.text = @"请选择数量"; + promit.textColor = text_Color1; + [self.bottomView addSubview:promit]; + + self.pick = [UIPickerView new]; + [self.bottomView addSubview:self.pick]; + self.pick.backgroundColor = [UIColor whiteColor]; +// self.pick.showsSelectionIndicator = YES; + self.pick.delegate = self; + self.pick.dataSource = self; + + + + [self.bottomView mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.right.bottom.equalTo(self); + make.height.mas_equalTo(240); + }]; + [self.pick mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.bottom.right.equalTo(self.bottomView); + make.height.mas_equalTo(200); + }]; + + [cancel mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(self.bottomView).offset(6); + make.bottom.equalTo(self.pick.mas_top).offset(-4); + }]; + + [promit mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerY.equalTo(cancel); + make.centerX.equalTo(self.bottomView); + }]; + [sure mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerY.equalTo(cancel); + make.right.equalTo(self.bottomView).offset(-6); + }]; + + if (IOS_SYSTEM_VERSION > 10) { + UIView * topL = [UIView new]; + topL.backgroundColor = line_Color; + [_pick addSubview:topL]; + + UIView * bottomL = [UIView new]; + bottomL.backgroundColor = line_Color; + [_pick addSubview:bottomL]; + + [topL mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.right.equalTo(_pick); + make.height.mas_equalTo(0.6); + make.centerY.equalTo(_pick).offset(-15); + }]; + + [bottomL mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.right.height.equalTo(topL); + make.centerY.equalTo(_pick).offset(15); + }]; + } + +} + +#pragma mark UIPickView DataSource Method +//指定pickerview有几个表盘 +-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{ + return 1; +} +//指定每个表盘上有几行数据 +-(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{ + + return self.number.count; +} + +#pragma mark UIPickerView Delegate Method +//指定每行如何展示数据 +-(NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component{ + + return [NSString stringWithFormat:@"%d", [self.number[row] intValue]]; +} + +-(void)PickNumberClickAction:(UIButton *)sender{ + + if (sender.tag == 31) { + NSInteger index = [[self.number objectAtIndex:[self.pick selectedRowInComponent:0]] integerValue]; + + if (index) { + if (self.didClickHandle) { + _didClickHandle(index); + } + } + + }else{ + + } + [self dissMiss]; +} + +-(void)show{ + + [[UIApplication sharedApplication].keyWindow addSubview:self]; + + [UIView animateWithDuration:0.4 animations:^{ + self.mj_y = 64; + self.alpha = 1; + } ]; + +} + +-(void)dissMiss{ + + [UIView animateWithDuration:0.4 animations:^{ + self.mj_y = 128; + self.alpha = 0; + } completion:^(BOOL finished) { + [self removeFromSuperview]; + }]; +} + +/* +// Only override drawRect: if you perform custom drawing. +// An empty implementation adversely affects performance during animation. +- (void)drawRect:(CGRect)rect { + // Drawing code +} +*/ + +@end diff --git a/iDearQRCode/OtherVC/PreloadVC/View/PreloadDetailCell.h b/iDearQRCode/OtherVC/PreloadVC/View/PreloadDetailCell.h new file mode 100644 index 0000000..20ae1d2 --- /dev/null +++ b/iDearQRCode/OtherVC/PreloadVC/View/PreloadDetailCell.h @@ -0,0 +1,20 @@ +// +// PreloadDetailCell.h +// iDearQRCode +// +// Created by Mortimer on 17/5/24. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import + +@interface PreloadDetailCell : UITableViewCell + +@property (nonatomic , assign) BOOL shouldMove; + + +@property (nonatomic , strong) NSArray * data; + +@property (nonatomic , copy) void (^didCopyHandle)(NSArray * data); + +@end diff --git a/iDearQRCode/OtherVC/PreloadVC/View/PreloadDetailCell.m b/iDearQRCode/OtherVC/PreloadVC/View/PreloadDetailCell.m new file mode 100644 index 0000000..67849f6 --- /dev/null +++ b/iDearQRCode/OtherVC/PreloadVC/View/PreloadDetailCell.m @@ -0,0 +1,244 @@ +// +// PreloadDetailCell.m +// iDearQRCode +// +// Created by Mortimer on 17/5/24. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import "PreloadDetailCell.h" +#import "UIView+MJExtension.h" +#import "PrereloadCellModel.h" +@interface PreloadDetailCell () + +@property (nonatomic , strong) UILabel * leftLabel; +@property (nonatomic , strong) UILabel * rightLabel; + +@property (nonatomic , strong) UIView * detailView; +@property (nonatomic , strong) UIButton * DataBtn; + +//@property (nonatomic , assign) BOOL swipe; + +@end + +@implementation PreloadDetailCell + + +-(instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier{ + if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) { + [self setupDefaultCell]; + } + return self; +} + + +-(void)setupDefaultCell{ + + _leftLabel = [self creatLabelTextColor:text_Color1 Font:nil]; + _rightLabel = [self creatLabelTextColor:text_Color1 Font:nil]; + + [self.contentView addSubview:_leftLabel]; + [self.contentView addSubview:_rightLabel]; + + _detailView = [UIView new]; +// _detailView.backgroundColor = [UIColor redColor]; + UISwipeGestureRecognizer * swipeLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(showSelectView:)]; + swipeLeft.direction = UISwipeGestureRecognizerDirectionLeft; + [_detailView addGestureRecognizer:swipeLeft]; + + UISwipeGestureRecognizer * swipeRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(showSelectView:)]; + swipeRight.direction = UISwipeGestureRecognizerDirectionRight; + [_detailView addGestureRecognizer:swipeRight]; + + + _DataBtn = [UIButton buttonWithType:UIButtonTypeCustom]; + _DataBtn.layer.cornerRadius = 3; + _DataBtn.layer.masksToBounds = YES; + _DataBtn.layer.borderColor = topView_Color.CGColor; + _DataBtn.layer.borderWidth = 0.8; + [_DataBtn setTitle:@"复制" forState:UIControlStateNormal]; + _DataBtn.titleLabel.font = kFont_12; + [_DataBtn setTitleColor:topView_Color forState:UIControlStateNormal]; + [_DataBtn addTarget:self action:@selector(copyPush) forControlEvents:UIControlEventTouchUpInside]; + [self.contentView addSubview:_DataBtn]; + _DataBtn.hidden = YES; + + + [self.contentView addSubview:_detailView]; + + [_leftLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(self.contentView).offset(6); + make.top.equalTo(self.contentView).offset(4); + }]; + + [_rightLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.right.equalTo(self.contentView).offset(-6); + make.centerY.equalTo(_leftLabel); + }]; + + + + [_detailView mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.mas_equalTo(12); + make.top.equalTo(_leftLabel.mas_bottom).offset(5); + make.right.bottom.equalTo(self.contentView); + + }]; + + +// _DataBtn.frame = CGRectMake(self.frame.size.width, (self.frame.size.height - 20)/2 - 10, 50, 20); + + [_DataBtn mas_makeConstraints:^(MASConstraintMaker *make) { + make.right.mas_equalTo(60); + make.centerY.equalTo(_detailView); + make.height.mas_equalTo(20); + make.width.mas_equalTo(50); +// make.left.equalTo(_detailView.mas_right).offset(8); +// make.width.mas_equalTo(44); + }]; +} + + + +-(UILabel *)creatLabelTextColor:(UIColor *)color Font:(UIFont *)font{ + UILabel * label = [UILabel new]; + if (!font) { + font = kFont_14; + } + label.font = font; + label.textColor = color; + return label; +} + + +-(void)showSelectView:(UISwipeGestureRecognizer *)swipe{ + + if (self.shouldMove == YES) { + if (swipe.direction == UISwipeGestureRecognizerDirectionRight) { + + [UIView animateWithDuration:0.3 animations:^{ + + _DataBtn.alpha = 0; + + [_detailView mas_updateConstraints:^(MASConstraintMaker *make) { + make.left.mas_equalTo(12); + + }]; + + + [_detailView mas_updateConstraints:^(MASConstraintMaker *make) { + make.right.equalTo(self.contentView); + }]; + + [_DataBtn mas_updateConstraints:^(MASConstraintMaker *make) { + make.right.mas_equalTo(60); + }]; + } completion:^(BOOL finished) { + _DataBtn.hidden = YES; + + }]; + + + }else if (swipe.direction == UISwipeGestureRecognizerDirectionLeft){ + + [UIView animateWithDuration:0.3 animations:^{ + + + [_detailView mas_updateConstraints:^(MASConstraintMaker *make) { + make.left.mas_equalTo(4); + }]; + [_detailView mas_updateConstraints:^(MASConstraintMaker *make) { + make.right.equalTo(self.contentView).offset(-80); + }]; + + + + _DataBtn.hidden = NO; + }completion:^(BOOL finished) { + + [UIView animateWithDuration:0.3 animations:^{ + + _DataBtn.alpha = 1; + + [_DataBtn mas_updateConstraints:^(MASConstraintMaker *make) { + make.right.mas_equalTo(-8); + }]; + + }]; + }]; + } + } + + +} + +-(void)copyPush{ + if (_didCopyHandle) { + _didCopyHandle(self.data); + } + + + +} + + +-(void)setData:(NSArray *)data{ + _data = data; + NSArray * left = data[0]; + NSArray * right = data[1]; + _leftLabel.text =left[0]; + _rightLabel.text = right[1]; + + for (UIView * view in _detailView.subviews) { + [view removeFromSuperview]; + } + CGFloat top = 0; + for (int i = 0; i + +@interface PreloadDetailView : UIView + +@property (nonatomic , assign) NSInteger isFirst; + +-(void)uploadDetailHeadView:(NSArray *)data; +@end diff --git a/iDearQRCode/OtherVC/PreloadVC/View/PreloadDetailView.m b/iDearQRCode/OtherVC/PreloadVC/View/PreloadDetailView.m new file mode 100644 index 0000000..78deefc --- /dev/null +++ b/iDearQRCode/OtherVC/PreloadVC/View/PreloadDetailView.m @@ -0,0 +1,133 @@ +// +// PreloadDetailView.m +// iDearQRCode +// +// Created by Mortimer on 17/5/24. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import "PreloadDetailView.h" + + +@interface PreloadDetailView () + +@property (nonatomic , strong) UIView * topView; +@property (nonatomic , strong) UIImageView * img; +@property (nonatomic , strong) UILabel * personName; +@property (nonatomic , strong) UILabel * personDoing; +@property (nonatomic , strong) UILabel * personJoingTime; + +@end +@implementation PreloadDetailView + + + +-(instancetype)initWithFrame:(CGRect)frame{ + if (self = [super initWithFrame:frame]) { + self.backgroundColor = [UIColor whiteColor]; + [self setupDefaultView]; + } + return self; +} + + +-(void)setupDefaultView{ + + _topView = [UIView new]; + _topView.backgroundColor = line_Color; + [self addSubview:_topView]; + +// UIView * view = [UIView new]; +// view.backgroundColor = [UIColor whiteColor]; + UIImageView * image = [[UIImageView alloc] init]; + image.layer.cornerRadius = 15.0f; + image.layer.masksToBounds = YES; + [self addSubview:image]; + _img = image; + + + UILabel * title = [self creatLabel:@"" TextColor:text_Color2 Font:nil]; + [self addSubview:title]; + _personName = title; + UILabel * detail = [self creatLabel:@"" TextColor:text_Color2 Font:nil]; + [self addSubview:detail]; + _personDoing = detail; + UILabel * time = [self creatLabel:@"" TextColor:text_Color3 Font:nil];; + [self addSubview:time]; + _personJoingTime = time; + + + + [_topView mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.left.right.equalTo(self); + make.height.mas_equalTo(0.6); + }]; + + [image mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(self).offset(6); + make.top.equalTo(_topView.mas_bottom).offset(8); + make.height.width.mas_equalTo(30); + }]; + + [title mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(image.mas_right).offset(8); + make.centerY.equalTo(image).offset(-8); + }]; + + [detail mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(title.mas_right).offset(6); + make.centerY.equalTo(title); + }]; + + [time mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(title); + make.centerY.equalTo(image).offset(8); + }]; +} + +-(void)setIsFirst:(NSInteger)isFirst{ + _isFirst = isFirst; + if (isFirst == YES) { + // 获取一条曲线。曲线路径为(0,0,96,50).圆角位置为右上和右下,圆角大小为25 + UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, kScreen_width - 20, 10) byRoundingCorners: UIRectCornerTopLeft | UIRectCornerTopRight cornerRadii:CGSizeMake(5, 5)]; + + // 初始化一个CAShapeLayer + CAShapeLayer *maskLayer = [[CAShapeLayer alloc] init]; + maskLayer.frame = CGRectMake(0, 0, kScreen_width - 20, 10); + // 将曲线路径设置为layer的路径 + maskLayer.path = path.CGPath; + + // 设置控件的mask为CAShapeLayer + _topView.layer.mask = maskLayer; + _topView.backgroundColor = topView_Color; + [_topView mas_updateConstraints:^(MASConstraintMaker *make) { + make.height.mas_equalTo(10); + }]; + } +} +-(void)uploadDetailHeadView:(NSArray *)data{ + [_img sd_setImageWithURL:[NSURL URLWithString:data[0]] placeholderImage:[UIImage imageNamed:@""]]; + _personName.text = data[1]; + _personDoing.text = data[2]; + _personJoingTime.text = data[3]; +} + +-(UILabel *)creatLabel:(NSString *)text TextColor:(UIColor *)color Font:(UIFont *)font{ + UILabel * label = [UILabel new]; + if (!font) { + font = kFont_14; + } + label.font = font; + label.text = text; + label.textColor = color; + return label; +} +/* +// Only override drawRect: if you perform custom drawing. +// An empty implementation adversely affects performance during animation. +- (void)drawRect:(CGRect)rect { + // Drawing code +} +*/ + +@end diff --git a/iDearQRCode/OtherVC/PreloadVC/View/PreloadNewView.h b/iDearQRCode/OtherVC/PreloadVC/View/PreloadNewView.h new file mode 100644 index 0000000..9c10d97 --- /dev/null +++ b/iDearQRCode/OtherVC/PreloadVC/View/PreloadNewView.h @@ -0,0 +1,21 @@ +// +// PreloadNewView.h +// iDearQRCode +// +// Created by Mortimer on 17/5/25. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import + +@interface PreloadNewView : UIView + +//@property (nonatomic , copy) NSString * partname; +//@property (nonatomic , copy) NSString * partnumber; +//@property (nonatomic , copy) NSString * partcount; + + +@property (nonatomic , strong) UITextField * nameText; +@property (nonatomic , strong) UITextField * numberText; +@property (nonatomic , strong) UITextField * countText; +@end diff --git a/iDearQRCode/OtherVC/PreloadVC/View/PreloadNewView.m b/iDearQRCode/OtherVC/PreloadVC/View/PreloadNewView.m new file mode 100644 index 0000000..7aa8ad9 --- /dev/null +++ b/iDearQRCode/OtherVC/PreloadVC/View/PreloadNewView.m @@ -0,0 +1,136 @@ +// +// PreloadNewView.m +// iDearQRCode +// +// Created by Mortimer on 17/5/25. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import "PreloadNewView.h" + +@interface PreloadNewView () + + + +@end + +@implementation PreloadNewView + +-(instancetype)initWithFrame:(CGRect)frame { + if (self = [super initWithFrame:frame]) { + self.backgroundColor = [UIColor whiteColor]; + [self setupDefaultView]; + } + return self; +} + + +-(void)setupDefaultView{ + + UILabel * (^creatLabel)(NSString * text , UIColor * textColor) = ^(NSString * text , UIColor * textColor){ + UILabel * label = [UILabel new]; + label.font = kFont_14; + label.text = text; + label.textColor = textColor; + return label; + }; + + UILabel * nameL = creatLabel(@"配件名称 :",topView_Color); + UILabel * numberL = creatLabel(@"配件编号 :",topView_Color); + UILabel * countL = creatLabel(@"预装数量 :",topView_Color); + [self addSubview:nameL]; + [self addSubview:numberL]; + [self addSubview:countL]; + UIView * (^creatView)() = ^{ + UIView * view = [UIView new]; + view.backgroundColor = line_Color; + return view; + }; + + UIView * nameV = creatView(); + UIView * numberV = creatView(); + UIView * countV = creatView(); + [self addSubview:nameV]; + [self addSubview:numberV]; + [self addSubview:countV]; + UITextField * (^creatTextField)()= ^{ + UITextField * textField = [[UITextField alloc] init]; +// textField = [[UITextField alloc] init]; + textField.borderStyle = UITextBorderStyleNone; + textField.font = kFont_16; + textField.textColor = text_Color1; + return textField; + }; + + UITextField * nameT = creatTextField(); + _nameText = nameT; + UITextField * numberT = creatTextField(); + _numberText = numberT; + UITextField * countT = creatTextField(); + _countText = countT; + [self addSubview:nameT]; + [self addSubview:numberT]; + [self addSubview:countT]; +// _nameText.text = self.partname; +// _numberText.text = self.partnumber; +// _countText.text = self.partcount; + + [nameL mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(self).offset(6); + make.top.equalTo(self).offset(10); + }]; + + [nameT mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(nameL.mas_bottom); + make.left.equalTo(nameL); + make.right.equalTo(self).offset(-6); + make.height.mas_equalTo(30); + }]; + + [nameV mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.right.equalTo(nameT); + make.top.equalTo(nameT.mas_bottom); + make.height.mas_equalTo(0.6); + }]; + + [numberL mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(nameV.mas_bottom).offset(15); + make.left.equalTo(nameL); + }]; + + [numberT mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(numberL.mas_bottom); + make.left.right.height.equalTo(nameT); + }]; + + [numberV mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.right.height.equalTo(nameV); + make.top.equalTo(numberT.mas_bottom); + }]; + + [countL mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(numberV.mas_bottom).offset(15); + make.left.equalTo(nameL); + }]; + + [countT mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.right.height.equalTo(numberT); + make.top.equalTo(countL.mas_bottom); + }]; + + [countV mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.right.height.mas_equalTo(numberV); + make.top.equalTo(countT.mas_bottom); + }]; +} + + +/* +// Only override drawRect: if you perform custom drawing. +// An empty implementation adversely affects performance during animation. +- (void)drawRect:(CGRect)rect { + // Drawing code +} +*/ + +@end diff --git a/iDearQRCode/OtherVC/PreloadVC/View/PrereloadCell.h b/iDearQRCode/OtherVC/PreloadVC/View/PrereloadCell.h new file mode 100644 index 0000000..2bb2be0 --- /dev/null +++ b/iDearQRCode/OtherVC/PreloadVC/View/PrereloadCell.h @@ -0,0 +1,28 @@ +// +// PrereloadCell.h +// iDearQRCode +// +// Created by Mortimer on 17/5/22. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import "BaseTableViewCell.h" +@class PrereloadCellModel; +@interface PrereloadCell : BaseTableViewCell + +@property (nonatomic ,strong) PrereloadCellModel * preModel; + + +@property (nonatomic , assign) NSInteger state; +@property (nonatomic , assign) NSUInteger index; + +@property (nonatomic , assign) selectCellType selectType; + +@property (nonatomic , assign) selectCellType selectCell; + + +//@property (nonatomic , assign) BOOL senderSelect; + + +@property (nonatomic , copy) void (^selectCellAction)(PrereloadCellModel * ,BOOL ,selectCellType,NSUInteger) ; +@end diff --git a/iDearQRCode/OtherVC/PreloadVC/View/PrereloadCell.m b/iDearQRCode/OtherVC/PreloadVC/View/PrereloadCell.m new file mode 100644 index 0000000..f4c4a94 --- /dev/null +++ b/iDearQRCode/OtherVC/PreloadVC/View/PrereloadCell.m @@ -0,0 +1,353 @@ +// +// PrereloadCell.m +// iDearQRCode +// +// Created by Mortimer on 17/5/22. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import "PrereloadCell.h" +#import "PrereloadCellModel.h" +#import "UIImageView+WebCache.h" +@interface PrereloadCell () +@property (nonatomic , strong) UIView * bakcView; +@property (nonatomic , strong) UIImageView * head; +@property (nonatomic , weak) UILabel * name_label; +@property (nonatomic , weak) UILabel * do_label; +@property (nonatomic , weak) UILabel * join_label; +@property (nonatomic , strong) UIButton * selectBtn; + + +@property (nonatomic , strong) UIView * LabelView; + + +@end +@implementation PrereloadCell + + + +-(void)setupDefaultCell{ + _bakcView = [UIView new]; + _bakcView.layer.borderColor = line_Color.CGColor; + _bakcView.layer.borderWidth = 0.5f; + _bakcView.layer.cornerRadius = 5.0f; + _bakcView.layer.masksToBounds = YES; + _bakcView.backgroundColor = [UIColor whiteColor]; + [self.contentView addSubview:_bakcView]; + + UIView * top = [UIView new]; + top.backgroundColor = topView_Color; + [_bakcView addSubview:top]; +// _topView = top; + + _head = [[UIImageView alloc] init]; + _head.layer.cornerRadius = 15.0f; + _head.layer.masksToBounds = YES; + // _head.backgroundColor = [UIColor orangeColor]; + [_bakcView addSubview:_head]; + + UILabel * (^creatLabel)(UIColor * color,CGFloat font) = ^(UIColor * color,CGFloat font){ + UILabel * label = [UILabel new]; + label.textColor = color; + label.font = [UIFont systemFontOfSize:font]; + return label; + }; + + [_bakcView addSubview:self.name_label = creatLabel(text_Color1,14) ]; + [_bakcView addSubview:self.do_label = creatLabel(text_Color1,14)]; + [_bakcView addSubview:self.join_label = creatLabel(text_Color3,14)]; + + _selectBtn = [UIButton buttonWithType:UIButtonTypeCustom]; + + [_selectBtn setImage:[UIImage imageNamed:@"btn_normal"] forState:UIControlStateNormal]; + [_selectBtn addTarget:self action:@selector(selectAction:) forControlEvents:UIControlEventTouchUpInside]; + _selectBtn.hidden = YES; + [_bakcView addSubview:_selectBtn]; + + + + _LabelView = [UIView new]; + [_bakcView addSubview:_LabelView]; + + + UIView * line = [UIView new]; + line.backgroundColor = line_Color; + [_bakcView addSubview:line]; + + UILabel * label = [UILabel new]; + label.text = @"共 333 项"; + label.textColor = text_Color2; + label.font = kFont_12; + [_bakcView addSubview:label]; + + + [_bakcView mas_updateConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(self.contentView).offset(5);//+10 + make.left.equalTo(self.contentView).offset(10); + make.right.equalTo(self.contentView).offset(-10); + make.bottom.equalTo(self.contentView).offset(-5); + }]; + + [top mas_updateConstraints:^(MASConstraintMaker *make) { + make.left.top.right.equalTo(_bakcView); + make.height.mas_equalTo(10);//+10 + }]; + + [_head mas_updateConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(top.mas_bottom).offset(10);//+10 + make.left.equalTo(_bakcView).offset(8); + make.height.width.mas_equalTo(30);//+30 + }]; + + [_name_label mas_updateConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(_head).offset(-3); + make.left.equalTo(_head.mas_right).offset(5); + // make.width.mas_equalTo(kScreen_width/2); + }]; + + [_do_label mas_updateConstraints:^(MASConstraintMaker *make) { + make.centerY.equalTo(_name_label); + make.left.equalTo(_name_label.mas_right).offset(5); + + }]; + + [_join_label mas_updateConstraints:^(MASConstraintMaker *make) { + make.bottom.equalTo(_head).offset(3); + make.left.equalTo(_name_label); + make.right.equalTo(_bakcView).offset(-8); + }]; + + [_selectBtn mas_updateConstraints:^(MASConstraintMaker *make) { + // make.top.equalTo(_head); + make.centerY.equalTo(_head); + make.right.equalTo(_bakcView).offset(-8); + make.width.height.mas_equalTo(42); + }]; + + + + [_LabelView mas_updateConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(_head.mas_bottom); + make.right.left.equalTo(_bakcView); + make.bottom.equalTo(line.mas_top); + }]; + + + + + + [line mas_makeConstraints:^(MASConstraintMaker *make) { + make.bottom.equalTo(label.mas_top); + make.left.right.equalTo(_LabelView); + make.height.mas_equalTo(0.6); + }]; + + + + + + + + [label mas_makeConstraints:^(MASConstraintMaker *make) { + make.right.equalTo(_LabelView).offset(-8); + make.bottom.equalTo(_bakcView); + make.height.mas_equalTo(20); + }]; + + + + +} + +-(void)setPreModel:(PrereloadCellModel *)preModel{ + _preModel = preModel; + + [_head sd_setImageWithURL:[NSURL URLWithString:preModel.URL] placeholderImage:[UIImage imageNamed:@""]]; + _name_label.text = preModel.pickId; + _do_label.text = preModel.doSometing; + _join_label.text = preModel.join_time; + + + for (UIView * view in _LabelView.subviews) { + [view removeFromSuperview]; + } + + UILabel * (^creatLabel)(NSString * text , UIColor * textColor) = ^(NSString * text , UIColor * textColor){ + UILabel * label = [UILabel new]; + label.font = kFont_14; + label.text = text; + label.textColor = textColor; + return label; + }; + + if (preModel.count>0) { + + +// NSLog(@">>>>%ld,%ld",preModel.count,preModel.numberSometing); + + CGFloat topSpace =0; + for (int i = 0; i0) { + + UILabel * more = creatLabel(@"...",text_Color2); + [_LabelView addSubview:more]; + + [more mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.mas_equalTo(topSpace ); + make.right.equalTo(_LabelView).offset(-8); + }]; + + + } + + } + } + + + + } + + + +} + +-(void)setSelectType:(selectCellType)selectType{ + _selectType = selectType; + + if (selectType == selectCellNormal) { + + [_selectBtn setImage:[UIImage imageNamed:@"btn_normal"] forState:UIControlStateNormal]; + + + }else if (selectType == selectCellDelete){ + + [_selectBtn setImage:[UIImage imageNamed:@"btn_deleteNormal"] forState:UIControlStateNormal]; + + }else if (selectType == selectCellCombine){ + + [_selectBtn setImage:[UIImage imageNamed:@"btn_combine"] forState:UIControlStateNormal]; + + }else{ + + } +} + +-(void)setSenderSelect:(BOOL)senderSelect{ + +} + + +-(void)setState:(NSInteger)state{ + _state = state; + if (state == 1) { + self.selectCell = selectCellDelete; + _selectBtn.hidden = NO; + + }else if(state == 2){ + self.selectCell = selectCellCombine; + + _selectBtn.hidden = NO; + }else{ + self.selectCell = selectCellNormal; + _selectBtn.hidden = YES; + + if (_selectBtn.selected == YES) { + _selectBtn.selected = NO; + } + + } +} + +#pragma mark selectAction +-(void)selectAction:(UIButton *)sender{ + + + sender.selected = !sender.selected; + + + if (sender.selected == YES) { + + if (self.selectType == selectCellDelete) { + + [sender setImage:[UIImage imageNamed:@"btn_deleteNormal"] forState:UIControlStateNormal]; + }else if (self.selectType == selectCellCombine){ + + [sender setImage:[UIImage imageNamed:@"btn_combine"] forState:UIControlStateNormal]; + }else{ + + } + if (self.selectCellAction) { + self.selectCellAction(self.preModel , YES ,self.selectCell,self.index); + } + }else{ + + [sender setImage:[UIImage imageNamed:@"btn_normal"] forState:UIControlStateNormal]; + + + if (self.selectCellAction) { + self.selectCellAction(self.preModel , NO ,selectCellNormal,self.index); + } + } + + +} + +/* +// Only override drawRect: if you perform custom drawing. +// An empty implementation adversely affects performance during animation. +- (void)drawRect:(CGRect)rect { + // Drawing code +} +*/ + +@end diff --git a/iDearQRCode/OtherVC/QRCodeVC/QRCodeResultVC.h b/iDearQRCode/OtherVC/QRCodeVC/QRCodeResultVC.h new file mode 100644 index 0000000..78be8a6 --- /dev/null +++ b/iDearQRCode/OtherVC/QRCodeVC/QRCodeResultVC.h @@ -0,0 +1,15 @@ +// +// QRCodeResultVC.h +// iDearQRCode +// +// Created by Mortimer on 17/5/23. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import + +@interface QRCodeResultVC : UIViewController +@property (nonatomic , copy) NSString * qrcode; +@property (nonatomic , copy) void(^restQRCode)(); + +@end diff --git a/iDearQRCode/OtherVC/QRCodeVC/QRCodeResultVC.m b/iDearQRCode/OtherVC/QRCodeVC/QRCodeResultVC.m new file mode 100644 index 0000000..557f6a0 --- /dev/null +++ b/iDearQRCode/OtherVC/QRCodeVC/QRCodeResultVC.m @@ -0,0 +1,55 @@ +// +// QRCodeResultVC.m +// iDearQRCode +// +// Created by Mortimer on 17/5/23. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import "QRCodeResultVC.h" +#import "QRCodeResultView.h" +@interface QRCodeResultVC () + +@end + +@implementation QRCodeResultVC + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.view.backgroundColor = RGBA(0, 0, 0, 0.4); + WeakObj(self); + QRCodeResultView * result = [[QRCodeResultView alloc] initWithResultViewCompleteData:^(NSDictionary *data, NSInteger index) { + if (index == 1) { + + + + + } + if (_restQRCode) { + _restQRCode(); + } + [selfWeak dismissViewControllerAnimated:NO completion:nil]; + }]; + + result.qrcode = self.qrcode; + [self.view addSubview:result]; + // Do any additional setup after loading the view. +} + +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +/* +#pragma mark - Navigation + +// In a storyboard-based application, you will often want to do a little preparation before navigation +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { + // Get the new view controller using [segue destinationViewController]. + // Pass the selected object to the new view controller. +} +*/ + +@end diff --git a/iDearQRCode/OtherVC/QRCodeVC/QRCodeVC.h b/iDearQRCode/OtherVC/QRCodeVC/QRCodeVC.h new file mode 100644 index 0000000..fdca829 --- /dev/null +++ b/iDearQRCode/OtherVC/QRCodeVC/QRCodeVC.h @@ -0,0 +1,34 @@ +// +// QRCodeVC.h +// iDearQRCode +// +// Created by Mortimer on 17/5/23. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import "LBXScanViewController.h" + +//继承LBXScanViewController,在界面上绘制想要的按钮,提示语等 +@interface QRCodeVC : LBXScanViewController + + +/** + @brief 扫码区域上方提示文字 + */ +@property (nonatomic, strong) UILabel *topTitle; + +//#pragma mark --增加拉近/远视频界面 +//@property (nonatomic, assign) BOOL isVideoZoom; + +#pragma mark - 底部几个功能:开启闪光灯、相册、我的二维码 +//底部显示的功能项 +@property (nonatomic, strong) UIView *bottomItemsView; +//相册 +@property (nonatomic, strong) UIButton *btnPhoto; +//闪光灯 +@property (nonatomic, strong) UIButton *btnFlash; +//我的二维码 +@property (nonatomic, strong) UIButton *btnMyQR; + + +@end diff --git a/iDearQRCode/OtherVC/QRCodeVC/QRCodeVC.m b/iDearQRCode/OtherVC/QRCodeVC/QRCodeVC.m new file mode 100644 index 0000000..632376c --- /dev/null +++ b/iDearQRCode/OtherVC/QRCodeVC/QRCodeVC.m @@ -0,0 +1,303 @@ +// +// QRCodeVC.m +// iDearQRCode +// +// Created by Mortimer on 17/5/23. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import "QRCodeVC.h" +#import "LBXAlertAction.h" +#import "LBXScanVideoZoomView.h" +#import "LBXScanWrapper.h" +#import "LBXScanResult.h" +#import "QRCodeResultVC.h" +@interface QRCodeVC () +@property (nonatomic, strong) LBXScanVideoZoomView *zoomView; +@end + +@implementation QRCodeVC + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.title = @"扫描"; + //创建参数对象 + LBXScanViewStyle * style = [[LBXScanViewStyle alloc] init]; + //矩形区域中心上移,默认中心为屏幕中心点 + style.centerUpOffset = 44; + //扫码框周围4个角的类型,设置为外挂式 + style.photoframeAngleStyle = LBXScanViewPhotoframeAngleStyle_Outer; + //扫码框周围4个角绘制的线条宽度 + style.photoframeLineW = 6; + //扫码框周围4个角的宽度 + style.photoframeAngleW = 24; + //扫码框周围4个角的高度 + style.photoframeAngleH = 24; + //扫码框内,动画类型 --线条上下移动 + style.anmiationStyle = LBXScanViewAnimationStyle_LineMove; + //线条上下移动图片 + style.animationImage = [UIImage imageNamed:@"CodeScan.bundle/qrcode_scan_light_green"]; + + self.style = style; + if ([self respondsToSelector:@selector(setEdgesForExtendedLayout:)]) { + + self.edgesForExtendedLayout = UIRectEdgeNone; + } + + self.view.backgroundColor = [UIColor blackColor]; + + //设置扫码后需要扫码图像 +// self.isNeedScanImage = YES; + // Do any additional setup after loading the view. +} + +-(void)viewDidAppear:(BOOL)animated{ + [super viewDidAppear:animated]; + + [self drawBottomItems]; + [self drawTitle]; + [self.view bringSubviewToFront:_topTitle]; +} +//绘制扫描区域 +-(void)drawTitle{ + if (!_topTitle) + { + self.topTitle = [[UILabel alloc]init]; + _topTitle.bounds = CGRectMake(0, 0, 145, 60); + _topTitle.center = CGPointMake(CGRectGetWidth(self.view.frame)/2, 50); + + //3.5inch iphone + if ([UIScreen mainScreen].bounds.size.height <= 568 ) + { + _topTitle.center = CGPointMake(CGRectGetWidth(self.view.frame)/2, 38); + _topTitle.font = [UIFont systemFontOfSize:14]; + } + + _topTitle.textAlignment = NSTextAlignmentCenter; + _topTitle.numberOfLines = 0; + _topTitle.text = @"将取景框对准二维码即可自动扫描"; + _topTitle.textColor = [UIColor whiteColor]; + [self.view addSubview:_topTitle]; + } +} + +- (void)drawBottomItems +{ + if (_bottomItemsView) { + + return; + } + + self.bottomItemsView = [[UIView alloc]initWithFrame:CGRectMake(0, CGRectGetMaxY(self.view.frame)-164, + CGRectGetWidth(self.view.frame), 100)]; + _bottomItemsView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.6]; + + [self.view addSubview:_bottomItemsView]; + + CGSize size = CGSizeMake(65, 87); + self.btnFlash = [[UIButton alloc]init]; + _btnFlash.bounds = CGRectMake(0, 0, size.width, size.height); + _btnFlash.center = CGPointMake(CGRectGetWidth(_bottomItemsView.frame)/3, CGRectGetHeight(_bottomItemsView.frame)/2); + [_btnFlash setImage:[UIImage imageNamed:@"CodeScan.bundle/qrcode_scan_btn_flash_nor"] forState:UIControlStateNormal]; + [_btnFlash addTarget:self action:@selector(openOrCloseFlash) forControlEvents:UIControlEventTouchUpInside]; + + self.btnPhoto = [[UIButton alloc]init]; + _btnPhoto.bounds = _btnFlash.bounds; + _btnPhoto.center = CGPointMake(CGRectGetWidth(_bottomItemsView.frame)*2/3, CGRectGetHeight(_bottomItemsView.frame)/2); + [_btnPhoto setImage:[UIImage imageNamed:@"CodeScan.bundle/qrcode_scan_btn_photo_nor"] forState:UIControlStateNormal]; + [_btnPhoto setImage:[UIImage imageNamed:@"CodeScan.bundle/qrcode_scan_btn_photo_down"] forState:UIControlStateHighlighted]; + [_btnPhoto addTarget:self action:@selector(openPhoto) forControlEvents:UIControlEventTouchUpInside]; + +// self.btnMyQR = [[UIButton alloc]init]; +// _btnMyQR.bounds = _btnFlash.bounds; +// _btnMyQR.center = CGPointMake(CGRectGetWidth(_bottomItemsView.frame) * 3/4, CGRectGetHeight(_bottomItemsView.frame)/2); +// [_btnMyQR setImage:[UIImage imageNamed:@"CodeScan.bundle/qrcode_scan_btn_myqrcode_nor"] forState:UIControlStateNormal]; +// [_btnMyQR setImage:[UIImage imageNamed:@"CodeScan.bundle/qrcode_scan_btn_myqrcode_down"] forState:UIControlStateHighlighted]; +// [_btnMyQR addTarget:self action:@selector(myQRCode) forControlEvents:UIControlEventTouchUpInside]; + + [_bottomItemsView addSubview:_btnFlash]; + [_bottomItemsView addSubview:_btnPhoto]; +// [_bottomItemsView addSubview:_btnMyQR]; + +} + +//- (void)cameraInitOver +//{ +// if (self.isVideoZoom) { +// [self zoomView]; +// } +//} + +//- (LBXScanVideoZoomView*)zoomView +//{ +// if (!_zoomView) +// { +// +// CGRect frame = self.view.frame; +// +// int XRetangleLeft = self.style.xScanRetangleOffset; +// +// CGSize sizeRetangle = CGSizeMake(frame.size.width - XRetangleLeft*2, frame.size.width - XRetangleLeft*2); +// +// if (self.style.whRatio != 1) +// { +// CGFloat w = sizeRetangle.width; +// CGFloat h = w / self.style.whRatio; +// +// NSInteger hInt = (NSInteger)h; +// h = hInt; +// +// sizeRetangle = CGSizeMake(w, h); +// } +// +// CGFloat videoMaxScale = [self.scanObj getVideoMaxScale]; +// +// //扫码区域Y轴最小坐标 +// CGFloat YMinRetangle = frame.size.height / 2.0 - sizeRetangle.height/2.0 - self.style.centerUpOffset; +// CGFloat YMaxRetangle = YMinRetangle + sizeRetangle.height; +// +// CGFloat zoomw = sizeRetangle.width + 40; +// _zoomView = [[LBXScanVideoZoomView alloc]initWithFrame:CGRectMake((CGRectGetWidth(self.view.frame)-zoomw)/2, YMaxRetangle + 40, zoomw, 18)]; +// +// [_zoomView setMaximunValue:videoMaxScale/4]; +// +// +// __weak __typeof(self) weakSelf = self; +// _zoomView.block= ^(float value) +// { +// [weakSelf.scanObj setVideoScale:value]; +// }; +// [self.view addSubview:_zoomView]; +// +//// UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tap)]; +//// [self.view addGestureRecognizer:tap]; +// } +// +// return _zoomView; +// +//} + + +- (void)scanResultWithArray:(NSArray*)array +{ + + if (array.count < 1) + { + [self popAlertMsgWithScanResult:nil]; + + return; + } + + //经测试,可以同时识别2个二维码,不能同时识别二维码和条形码 + for (LBXScanResult *result in array) { + + NSLog(@"scanResult:%@",result.strScanned); + } + + LBXScanResult *scanResult = array[0]; + + NSString*strResult = scanResult.strScanned; + + self.scanImage = scanResult.imgScanned; + + if (!strResult) { + + [self popAlertMsgWithScanResult:nil]; + + return; + } + + //震动提醒 +// [LBXScanWrapper systemVibrate]; + //声音提醒 +// [LBXScanWrapper systemSound]; + + + [self showNextVCWithScanResult:scanResult]; + +} + +-(void)showNextVCWithScanResult:(LBXScanResult*)result{ + QRCodeResultVC * vc = [[QRCodeResultVC alloc] init]; + vc.modalPresentationStyle = UIModalPresentationCustom; + __weak __typeof(self) weakSelf = self; + vc.restQRCode = ^{ + [weakSelf reStartDevice]; + }; + vc.qrcode = result.strScanned; + [self presentViewController:vc animated:NO completion:nil]; + +} + +- (void)popAlertMsgWithScanResult:(NSString*)strResult +{ + if (!strResult) { + + strResult = @"识别失败"; + } + + UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提示" message:strResult preferredStyle:UIAlertControllerStyleAlert]; + __weak __typeof(self) weakSelf = self; + UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + [weakSelf reStartDevice]; + }]; + [alert addAction:defaultAction]; + [self presentViewController:alert animated:YES completion:nil]; +} + + +- (void)showError:(NSString*)str +{ + + +} + +#pragma mark -底部功能项 +//打开相册 +- (void)openPhoto +{ + if ([LBXScanWrapper isGetPhotoPermission]) + [self openLocalPhoto]; + else + { + UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"提示" message:@"请到设置->隐私中开启本程序相册权限" preferredStyle:UIAlertControllerStyleAlert]; + UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"好的" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { + + }]; + [alert addAction:defaultAction]; + [self presentViewController:alert animated:YES completion:nil]; + } +} + +//开关闪光灯 +- (void)openOrCloseFlash +{ + + [super openOrCloseFlash]; + + + if (self.isOpenFlash) + { + [_btnFlash setImage:[UIImage imageNamed:@"CodeScan.bundle/qrcode_scan_btn_flash_down"] forState:UIControlStateNormal]; + } + else + [_btnFlash setImage:[UIImage imageNamed:@"CodeScan.bundle/qrcode_scan_btn_flash_nor"] forState:UIControlStateNormal]; +} + +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; + // Dispose of any resources that can be recreated. +} + +/* +#pragma mark - Navigation + +// In a storyboard-based application, you will often want to do a little preparation before navigation +- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { + // Get the new view controller using [segue destinationViewController]. + // Pass the selected object to the new view controller. +} +*/ + +@end diff --git a/iDearQRCode/OtherVC/QRCodeVC/View/QRCodeResultView.h b/iDearQRCode/OtherVC/QRCodeVC/View/QRCodeResultView.h new file mode 100644 index 0000000..61e2d02 --- /dev/null +++ b/iDearQRCode/OtherVC/QRCodeVC/View/QRCodeResultView.h @@ -0,0 +1,18 @@ +// +// QRCodeResultView.h +// iDearQRCode +// +// Created by Mortimer on 17/5/23. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import + +@interface QRCodeResultView : UIView + +-(instancetype)initWithResultViewCompleteData:(void(^)(NSDictionary * data,NSInteger index))complete; + +@property (nonatomic , copy) NSString * qrcode; + + +@end diff --git a/iDearQRCode/OtherVC/QRCodeVC/View/QRCodeResultView.m b/iDearQRCode/OtherVC/QRCodeVC/View/QRCodeResultView.m new file mode 100644 index 0000000..8be1184 --- /dev/null +++ b/iDearQRCode/OtherVC/QRCodeVC/View/QRCodeResultView.m @@ -0,0 +1,232 @@ +// +// QRCodeResultView.m +// iDearQRCode +// +// Created by Mortimer on 17/5/23. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import "QRCodeResultView.h" +#import "NSString+Validate.h" +#import "UIView+Toast.h" +@interface QRCodeResultView () + +@property (nonatomic , copy) void(^didSelectHandle)(NSDictionary * data,NSInteger index); + +@property (nonatomic , strong) UILabel * qrcode_num; + +@property (nonatomic , strong) UITextField * count; +@property (nonatomic , strong) UITextField * name; + +@end +@implementation QRCodeResultView + +-(instancetype)initWithResultViewCompleteData:(void (^)(NSDictionary *, NSInteger))complete{ + + self = [super init]; + + if (self) { + self.frame = CGRectMake(20, (kScreen_height - 266)/2, kScreen_width - 40, 266); + self.layer.cornerRadius = 5; + self.layer.masksToBounds = YES; + self.backgroundColor = [UIColor whiteColor]; + [self setupDefaultResultView]; + if (complete) { + self.didSelectHandle = ^(NSDictionary * data, NSInteger index){ + complete(data,index); + }; + } + } + return self; +} + +-(void)setupDefaultResultView{ + + UILabel * (^creatLabel)(NSString * text , UIColor * textColor) = ^(NSString * text , UIColor * textColor){ + UILabel * label = [UILabel new]; + label.font = kFont_14; + label.text = text; + label.textColor = textColor; + return label; + }; + + UILabel * qrcodeLabel = creatLabel(@"条形码 :",topView_Color); + self.qrcode_num = creatLabel(@"",text_Color1); + UILabel * qrcodeNum = creatLabel(@"领料数量",topView_Color); + UILabel * qrcodeName = creatLabel(@"领料名称",topView_Color); + + [self addSubview:qrcodeLabel]; + [self addSubview:self.qrcode_num]; + [self addSubview:qrcodeNum]; + [self addSubview:qrcodeName]; + + UITextField *(^creatTextField)()= ^{ + UITextField * textField = [[UITextField alloc] init]; + textField = [[UITextField alloc] init]; + textField.borderStyle = UITextBorderStyleNone; + textField.font = kFont_14; + textField.textColor = text_Color1; + return textField; + }; + [self addSubview:self.count = creatTextField()]; + self.count.keyboardType = UIKeyboardTypeNumberPad; + + [self addSubview:self.name = creatTextField()]; + self.name.keyboardType = UIKeyboardTypeDefault; + + UIView * (^creatLine)() = ^{ + UIView * view = [UIView new]; + view.backgroundColor = line_Color; + return view; + }; + + UIView * countLine = creatLine(); + UIView * nameLine = creatLine(); + UIView * topLine = creatLine(); + UIView * HLine = creatLine(); + + [self addSubview:countLine]; + [self addSubview:nameLine]; + [self addSubview:topLine]; + [self addSubview:HLine]; + + UIButton * cancel = [UIButton buttonWithType:UIButtonTypeCustom]; + [cancel setTitle:@"取消" forState:UIControlStateNormal]; + [cancel setTitleColor:text_Color1 forState:UIControlStateNormal]; + [cancel addTarget:self action:@selector(disMissView:) forControlEvents:UIControlEventTouchUpInside]; + cancel.tag = 24; + [self addSubview:cancel]; + + UIButton * sure = [UIButton buttonWithType:UIButtonTypeCustom]; + [sure setTitle:@"导入" forState:UIControlStateNormal]; + [sure setTitleColor:topView_Color forState:UIControlStateNormal]; + [sure addTarget:self action:@selector(disMissView:) forControlEvents:UIControlEventTouchUpInside]; + sure.tag = 25; + [self addSubview:sure]; + + + [qrcodeLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(self).offset(20); + make.top.equalTo(self).offset(15); + }]; + + [self.qrcode_num mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(qrcodeLabel); + make.top.equalTo(qrcodeLabel.mas_bottom).offset(4); + }]; + + [qrcodeNum mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(qrcodeLabel); + make.top.equalTo(self.qrcode_num.mas_bottom).offset(15); + }]; + + [self.count mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(qrcodeNum.mas_bottom); + make.left.equalTo(qrcodeLabel); + make.right.equalTo(self); + make.height.mas_equalTo(30); + }]; + + [countLine mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.right.equalTo(self.count); + make.height.mas_equalTo(0.6); + make.top.equalTo(self.count.mas_bottom); + }]; + + [qrcodeName mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(countLine.mas_bottom).offset(15); + make.left.equalTo(qrcodeLabel); + }]; + + [self.name mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(qrcodeLabel); + make.top.equalTo(qrcodeName.mas_bottom); + make.right.height.equalTo(self.count); + }]; + + [nameLine mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.right.height.equalTo(countLine); + make.top.equalTo(self.name.mas_bottom); + }]; + + [topLine mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.right.equalTo(self); + make.height.mas_equalTo(0.6); + make.bottom.equalTo(cancel.mas_top); + }]; + + [cancel mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(self); + make.width.mas_equalTo((kScreen_width -40.6)/2); + make.bottom.equalTo(self); + make.height.mas_equalTo(50); + }]; + + + [HLine mas_makeConstraints:^(MASConstraintMaker *make) { + + make.height.equalTo(cancel); + make.width.mas_equalTo(0.6); + make.centerX.equalTo(self); + make.centerY.equalTo(cancel); + }]; + + [sure mas_makeConstraints:^(MASConstraintMaker *make) { + make.right.equalTo(self); + make.height.width.bottom.equalTo(cancel); + }]; + +} + +-(void)setQrcode:(NSString *)qrcode{ + _qrcode = qrcode; + _qrcode_num.text = qrcode; +} +-(void)disMissView:(UIButton *)sender{ + + NSInteger selectIndex = 0; + NSDictionary * data = [[NSDictionary alloc] init]; + if (sender.tag == 24) { + selectIndex = 0; + }else{ + selectIndex = 1; + NSString * count = _count.text; + if ([count emptyOrNull]) { + [self makeToast:@"请输入数量" duration:0.2 position:CSToastPositionTop]; +// [self makeToast:@"请输入数量" ]; + return; + } + + if (![count validateOnlyNumber]) { + [self makeToast:@"请输入纯数字" duration:0.2 position:CSToastPositionTop]; +// [self makeToast:@"请输入纯数字"]; + return; + } + + NSString * name = _name.text; + if ([name emptyOrNull]) { + [self makeToast:@"请输入物料名称" duration:0.2 position:CSToastPositionTop]; +// [self makeToast:@"请输入物料名称"]; + return; + } + + data = @{ @"qrcode" : self.qrcode, + @"qrcodeNum" : self.count.text, + @"qrcodeName" : self.name.text + }; + } + + if (self.didSelectHandle) { + self.didSelectHandle(data,selectIndex); + } +} + +/* +// Only override drawRect: if you perform custom drawing. +// An empty implementation adversely affects performance during animation. +- (void)drawRect:(CGRect)rect { + // Drawing code +} +*/ + +@end diff --git a/iDearQRCode/OtherVC/View/PickDateView.m b/iDearQRCode/OtherVC/View/PickDateView.m index c0bbb26..b06b678 100644 --- a/iDearQRCode/OtherVC/View/PickDateView.m +++ b/iDearQRCode/OtherVC/View/PickDateView.m @@ -14,6 +14,7 @@ #import "PickingCell.h" #import "PickingModel.h" #import "PickingViewModel.h" +#import "UIView+Toast.h" @interface PickDateView () { BOOL canTouch; @@ -194,6 +195,7 @@ -(void)PickDateClickAction:(UIButton *)sender{ NSDate * start = [NSDate date:start_date WithFormat:@"yyyy-MM-dd"]; NSDate * end = [NSDate date:end_date WithFormat:@"yyyy-MM-dd"]; if ([start isLaterThanDate:end]) { + [self makeToast:@"请输入合理的区间" duration:0.5 position:CSToastPositionCenter]; return; } @@ -217,7 +219,7 @@ -(void)PickDateClickAction:(UIButton *)sender{ }]; - [model fetchPickingList]; + [model fetchPickingList:1]; @@ -342,7 +344,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N cell.pickModel = self.screenArray[indexPath.row]; - cell.isLastCell = self.screenArray.count - 1 == indexPath.row ? YES : NO; +// cell.isLastCell = self.screenArray.count - 1 == indexPath.row ? YES : NO; return cell; diff --git a/iDearQRCode/OtherVC/View/PickDetailFootView.h b/iDearQRCode/OtherVC/View/PickDetailFootView.h new file mode 100644 index 0000000..830e107 --- /dev/null +++ b/iDearQRCode/OtherVC/View/PickDetailFootView.h @@ -0,0 +1,14 @@ +// +// PickDetailFootView.h +// iDearQRCode +// +// Created by Mortimer on 17/5/22. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import + +@interface PickDetailFootView : UIView + +-(void)UPDetailFootView:(NSMutableArray *)data; +@end diff --git a/iDearQRCode/OtherVC/View/PickDetailFootView.m b/iDearQRCode/OtherVC/View/PickDetailFootView.m new file mode 100644 index 0000000..50fe77e --- /dev/null +++ b/iDearQRCode/OtherVC/View/PickDetailFootView.m @@ -0,0 +1,96 @@ +// +// PickDetailFootView.m +// iDearQRCode +// +// Created by Mortimer on 17/5/22. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import "PickDetailFootView.h" + +@interface PickDetailFootView () + +@property (nonatomic , strong) UIView * backView; +@property (nonatomic , strong) UIView * bottomView; + +@end +@implementation PickDetailFootView + + +-(instancetype)initWithFrame:(CGRect)frame{ + if (self = [super initWithFrame:frame]) { + [self setupDefaultFootView]; + } + return self; +} + + +-(void)setupDefaultFootView{ + + _backView = [UIView new]; + _backView.layer.cornerRadius = 4; + _backView.layer.masksToBounds = YES; + _backView.layer.borderWidth = 0.6; + _backView.layer.borderColor = line_Color.CGColor; + _backView.backgroundColor = [UIColor whiteColor]; + [self addSubview:_backView]; + + + UILabel * nameLabel = [UILabel new]; + nameLabel.font = kFont_14; + nameLabel.text = @"领料明细:"; + [_backView addSubview:nameLabel]; + + + UIView * line = [UIView new]; + line.backgroundColor = line_Color; + [_backView addSubview:line]; + + _bottomView = [UIView new]; + [_backView addSubview:_bottomView]; + + [_backView mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.top.equalTo(self).offset(10); + make.right.bottom.equalTo(self).offset(-10); + }]; + + [nameLabel mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.equalTo(_backView).offset(6); + make.top.equalTo(_backView).offset(4); + }]; + + [line mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(nameLabel.mas_bottom).offset(4); + make.left.right.equalTo(_backView); + make.height.mas_equalTo(0.6); + }]; + + [_bottomView mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(line.mas_bottom); + make.left.right.bottom.equalTo(_backView); + }]; +} + +-(void)UPDetailFootView:(NSMutableArray *)data{ + + UILabel * (^creatLabel)(NSString * text , UIColor * textColor) = ^(NSString * text , UIColor * textColor){ + UILabel * label = [UILabel new]; + label.font = kFont_14; + label.text = text; + label.textColor = textColor; + return label; + }; + + + +} + +/* +// Only override drawRect: if you perform custom drawing. +// An empty implementation adversely affects performance during animation. +- (void)drawRect:(CGRect)rect { + // Drawing code +} +*/ + +@end diff --git a/iDearQRCode/OtherVC/View/PickDetailView.h b/iDearQRCode/OtherVC/View/PickDetailView.h new file mode 100644 index 0000000..16eda75 --- /dev/null +++ b/iDearQRCode/OtherVC/View/PickDetailView.h @@ -0,0 +1,16 @@ +// +// PickDetailView.h +// iDearQRCode +// +// Created by Mortimer on 17/5/22. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import + +@interface PickDetailView : UIView + + + +-(void)UPDetailView:(NSMutableArray *)data; +@end diff --git a/iDearQRCode/OtherVC/View/PickDetailView.m b/iDearQRCode/OtherVC/View/PickDetailView.m new file mode 100644 index 0000000..2bc1830 --- /dev/null +++ b/iDearQRCode/OtherVC/View/PickDetailView.m @@ -0,0 +1,229 @@ +// +// PickDetailView.m +// iDearQRCode +// +// Created by Mortimer on 17/5/22. +// Copyright © 2017年 Mortimer. All rights reserved. +// + +#import "PickDetailView.h" +#import "UIImageView+WebCache.h" + +@interface PickDetailView () +{ + UIView * _topView; +} +@property (nonatomic , strong) UIView * backView; +@property (nonatomic , strong) UIView * bottomView; + + +@property (nonatomic , assign) CGFloat lastHeight; + +@end +@implementation PickDetailView + + +-(instancetype)initWithFrame:(CGRect)frame{ + if (self = [super initWithFrame:frame]) { + [self setupDefaultView]; + } + return self; +} + +-(void)setupDefaultView{ + _backView = [UIView new]; + _backView.layer.cornerRadius = 4; + _backView.layer.masksToBounds = YES; + _backView.layer.borderWidth = 0.6; + _backView.layer.borderColor = line_Color.CGColor; + _backView.backgroundColor = [UIColor whiteColor]; + [self addSubview:_backView]; + + + _topView = [UIView new]; + _topView.backgroundColor = [UIColor greenColor]; + [_backView addSubview:_topView]; + + _bottomView = [UIView new]; + [_backView addSubview:_bottomView]; + + [_backView mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.top.equalTo(self).offset(10); + make.right.equalTo(self).offset(-10); + make.bottom.equalTo(self); + }]; + + [_topView mas_makeConstraints:^(MASConstraintMaker *make) { + make.left.right.top.equalTo(_backView); + make.height.mas_equalTo(8); + }]; + + [_bottomView mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(_topView.mas_bottom); + make.left.right.bottom.equalTo(_backView); + }]; + + _lastHeight = 0; +} + +-(void)UPDetailView:(NSMutableArray *)data{ + + + for (UIView * view in _bottomView.subviews) { + [view removeFromSuperview]; + } + + for (int i = 0; i + +@required + +-(void)didHandelAction:(PickModelType)type; + +@end @interface PickingFootView : UIView -(instancetype)initWithPickAction:(void(^)(PickModelType type))pick; -@property (nonatomic , copy) void(^pickAction)(PickModelType) ; + +@property (nonatomic , weak) id delegate; + + diff --git a/iDearQRCode/OtherVC/View/PickingFootView.m b/iDearQRCode/OtherVC/View/PickingFootView.m index a57d685..0887b53 100644 --- a/iDearQRCode/OtherVC/View/PickingFootView.m +++ b/iDearQRCode/OtherVC/View/PickingFootView.m @@ -21,6 +21,7 @@ @interface PickingFootView () @property (nonatomic , strong) UIView * combineView; +@property (nonatomic , copy) void(^pickAction)(PickModelType) ; @end @implementation PickingFootView -(instancetype)initWithPickAction:(void(^)(PickModelType ))pick{ @@ -36,14 +37,14 @@ -(instancetype)initWithPickAction:(void(^)(PickModelType ))pick{ } return self; } -//-(instancetype)initWithFrame:(CGRect)frame{ -// if (self = [super initWithFrame:frame]) { -// self.backgroundColor = [UIColor whiteColor]; -// [self setupFootView]; -// } -// -// return self; -//} +-(instancetype)initWithFrame:(CGRect)frame{ + if (self = [super initWithFrame:frame]) { + self.backgroundColor = [UIColor whiteColor]; + [self setupFootView]; + } + + return self; +} -(void)setupFootView{ @@ -88,36 +89,48 @@ -(void)selectAllAction:(UIButton *)sender{ sender.selected = !sender.selected; if (sender.selected == YES) { [sender setImage:[UIImage imageNamed:@"btn_select_hlight"] forState:UIControlStateNormal]; + + if ([_delegate respondsToSelector:@selector(didHandelAction:)]) { + [_delegate didHandelAction:PickModelSelectAll]; + } if (self.pickAction) { self.pickAction(PickModelSelectAll); } }else{ [sender setImage:[UIImage imageNamed:@"btn_select_normal"] forState:UIControlStateNormal]; - if (self.pickAction) { - self.pickAction(PickModelNormal); + if ([_delegate respondsToSelector:@selector(didHandelAction:)]) { + [_delegate didHandelAction:PickModelNormal]; } +// if (self.pickAction) { +// self.pickAction(PickModelNormal); +// } } } -(void)combineAction:(UIButton *)sender{ - if (self.pickAction) { - self.pickAction(PickModelCombine); + + if ([_delegate respondsToSelector:@selector(didHandelAction:)]) { + [_delegate didHandelAction:PickModelCombine]; } +// if (self.pickAction) { +// self.pickAction(PickModelCombine); +// } } -(void)deleteAction:(UIButton *)sender{ - - if (self.pickAction) { - self.pickAction(PickModelDelete); + + if ([_delegate respondsToSelector:@selector(didHandelAction:)]) { + [_delegate didHandelAction:PickModelDelete]; } +// if (self.pickAction) { +// self.pickAction(PickModelDelete); +// } } -(void)show:(PickModelType)type{ -// [self remove]; -// [[self viewController].view addSubview:self]; -// [[UIApplication sharedApplication].keyWindow addSubview:self]; + if (type == PickModelDelete) { self.deleteBtn.hidden = NO; self.selectAllBtn.hidden = YES; @@ -127,7 +140,9 @@ -(void)show:(PickModelType)type{ self.selectAllBtn.hidden = NO; self.combineBtn.hidden = NO; }else{ - + self.deleteBtn.hidden = YES; + self.selectAllBtn.hidden = YES; + self.combineBtn.hidden = YES; } [UIView animateWithDuration:0.5 animations:^{ diff --git a/iDearQRCode/OtherVC/View/PickingHeadView.h b/iDearQRCode/OtherVC/View/PickingHeadView.h index a700caf..8ac7129 100644 --- a/iDearQRCode/OtherVC/View/PickingHeadView.h +++ b/iDearQRCode/OtherVC/View/PickingHeadView.h @@ -15,8 +15,23 @@ typedef enum { UPViewCombineType, UPViewNormal } UPViewtype; + + +//类名+delegate +@protocol PickingHeadViewDelegate +-(void)didClick:(UPViewtype)type WithSelect:(BOOL)select; +//代理方法必须实现的方法 +@required + +//代理方法可选实现的方法 +@optional + +@end @interface PickingHeadView : UIView -@property (nonatomic , copy) void(^didClickHandler)(UPViewtype,BOOL) ; +@property (nonatomic , weak) id delegate; + + +//@property (nonatomic , copy) void(^didClickHandler)(UPViewtype,BOOL) ; @end diff --git a/iDearQRCode/OtherVC/View/PickingHeadView.m b/iDearQRCode/OtherVC/View/PickingHeadView.m index 84306c2..2505588 100644 --- a/iDearQRCode/OtherVC/View/PickingHeadView.m +++ b/iDearQRCode/OtherVC/View/PickingHeadView.m @@ -44,22 +44,18 @@ -(void)upView:(UIButton *)sender{ //判断点击的是那个button if (btn.tag==[(UIButton *)sender tag]) { -// if (btn.tag == 716 || btn.tag == 717) { -// btn.selected = !btn.selected; //不管用,卧槽 -// if (btn.selected == YES) { - if (self.didClickHandler) { - self.didClickHandler((UPViewtype)btn.tag - 714,sender.selected); - } -// }else{ + + if ([_delegate respondsToSelector:@selector(didClick:WithSelect:)]) { + //如果协议响应了sendvalue:方法 + //通知代理执行协议的方法 + [_delegate didClick:(UPViewtype)btn.tag - 714 WithSelect:sender.selected]; + } + // if (self.didClickHandler) { -// self.didClickHandler(UPViewNormal,sender.selected); +// self.didClickHandler((UPViewtype)btn.tag - 714,sender.selected); // } -// } -// }else{ -// if (self.didClickHandler) { -// self.didClickHandler((UPViewtype)btn.tag - 714,sender.selected); -// } -// } + + }else{ diff --git a/iDearQRCode/Tools/Category/UIImage+Common/UIImage+Common.h b/iDearQRCode/Tools/Category/UIImage+Common/UIImage+Common.h index e5218cf..7d20f06 100644 --- a/iDearQRCode/Tools/Category/UIImage+Common/UIImage+Common.h +++ b/iDearQRCode/Tools/Category/UIImage+Common/UIImage+Common.h @@ -32,4 +32,8 @@ +(UIImage *)imageWithName:(NSString *)name withType:(NSString *)type; - (UIImage *)circleImage; + ++ (UIImage *)getNormalImage:(NSString *)imageStr; + ++ (UIImage *)creatImageWithColor:(UIColor *)color; @end diff --git a/iDearQRCode/Tools/Category/UIImage+Common/UIImage+Common.m b/iDearQRCode/Tools/Category/UIImage+Common/UIImage+Common.m index 9ee1aed..8e2076b 100644 --- a/iDearQRCode/Tools/Category/UIImage+Common/UIImage+Common.m +++ b/iDearQRCode/Tools/Category/UIImage+Common/UIImage+Common.m @@ -29,6 +29,32 @@ +(UIImage *)imageWithName:(NSString *)name withType:(NSString *)type{ return image; } + ++ (UIImage *)getNormalImage:(NSString *)imageStr{ + + UIImage *image = [UIImage imageNamed:imageStr]; + // 设置左边端盖宽度 + NSInteger leftCapWidth = image.size.width * 0.5; + // 设置上边端盖高度 + NSInteger topCapHeight = image.size.height * 0.5; + + UIImage *newImage = [image stretchableImageWithLeftCapWidth:leftCapWidth topCapHeight:topCapHeight]; + return newImage; + +} + ++(UIImage *)creatImageWithColor:(UIColor *)color{ + CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f); + UIGraphicsBeginImageContext(rect.size); + CGContextRef context = UIGraphicsGetCurrentContext(); + CGContextSetFillColorWithColor(context, [color CGColor]); + CGContextFillRect(context, rect); + UIImage * Image = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + return Image; +} + + - (UIImage *)circleImage { // 开始图形上下文 diff --git a/iDearQRCode/Tools/Category/UIImage+Normalimage.h b/iDearQRCode/Tools/Category/UIImage+Normalimage.h deleted file mode 100644 index e0129ff..0000000 --- a/iDearQRCode/Tools/Category/UIImage+Normalimage.h +++ /dev/null @@ -1,16 +0,0 @@ -// -// UIImage+Normalimage.h -// SHUFEAlarm -// -// Created by 刘 on 16/11/24. -// Copyright © 2016年 suxx. All rights reserved. -// - -#import - -@interface UIImage (Normalimage) - -+ (UIImage *)getNormalImage:(NSString *)imageStr; - -+ (UIImage *)creatImageWithColor:(UIColor *)color; -@end diff --git a/iDearQRCode/Tools/Category/UIImage+Normalimage.m b/iDearQRCode/Tools/Category/UIImage+Normalimage.m deleted file mode 100644 index 96dd401..0000000 --- a/iDearQRCode/Tools/Category/UIImage+Normalimage.m +++ /dev/null @@ -1,35 +0,0 @@ -// -// UIImage+Normalimage.m -// SHUFEAlarm -// -// Created by 刘 on 16/11/24. -// Copyright © 2016年 suxx. All rights reserved. -// - -#import "UIImage+Normalimage.h" - -@implementation UIImage (Normalimage) -+ (UIImage *)getNormalImage:(NSString *)imageStr{ - - UIImage *image = [UIImage imageNamed:imageStr]; - // 设置左边端盖宽度 - NSInteger leftCapWidth = image.size.width * 0.5; - // 设置上边端盖高度 - NSInteger topCapHeight = image.size.height * 0.5; - - UIImage *newImage = [image stretchableImageWithLeftCapWidth:leftCapWidth topCapHeight:topCapHeight]; - return newImage; - -} - -+(UIImage *)creatImageWithColor:(UIColor *)color{ - CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f); - UIGraphicsBeginImageContext(rect.size); - CGContextRef context = UIGraphicsGetCurrentContext(); - CGContextSetFillColorWithColor(context, [color CGColor]); - CGContextFillRect(context, rect); - UIImage * Image = UIGraphicsGetImageFromCurrentImageContext(); - UIGraphicsEndImageContext(); - return Image; -} -@end diff --git a/iDearQRCode/Tools/LBXScan/CodeScan.bundle/device_scan@2x.png b/iDearQRCode/Tools/LBXScan/CodeScan.bundle/device_scan@2x.png new file mode 100755 index 0000000000000000000000000000000000000000..07d90a5401cce30f6746854a8993872d66aa92ff GIT binary patch literal 336 zcmeAS@N?(olHy`uVBq!ia0vp^Iv~u!3?wz9Rv7~+%K)DcSD(y6hNTb4Kzm-EI|npG zs3gcQm|<_{1En9USaU+6`JUXivYc|`LDDI6pzIb;7srr_xVKjw`wlCJFb6O*K6jq9 zZQuVy>4S?F2Zknutu)E++_&ejo2$3ttCskZuKtu7+neiN-7VZKEmd`LE%!&cQ=6<# zZZFVZ`yxWMf3he0F20itdAi%@?-h*XbDm=q#4Fe3#}Q?a66hde*wQt@z+=~`kMsXt zZrS-bTQSm0ao@r4e+O3>#ToT?{+gwAY~`u9Q!G!;Pvx7O_hOf)nYF`%zn`~k^t(NG k^5UBY^|KyNDC(|dO6C?ymVGs~7U+HkPgg&ebxsLQ0LYt=CjbBd literal 0 HcmV?d00001 diff --git a/iDearQRCode/Tools/LBXScan/CodeScan.bundle/qrcode_Scan_weixin_Line@2x.png b/iDearQRCode/Tools/LBXScan/CodeScan.bundle/qrcode_Scan_weixin_Line@2x.png new file mode 100755 index 0000000000000000000000000000000000000000..64dc43bdc718e49d3def7c8e9953a550aaefe232 GIT binary patch literal 1500 zcmZA1e>~H99KiAK#)!;@{G4BPO3{Oy^O@!0?g*7ulLi0)>U75b z8~}icd#$ohV($$NcGUp@NQINV?S**1MHK3qrYSruBqfcKlDUmdCixx=9!!eJ&mfl| z2_G8UiB0e7uTn>pPLB-7P*goh$M3aV80}B44>YoI@(k2~i`#x0@1^}|+WS6@1o`hB zue+dJtiJUcjidCH1PDL{Ppkk5MTrkT73uFZ+ zfGb8qe5|vu1d-J;UOSG2M_5ke#av0hr#ms8oina5RFS{n{ri;OgY$?jJ3`$eY{e-8 zs)n4=r`S~ANMj|4!A~5)?8Iwu)J-ksmlOIE%ym!psj<07Wd&DPcTBo*R}B0(<{7VN zY4^uHa$aD@sKH4j3N}`v344quIDVSQYxyoLoVa` znwTrS%heq(fW9ztZv~lE-*S8)`uwwR%$U9?&UHxafjKvRY&=4iAh)DqM706>J*ujJ zqjhgLuGG`;qk0eS>)fnN;UodC+H`&<(y?1zovTvIVZ{#sgWhX8zW6Wzt=6>OsL0n* zX_CbPA>b#Xwgpw&lMoDG{7!ZQj#%ce1qm!z#r=En;SrI>dLC6^B^UR8^!D|xu-GlS z#-phI^3qp#8U`t*HNicuIr?qPA#9FtInfw@)7K?v<5nV{mqvYybAG3}aJ3wy^ONF9 z60=;2ZG_OyphaoncL-l$npbM8w!B36O%p!Dg$Hc91*wJf{Os0|z@~Horx%|&P`}K% zRmyW+gK9@tZBka(pON@So2Y~S%R_IuIUNQmVwo+3U8Jnw5Ee+#nieZgx4huL)SPKt z48zWaEXKQwqS$EV28)1J8v`$`fq_}wm_Rt!`wO!fWD>=OYUdW2JOLNaAz^A zEvVtH-{5UzX$l-guk5)uW^tu6kIPRj(RH^?!ZtfiG=F3I(v)#6vW(%Cm*M#4>%6&= zj;IX6!Bt1GGdXcmrL&CrL=?SItXBiM1Vl@cEs0a0Sy_zD&S+s|I&ZeI98@XC-a0J* zEj<~g{T?)HO>C7UuLCQZ$k$@n@NE4upbAte6yr-a=-WX0?-GRvPLzQK=R1?7DQ7|c z$1vh0V5s&0`l;#d3SrBuBtWQ%Y?mbO9r~PtJPERZvD;DALXi3%4SrLC+&B#XoW%sF z3{=~wIj?F;=+h}uI?(~?j|8p$lQL0!LrFE{61b-O;kiz6_04pp{}SPVCo6Y4V&Uit zGfMWr7WV+-2UffWW29rpT#LtRrU@%RI_(9HLcOzCFw_Dkf{%zc5@zO+OSk7w5o*z0 z3pNsIAGV)uqlZO@ab??i(=6_uf5QLy2YC?> i|2L(@;J-)}Up9Q|_VS1dO3!;wZNSOF-JX6LllCVB!Pp@H literal 0 HcmV?d00001 diff --git a/iDearQRCode/Tools/LBXScan/CodeScan.bundle/qrcode_scan_btn_flash_down@2x.png b/iDearQRCode/Tools/LBXScan/CodeScan.bundle/qrcode_scan_btn_flash_down@2x.png new file mode 100755 index 0000000000000000000000000000000000000000..4fa7ce10f7cadbb5db95afa31a63aa7b4090cf15 GIT binary patch literal 938 zcmV;b16BNqP)Kb3A^aKU~00TNnL_t(| z+U=X$ZreZ%L_NdX|Nn6 zDo&*XBAH1Cj|=fa7$!m?k<3(u#l>*S2?@rWkZ`IX6O1__;RTr>Y%B_`dDi12th+I) zeVReuos9mm^U$1(C|qZ)aZoEI$s4RQ6<}oN1{ojR_gQu6&f5FByFjP`imVesx0a9y%pK?OZ3H314CDg-Em(U-Ex`cWd>gkAcj~I(a3AKBnu{AB}(`Z~zdhKB)jbkpWJt?Gb z;EAFKy>B@uMfL1k*|Rt&>|4)iF_F=?ltD3%rEfv!8HS!AN3A4LD&?+Z&|*75--tts zQ*-GX^sxA3Vc)o`I-~0w`k@wvkiOBU6d&-`HvpzY1^m=8`21!-!X-`^b_3?O$2h)8 zi1Dq`u<;FJ`5D{hW1+|}jE2I;50c=g9H$vf2ercCuHoZd98-{RtQZoGDM+YOQRuG= z<^1v6`9sL_N3rJ*q<7#t6@>T=127 zx7#x4B7kb#Q3XVtx6Nj=*=#nO&1UoeAm9=^_F{&1dxGFyhd7_OT(qcTydZx|c$xF{ zL)_6&96W#c9|=b^oCg8Y#V(Bc?@t~`X@`W2O8#e^1jQl26mt^dAps$S66CNSxQ$7$ zhlGG#FTvyh0XYbj13xzOJfm=}1b(sSg|KH)F7Sf$jzm`f9Y30Lnq8C&d@;0G0>WMm zF_h~hguXH45z18({A~k5xGL93Fb%#MvcSzlxk7^BZ4Z=qv)w@@X7$xdb9o zfdx`n?u3#ifh+SsQcoH}q|G?Mg>kU_-N^J#{@n$TJ&oRMHkZ0<4gdfE M07*qoM6N<$f^_<~y#N3J literal 0 HcmV?d00001 diff --git a/iDearQRCode/Tools/LBXScan/CodeScan.bundle/qrcode_scan_btn_flash_nor@2x.png b/iDearQRCode/Tools/LBXScan/CodeScan.bundle/qrcode_scan_btn_flash_nor@2x.png new file mode 100755 index 0000000000000000000000000000000000000000..ee4b194524261d7c88cc50cc4dcdb4fb545f9d85 GIT binary patch literal 1173 zcmV;G1Zw+vH2D4298M@BhRbC*4uDaoQk(nVsSL)0s3e$2vj=18uX}Y&HWCQZ{sV z0Cz`YC27||j1DI_GPU`LA{;z!oa7FXvVEySog0lu`^YNi<}f}~ObYAqVG5{B%GTpw!aX$|l&_ zdvI_X;UpD)j4~#lDXAbrSj3VVDAHhohET9lgLo)dqd^?74aLBv^?;FyqrkqK;tt7k ztfda)x~{4%2oYOd9>PcN+F6CuK@AAXNpu)+!kY}3F`vP`PIp?-A>or^M(!mT+t z(BvT0Q%xcWtHQvkATV}igH<0H2X?`y*V?$K4dNMdj z!Upix4Zyn#dd3E@^rNbtjSL65f~s$fwN6JLqy`NGXa}j;K-WnSIEA~O zZ?#T|c^jfr)=JZPNGMgB>VwzF3r-d2`nWAz@#14DKJO=CL)`6<2_=OM)geoyX=dbv zquwz9NHP^9J$$YAN=c0#34GjCM#F|&hp12JECvb130+v!iH8lvX>F+MPX)`49Fvvd z8=A498SuClJqSRh>0I53u%Z6CE1amAT7T)+`U1-t8w5bcy#+@e_#S-yYw!RsSPWRd zB%;*?ta=cZEEWgiK$Qio`Kx0gRA(-gu3a#0u@Jl}BMtoX63UZopz3$)>-N+3zD)5K z0mm!w1>2fxfh8EfwQBhWGhM#TPFHR93k7R8JR*QD*fSasg45FNw+huV$Hi^sHXxzY z!FADA>@Xvnm11QR!p>AQ*~dKe<94`T07@GNA%K6Lm%={boCsm(K^2{KTElYn;#jJ#L^Bd;?;P#Ys!n=e81fRXh8O%JFwLJAk=N+3Le zTVs@aI$jY4I$+f3{Wn@uj%F{)1$t@dVhN1$+7O}1brSHb04bu$RTAj502z{*TqMDe zUKZ26D5eW nfGDE#^eHo|w9RI-*;M%hx2zR=y;v5c00000NkvXXu0mjfhqN8R literal 0 HcmV?d00001 diff --git a/iDearQRCode/Tools/LBXScan/CodeScan.bundle/qrcode_scan_btn_myqrcode_down@2x.png b/iDearQRCode/Tools/LBXScan/CodeScan.bundle/qrcode_scan_btn_myqrcode_down@2x.png new file mode 100755 index 0000000000000000000000000000000000000000..973fdd89ab43757305bda597bd44334b2bc7b1b6 GIT binary patch literal 1327 zcmV+~1s#00g^9 zL_t(|+U=W-a-=E{M*E-d{h#)?iyF?lB!hU5j~18~Qj zcs7L&Blr-}F%(A)hk}p6!@`h6M;JzgLXnKg3de_$QDZUTVV#i3s7^?DSSKXXkq(z8 zh2aXEwh3H9yz?=E8i4%wlQ#yW;~E9{8*%tqeWTEp_kYJLS1Irt`H-Fds*vUVIU%@A zA!r@FPC;oMzD|K@9lK5ew2Gro0q9VWt>Y{azKBBKq?cL<`v4l(?J zN1S6gzPq7K9`Wz391bM+|;LLbxLaLgykpOdydm>`j@(gK+>> zrw`)Fd+iH-9FHvxF5z?;%UgT^u)N1dH#avoH#avoH#av|BSnar$SF~a`a2Xl0tZbL zmZHCHKNw&FC=gl9kg9^90|c19aWgXbqBCKFgj!sb4KNiV207#5@32M1n=8DnAdj|W zRtbuw8a6h3D;Up!S9UqsFgHcyHs7+UqKGPyz_cQ(`=X1>Qny+Ck!tC@8dVV@P6d*= z53_;NZr+G-gAq013b3j&ifS!j``MQQr59QSifRd#FBl|XnJ5t2#?6RC-R=1p0-Uv{ zY2vLy7J}y@URu^Ih5W5S3NZa|?%=#_vm7z|hcKK9P!u|#5U{ED1F6tn2F`diXi-&z z>Kwmsilzc!USeNC0T?V`{G?DT&&~jCkA--dX$*E}_#NO)C2)MUEzf@l?L<@*YOlJ}#?0P)BEr3GVmx4Pa(okPBG za+4JWeF`90897@ktthzZo&tRy z5G;^lJ0qOyU@fIlSg3kVEp1t}V<8n>7N~41h=Ca~uPb$VG(3$W-9CG8DF%I2u&gFq zTT>7QlmsSq)oqsIoVXOmPuRDDC<8F{pTlud%W85_ZwXZeoB@+MtP0{O5TYRpIBin^ zQ>m9E8HgNu3SB#yWhxerxx{j%46T2&d)_ADIUFA>3ZYct)pPusz=^2LzKMjY&@q&$ lL8IyOd&m0b=H_OP{{XD_C{j^IHk<$e002ovPDHLkV1n)qU{(MC literal 0 HcmV?d00001 diff --git a/iDearQRCode/Tools/LBXScan/CodeScan.bundle/qrcode_scan_btn_myqrcode_nor@2x.png b/iDearQRCode/Tools/LBXScan/CodeScan.bundle/qrcode_scan_btn_myqrcode_nor@2x.png new file mode 100755 index 0000000000000000000000000000000000000000..20e73a2c5ea5aacca4a1d8467bcbe78f3d654f6f GIT binary patch literal 1603 zcmV-J2E6%+P)(;GXCrXV_V4fDuAV{X+cQS-2zR?8u3l60`{j?;`tbbxoC7Cl8&{ztBG|OJHY6xQ~ z7^ixCB}p|B9swXe|2MS)9swYHjQ30k#RQ;-hKLV2K{j~>jzLUxP6;4Ju%_;%k$Of6 zI&z`;ghF6zBHj(`Zi0j^QH*m>4s)C=bc+9iaP#0Pf}Y~%$*v)ANh1SKZi9Y?XsrZS zGN==r)eAnn79fO^8IBnX8WwXsWH=ynG)S&aitLa&$DV<ZD@Hb(pn0!7?~v)>?aoGVrsg-~~_#woNQY_GT6s@#nYi}KC& znk3SWNn{*C-S~d}=m!1%y6aH366r?>-t+pJY_)d7s&t!ns#XPGd=1+|rQnw$Y=B~H zXrLoB=-)%|Ui-9{BeY55G-gruBS5q+FSwewCWzF$C|ft^{@YZmD9UL!>$(nQYY}=8 zzO9Z#I^i3)E`&MqN#DMq)qUz2WdRZx&0ya_#${2Mi=4QcZPI|*7XKfza+}VZ_@SC-6Y&JQoISBqN%BxIQ5+b-=>2H0cJnS zeu@|p1b@w(0A>s4${@xF^z}<;8}-{Vvs6Nx%!$>)7%8Rj5r}sn31Y%T4FkoPC{i_$ zj8zvhWg}d&cgGBsQpVV77SixDarrI2G;{eqJ`T5T-MV$_)~#E&Zr%E|7%d=%put6A z`D;Mo8=;kdk%^AZZwP<^AQ;$FNZ^c;F4kp$AxTAofR-3p!r*%Q|BHYSrzwM?XRII( z6n!4S8djga5~nom5e5YX5`th+0d*xh6euxL3MFMC0yLuZ5}__x zn@Lr?K3F1obSHJ`8o@6DmP-iyNRz``d1!%T?B%mkV6VK$P85VU!Y2euAJh>HBvl^` z9KnaJilMLYsc`~CrGH6CPY582Rzt{!5fB5x7la(#iveNZ3uRNVMCk~|D!^3)W>o|> zU|g>iD<2vVCxI~YE&>DjZUBq%7iI?03PMIq!vn%HE{)Dv<1zt(3*RCz2?s!TtRv*$ zj!@Yg*Nq@32uAbbT74HPy zAOziAPTRXxse%!eK+83F=$)rLSIlN5S|b!?yp11L*KF+tM^Jv~6M_jKf|dJ9zCAu= z&KVEhh%$+h0BsS(!}x6P5ExS^2H||yUEPX(<024zkt76OY%QcucC-b}!}v{oEh8cT z#pLEf?n@g000U%6L_t(| z+U=X&QsXcTM)m3U{oi;4VbQ>bP3y+_xbT^wllFohTax40t}GUd#o|K3QUUlo05mP+ zK1|_tfJ5z$)+fCF2Qp+PiFyE}Od{0lL0n^o0O~1Vm-j$D4MHwNYl!Q@kzRv%PDlbq zG|a1^bcEK+C@lyLf@RQnu+pG$qZu?tGiYqgfa?%m7vuIyEl}zLH33W*6DN+7R+Gqq zRAi+Cs^O$V)Y zqG+$`+Vk1i{}!R{8a|+KnveOIf@y7N4k(=Fqdumvr;N)C1w5q?uPNXah3r7E6#SBO z^nqca|E*_4dhryF@eGN?6T{fG3Z35pmO_f8m+!+SL&5E{^#}>vuizo()jERlbi|Vi zZSXBE^j-x--&@*Y-q3Vd3VHAu&K1UQQyLPfUR?@DUU90Rqc>|r@0`0Me(+WqRIpP8 zY@Tpv#>o?lo+{+v#I3*5krtsoK5-kIzJ^bpzMfCwF>eyjf0W@r&^1MPtmQr2^OrdI z3q3|(?sER3pYoSJgT4Ta-?|LW-wbGs)(H&=oj}?iBNhedTcs8J4P*YcIrZ>Bhk+W3 zq#q=~Z#hmwOb3sF!(HU#T{gjh?2sa4hh!aiJd6URF5LLXZ|R4S`A4z&2hz#M@+;*c zLTO#l7^-3YPQ*YHXiRAWO(bZ)7ivOJEN=M)S>#U|&^Q`E5K(fc$J%2xo&jociRh-6|xGB_*xML zcwwV_|Jz?prT{Nw={JQsWR8MW76jErd3zw-qadcdT+q_vdqgWl=}ZMHkK+Nl+ir6e z1S!V~@u`rNvT^@ys@tw*9EEN>D(+JFS`ql$_UPQWch+R(BAQvy%I(VTpR%BIpS!_5 z_PLwRRH!!vsO-F7n8)^_nqm2t8E;pzSS%KcSNH=$pa5;yF4vL(00003P)o0R|n010$bPE!E2g%5#o;voqdd_5cUvaBRR$|Dji=tGj&nactm{}DzcVBqKd?aS7Lk&a-u zt+k-J6526`@C$)x2Cb(mHTYaQq6m(qqkNPg=Zex)jmwyX=#}shHVrk;W1~xA^h=vsFY&4d$I(>%1>Ja^y2t{b?X5Mm>;VI{`r8AyC=Yh zeMUsSOaj3Vv`m696Cg7?AXlE0kdE*-6+tP%W=k*tOkOhJ2 z*bU93j@@Xc1UMuhmCC;xd^F5NF6>8U99w0x*=#l=`~$~@ELKB6pCkYP002ovPDHLk FV1oP4OjrN_ literal 0 HcmV?d00001 diff --git a/iDearQRCode/Tools/LBXScan/CodeScan.bundle/qrcode_scan_btn_scan_off@2x.png b/iDearQRCode/Tools/LBXScan/CodeScan.bundle/qrcode_scan_btn_scan_off@2x.png new file mode 100755 index 0000000000000000000000000000000000000000..ecc02c677291957771fbc72dc96c2afbef69f47b GIT binary patch literal 956 zcmV;t14I0YP)&&0+`W3iOP&n<}Ehn7jec^+lWN>3=Uyio$Lc4C($ z;BtMvx=wn)hGYp0l-IBkaU0?i;x=f{l(2q@@x*r0+rVoi#OpK?`$@(YD`a+av6Vve zBp?_;=CyMg{LCPEoxKE~6Xx}E9=y==S{VeBNb?#x4jWRkG2Wgc^D!_Yma^ydbFoJi z=Be8=7O)h-b}q|_U`h47hkj_5zfJb(ze4u5$gEE9AqmY~-DB|j&4BtXk@}6H>M%(C zCSmSLcS z)yHq$>JK4bgkF^f6GNE^6PB4UF)cfjKM@23Nc|U8@)48?nAm$W)YaNTO!2qzr7g#( z{=4C6?KXr8_>eNb$JaKS&1SRNY&M(CzlSN?faj)#YV9rn`FeF4Rgbqx`3bpBk^tkr z!S;&;oRPMMIkW-ogdTs5AV5WARTShgnta{1NjtEogfEA*tphK#1J#EF=nWE7`2gd$ z>KOBopx~6S8UfoGuqg;_WfJTm0ov*$2xPdhT!P7fm^J7z8>}hX9TJFFj^U_d*!2>G z0|k^E%wg}$1t|2TY}=g@2oikp$nKM1z*r_H3IXgk2?~zLpH%65XSoDZaJbKt4|4p# zEfV-OvH&XM<#SNwdI>@RobebU43IVuX`C{ma}`0dk2 z7omMBU?0ZY&G`g@=&5N(@Nh%v>*^VxjnI0g#Uo@xpo(B+V+UPlLjpb@Ao*eJ3jHnn z-ZeY(JLvipYqiy`_jRu4$DOLdznoQy2~sqEqgFr>*)w9}vTVyQy3wwv>lFRLy=i~B zwsg>}a^lyajL#F1)QU-J(a$$3Lzm)ZF4PWFszKqxLa-bh1Ko5eWXu6KxB{&qpk#y4 zpzt>5%JM5XMHrquLG4wLRW^uuj`2w%eI3(m@=Si@RW51 z`htt&IrC?*>bb-G5N+(vc&#XHf*huI%^aYHHBy}gpL|OTR*&iZNvwAx^we`SeO>sY zb>aGd&jNcpzB7gO(-$aYOi(mvA>~yVZr_r9(D&^epsv{3YZ7P0N7B0#Cu(E0cBkI& zNxhHJXq}nUEL9h5yMGN`jor%wPTQ)wSS$k%Z;2N9fQ#0taoI4TL*l}a z0H65*zk&SH=U4m=!tFU5R(b?-`(}YMzXX0Lh!_vlvD|TUhpMvr5(rb~Nq>?AkHN(u zs;9xD?r|ep8ewAy4z7pIsZbst>RqOVP-X+t@Hv}zM&2tGH<@Xe<(8C?yf_s-wTATZw5EezC$Q7l>o zN{sHtXv@+Ft`7Vx=+a&q6aoYy<-K?zD3O+KwnoLwQ7vvTZ~9&&tSnAgDaq6fToxN+ zLLqO=iDohKBn@SJMR~sdGG?N>((&XxYLn4aA(QrhEXz=-+_{DE&s8Jlus$rEK`A3n z_t$j@1GhB)8?T4yaq1C`?-ub;6H!KYQ<~VkB-r+A=5YpJSx63_wsX_ZNrG6qv5@8` z@@?YV&luhivy^~(xWXRBk3?x>&*(!Hv)efo)XCv8Mg zTj1IQSec=H^IPSqL{+@53_j??y!qOxmkYjsP-|^)qB%w;qp7-MK31 z!nZo|#s^%ht?h-ePg0{fCrA~y76o25UmVV95*Ry`la6|tMY}^HuO|YLq3)W3@E1~9 zMsdUvNW%QY{46JKzS4ETItsX_%K(b|zW*xoUE!^x+hBs1Wj!{md*g7^eUPLy{dvux zBb9=lUg{k>$Y`)Mw|5BTFA$UCq-RU_Ace6JBcu~Fv1_=5F3U7+Z0Yw<3ilc*kk~dy zfy*6xr(pV^j)Q|IJsxnMWYcBg94AR3ab+(wnqaR3X0%hp^op60yJGxkLziP@`#WZ= zce1}YRn)|mlivfT-DeIgjKbj7;f`-uiq0+;o)ZsJ^TxL?1isQ#jm%~kZ^&HS&h)&; zOo%7ku0nREEDtvAUn3?S9r0W=6>Fva)^jv%pcj(Q3{RK)$4DcE3>z5`7!FaY{jcrZ z6t0+5;eyfWho=S76bG`OuYgF$jti!hTHQi(cv`{9q}Mc8?K?(%dtv&pA*3TtcwSR_ zT1TEIG+XQjWq(YyogObPQ0e3?a~VH-jxl%o?DX8s40hA&{Z#35zs~E@q!+inQ!>{4 z|6V7jrQ|?jGQ9@rNsg=wXN6hSSj%36jeJC)gmwg4f-yubdinvJE=OnfzZnJc8PHSV zQF8KfmYR0hjRQOui^h0K z;oEK7W#kgSqA?=Byyk^~X2I0mRPT$0YP@<>`SVT@oser-v*{G!-pSs$7z*6LRu2@^ zdo_*#Nx%%KUAO>`(Vb1B${ObWZ@ui0O(Q!GCuXnoPWIMc!6RE6HQ<^qs5#BygR~U`a0EVGodm+un3ej8kpOfX~ki?mB`%CVL>7w~O(ft7~CD)`q|6#{Wz~insBTlf64m|-GzCNYs383b9t7MMP7I33rMyx ztE!g&;}$xLS+^9q^&)y48*FZ`C>AHm8iVoGupve`b~jLqQPNv7plAV##k3@TEBW*6i0 zO7ZN|YoR8pW5z$-clC${EkJ*Zh3{%)qcfSzuWoAUvmxFuV^a~ljr106kEaZ^Csq!4 zI<`n)c$!<3nHTM3*61f_{FE&5$lFzsbGA2E7$L^fdE^g&rXi-_9E(;y(~d&GZu;Kba%a7 z_o}~CsqRC`UA31LFLvzC_~Q0H<4Yfy*!3d$dG+zN^p_~ClB=PM_BX~uWuF>xkVyI-3yW=BoC6Kqp>W~yKE z4EdMKZ!%k@G$hyZ&gm)Pi1Lj6bU-g$HDJ@Kn~ML;EdBPs(C3PM*4}yKc)6?J;|;Ip z-1{Pxo&WCKgVL9u7cFMAFBJc+8S?8#PM>*bpVkMh_Zxn$esg-U@viOGlIxt(XQa)S zoazL6fivHbTd{pKERK5}~fz7xG$_O9+->b1Q5)>OYk-e+&`w!d7S z^FHb6hhN{~B<{YNy}i7Cnf`+3`R}*<`zCjHX3CEQy@DN&6ro_?wH*EH**E&G(kuO{Ez{iD9dJ+Ddr-HF`&-}Op_=3o1MZ>jxTuT4eo z=XyGs|GsaNDt%SE_HwYM5eir_^_WY$!zW2TJm%slnQrj)AeqPJ`|I?mFclJ;G q9lw9#<}DYs-P{*n?}tWo1?#fiduQ;9JBb358H1;*pUXO@geCwKN~U)J literal 0 HcmV?d00001 diff --git a/iDearQRCode/Tools/LBXScan/CodeScan.bundle/qrcode_scan_part_net.png b/iDearQRCode/Tools/LBXScan/CodeScan.bundle/qrcode_scan_part_net.png new file mode 100755 index 0000000000000000000000000000000000000000..093caf9801138b77876f8f04405fcaff8c9dc891 GIT binary patch literal 4637 zcmZ8j2UJtt(gnn*2q;J|(iQ1QM~WDlph%HoFh~nUN{~>cMCnDENbjITdJ91bNN>`S zjsXn_3IwEtQ03kDeebP*{aKmZb0#x;_RO3)NwlGX4jl~#4Fv@SHQ4daT|)|9D$$8L zB(SHutE*`YJhuSxIu8OqA7aLBDJaftID^54cfnv@Lr=Javnz~(BJRyFoC(I(qmJDf zD!-t3&V(|yEn59W;vI~2B1pp*+mA8qcbK!COHU`P&*5sm%xvY%YzwG98|8eDd=bN? zlJ0l2?FoZKtHzlN8emu5dx~%N1vD8YBE~!J`JQv?BJB?B1m|s%j#M_2UkR%M~zHJ3$TJqsn55S&p-HHlx|{GJU346(R`cTOW8c#DKF`3jTpaj zyN+eLE>RiO=yD`Ny~t9%;`B2z(Vyj~@#2-_#6Bu0QCNZkYGR~9?^QCYr*8ka70o%p zVZZz`w?y+(Zj`_!3a^y6*Hi2)Q;g?D%9hcKpTlrHk57kX)-b6=c}kbij3jWYnJ%}> z`#`VYpnre1qB-)|dvsGSKU9N)umDc`l*>#R0IMo_26w%%`s)%gQ z;!xw7C>|b=y<}=T0K4@wk2*JUcQAsBE9Tf~+`i!a?h8!GC`Z&meQ4WP-Depqnng%O z{OI_tiBMQRCz@nh=c%||o|EKW!nozadQ#05Fv6nh>nDt7DyEGQ=s&2IR=zwDgDc>O zbLm<_Bdn#mhmYL-g}1K_m72lCx*u1R+TOr3Aoby5%i{{;rQzUK`VkUB&{S*8o+di3 zCrC`>O|RYeBBz^iq52o1BQ?Lj&9w(PGCyXIj#;EHjPJB#2oG(hxn}%<+b+|#xi<#N zFS-}QSMy+x#Lf;?BL1aTg$1`Ylz}oDr{tj30*Fd7>VPP<|<=w&vtMd61 z^B|2UBk;tIu6ObFEYYEng1U;jdmfZ&i6Rm$-$(C#yK0!dXW;AWzAlQ|=p{vL(jjV5 z$%B7hpU4EL9y#y1?vWykoA7VY3Fs>HW_?vX9L-aM-kCj1I7cYld$;F?uP|Fk*qck% z_Y&PQ%dYQ~+gaA$Ia_C~=J?5;-g|$5=uo9(?Jj+BxqA;QM10+>c<&nq)mUp5#@W&F zU6@hpHZyC&;w1v|vABG+mGu6|6hP+_7CyZBCLRLbGUyX*BmsiEp-a*+|Q~O_cV5iFOnq_aBLVkxl$2IdQj(OqDS7jzIA9@;@OSsJ@e_AP2>b)`UmQ&s!p_s#!^;`&&P&F% zv4wkksq*ua1O4yyFHbj*{{?bK{F@b!pQN9ShorQGl;r=A0Y?=eM`f@l%*G4u`4A3w zRns6Bfmhqv6Xpx|bV2ZfP2^Q1|G&|{QB@?#RQ?aOfAapT1rk@I0X+X(L^Ya@hPod> zT`zd(K0;7XTx28*~sbI+nlf4ZZhRP18TW)Fn|wiSJH<;Z&t_p>w8F zNSpPP%;WQH>qu+a<~0%(EeIRY3|1NbqLTA87sU<=g?2b)2D1!RNwK;5Wv%#U{<2U^ zaAKqN;qC~3(N=jC56fUByW{!jZRq=Niud1?>^Vvs1gt%ZU>Rv_sry&(zs6}p+q&z0 zqY~`%baqE6fQ^FkSdi5VAa*s(|AFmeF1GbrzTo?|NxXameBDA3Qs8#xfT(mx0cU@TsDcigQ z7qhfw!rQEivYtM)wVHnQrOF|8&%D}3YTB=OR9Emk;@eJ?13j5m16!IdzlLT=_N9I@ zdN)_PX2{ixIyqT@?T79rsc7oHN42__C(QE^`0Ohk*41s|LI#42Z<%gXh3`Kd%0{SV z0+#v3N{DL{P9hq^0uZ_PBD5e*TzY8Y>KcZ)R(*V!h3TnqWuukHlu!%RIhAe+Y#9MQ z``5N}J16Q(wdG>(%4K33v4;VA06yiQEaV2>o}1}fKOBHFA&vz`Xt$In-wI&U}*-FWtN@VN`Q zcV&~pLIy4mTx#>e=gUb64gj6pdWSf@RL}Lg1m)b(ur_PEtVgmUkMwRB&qw~qhUhJdQ$Mw~(%Etf%}maXh&Jvs-b=U)cbUcf z17G0+>4UD-46Cg+kpSOCh+cLtw7Jo&kc8yE&hJ}6AKDht@cNx$(0yBV)LiTbAo=g& zLPJYh$HAh$lKA?kME*~k2bj$RP-q)S-h82>ie7Q1suAhKO%fhx>S3j%R z2>4`FHc770M7zYOAcx3*{>exB$pez$P7;%PPd#@(aezU!5nl zL3|Ui3S1jJYyqbK^mJ%gA)SKaybO8l318<-Os1~3Zh5~Mv8xOKe%wArhFzusX;IsK z2&IzNkoF{Amf+_Hp{aidpLuJ@^u~`ep)f_5$wf%7qlRc)hEe`fA``S`a+2)^(rfS_8(&><{!zt0)%I`SqPbmok}!gwjNi~-Ozr;dGjlil_z{<53l?o{Z9T6L_dE_{quo|((Z?S)Qfhh%iMxD9%q-;P%ab#&ikE0@YhK$q zo&EFHPx~c1h?e%1*B7Tr!>9u0>GzKJXe(N|%skVLtefNIe|n=SWvs2O1+xtFe=#^P zP22CYNgsWW(9q$eQ=W}tmy(hSiJNe_p^CQzIanl6%?M~ zjuUa!w2a|Sl%uK2Fu)jArwPwO8HEfxR_b33X0L9eCZyj z+y181H5O4NAd2T;J}NG%OK-@worOg-mEYk$sN40X)H2K_6mWOUHhRFB^n1(pfMw7| zs0Tn~fXfOwCbpJPzci2Sztm4v#nRT=+N%J73I2YXWM|GaEaD$;y8V|axR1TFMr8h} zjT=|ll9rYDc6m%gx<^P?*cCssvmlUm=`)de*Usex2E=7)wrO=aTO&h#eV)WL&~OQL zuE~XeFhr#o{p$rUa1gdTY6YDH?~dsH)eo2Y0ZL~Wjta#{4dj8Rlc9MNLrIPj(BK z(Seam5(i@v8;jwnFevl_Qq*thrUp*L901Onqxq|o**mrg0&t=RGQiYW^zkK`>)(wI z0WVFwHYnUJ%ui*kXi^>hJf}qo^#5Tpb)0>jN3<@}_-g?pU8}1#xX*J0(SOd^pLmO^ zce{|S4#eKrNDK!za4rwJ5h9fA#8-Wpt=GHz@b;cvjxmalvc=lkXBfq@=>WvX$z45N zS+AyFi8%~CeenAAqW#T`JN4Sktdg+}b6Sx&31vJUwneT{rkE8=USjK9VpsbkoO{5= z%8kQ%mz-|z8zmq|v(&+y6c_^amLnT5U4l3iPlT77@zvz>!t`gK??lkCPY!thN_~~h zr4wurFMxzL3Y`Ih-?Pkf@AGiH{-a>Y9vUM$m(<}>Gil8r7Q*5p1NHGO?%!YmrlePn zyKJs{G&S7Vm~NNT91nRB**V-pl7A8 zn;xz2qerVL3r~k zqLp?1=N`$&>nMQ4_4_P&ijIZRpwd4~ zA~UH!)_8F0lU!e!T`x|AL6k*rC0vrtyQMY~SoyB5_6krt!&?^KzjdFOsEZIke(o@7 zZg@anPfvnQBfk&m&h;98SllK{MiPbrK(-|ur!8{ZEX{1pOZ$^Ln_t#^>nix&)*rf< zvsjc|utpa08lc<>*>BgJ5)>h=m|A^A*fy@XuFWih3E;@1xkH`G@N3$D(32X7TT&etln~L zyKS{FFn-c@q_8|Rcz^hk4r(Q`h`j!LHTzzrA1qouti8QXBq}uU(5gpi4y$M8@oSpx78|eW*uoQ6(0C2LL#l!|ePU5!{U}YE__{POGT^#y>niUfEw3aa zdxlIGn#Z2`u|W#+V$~AUpmHLuM8I#r4{}q9EzIC zEsU6qnM^|l?)2b#(s+hdGyHC1{k)%jpBOa1SmpjH6WY{xo_t?JEdzJAyYvW{peUR8AkfC`ja}az1YZMRPNtO??@I~srcVIVX5bOulD;-RaeW^ z(_`ZB=@D_hszxD6LA^OI;PlJUM-q8MK6$fvNnfP@){#QXDbM3Evj@Qc2#UK}2AY+3 HtV8|-O^VLL literal 0 HcmV?d00001 diff --git a/iDearQRCode/Tools/LBXScan/CodeScan.bundle/qrcode_scan_titlebar_back_nor@2x.png b/iDearQRCode/Tools/LBXScan/CodeScan.bundle/qrcode_scan_titlebar_back_nor@2x.png new file mode 100755 index 0000000000000000000000000000000000000000..5bb2e31db095bba8f8f82020b14792ffbaf46ad0 GIT binary patch literal 185 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sLIFM@u0Z-fDzFP$YXuZ#EeY}q zW>9?WdTGj}6{~>)fu1goAr-gYUfalfz<`I@F;M7x{7vp9l?qHbH`ctbKK4DNaal=s z(PN^U!y(MXncLf4FRU@OwIAu_o)* SSng(!;S8RxelF{r5}E)InNec^ literal 0 HcmV?d00001 diff --git a/iDearQRCode/Tools/LBXScan/CodeScan.bundle/qrcode_scan_titlebar_back_pressed@2x.png b/iDearQRCode/Tools/LBXScan/CodeScan.bundle/qrcode_scan_titlebar_back_pressed@2x.png new file mode 100755 index 0000000000000000000000000000000000000000..4b5cbace1a760926c0d5b55619c92d528d13d17c GIT binary patch literal 164 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA3?vioaBc-sJOMr-u0Z-f3|JhnUIFB@lmz(& zGo%SbF5jcY3FJF_x;TbZ+ + + +@interface UIActionSheet (LBXAlertAction) + + +- (void)showInView:(UIView *)view block:(void(^)(NSInteger idx,NSString* buttonTitle))block; + +@end diff --git a/iDearQRCode/Tools/LBXScan/LBXAlertAction/Class/UIActionSheet+LBXAlertAction.m b/iDearQRCode/Tools/LBXScan/LBXAlertAction/Class/UIActionSheet+LBXAlertAction.m new file mode 100755 index 0000000..6b295ec --- /dev/null +++ b/iDearQRCode/Tools/LBXScan/LBXAlertAction/Class/UIActionSheet+LBXAlertAction.m @@ -0,0 +1,46 @@ +// +// UIActionSheet+Block.m +// +// +// Created by lbxia on 15/10/27. +// Copyright © 2015年 lbxia. All rights reserved. +// + +#import "UIActionSheet+LBXAlertAction.h" +#import + +static char key; + +@implementation UIActionSheet (LBXAlertAction) + + +- (void)showInView:(UIView *)view block:(void(^)(NSInteger idx,NSString* buttonTitle))block +{ + if (block) { + objc_removeAssociatedObjects(self); + objc_setAssociatedObject(self, &key, block, OBJC_ASSOCIATION_COPY); + self.delegate = self; + } + [self showInView:view]; +} + + +// Called when a button is clicked. The view will be automatically dismissed after this call returns +- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex +{ + void(^block)(NSInteger idx,NSString* buttonTitle); + block = objc_getAssociatedObject(self, &key); + objc_removeAssociatedObjects(self); + if (block) { + block(buttonIndex,[self buttonTitleAtIndex:buttonIndex]); + } +} + +// Called when we cancel a view (eg. the user clicks the Home button). This is not called when the user clicks the cancel button. +// If not defined in the delegate, we simulate a click in the cancel button +- (void)actionSheetCancel:(UIActionSheet *)actionSheet +{ + +} + +@end diff --git a/iDearQRCode/Tools/LBXScan/LBXAlertAction/Class/UIAlertController+supportedInterfaceOrientations.h b/iDearQRCode/Tools/LBXScan/LBXAlertAction/Class/UIAlertController+supportedInterfaceOrientations.h new file mode 100755 index 0000000..b2d0b7e --- /dev/null +++ b/iDearQRCode/Tools/LBXScan/LBXAlertAction/Class/UIAlertController+supportedInterfaceOrientations.h @@ -0,0 +1,13 @@ +// +// UIAlertController+supportedInterfaceOrientations.h +// +// +// Created by lbxia on 16/1/16. +// Copyright © 2016年 lbxia. All rights reserved. +// + +#import + +@interface UIAlertController (supportedInterfaceOrientations) + +@end diff --git a/iDearQRCode/Tools/LBXScan/LBXAlertAction/Class/UIAlertController+supportedInterfaceOrientations.m b/iDearQRCode/Tools/LBXScan/LBXAlertAction/Class/UIAlertController+supportedInterfaceOrientations.m new file mode 100755 index 0000000..f3ed743 --- /dev/null +++ b/iDearQRCode/Tools/LBXScan/LBXAlertAction/Class/UIAlertController+supportedInterfaceOrientations.m @@ -0,0 +1,21 @@ +// +// UIAlertController+supportedInterfaceOrientations.m +// +// +// Created by lbxia on 16/1/16. +// Copyright © 2016年 lbxia. All rights reserved. +// + +#import "UIAlertController+supportedInterfaceOrientations.h" + +@implementation UIAlertController (supportedInterfaceOrientations) +#if __IPHONE_OS_VERSION_MAX_ALLOWED < 90000 +- (NSUInteger)supportedInterfaceOrientations; { + return UIInterfaceOrientationMaskPortrait; +} +#else +- (UIInterfaceOrientationMask)supportedInterfaceOrientations { + return UIInterfaceOrientationMaskPortrait; +} +#endif +@end diff --git a/iDearQRCode/Tools/LBXScan/LBXAlertAction/Class/UIAlertView+LBXAlertAction.h b/iDearQRCode/Tools/LBXScan/LBXAlertAction/Class/UIAlertView+LBXAlertAction.h new file mode 100755 index 0000000..c20d019 --- /dev/null +++ b/iDearQRCode/Tools/LBXScan/LBXAlertAction/Class/UIAlertView+LBXAlertAction.h @@ -0,0 +1,21 @@ +// +// UIAlertView+Block.h +// +// +// Created by lbxia on 15/10/27. +// Copyright © 2015年 lbxia. All rights reserved. +// + + +#import + + +@interface UIAlertView (LBXAlertAction) + +// 用Block的方式回调,这时候会默认用self作为Delegate +- (void)showWithBlock:(void(^)(NSInteger buttonIndex)) block; + + + + +@end \ No newline at end of file diff --git a/iDearQRCode/Tools/LBXScan/LBXAlertAction/Class/UIAlertView+LBXAlertAction.m b/iDearQRCode/Tools/LBXScan/LBXAlertAction/Class/UIAlertView+LBXAlertAction.m new file mode 100755 index 0000000..69e32f7 --- /dev/null +++ b/iDearQRCode/Tools/LBXScan/LBXAlertAction/Class/UIAlertView+LBXAlertAction.m @@ -0,0 +1,41 @@ +// +// UIAlertView+Block.h +// +// +// Created by lbxia on 15/10/27. +// Copyright © 2015年 lbxia. All rights reserved. +// + +#import "UIAlertView+LBXAlertAction.h" +#import + +@implementation UIAlertView (LBXAlertAction) + + +static char key; + + + +- (void)showWithBlock:(void(^)(NSInteger buttonIndex))block +{ + if (block) { + objc_removeAssociatedObjects(self); + objc_setAssociatedObject(self, &key, block, OBJC_ASSOCIATION_COPY); + self.delegate = self; + } + + [self show]; +} + +- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex +{ + void(^block)(NSInteger buttonIndex); + block = objc_getAssociatedObject(self, &key); + objc_removeAssociatedObjects(self); + if (block) + block(buttonIndex); +} + + + +@end \ No newline at end of file diff --git a/iDearQRCode/Tools/LBXScan/LBXAlertAction/LBXAlertAction.h b/iDearQRCode/Tools/LBXScan/LBXAlertAction/LBXAlertAction.h new file mode 100755 index 0000000..b9893d0 --- /dev/null +++ b/iDearQRCode/Tools/LBXScan/LBXAlertAction/LBXAlertAction.h @@ -0,0 +1,47 @@ +// +// LBXAlertAction.h +// +// +// Created by lbxia on 15/10/27. +// Copyright © 2015年 lbxia. All rights reserved. +// + +#import + + +/** + @brief 封装UIAlertView、UIActionSheet、UIAlertController + 根据不同系统版本,对应选择,方便调用 + */ +@interface LBXAlertAction : NSObject + + + +/** + @brief 模式对话框,选择一项(UIAlertView与与UIAlertController封装,根据不同ios版本对应选择调用方法) + @param title 标题 + @param msg 提示内容 + @param block 返回点击的按钮index,按照buttonsStatement按钮的顺序,从0开始 + @param cancelString 取消按钮 文本,必须以nil结束 + */ ++ (void)showAlertWithTitle:(NSString*)title msg:(NSString*)msg chooseBlock:(void (^)(NSInteger buttonIdx))block buttonsStatement:(NSString*)cancelString, ...; + +//增加延时消失入口 + + + +/** + @brief 显示UIActionSheet模式对话框,UIActionSheet与UIAlertController封装,根据不同ios版本对应选择调用方法。 + @param title 标题 + @param message 消息内容,大于ios8.0才会显示 + @param block 返回block,buttonIdx:cancelString,destructiveButtonTitle分别为0、1, + otherButtonTitle从后面开始,如果destructiveButtonTitle没有,buttonIndex1开始,反之2开始 + @param cancelString 取消文本 + @param destructiveButtonTitle 特殊标记按钮,默认红色文字显示 + @param otherButtonTitle 其他选项,必须以nil结束 + */ ++ (void)showActionSheetWithTitle:(NSString*)title message:(NSString*)message chooseBlock:(void (^)(NSInteger buttonIdx))block + cancelButtonTitle:(NSString*)cancelString destructiveButtonTitle:(NSString*)destructiveButtonTitle otherButtonTitle:(NSString*)otherButtonTitle,...; + + +@end diff --git a/iDearQRCode/Tools/LBXScan/LBXAlertAction/LBXAlertAction.m b/iDearQRCode/Tools/LBXScan/LBXAlertAction/LBXAlertAction.m new file mode 100755 index 0000000..f72499e --- /dev/null +++ b/iDearQRCode/Tools/LBXScan/LBXAlertAction/LBXAlertAction.m @@ -0,0 +1,217 @@ +// +// LBXAlertAction.m +// +// +// Created by lbxia on 15/10/27. +// Copyright © 2015年 lbxia. All rights reserved. +// + +#import "LBXAlertAction.h" +#import +#import "UIAlertView+LBXAlertAction.h" +#import "UIActionSheet+LBXAlertAction.h" + +@implementation LBXAlertAction + + ++ (BOOL)isIosVersion8AndAfter +{ + //return NO; + + + return [[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0 ; +} + ++ (void)showAlertWithTitle:(NSString*)title msg:(NSString*)message chooseBlock:(void (^)(NSInteger buttonIdx))block buttonsStatement:(NSString*)cancelString, ... +{ + + NSMutableArray* argsArray = [[NSMutableArray alloc] initWithCapacity:2]; + [argsArray addObject:cancelString]; + id arg; + va_list argList; + if(cancelString) + { + va_start(argList,cancelString); + while ((arg = va_arg(argList,id))) + { + [argsArray addObject:arg]; + } + va_end(argList); + } + + if ( [LBXAlertAction isIosVersion8AndAfter]) + { + //UIAlertController style + + UIAlertController* alertController = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert]; + for (int i = 0; i < [argsArray count]; i++) + { + UIAlertActionStyle style = (0 == i)? UIAlertActionStyleCancel: UIAlertActionStyleDefault; + // Create the actions. + UIAlertAction *action = [UIAlertAction actionWithTitle:[argsArray objectAtIndex:i] style:style handler:^(UIAlertAction *action) { + if (block) { + block(i); + } + }]; + [alertController addAction:action]; + } + + [[LBXAlertAction getTopViewController] presentViewController:alertController animated:YES completion:nil]; + + return; + } + + //UIAlertView style + + UIAlertView* alertView = [[UIAlertView alloc]initWithTitle:title message:message delegate:nil cancelButtonTitle:cancelString otherButtonTitles:nil, nil]; + + [argsArray removeObject:cancelString]; + for (NSString *buttonTitle in argsArray) { + + NSLog(@"buttonTitle:%@",buttonTitle); + [alertView addButtonWithTitle:buttonTitle]; + } + + [alertView showWithBlock:^(NSInteger buttonIdx) + { + + block(buttonIdx); + }]; +} + + + ++ (UIViewController*)getTopViewController +{ + UIViewController *result = nil; + + + UIWindow * window = [[UIApplication sharedApplication] keyWindow]; + if (window.windowLevel != UIWindowLevelNormal) + { + NSArray *windows = [[UIApplication sharedApplication] windows]; + for(UIWindow * tmpWin in windows) + { + if (tmpWin.windowLevel == UIWindowLevelNormal) + { + window = tmpWin; + break; + } + } + } + + + UIView *frontView = [[window subviews] objectAtIndex:0]; + id nextResponder = [frontView nextResponder]; + + + if ([nextResponder isKindOfClass:[UIViewController class]]) + result = nextResponder; + else + result = window.rootViewController; + + return result; +} + + + ++ (void)showActionSheetWithTitle:(NSString*)title message:(NSString*)message chooseBlock:(void (^)(NSInteger buttonIdx))block + cancelButtonTitle:(NSString*)cancelString destructiveButtonTitle:(NSString*)destructiveButtonTitle otherButtonTitle:(NSString*)otherButtonTitle,... +{ + NSMutableArray* argsArray = [[NSMutableArray alloc] initWithCapacity:3]; + + + if (cancelString) { + [argsArray addObject:cancelString]; + } + if (destructiveButtonTitle) { + [argsArray addObject:destructiveButtonTitle]; + } + + + id arg; + va_list argList; + if(otherButtonTitle) + { + [argsArray addObject:otherButtonTitle]; + va_start(argList,otherButtonTitle); + while ((arg = va_arg(argList,id))) + { + [argsArray addObject:arg]; + } + va_end(argList); + } + + if ( [LBXAlertAction isIosVersion8AndAfter]) + { + UIAlertController* alertController = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleActionSheet]; + for (int i = 0; i < [argsArray count]; i++) + { + UIAlertActionStyle style = (0 == i)? UIAlertActionStyleCancel: UIAlertActionStyleDefault; + + if (1==i && destructiveButtonTitle) { + + style = UIAlertActionStyleDestructive; + } + + // Create the actions. + UIAlertAction *action = [UIAlertAction actionWithTitle:[argsArray objectAtIndex:i] style:style handler:^(UIAlertAction *action) { + if (block) { + block(i); + } + }]; + [alertController addAction:action]; + } + + [[LBXAlertAction getTopViewController] presentViewController:alertController animated:YES completion:nil]; + return; + } + + //UIActionSheet + UIView *view = [self getTopViewController].view; + UIActionSheet *sheet = [[UIActionSheet alloc]initWithTitle:title delegate:nil cancelButtonTitle:cancelString destructiveButtonTitle:destructiveButtonTitle otherButtonTitles:nil, nil]; + + + if (cancelString) { + [argsArray removeObject:cancelString]; + } + if (destructiveButtonTitle) { + [argsArray removeObject:destructiveButtonTitle]; + } + + for (NSString* title in argsArray) + { + [sheet addButtonWithTitle:title]; + } + + __block BOOL isDestructiveExist = destructiveButtonTitle ? YES:NO; + + [sheet showInView:view block:^(NSInteger buttonIdx,NSString* buttonTitle) + { + NSInteger idx = buttonIdx; + + if (isDestructiveExist ) { + + switch (idx) { + case 0: + idx = 1; + break; + case 1: + idx = 0; + break; + + default: + break; + } + } + + if (block) { + block(idx); + } + }]; + + +} + + +@end diff --git a/iDearQRCode/Tools/LBXScan/LBXScanLineAnimation.h b/iDearQRCode/Tools/LBXScan/LBXScanLineAnimation.h new file mode 100755 index 0000000..6d31652 --- /dev/null +++ b/iDearQRCode/Tools/LBXScan/LBXScanLineAnimation.h @@ -0,0 +1,29 @@ +// +// LBXScanLineAnimation.h +// +// github:https://github.com/MxABC/LBXScan +// Created by lbxia on 15/11/3. +// Copyright © 2015年 lbxia. All rights reserved. +// + +#import + +@interface LBXScanLineAnimation : UIImageView + + + +/** + * 开始扫码线动画 + * + * @param animationRect 显示在parentView中得区域 + * @param parentView 动画显示在UIView + * @param image 扫码线的图像 + */ +- (void)startAnimatingWithRect:(CGRect)animationRect InView:(UIView*)parentView Image:(UIImage*)image; + +/** + * 停止动画 + */ +- (void)stopAnimating; + +@end diff --git a/iDearQRCode/Tools/LBXScan/LBXScanLineAnimation.m b/iDearQRCode/Tools/LBXScan/LBXScanLineAnimation.m new file mode 100755 index 0000000..8191e90 --- /dev/null +++ b/iDearQRCode/Tools/LBXScan/LBXScanLineAnimation.m @@ -0,0 +1,163 @@ +// +// LBXScanLineAnimation.m +// +// +// Created by lbxia on 15/11/3. +// Copyright © 2015年 lbxia. All rights reserved. +// + +#import "LBXScanLineAnimation.h" + + +@interface LBXScanLineAnimation() +{ + int num; + BOOL down; + NSTimer * timer; + + BOOL isAnimationing; +} + +@property (nonatomic,assign) CGRect animationRect; + +@end + + + +@implementation LBXScanLineAnimation + + + +- (void)stepAnimation +{ + if (!isAnimationing) { + return; + } + + + CGFloat leftx = _animationRect.origin.x + 5; + CGFloat width = _animationRect.size.width - 10; + + self.frame = CGRectMake(leftx, _animationRect.origin.y + 8, width, 8); + + self.alpha = 0.0; + + self.hidden = NO; + + __weak __typeof(self) weakSelf = self; + + [UIView animateWithDuration:0.5 animations:^{ + weakSelf.alpha = 1.0; + + + + } completion:^(BOOL finished) + { + + }]; + + [UIView animateWithDuration:3 animations:^{ + CGFloat leftx = _animationRect.origin.x + 5; + CGFloat width = _animationRect.size.width - 10; + + + + weakSelf.frame = CGRectMake(leftx, _animationRect.origin.y + _animationRect.size.height - 8, width, 4); + + } completion:^(BOOL finished) + { + self.hidden = YES; + [weakSelf performSelector:@selector(stepAnimation) withObject:nil afterDelay:0.3]; + }]; +} + + + +- (void)startAnimatingWithRect:(CGRect)animationRect InView:(UIView *)parentView Image:(UIImage*)image +{ + if (isAnimationing) { + return; + } + + isAnimationing = YES; + + + self.animationRect = animationRect; + down = YES; + num =0; + + CGFloat centery = CGRectGetMinY(animationRect) + CGRectGetHeight(animationRect)/2; + CGFloat leftx = animationRect.origin.x + 5; + CGFloat width = animationRect.size.width - 10; + + self.frame = CGRectMake(leftx, centery+2*num, width, 2); + self.image = image; + + [parentView addSubview:self]; + + [self startAnimating_UIViewAnimation]; + +// [self startAnimating_NSTimer]; + + +} + +- (void)startAnimating_UIViewAnimation +{ + [self stepAnimation]; +} + +- (void)startAnimating_NSTimer +{ + timer = [NSTimer scheduledTimerWithTimeInterval:.02 target:self selector:@selector(scanLineAnimation) userInfo:nil repeats:YES]; +} + +-(void)scanLineAnimation +{ + CGFloat centery = CGRectGetMinY(_animationRect) + CGRectGetHeight(_animationRect)/2; + CGFloat leftx = _animationRect.origin.x + 5; + CGFloat width = _animationRect.size.width - 10; + + if (down) + { + num++; + + self.frame = CGRectMake(leftx, centery+2*num, width, 2); + + if (centery+2*num > (CGRectGetMinY(_animationRect) + CGRectGetHeight(_animationRect) - 5 ) ) + { + down = NO; + } + } + else { + num --; + self.frame = CGRectMake(leftx, centery+2*num, width, 2); + if (centery+2*num < (CGRectGetMinY(_animationRect) + 5 ) ) + { + down = YES; + } + } +} + +- (void)dealloc +{ + [self stopAnimating]; +} + +- (void)stopAnimating +{ + if (isAnimationing) { + + isAnimationing = NO; + + if (timer) { + [timer invalidate]; + timer = nil; + } + + [self removeFromSuperview]; + } + [NSObject cancelPreviousPerformRequestsWithTarget:self]; +} + +@end diff --git a/iDearQRCode/Tools/LBXScan/LBXScanNative.h b/iDearQRCode/Tools/LBXScan/LBXScanNative.h new file mode 100755 index 0000000..3010ff9 --- /dev/null +++ b/iDearQRCode/Tools/LBXScan/LBXScanNative.h @@ -0,0 +1,86 @@ +// +// +// +// github:https://github.com/MxABC/LBXScan +// Created by lbxia on 15/3/4. +// Copyright (c) 2015年 lbxia. All rights reserved. +// + + +@import UIKit; +@import Foundation; +@import AVFoundation; + +#import "LBXScanResult.h" + +/** + @brief ios系统自带扫码功能 + */ +@interface LBXScanNative : NSObject + + + +/** + @brief 初始化采集相机 + @param preView 视频显示区域 + @param objType 识别码类型:如果为nil,默认支持很多类型。 + @param cropRect 识别区域,值CGRectZero 全屏识别 + @param block 识别结果 + @return LBXScanNative的实例 + */ +- (instancetype)initWithPreView:(UIView*)preView ObjectType:(NSArray*)objType cropRect:(CGRect)cropRect + success:(void(^)(NSArray *array))block; + + +/*! + * 设置扫码成功后是否拍照 + * + * @param isNeedCaputureImg YES:拍照, NO:不拍照 + */ +- (void)setNeedCaptureImage:(BOOL)isNeedCaputureImg; + + +/*! + * 开始扫码 + */ +- (void)startScan; + +/*! + * 停止扫码 + */ +- (void)stopScan; + +/*! + * 开启关闭闪光灯 + * + * @param torch ... + */ +- (void)setTorch:(BOOL)torch; + +/*! + * 开启关闭闪光灯 + */ +- (void)changeTorch; + +/*! + * 修改扫码类型:二维码、条形码 + * + * @param objType + */ +- (void)changeScanType:(NSArray*)objType; + + +/** + @brief 获取摄像机最大拉远镜头 + @return 放大系数 + */ +- (CGFloat)getVideoMaxScale; + +/** + @brief 拉近拉远镜头 + @param scale 系数 + */ +- (void)setVideoScale:(CGFloat)scale; + +@end + diff --git a/iDearQRCode/Tools/LBXScan/LBXScanNative.m b/iDearQRCode/Tools/LBXScan/LBXScanNative.m new file mode 100755 index 0000000..713d07d --- /dev/null +++ b/iDearQRCode/Tools/LBXScan/LBXScanNative.m @@ -0,0 +1,458 @@ + + + +#import "LBXScanNative.h" + + +@interface LBXScanNative() +{ + BOOL bNeedScanResult; +} + +@property (assign,nonatomic)AVCaptureDevice * device; +@property (strong,nonatomic)AVCaptureDeviceInput * input; +@property (strong,nonatomic)AVCaptureMetadataOutput * output; +@property (strong,nonatomic)AVCaptureSession * session; +@property (strong,nonatomic)AVCaptureVideoPreviewLayer * preview; + +@property(nonatomic,strong) AVCaptureStillImageOutput *stillImageOutput;//拍照 + +@property(nonatomic,assign)BOOL isNeedCaputureImage; + +//扫码结果 +@property (nonatomic, strong) NSMutableArray *arrayResult; + +//扫码类型 +@property (nonatomic, strong) NSArray* arrayBarCodeType; + +/** + @brief 视频预览显示视图 + */ +@property (nonatomic,weak)UIView *videoPreView; + + +/*! + * 扫码结果返回 + */ +@property(nonatomic,copy)void (^blockScanResult)(NSArray *array); + + + +@end + +@implementation LBXScanNative + + +- (void)setNeedCaptureImage:(BOOL)isNeedCaputureImg +{ + _isNeedCaputureImage = isNeedCaputureImg; +} + ++ (CGFloat)getCameraVideoMaxScale +{ + + + return 50.0; +} + +- (id)initWithPreView:(UIView*)preView ObjectType:(NSArray*)objType cropRect:(CGRect)cropRect success:(void(^)(NSArray *array))block +{ + if (self = [super init]) { + + [self initParaWithPreView:preView ObjectType:objType cropRect:cropRect success:block]; + } + + return self; +} + + +- (void)initParaWithPreView:(UIView*)videoPreView ObjectType:(NSArray*)objType cropRect:(CGRect)cropRect success:(void(^)(NSArray *array))block +{ + self.arrayBarCodeType = objType; + self.blockScanResult = block; + self.videoPreView = videoPreView; + + _device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; + + if (!_device) { + return; + } + + // Input + _input = [AVCaptureDeviceInput deviceInputWithDevice:self.device error:nil]; + if ( !_input ) + return ; + + + bNeedScanResult = YES; + + // Output + _output = [[AVCaptureMetadataOutput alloc]init]; + [_output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()]; + + + if ( !CGRectEqualToRect(cropRect,CGRectZero) ) + { + _output.rectOfInterest = cropRect; + } + + /* + // Setup the still image file output + */ + + + _stillImageOutput = [[AVCaptureStillImageOutput alloc] init]; + NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys: + AVVideoCodecJPEG, AVVideoCodecKey, + nil]; + [_stillImageOutput setOutputSettings:outputSettings]; + + // Session + _session = [[AVCaptureSession alloc]init]; + [_session setSessionPreset:AVCaptureSessionPresetHigh]; + + // _session. + + // videoScaleAndCropFactor + + if ([_session canAddInput:_input]) + { + [_session addInput:_input]; + } + + if ([_session canAddOutput:_output]) + { + [_session addOutput:_output]; + } + + if ([_session canAddOutput:_stillImageOutput]) + { + [_session addOutput:_stillImageOutput]; + } + + + + + // 条码类型 AVMetadataObjectTypeQRCode + // _output.metadataObjectTypes =@[AVMetadataObjectTypeQRCode]; + + if (!objType) { + objType = [self defaultMetaDataObjectTypes]; + } + + _output.metadataObjectTypes = objType; + + // Preview + _preview =[AVCaptureVideoPreviewLayer layerWithSession:_session]; + _preview.videoGravity = AVLayerVideoGravityResizeAspectFill; + + //_preview.frame =CGRectMake(20,110,280,280); + + CGRect frame = videoPreView.frame; + frame.origin = CGPointZero; + _preview.frame = frame; + + [videoPreView.layer insertSublayer:self.preview atIndex:0]; + + + + AVCaptureConnection *videoConnection = [self connectionWithMediaType:AVMediaTypeVideo fromConnections:[[self stillImageOutput] connections]]; +// CGFloat maxScale = videoConnection.videoMaxScaleAndCropFactor; + CGFloat scale = videoConnection.videoScaleAndCropFactor; + NSLog(@"%f",scale); +// CGFloat zoom = maxScale / 50; +// if (zoom < 1.0f || zoom > maxScale) +// { +// return; +// } +// videoConnection.videoScaleAndCropFactor += zoom; +// CGAffineTransform transform = videoPreView.transform; +// videoPreView.transform = CGAffineTransformScale(transform, zoom, zoom); + + + + //先进行判断是否支持控制对焦,不开启自动对焦功能,很难识别二维码。 + if (_device.isFocusPointOfInterestSupported &&[_device isFocusModeSupported:AVCaptureFocusModeAutoFocus]) + { + [_input.device lockForConfiguration:nil]; + [_input.device setFocusMode:AVCaptureFocusModeContinuousAutoFocus]; + [_input.device unlockForConfiguration]; + } +} + +- (CGFloat)getVideoMaxScale +{ + [_input.device lockForConfiguration:nil]; + AVCaptureConnection *videoConnection = [self connectionWithMediaType:AVMediaTypeVideo fromConnections:[[self stillImageOutput] connections]]; + CGFloat maxScale = videoConnection.videoMaxScaleAndCropFactor; + [_input.device unlockForConfiguration]; + + return maxScale; +} + +- (void)setVideoScale:(CGFloat)scale +{ + [_input.device lockForConfiguration:nil]; + + AVCaptureConnection *videoConnection = [self connectionWithMediaType:AVMediaTypeVideo fromConnections:[[self stillImageOutput] connections]]; + + CGFloat zoom = scale / videoConnection.videoScaleAndCropFactor; + + videoConnection.videoScaleAndCropFactor = scale; + + [_input.device unlockForConfiguration]; + + CGAffineTransform transform = _videoPreView.transform; + + _videoPreView.transform = CGAffineTransformScale(transform, zoom, zoom); +} + +- (void)setScanRect:(CGRect)scanRect +{ + //识别区域设置 + if (_output) { + _output.rectOfInterest = [self.preview metadataOutputRectOfInterestForRect:scanRect]; + } + +} + +- (void)changeScanType:(NSArray*)objType +{ + _output.metadataObjectTypes = objType; +} + +- (void)startScan +{ + if ( _input && !_session.isRunning ) + { + [_session startRunning]; + bNeedScanResult = YES; + + [_videoPreView.layer insertSublayer:self.preview atIndex:0]; + + // [_input.device addObserver:self forKeyPath:@"torchMode" options:0 context:nil]; + } + bNeedScanResult = YES; +} + +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context +{ + if ( object == _input.device ) { + + NSLog(@"flash change"); + } +} + +- (void)stopScan +{ + bNeedScanResult = NO; + if ( _input && _session.isRunning ) + { + bNeedScanResult = NO; + [_session stopRunning]; + + // [self.preview removeFromSuperlayer]; + } +} + +- (void)setTorch:(BOOL)torch { + + [self.input.device lockForConfiguration:nil]; + self.input.device.torchMode = torch ? AVCaptureTorchModeOn : AVCaptureTorchModeOff; + [self.input.device unlockForConfiguration]; +} + +- (void)changeTorch +{ + AVCaptureTorchMode torch = self.input.device.torchMode; + + switch (_input.device.torchMode) { + case AVCaptureTorchModeAuto: + break; + case AVCaptureTorchModeOff: + torch = AVCaptureTorchModeOn; + break; + case AVCaptureTorchModeOn: + torch = AVCaptureTorchModeOff; + break; + default: + break; + } + + [_input.device lockForConfiguration:nil]; + _input.device.torchMode = torch; + [_input.device unlockForConfiguration]; +} + + +-(UIImage *)getImageFromLayer:(CALayer *)layer size:(CGSize)size +{ + UIGraphicsBeginImageContextWithOptions(size, YES, [[UIScreen mainScreen]scale]); + [layer renderInContext:UIGraphicsGetCurrentContext()]; + UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + return image; +} + +- (AVCaptureConnection *)connectionWithMediaType:(NSString *)mediaType fromConnections:(NSArray *)connections +{ + for ( AVCaptureConnection *connection in connections ) { + for ( AVCaptureInputPort *port in [connection inputPorts] ) { + if ( [[port mediaType] isEqual:mediaType] ) { + return connection; + } + } + } + return nil; +} + +- (void)captureImage +{ + AVCaptureConnection *stillImageConnection = [self connectionWithMediaType:AVMediaTypeVideo fromConnections:[[self stillImageOutput] connections]]; + + + [[self stillImageOutput] captureStillImageAsynchronouslyFromConnection:stillImageConnection + completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) + { + [self stopScan]; + + if (imageDataSampleBuffer) + { + NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer]; + + UIImage *img = [UIImage imageWithData:imageData]; + + for (LBXScanResult* result in _arrayResult) { + + result.imgScanned = img; + } + } + + if (_blockScanResult) + { + _blockScanResult(_arrayResult); + } + + }]; +} + + +#pragma mark AVCaptureMetadataOutputObjectsDelegate +- (void)captureOutput2:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection +{ + + + //识别扫码类型 + for(AVMetadataObject *current in metadataObjects) + { + if ([current isKindOfClass:[AVMetadataMachineReadableCodeObject class]] ) + { + + NSString *scannedResult = [(AVMetadataMachineReadableCodeObject *) current stringValue]; + NSLog(@"type:%@",current.type); + NSLog(@"result:%@",scannedResult); + + + + + + //测试可以同时识别多个二维码 + } + } + + + +} +- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection +{ + if (!bNeedScanResult) { + return; + } + + bNeedScanResult = NO; + + if (!_arrayResult) { + + self.arrayResult = [NSMutableArray arrayWithCapacity:1]; + } + else + { + [_arrayResult removeAllObjects]; + } + + //识别扫码类型 + for(AVMetadataObject *current in metadataObjects) + { + if ([current isKindOfClass:[AVMetadataMachineReadableCodeObject class]] ) + { + bNeedScanResult = NO; + + NSLog(@"type:%@",current.type); + NSString *scannedResult = [(AVMetadataMachineReadableCodeObject *) current stringValue]; + + if (scannedResult && ![scannedResult isEqualToString:@""]) + { + LBXScanResult *result = [LBXScanResult new]; + result.strScanned = scannedResult; + result.strBarCodeType = current.type; + + [_arrayResult addObject:result]; + } + //测试可以同时识别多个二维码 + } + } + + if (_arrayResult.count < 1) + { + bNeedScanResult = YES; + return; + } + + if (_isNeedCaputureImage) + { + [self captureImage]; + } + else + { + [self stopScan]; + + if (_blockScanResult) { + _blockScanResult(_arrayResult); + } + } +} + + +/** + @brief 默认支持码的类别 + @return 支持类别 数组 + */ +- (NSArray *)defaultMetaDataObjectTypes +{ + NSMutableArray *types = [@[AVMetadataObjectTypeQRCode, + AVMetadataObjectTypeUPCECode, + AVMetadataObjectTypeCode39Code, + AVMetadataObjectTypeCode39Mod43Code, + AVMetadataObjectTypeEAN13Code, + AVMetadataObjectTypeEAN8Code, + AVMetadataObjectTypeCode93Code, + AVMetadataObjectTypeCode128Code, + AVMetadataObjectTypePDF417Code, + AVMetadataObjectTypeAztecCode] mutableCopy]; + + if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_7_1) + { + [types addObjectsFromArray:@[ + AVMetadataObjectTypeInterleaved2of5Code, + AVMetadataObjectTypeITF14Code, + AVMetadataObjectTypeDataMatrixCode + ]]; + } + + return types; +} + + + +@end diff --git a/iDearQRCode/Tools/LBXScan/LBXScanNetAnimation.h b/iDearQRCode/Tools/LBXScan/LBXScanNetAnimation.h new file mode 100755 index 0000000..8ec44f6 --- /dev/null +++ b/iDearQRCode/Tools/LBXScan/LBXScanNetAnimation.h @@ -0,0 +1,29 @@ +// +// LBXScanLineAnimation.h +// +// github:https://github.com/MxABC/LBXScan +// Created by lbxia on 15/11/3. +// Copyright © 2015年 lbxia. All rights reserved. +// + +#import + +@interface LBXScanNetAnimation :UIView + + + +/** + * 开始扫码网格效果 + * + * @param animationRect 显示在parentView中得区域 + * @param parentView 动画显示在UIView + * @param image 扫码线的图像 + */ +- (void)startAnimatingWithRect:(CGRect)animationRect InView:(UIView*)parentView Image:(UIImage*)image; + +/** + * 停止动画 + */ +- (void)stopAnimating; + +@end diff --git a/iDearQRCode/Tools/LBXScan/LBXScanNetAnimation.m b/iDearQRCode/Tools/LBXScan/LBXScanNetAnimation.m new file mode 100755 index 0000000..ef29413 --- /dev/null +++ b/iDearQRCode/Tools/LBXScan/LBXScanNetAnimation.m @@ -0,0 +1,99 @@ +// +// LBXScanLineAnimation.m +// +// +// Created by lbxia on 15/11/3. +// Copyright © 2015年 lbxia. All rights reserved. +// + +#import "LBXScanNetAnimation.h" + + +@interface LBXScanNetAnimation() +{ + BOOL isAnimationing; +} + +@property (nonatomic,assign) CGRect animationRect; +@property (nonatomic,strong) UIImageView *scanImageView; + +@end + +@implementation LBXScanNetAnimation + +- (instancetype)init{ + self = [super init]; + if (self) { + self.clipsToBounds = YES; + [self addSubview:self.scanImageView]; + } + return self; +} + +- (UIImageView *)scanImageView{ + if (!_scanImageView) { + _scanImageView = [[UIImageView alloc] init]; + } + return _scanImageView; +} + +- (void)stepAnimation +{ + if (!isAnimationing) { + return; + } + + self.frame = _animationRect; + + CGFloat scanNetImageViewW = self.frame.size.width; + CGFloat scanNetImageH = self.frame.size.height; + + __weak __typeof(self) weakSelf = self; + self.alpha = 0.5; + _scanImageView.frame = CGRectMake(0, -scanNetImageH, scanNetImageViewW, scanNetImageH); + [UIView animateWithDuration:1.4 animations:^{ + weakSelf.alpha = 1.0; + + _scanImageView.frame = CGRectMake(0, scanNetImageViewW-scanNetImageH, scanNetImageViewW, scanNetImageH); + + } completion:^(BOOL finished) + { + [weakSelf performSelector:@selector(stepAnimation) withObject:nil afterDelay:0.3]; + }]; +} + +- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{ + [self performSelector:@selector(stepAnimation) withObject:nil afterDelay:0.3]; +} + + +- (void)startAnimatingWithRect:(CGRect)animationRect InView:(UIView *)parentView Image:(UIImage*)image +{ + [self.scanImageView setImage:image]; + + self.animationRect = animationRect; + + [parentView addSubview:self]; + + self.hidden = NO; + + isAnimationing = YES; + + [self stepAnimation]; +} + + +- (void)dealloc +{ + [self stopAnimating]; +} + +- (void)stopAnimating +{ + self.hidden = YES; + isAnimationing = NO; + + [NSObject cancelPreviousPerformRequestsWithTarget:self]; +} + +@end diff --git a/iDearQRCode/Tools/LBXScan/LBXScanResult.h b/iDearQRCode/Tools/LBXScan/LBXScanResult.h new file mode 100755 index 0000000..e0cb91a --- /dev/null +++ b/iDearQRCode/Tools/LBXScan/LBXScanResult.h @@ -0,0 +1,30 @@ +// +// LBXScanResult.h +// +// github:https://github.com/MxABC/LBXScan +// Created by lbxia on 15/11/17. +// Copyright © 2015年 lbxia. All rights reserved. +// + +#import + +@interface LBXScanResult : NSObject + + +- (instancetype)initWithScanString:(NSString*)str imgScan:(UIImage*)img barCodeType:(NSString*)type; + +/** + @brief 扫码字符串 + */ +@property (nonatomic, copy) NSString* strScanned; +/** + @brief 扫码图像 + */ +@property (nonatomic, strong) UIImage* imgScanned; +/** + @brief 扫码码的类型,AVMetadataObjectType 如AVMetadataObjectTypeQRCode,AVMetadataObjectTypeEAN13Code等 + 如果使用ZXing扫码,返回类型也已经转换成对应的AVMetadataObjectType + */ +@property (nonatomic, copy) NSString* strBarCodeType; + +@end diff --git a/iDearQRCode/Tools/LBXScan/LBXScanResult.m b/iDearQRCode/Tools/LBXScan/LBXScanResult.m new file mode 100755 index 0000000..a76c16f --- /dev/null +++ b/iDearQRCode/Tools/LBXScan/LBXScanResult.m @@ -0,0 +1,25 @@ +// +// LBXScanResult.m +// +// +// Created by lbxia on 15/11/17. +// Copyright © 2015年 lbxia. All rights reserved. + + +#import "LBXScanResult.h" + +@implementation LBXScanResult + +- (instancetype)initWithScanString:(NSString*)str imgScan:(UIImage*)img barCodeType:(NSString*)type +{ + if (self = [super init]) { + + self.strScanned = str; + self.imgScanned = img; + self.strBarCodeType = type; + } + + return self; +} + +@end diff --git a/iDearQRCode/Tools/LBXScan/LBXScanVideoZoomView.h b/iDearQRCode/Tools/LBXScan/LBXScanVideoZoomView.h new file mode 100755 index 0000000..2b829bf --- /dev/null +++ b/iDearQRCode/Tools/LBXScan/LBXScanVideoZoomView.h @@ -0,0 +1,19 @@ +// +// LBXScanVideoZoomView.h +// testSlider +// +// Created by csc on 16/3/19. +// Copyright © 2016年 csc. All rights reserved. +// + +#import + +@interface LBXScanVideoZoomView : UIView + +/** + @brief 控件值变化 + */ +@property (nonatomic, copy) void (^block)(float value); + +- (void)setMaximunValue:(CGFloat)value; +@end diff --git a/iDearQRCode/Tools/LBXScan/LBXScanVideoZoomView.m b/iDearQRCode/Tools/LBXScan/LBXScanVideoZoomView.m new file mode 100755 index 0000000..49adab7 --- /dev/null +++ b/iDearQRCode/Tools/LBXScan/LBXScanVideoZoomView.m @@ -0,0 +1,128 @@ +// +// LBXScanVideoZoomView.m +// testSlider +// +// Created by csc on 16/3/19. +// Copyright © 2016年 csc. All rights reserved. +// + +#import "LBXScanVideoZoomView.h" + + + +@interface LBXScanVideoZoomView() +@property (nonatomic, strong) UISlider *slider; +@end + +@implementation LBXScanVideoZoomView + + +// Only override drawRect: if you perform custom drawing. +// An empty implementation adversely affects performance during animation. +- (void)drawRect:(CGRect)rect +{ + // Drawing code + + UIColor *colorLine = [UIColor whiteColor]; + + + CGColorRef color = colorLine.CGColor; + CGContextRef ctx = UIGraphicsGetCurrentContext(); + CGContextSetStrokeColorWithColor(ctx, color); + CGContextSetLineWidth(ctx, 2.0); + + + CGFloat borderDiff = 20; + CGFloat w = borderDiff/2; + CGFloat diff = 5; + //左边减号 + CGContextMoveToPoint(ctx, diff, CGRectGetHeight(self.frame)/2); + CGContextAddLineToPoint(ctx, diff + w, CGRectGetHeight(self.frame)/2); + + //右边加号 + //横 + CGFloat rx = CGRectGetWidth(self.frame) - borderDiff + diff; + CGContextMoveToPoint(ctx, rx, CGRectGetHeight(self.frame)/2); + CGContextAddLineToPoint(ctx, rx + w, CGRectGetHeight(self.frame)/2); + + //竖 + CGFloat hDiff = CGRectGetHeight(self.frame)/2 - w/2; + CGContextMoveToPoint(ctx, rx+w/2 , hDiff); + CGContextAddLineToPoint(ctx, rx+w/2, CGRectGetHeight(self.frame)-hDiff); + + + CGContextStrokePath(ctx); +} + +- (UIImage *) toImage:(UIColor*)color size:(CGSize)size +{ + CGRect rect=CGRectMake(0.0f, 0.0f, size.width, size.height); + UIGraphicsBeginImageContext(rect.size); + CGContextRef context = UIGraphicsGetCurrentContext(); + CGContextSetFillColorWithColor(context, [color CGColor]); + CGContextFillRect(context, rect); + + UIImage *theImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + return theImage; +} + +- (id)initWithFrame:(CGRect)frame +{ + if (self = [super initWithFrame:frame]) { + } + + self.backgroundColor = [UIColor colorWithRed:10 green:10 blue:10 alpha:0.2]; + [self.slider setThumbImage:[self toImage:[UIColor whiteColor] size:CGSizeMake(3, 12)] forState:UIControlStateNormal]; + self.slider.minimumTrackTintColor = [UIColor whiteColor]; + self.slider.maximumTrackTintColor = [UIColor colorWithRed:146/255.0 green:146/255.0 blue:146/255.0 alpha:1.0]; + [self.slider addTarget:self action:@selector(sliderValueChange) forControlEvents:UIControlEventValueChanged]; + + self.layer.masksToBounds = YES; + self.layer.cornerRadius = 8.0; + + return self; +} + +- (void)sliderValueChange +{ +// NSLog(@"%f",self.slider.value); + + if (_block) { + _block(self.slider.value); + } +} + +//- (void)addTarget:(nullable id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents; + +- (UISlider*)slider +{ + if (!_slider) { + + _slider = [[UISlider alloc]init]; + [self addSubview:_slider]; + _slider.minimumValue = 1.0; + _slider.maximumValue = 50.0; + } + return _slider; +} + +- (void)setMaximunValue:(CGFloat)value +{ + self.slider.maximumValue = value; +} + +- (void)layoutSubviews +{ + [super layoutSubviews]; + + CGFloat borderDiff = 20; + + _slider.bounds = CGRectMake(0, 0, CGRectGetWidth(self.frame)-borderDiff*2, CGRectGetHeight(self.frame)); + _slider.center = CGPointMake(CGRectGetWidth(self.frame)/2, CGRectGetHeight(self.frame)/2); +} + +@end + + diff --git a/iDearQRCode/Tools/LBXScan/LBXScanView.h b/iDearQRCode/Tools/LBXScan/LBXScanView.h new file mode 100755 index 0000000..6ff9aed --- /dev/null +++ b/iDearQRCode/Tools/LBXScan/LBXScanView.h @@ -0,0 +1,62 @@ +// +// LBXScanView.h +// +// github:https://github.com/MxABC/LBXScan +// Created by lbxia on 15/11/15. +// Copyright © 2015年 lbxia. All rights reserved. +// + + +#import +#import "LBXScanLineAnimation.h" +#import "LBXScanNetAnimation.h" +#import "LBXScanViewStyle.h" + + + +/** + 扫码区域显示效果 + */ +@interface LBXScanView : UIView + +/** + @brief 初始化 + @param frame 位置大小 + @param style 类型 + + @return instancetype + */ +-(id)initWithFrame:(CGRect)frame style:(LBXScanViewStyle*)style; + +/** + * 设备启动中文字提示 + */ +- (void)startDeviceReadyingWithText:(NSString*)text; + +/** + * 设备启动完成 + */ +- (void)stopDeviceReadying; + +/** + * 开始扫描动画 + */ +- (void)startScanAnimation; + +/** + * 结束扫描动画 + */ +- (void)stopScanAnimation; + +// + +/** + @brief 根据矩形区域,获取识别兴趣区域 + @param view 视频流显示UIView + @param style 效果界面参数 + @return 识别区域 + */ ++ (CGRect)getScanRectWithPreView:(UIView*)view style:(LBXScanViewStyle*)style; + + +@end diff --git a/iDearQRCode/Tools/LBXScan/LBXScanView.m b/iDearQRCode/Tools/LBXScan/LBXScanView.m new file mode 100755 index 0000000..b96f90d --- /dev/null +++ b/iDearQRCode/Tools/LBXScan/LBXScanView.m @@ -0,0 +1,416 @@ + +// +// LBXScanView.m +// +// +// Created by lbxia on 15/11/15. +// Copyright © 2015年 lbxia. All rights reserved. +// + +#import "LBXScanView.h" + + + +@interface LBXScanView() + +//扫码区域各种参数 +@property (nonatomic, strong) LBXScanViewStyle* viewStyle; + + +//扫码区域 +@property (nonatomic,assign)CGRect scanRetangleRect; + +//线条扫码动画封装 +@property (nonatomic,strong)LBXScanLineAnimation *scanLineAnimation; +//网格扫码动画封装 +@property (nonatomic,strong)LBXScanNetAnimation *scanNetAnimation; + +//线条在中间位置,不移动 +@property (nonatomic,strong)UIImageView *scanLineStill; + +/** + @brief 启动相机时 菊花等待 + */ +@property(nonatomic,strong)UIActivityIndicatorView* activityView; + +/** + @brief 启动相机中的提示文字 + */ +@property(nonatomic,strong)UILabel *labelReadying; + + + +@end + +@implementation LBXScanView + + +-(id)initWithFrame:(CGRect)frame style:(LBXScanViewStyle*)style +{ + if (self = [super initWithFrame:frame]) + { + self.viewStyle = style; + self.backgroundColor = [UIColor clearColor]; + } + + return self; +} + + +- (void)drawRect:(CGRect)rect +{ + [self drawScanRect]; + +} + + +- (void)startDeviceReadyingWithText:(NSString*)text +{ + int XRetangleLeft = _viewStyle.xScanRetangleOffset; + + CGSize sizeRetangle = CGSizeMake(self.frame.size.width - XRetangleLeft*2, self.frame.size.width - XRetangleLeft*2); + + if (!_viewStyle.isNeedShowRetangle) { + + CGFloat w = sizeRetangle.width; + CGFloat h = w / _viewStyle.whRatio; + + NSInteger hInt = (NSInteger)h; + h = hInt; + + sizeRetangle = CGSizeMake(w, h); + } + + //扫码区域Y轴最小坐标 + CGFloat YMinRetangle = self.frame.size.height / 2.0 - sizeRetangle.height/2.0 - _viewStyle.centerUpOffset; + + //设备启动状态提示 + if (!_activityView) + { + self.activityView = [[UIActivityIndicatorView alloc]initWithFrame:CGRectMake(0, 0, 30, 30)]; + [_activityView setCenter:CGPointMake(XRetangleLeft + sizeRetangle.width/2 - 50, YMinRetangle + sizeRetangle.height/2)]; + + [_activityView setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleWhiteLarge]; + [self addSubview:_activityView]; + + CGRect labelReadyRect = CGRectMake(_activityView.frame.origin.x + _activityView.frame.size.width + 10, _activityView.frame.origin.y, 100, 30); + self.labelReadying = [[UILabel alloc]initWithFrame:labelReadyRect]; + _labelReadying.backgroundColor = [UIColor clearColor]; + _labelReadying.textColor = [UIColor whiteColor]; + _labelReadying.font = [UIFont systemFontOfSize:18.]; + _labelReadying.text = text; + + [self addSubview:_labelReadying]; + + [_activityView startAnimating]; + } + +} + +- (void)stopDeviceReadying +{ + if (_activityView) { + + [_activityView stopAnimating]; + [_activityView removeFromSuperview]; + [_labelReadying removeFromSuperview]; + + self.activityView = nil; + self.labelReadying = nil; + } +} + + +/** + * 开始扫描动画 + */ +- (void)startScanAnimation +{ + switch (_viewStyle.anmiationStyle) + { + case LBXScanViewAnimationStyle_LineMove: + { + //线动画 + if (!_scanLineAnimation) + self.scanLineAnimation = [[LBXScanLineAnimation alloc]init]; + [_scanLineAnimation startAnimatingWithRect:_scanRetangleRect + InView:self + Image:_viewStyle.animationImage]; + } + break; + case LBXScanViewAnimationStyle_NetGrid: + { + //网格动画 + if (!_scanNetAnimation) + self.scanNetAnimation = [[LBXScanNetAnimation alloc]init]; + [_scanNetAnimation startAnimatingWithRect:_scanRetangleRect + InView:self + Image:_viewStyle.animationImage]; + } + break; + case LBXScanViewAnimationStyle_LineStill: + { + if (!_scanLineStill) { + + CGRect stillRect = CGRectMake(_scanRetangleRect.origin.x+20, + _scanRetangleRect.origin.y + _scanRetangleRect.size.height/2, + _scanRetangleRect.size.width-40, + 2); + _scanLineStill = [[UIImageView alloc]initWithFrame:stillRect]; + _scanLineStill.image = _viewStyle.animationImage; + } + [self addSubview:_scanLineStill]; + } + + default: + break; + } + +} + + + +/** + * 结束扫描动画 + */ +- (void)stopScanAnimation +{ + if (_scanLineAnimation) { + [_scanLineAnimation stopAnimating]; + } + + if (_scanNetAnimation) { + [_scanNetAnimation stopAnimating]; + } + + if (_scanLineStill) { + [_scanLineStill removeFromSuperview]; + } +} + + +- (void)drawScanRect +{ + int XRetangleLeft = _viewStyle.xScanRetangleOffset; + + CGSize sizeRetangle = CGSizeMake(self.frame.size.width - XRetangleLeft*2, self.frame.size.width - XRetangleLeft*2); + + //if (!_viewStyle.isScanRetangelSquare) + if (_viewStyle.whRatio != 1) + { + CGFloat w = sizeRetangle.width; + CGFloat h = w / _viewStyle.whRatio; + + NSInteger hInt = (NSInteger)h; + h = hInt; + + sizeRetangle = CGSizeMake(w, h); + } + + //扫码区域Y轴最小坐标 + CGFloat YMinRetangle = self.frame.size.height / 2.0 - sizeRetangle.height/2.0 - _viewStyle.centerUpOffset; + CGFloat YMaxRetangle = YMinRetangle + sizeRetangle.height; + CGFloat XRetangleRight = self.frame.size.width - XRetangleLeft; + + + + NSLog(@"frame:%@",NSStringFromCGRect(self.frame)); + + CGContextRef context = UIGraphicsGetCurrentContext(); + + + //非扫码区域半透明 + { + //设置非识别区域颜色 + CGContextSetRGBFillColor(context, _viewStyle.red_notRecoginitonArea, _viewStyle.green_notRecoginitonArea, + _viewStyle.blue_notRecoginitonArea, _viewStyle.alpa_notRecoginitonArea); + + //填充矩形 + + //扫码区域上面填充 + CGRect rect = CGRectMake(0, 0, self.frame.size.width, YMinRetangle); + CGContextFillRect(context, rect); + + + //扫码区域左边填充 + rect = CGRectMake(0, YMinRetangle, XRetangleLeft,sizeRetangle.height); + CGContextFillRect(context, rect); + + //扫码区域右边填充 + rect = CGRectMake(XRetangleRight, YMinRetangle, XRetangleLeft,sizeRetangle.height); + CGContextFillRect(context, rect); + + //扫码区域下面填充 + rect = CGRectMake(0, YMaxRetangle, self.frame.size.width,self.frame.size.height - YMaxRetangle); + CGContextFillRect(context, rect); + //执行绘画 + CGContextStrokePath(context); + } + + if (_viewStyle.isNeedShowRetangle) + { + //中间画矩形(正方形) + CGContextSetStrokeColorWithColor(context, _viewStyle.colorRetangleLine.CGColor); + CGContextSetLineWidth(context, 1); + + CGContextAddRect(context, CGRectMake(XRetangleLeft, YMinRetangle, sizeRetangle.width, sizeRetangle.height)); + + //CGContextMoveToPoint(context, XRetangleLeft, YMinRetangle); + //CGContextAddLineToPoint(context, XRetangleLeft+sizeRetangle.width, YMinRetangle); + + CGContextStrokePath(context); + + } + _scanRetangleRect = CGRectMake(XRetangleLeft, YMinRetangle, sizeRetangle.width, sizeRetangle.height); + + + //画矩形框4格外围相框角 + + //相框角的宽度和高度 + int wAngle = _viewStyle.photoframeAngleW; + int hAngle = _viewStyle.photoframeAngleH; + + //4个角的 线的宽度 + CGFloat linewidthAngle = _viewStyle.photoframeLineW;// 经验参数:6和4 + + //画扫码矩形以及周边半透明黑色坐标参数 + CGFloat diffAngle = 0.0f; + //diffAngle = linewidthAngle / 2; //框外面4个角,与框有缝隙 + //diffAngle = linewidthAngle/2; //框4个角 在线上加4个角效果 + //diffAngle = 0;//与矩形框重合 + + switch (_viewStyle.photoframeAngleStyle) + { + case LBXScanViewPhotoframeAngleStyle_Outer: + { + diffAngle = linewidthAngle/3;//框外面4个角,与框紧密联系在一起 + } + break; + case LBXScanViewPhotoframeAngleStyle_On: + { + diffAngle = 0; + } + break; + case LBXScanViewPhotoframeAngleStyle_Inner: + { + diffAngle = -_viewStyle.photoframeLineW/2; + + } + break; + + default: + { + diffAngle = linewidthAngle/3; + } + break; + } + + CGContextSetStrokeColorWithColor(context, _viewStyle.colorAngle.CGColor); + CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0); + + // Draw them with a 2.0 stroke width so they are a bit more visible. + CGContextSetLineWidth(context, linewidthAngle); + + + // + CGFloat leftX = XRetangleLeft - diffAngle; + CGFloat topY = YMinRetangle - diffAngle; + CGFloat rightX = XRetangleRight + diffAngle; + CGFloat bottomY = YMaxRetangle + diffAngle; + + //左上角水平线 + CGContextMoveToPoint(context, leftX-linewidthAngle/2, topY); + CGContextAddLineToPoint(context, leftX + wAngle, topY); + + //左上角垂直线 + CGContextMoveToPoint(context, leftX, topY-linewidthAngle/2); + CGContextAddLineToPoint(context, leftX, topY+hAngle); + + + //左下角水平线 + CGContextMoveToPoint(context, leftX-linewidthAngle/2, bottomY); + CGContextAddLineToPoint(context, leftX + wAngle, bottomY); + + //左下角垂直线 + CGContextMoveToPoint(context, leftX, bottomY+linewidthAngle/2); + CGContextAddLineToPoint(context, leftX, bottomY - hAngle); + + + //右上角水平线 + CGContextMoveToPoint(context, rightX+linewidthAngle/2, topY); + CGContextAddLineToPoint(context, rightX - wAngle, topY); + + //右上角垂直线 + CGContextMoveToPoint(context, rightX, topY-linewidthAngle/2); + CGContextAddLineToPoint(context, rightX, topY + hAngle); + + + //右下角水平线 + CGContextMoveToPoint(context, rightX+linewidthAngle/2, bottomY); + CGContextAddLineToPoint(context, rightX - wAngle, bottomY); + + //右下角垂直线 + CGContextMoveToPoint(context, rightX, bottomY+linewidthAngle/2); + CGContextAddLineToPoint(context, rightX, bottomY - hAngle); + + CGContextStrokePath(context); +} + + + +//根据矩形区域,获取识别区域 ++ (CGRect)getScanRectWithPreView:(UIView*)view style:(LBXScanViewStyle*)style +{ + int XRetangleLeft = style.xScanRetangleOffset; + CGSize sizeRetangle = CGSizeMake(view.frame.size.width - XRetangleLeft*2, view.frame.size.width - XRetangleLeft*2); + + if (style.whRatio != 1) + { + CGFloat w = sizeRetangle.width; + CGFloat h = w / style.whRatio; + + NSInteger hInt = (NSInteger)h; + h = hInt; + + sizeRetangle = CGSizeMake(w, h); + } + + //扫码区域Y轴最小坐标 + CGFloat YMinRetangle = view.frame.size.height / 2.0 - sizeRetangle.height/2.0 - style.centerUpOffset; + //扫码区域坐标 + CGRect cropRect = CGRectMake(XRetangleLeft, YMinRetangle, sizeRetangle.width, sizeRetangle.height); + + + //计算兴趣区域 + CGRect rectOfInterest; + + //ref:http://www.cocoachina.com/ios/20141225/10763.html + CGSize size = view.bounds.size; + CGFloat p1 = size.height/size.width; + CGFloat p2 = 1920./1080.; //使用了1080p的图像输出 + if (p1 < p2) { + CGFloat fixHeight = size.width * 1920. / 1080.; + CGFloat fixPadding = (fixHeight - size.height)/2; + rectOfInterest = CGRectMake((cropRect.origin.y + fixPadding)/fixHeight, + cropRect.origin.x/size.width, + cropRect.size.height/fixHeight, + cropRect.size.width/size.width); + + + } else { + CGFloat fixWidth = size.height * 1080. / 1920.; + CGFloat fixPadding = (fixWidth - size.width)/2; + rectOfInterest = CGRectMake(cropRect.origin.y/size.height, + (cropRect.origin.x + fixPadding)/fixWidth, + cropRect.size.height/size.height, + cropRect.size.width/fixWidth); + + + } + + + return rectOfInterest; +} + + +@end diff --git a/iDearQRCode/Tools/LBXScan/LBXScanViewController.h b/iDearQRCode/Tools/LBXScan/LBXScanViewController.h new file mode 100755 index 0000000..b6defcc --- /dev/null +++ b/iDearQRCode/Tools/LBXScan/LBXScanViewController.h @@ -0,0 +1,84 @@ +// +// QQStyleQRScanViewController.h +// LBXScanDemo +// github:https://github.com/MxABC/LBXScan +// Created by lbxia on 15/10/21. +// Copyright © 2015年 lbxia. All rights reserved. +// + +#import +#import +#import "LBXScanView.h" +#import "LBXScanWrapper.h" + + + + +@interface LBXScanViewController : UIViewController + + +/** + @brief 是否需要扫码图像 + */ +@property (nonatomic, assign) BOOL isNeedScanImage; + +/** + @brief 扫码功能封装对象 + */ +@property (nonatomic,strong) LBXScanWrapper* scanObj; + +#pragma mark - 扫码界面效果及提示等 +/** + @brief 扫码区域视图,二维码一般都是框 + */ +@property (nonatomic,strong) LBXScanView* qRScanView; + + + + +/** + * 界面效果参数 + */ +@property (nonatomic, strong) LBXScanViewStyle *style; + + +#pragma mark - 扫码界面效果及提示等 + + +/** + @brief 扫码当前图片 + */ +@property(nonatomic,strong)UIImage* scanImage; + + +/** + @brief 启动区域识别功能 + */ +@property(nonatomic,assign)BOOL isOpenInterestRect; + + +/** + @brief 闪关灯开启状态 + */ +@property(nonatomic,assign)BOOL isOpenFlash; + + +//打开相册 +- (void)openLocalPhoto; +//开关闪光灯 +- (void)openOrCloseFlash; + + +//子类继承必须实现的提示 +/** + * 继承者实现的alert提示功能:如没有权限时会调用 + * + * @param str 提示语 + */ +- (void)showError:(NSString*)str; + + +- (void)reStartDevice; + + +@end diff --git a/iDearQRCode/Tools/LBXScan/LBXScanViewController.m b/iDearQRCode/Tools/LBXScan/LBXScanViewController.m new file mode 100755 index 0000000..ac6f411 --- /dev/null +++ b/iDearQRCode/Tools/LBXScan/LBXScanViewController.m @@ -0,0 +1,226 @@ +// +// +// +// +// Created by lbxia on 15/10/21. +// Copyright © 2015年 lbxia. All rights reserved. +// + +#import "LBXScanViewController.h" + + +@interface LBXScanViewController () + + +@end + +@implementation LBXScanViewController + + +- (void)viewDidLoad { + [super viewDidLoad]; + // Do any additional setup after loading the view. + + if ([self respondsToSelector:@selector(setEdgesForExtendedLayout:)]) { + + self.edgesForExtendedLayout = UIRectEdgeNone; + } + + self.view.backgroundColor = [UIColor blackColor]; +} + + +- (void)viewDidAppear:(BOOL)animated +{ + [super viewDidAppear:animated]; + + [self drawScanView]; + + + [self performSelector:@selector(startScan) withObject:nil afterDelay:0.2]; +} + +//绘制扫描区域 +- (void)drawScanView +{ + if (!_qRScanView) + { + CGRect rect = self.view.frame; + rect.origin = CGPointMake(0, 0); + + self.qRScanView = [[LBXScanView alloc]initWithFrame:rect style:_style]; + + [self.view addSubview:_qRScanView]; + + } + + [_qRScanView startDeviceReadyingWithText:@"相机启动中"]; + + +} + +- (void)reStartDevice +{ + [_scanObj startScan]; +} + +//启动设备 +- (void)startScan +{ + if ( ![LBXScanWrapper isGetCameraPermission] ) + { + [_qRScanView stopDeviceReadying]; + + [self showError:@" 请到设置隐私中开启本程序相机权限 "]; + return; + } + + + + if (!_scanObj ) + { + __weak __typeof(self) weakSelf = self; + // AVMetadataObjectTypeQRCode AVMetadataObjectTypeEAN13Code + + CGRect cropRect = CGRectZero; + + if (_isOpenInterestRect) { + + cropRect = [LBXScanView getScanRectWithPreView:self.view style:_style]; + } + + UIView *videoView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.view.frame), CGRectGetHeight(self.view.frame))]; + videoView.backgroundColor = [UIColor clearColor]; + [self.view insertSubview:videoView atIndex:0]; + + self.scanObj = [[LBXScanWrapper alloc]initWithPreView:videoView + ArrayObjectType:nil + cropRect:cropRect + success:^(NSArray *array){ + [weakSelf scanResultWithArray:array]; + }]; + + [_scanObj setNeedCaptureImage:_isNeedScanImage]; + + [self cameraInitOver]; + + } + [_scanObj startScan]; + + + [_qRScanView stopDeviceReadying]; + + [_qRScanView startScanAnimation]; + + self.view.backgroundColor = [UIColor clearColor]; +} + +- (void)cameraInitOver +{ + +} + + +- (void)viewWillDisappear:(BOOL)animated +{ + [super viewWillDisappear:animated]; + + [NSObject cancelPreviousPerformRequestsWithTarget:self]; + + [_scanObj stopScan]; + [_qRScanView stopScanAnimation]; +} + + + +#pragma mark -实现类继承该方法,作出对应处理 +- (void)scanResultWithArray:(NSArray*)array +{ + +} + + + + + +//开关闪光灯 +- (void)openOrCloseFlash +{ + [_scanObj openOrCloseFlash]; + + self.isOpenFlash =!self.isOpenFlash; + +} + + +#pragma mark --打开相册并识别图片 + +/*! + * 打开本地照片,选择图片识别 + */ +- (void)openLocalPhoto +{ + UIImagePickerController *picker = [[UIImagePickerController alloc] init]; + + picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; + + picker.delegate = self; + + +// picker.allowsEditing = YES; + + + [self presentViewController:picker animated:YES completion:nil]; +} + + + +//当选择一张图片后进入这里 + +-(void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary *)info +{ + [picker dismissViewControllerAnimated:YES completion:nil]; + + __block UIImage* image = [info objectForKey:UIImagePickerControllerEditedImage]; + + if (!image){ + image = [info objectForKey:UIImagePickerControllerOriginalImage]; + } + + __weak __typeof(self) weakSelf = self; + [LBXScanWrapper recognizeImage:image success:^(NSArray *array) { + + [weakSelf scanResultWithArray:array]; + }]; + + + + //系统自带识别方法 + /* + CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeQRCode context:nil options:@{ CIDetectorAccuracy : CIDetectorAccuracyHigh }]; + NSArray *features = [detector featuresInImage:[CIImage imageWithCGImage:image.CGImage]]; + if (features.count >=1) + { + CIQRCodeFeature *feature = [features objectAtIndex:0]; + NSString *scanResult = feature.messageString; + + NSLog(@"%@",scanResult); + } + */ + + +} +- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker +{ + NSLog(@"cancel"); + + [picker dismissViewControllerAnimated:YES completion:nil]; +} + +//子类继承必须实现的提示 +- (void)showError:(NSString*)str +{ + +} + +@end diff --git a/iDearQRCode/Tools/LBXScan/LBXScanViewStyle.h b/iDearQRCode/Tools/LBXScan/LBXScanViewStyle.h new file mode 100755 index 0000000..f69d2e9 --- /dev/null +++ b/iDearQRCode/Tools/LBXScan/LBXScanViewStyle.h @@ -0,0 +1,125 @@ +// +// LBXScanViewStyle.h +// +// github:https://github.com/MxABC/LBXScan +// Created by lbxia on 15/11/15. +// Copyright © 2015年 lbxia. All rights reserved. +// + +#import + + + +/** + 扫码区域动画效果 + */ +typedef enum LBXScanViewAnimationStyle +{ + LBXScanViewAnimationStyle_LineMove, //线条上下移动 + LBXScanViewAnimationStyle_NetGrid,//网格 + LBXScanViewAnimationStyle_LineStill,//线条停止在扫码区域中央 + LBXScanViewAnimationStyle_None //无动画 + +}LBXScanViewAnimationStyle; + + +/** + 扫码区域4个角位置类型 + */ +typedef enum LBXScanViewPhotoframeAngleStyle +{ + LBXScanViewPhotoframeAngleStyle_Inner,//内嵌,一般不显示矩形框情况下 + LBXScanViewPhotoframeAngleStyle_Outer,//外嵌,包围在矩形框的4个角 + LBXScanViewPhotoframeAngleStyle_On //在矩形框的4个角上,覆盖 +}LBXScanViewPhotoframeAngleStyle; + + + + +@interface LBXScanViewStyle : NSObject + + +#pragma mark -中心位置矩形框 +/** + @brief 是否需要绘制扫码矩形框,默认YES + */ +@property (nonatomic, assign) BOOL isNeedShowRetangle; + + +/** + * 默认扫码区域为正方形,如果扫码区域不是正方形,设置宽高比 + */ +@property (nonatomic, assign) CGFloat whRatio; + + +/** + @brief 矩形框(视频显示透明区)域向上移动偏移量,0表示扫码透明区域在当前视图中心位置,如果负值表示扫码区域下移 + */ +@property (nonatomic, assign) CGFloat centerUpOffset; + +/** + * 矩形框(视频显示透明区)域离界面左边及右边距离,默认60 + */ +@property (nonatomic, assign) CGFloat xScanRetangleOffset; + +/** + @brief 矩形框线条颜色 + */ +@property (nonatomic, strong) UIColor *colorRetangleLine; + + + +#pragma mark -矩形框(扫码区域)周围4个角 +/** + @brief 扫码区域的4个角类型 + */ +@property (nonatomic, assign) LBXScanViewPhotoframeAngleStyle photoframeAngleStyle; + +//4个角的颜色 +@property (nonatomic, strong) UIColor* colorAngle; + +//扫码区域4个角的宽度和高度 +@property (nonatomic, assign) CGFloat photoframeAngleW; +@property (nonatomic, assign) CGFloat photoframeAngleH; +/** + @brief 扫码区域4个角的线条宽度,默认6,建议8到4之间 + */ +@property (nonatomic, assign) CGFloat photoframeLineW; + + + + +#pragma mark --动画效果 +/** + @brief 扫码动画效果:线条或网格 + */ +@property (nonatomic, assign) LBXScanViewAnimationStyle anmiationStyle; + +/** + * 动画效果的图像,如线条或网格的图像 + */ +@property (nonatomic,strong) UIImage *animationImage; + + + +#pragma mark -非识别区域颜色,默认 RGBA (0,0,0,0.5),范围(0--1) +@property (nonatomic, assign) CGFloat red_notRecoginitonArea; +@property (nonatomic, assign) CGFloat green_notRecoginitonArea; +@property (nonatomic, assign) CGFloat blue_notRecoginitonArea; +@property (nonatomic, assign) CGFloat alpa_notRecoginitonArea; + + + + + + + + + + + + + +@end + + diff --git a/iDearQRCode/Tools/LBXScan/LBXScanViewStyle.m b/iDearQRCode/Tools/LBXScan/LBXScanViewStyle.m new file mode 100755 index 0000000..2710e05 --- /dev/null +++ b/iDearQRCode/Tools/LBXScan/LBXScanViewStyle.m @@ -0,0 +1,50 @@ +// +// LBXScanViewStyle.m +// +// +// Created by lbxia on 15/11/15. +// Copyright © 2015年 lbxia. All rights reserved. +// + +#import "LBXScanViewStyle.h" + +@implementation LBXScanViewStyle + +- (id)init +{ + if (self = [super init]) + { + self.isNeedShowRetangle = YES; + + self.whRatio = 1.0; + + self.colorRetangleLine = [UIColor whiteColor]; + + self.centerUpOffset = 44; + self.xScanRetangleOffset = 60; +// if ([UIScreen mainScreen].bounds.size.height <= 480 ) +// { +// //3.5inch 显示的扫码缩小 +// self.xScanRetangleOffset = self.xScanRetangleOffset - 10; +// } + + self.anmiationStyle = LBXScanViewAnimationStyle_LineMove; + self.photoframeAngleStyle = LBXScanViewPhotoframeAngleStyle_Outer; + self.colorAngle = [UIColor colorWithRed:0. green:167./255. blue:231./255. alpha:1.0]; + + self.red_notRecoginitonArea = 0.0; + self.green_notRecoginitonArea = 0.0; + self.blue_notRecoginitonArea = 0.0; + self.alpa_notRecoginitonArea = 0.5; + + self.photoframeAngleW = 24; + self.photoframeAngleH = 24; + self.photoframeLineW = 7; + + } + + return self; +} + +@end + diff --git a/iDearQRCode/Tools/LBXScan/LBXScanWrapper.h b/iDearQRCode/Tools/LBXScan/LBXScanWrapper.h new file mode 100755 index 0000000..20bdd27 --- /dev/null +++ b/iDearQRCode/Tools/LBXScan/LBXScanWrapper.h @@ -0,0 +1,212 @@ +// +// +// +// github:https://github.com/MxABC/LBXScan +// Created by lbxia on 15/3/4. +// Copyright (c) 2015年 lbxia. All rights reserved. +// + +#import +#import +#import "LBXScanResult.h" + + + +/** + @brief 封装ZXing和ios系统自带原生扫码功能 + ZXing识别图片二维码以及生成二维码功能 + 识别码类型,AVMetadataObjectTypeQRCode:二维码 AVMetadataObjectTypeEAN13Code/AVMetadataObjectTypeEAN8Code:条形码 + */ +@interface LBXScanWrapper : NSObject + + + + +/** + @brief 初始化相机,根据系统自动选择ZXing或ios自带识别功能 + @param preView 视屏预览View + @param arrayBarCodeType 扫码类型,传值nil,默认很多种类型... + @param cropRect 识别区域 + @param blockScanResult 返回扫码结果 + @return LBXScanVendor + */ +- (instancetype)initWithPreView:(UIView*)preView ArrayObjectType:(NSArray*)arrayBarCodeType cropRect:(CGRect)cropRect + success:(void(^)(NSArray *array))blockScanResult; + + + +/** + @brief 初始化相机,并指定使用ZXing库识别各种码 + @param preView 视频显示View + @param blockScanResult 返回结果 + @return LBXScanVendor + */ +- (instancetype)initZXingWithPreView:(UIView *)preView success:(void(^)(NSArray *array))blockScanResult; + + + +/*! + * 设置扫码成功后是否拍照,ios7 AVFoundation框架, + * 从 CALayer获取不到图像,如果有谁知道怎么做,请告诉我,谢谢 lbxia20091227@foxmail.com + * 当前如果想要扫码后的照片,又没有拍照声音,可以考虑使用ZXing的代码库的方式 + * + * @param isNeedCaputureImg YES:拍照, NO:不拍照 + */ +- (void)setNeedCaptureImage:(BOOL)isNeedCaputureImg; + + +/*! + * 开始扫码,扫码成功返回数据后,内部调用stopScan,重新扫描需要重新调用startScan + */ +- (void)startScan; + +/*! + * 停止扫码 + */ +- (void)stopScan; + +/*! + * 开启关闭闪光灯 + * + * @param bOpen YES:开启,NO:关闭 + */ +- (void)openFlash:(BOOL)bOpen; + + +/*! + * 开启或关闭闪光灯 + * 之前是开启,则这次是关闭 + * 之前是关闭,则这次是开启 + */ +- (void)openOrCloseFlash; + + +/*! + * 修改扫码类型 + * + * @param objType 扫码类型: AVMetadataObjectTypeQRCode:二维码 AVMetadataObjectTypeEAN13Code:条形码 + */ +- (void)changeScanObjType:(NSArray*)barCodeType; + + +/*! + * 生成二维码(根据系统版本,选择对应生成方法) + * + * @param str 二维码字符串 + * @param size 二维码图片大小 + * + * @return 返回生成的图像 + */ ++ (UIImage*)createQRWithString:(NSString*)str size:(CGSize)size; + +/** + @brief 给二维码图像上色 + @param image 二维码图像 + @param red 红色 + @param green 绿色 + @param blue 蓝色 + @return 上色后的图像 + */ ++ (UIImage*)imageBlackToTransparent:(UIImage*)image withRed:(CGFloat)red andGreen:(CGFloat)green andBlue:(CGFloat)blue; + +/** + @brief 图像中间加logo图片 + @param srcImg 原图像 + @param LogoImage logo图像 + @param logoSize logo图像尺寸 + @return 加Logo的图像 + */ ++ (UIImage*)addImageLogo:(UIImage*)srcImg centerLogoImage:(UIImage*)LogoImage logoSize:(CGSize)logoSize; + + +/** + * 通过UIImageView形式添加Logo + * + * @param srcImgView 显示二维码的UIImageView + * @param logoView logo的UIImageView + * @param logoSize logo大小 + */ ++ (void)addImageViewLogo:(UIImageView*)srcImgView centerLogoImageView:(UIImageView*)logoView logoSize:(CGSize)logoSize; + + + +#pragma mark - 生成二维码,背景色及二维码颜色设置 +/** + @brief 生成颜色二维码,引用http://www.jianshu.com/p/e8f7a257b612 + @param text 二维码字符串 + @param size 大小 + @param qrColor 二维码颜色 + @param bkColor 背景色 + @return 二维码图像 + */ ++ (UIImage*)createQRWithString:(NSString*)text QRSize:(CGSize)size QRColor:(UIColor*)qrColor bkColor:(UIColor*)bkColor; + + + + +/** + @brief 各种码生成,如条形码等 + @param str 字符串 + @param size 大小 + @param format 格式 AVMetadataObjectTypeEAN13Code、AVMetadataObjectTypeCode39Code等 + @return 码的图像 + */ ++ (UIImage*)createCodeWithString:(NSString*)str size:(CGSize)size CodeFomart:(NSString*)format; + + +//识别图片上的二维码 + +/*! + * 识别各种码图片 + * + * @param image 图像 + * @param block 返回识别结果 + */ ++ (void)recognizeImage:(UIImage*)image success:(void(^)(NSArray *array))block; + + + + +#pragma mark- 震动、声音效果 +/** + @brief 识别成功震动提醒 + */ ++ (void)systemVibrate; + +/** + @brief 扫码成功声音提醒 + */ ++ (void)systemSound; + + +#pragma mark -相机、相册权限 + +/** + @brief 获取相机权限 + */ ++ (BOOL)isGetCameraPermission; +/** + @brief 获取相册权限 + */ ++ (BOOL)isGetPhotoPermission; + + + +/** + @brief 获取摄像机最大拉远镜头 + @return 放大系数 + */ +- (CGFloat)getVideoMaxScale; + +/** + @brief 拉近拉远镜头 + @param scale 系数 + */ +- (void)setVideoScale:(CGFloat)scale; + + +@end + + + + diff --git a/iDearQRCode/Tools/LBXScan/LBXScanWrapper.m b/iDearQRCode/Tools/LBXScan/LBXScanWrapper.m new file mode 100755 index 0000000..95a26f7 --- /dev/null +++ b/iDearQRCode/Tools/LBXScan/LBXScanWrapper.m @@ -0,0 +1,650 @@ +// +// LBXScanWrapper.m +// +// +// Created by lbxia on 15/3/4. +// Copyright (c) 2015年 lbxia. All rights reserved. +// + +#import "LBXScanWrapper.h" +#import "LBXScanNative.h" +#import "ZXingWrapper.h" +#import "ZXBarcodeFormat.h" +#import +#import + +@interface LBXScanWrapper() +{ + +} + +//ios7之后native封装 +@property(nonatomic,strong)LBXScanNative* scanNativeObj; + +//ZXing封装 +@property(nonatomic,strong)ZXingWrapper *scanZXingObj; + +/** + @brief 扫码类型 + */ +@property(nonatomic,strong)NSArray* arrayBarCodeType; + +//是否指定使用ZXing库 +@property(nonatomic,assign)BOOL isUseZXingLib; + + +@end + + +@implementation LBXScanWrapper + + ++ (BOOL)isSysIos7Later +{ + // return NO; + + if([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) + return YES; + return NO; +} + ++ (BOOL)isSysIos8Later +{ + // return NO; + + if([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) + return YES; + return NO; +} + +- (void)setNeedCaptureImage:(BOOL)isNeedCaputureImg +{ + if (_scanNativeObj) { + [_scanNativeObj setNeedCaptureImage:isNeedCaputureImg]; + } +} + +- (instancetype)initWithPreView:(UIView*)preView ArrayObjectType:(NSArray*)arrayBarCodeType cropRect:(CGRect)cropRect + success:(void(^)(NSArray *array))blockScanResult +{ + if (self = [super init]) + { + self.isUseZXingLib = NO; + + self.arrayBarCodeType = arrayBarCodeType; + + + CGRect frame = preView.frame; + frame.origin = CGPointZero; + + if ( [LBXScanWrapper isSysIos7Later] ) + { + _scanNativeObj = [[LBXScanNative alloc]initWithPreView:preView ObjectType:arrayBarCodeType cropRect:cropRect success:^(NSArray *array) { + + if (blockScanResult) + { + blockScanResult(array); + } + }]; + + } + else + { + _scanZXingObj = [[ZXingWrapper alloc]initWithPreView:preView block:^(ZXBarcodeFormat barcodeFormat, NSString *str, UIImage *scanImg) { + + //TODO:ZXing统一识别所有的码 + if ( blockScanResult ) + { + NSString *barCodeType = [LBXScanWrapper convertZXBarcodeFormat:barcodeFormat]; + + LBXScanResult *result = [[LBXScanResult alloc]initWithScanString:str imgScan:scanImg barCodeType:barCodeType]; + + blockScanResult(@[result]); + } + }]; + + } + + } + + return self; +} + + + +/** + @brief 初始化相机,并指定使用ZXing库识别各种码 + @param preView 视频显示View + @param blockScanResult 返回结果 + @return LBXScanVendor + */ +- (instancetype)initZXingWithPreView:(UIView *)preView success:(void(^)(NSArray *array))blockScanResult +{ + if (self = [super init]) + { + self.isUseZXingLib = YES; + + _scanZXingObj = [[ZXingWrapper alloc]initWithPreView:preView block:^(ZXBarcodeFormat barcodeFormat, NSString *str, UIImage *scanImg) { + + NSString *barCodeType = [LBXScanWrapper convertZXBarcodeFormat:barcodeFormat]; + + if (blockScanResult) { + blockScanResult(@[str,scanImg,barCodeType]); + } + }]; + } + + return self; +} + + + +/*! + * 开始扫码 + */ +- (void)startScan +{ + + if ( [LBXScanWrapper isSysIos7Later] && !_isUseZXingLib ) + [_scanNativeObj startScan]; + else + [_scanZXingObj start]; +} + +/*! + * 停止扫码 + */ +- (void)stopScan +{ + if ( [LBXScanWrapper isSysIos7Later] && !_isUseZXingLib ) + [_scanNativeObj stopScan]; + else + [_scanZXingObj stop]; +} + +- (void)openFlash:(BOOL)bOpen +{ + + AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; + + if ([device hasTorch] && [device hasFlash]) + { + if ([LBXScanWrapper isSysIos7Later] && !_isUseZXingLib ) + [_scanNativeObj setTorch:bOpen]; + else + [_scanZXingObj openTorch:bOpen]; + } + +} + +- (void)openOrCloseFlash +{ + AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; + + if ([device hasTorch] && [device hasFlash]) + { + if ([LBXScanWrapper isSysIos7Later] && !_isUseZXingLib ) + [_scanNativeObj changeTorch]; + else + [_scanZXingObj openOrCloseTorch]; + } + + +} + +/*! + * 修改扫码类型 + * + * @param objType 扫码类型 + */ +- (void)changeScanObjType:(NSArray*)objType +{ + if ( [LBXScanWrapper isSysIos7Later] && !_isUseZXingLib ) + { + [_scanNativeObj changeScanType:objType]; + } +} + + + + + + +//识别图片上的二维码 + +/*! + * 识别各种码图片 + * + * @param image 图像 + * @param block 返回识别结果 + */ ++ (void)recognizeImage:(UIImage*)image success:(void(^)(NSArray *array))block; +{ + __block UIImage* tmpImg = image; + + [ZXingWrapper recognizeImage:image block:^(ZXBarcodeFormat barCodeFormat,NSString* str) + { + NSString *barCodeType = [LBXScanWrapper convertZXBarcodeFormat:barCodeFormat]; + + if (block) { + + LBXScanResult *result = [[LBXScanResult alloc]initWithScanString:str imgScan:tmpImg barCodeType:barCodeType]; + block(@[result]); + } + + }]; +} + + + + + + + +#pragma mark- 震动、声音效果 + +#define SOUNDID 1109 //1012 -iphone 1152 ipad 1109 ipad ++ (void)systemVibrate +{ + AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); +} + ++ (void)systemSound +{ + AudioServicesPlaySystemSound(SOUNDID); +} + + +#pragma mark -相机、相册权限 ++ (BOOL)isGetCameraPermission +{ + BOOL isCameraValid = YES; + //ios7之前系统默认拥有权限 + if([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) + { + AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]; + + if (authStatus == AVAuthorizationStatusDenied) + { + isCameraValid = NO; + } + } + return isCameraValid; +} + + ++ (BOOL)isGetPhotoPermission +{ + if ([[[UIDevice currentDevice] systemVersion] floatValue] < 8.0) + { + ALAuthorizationStatus author = [ALAssetsLibrary authorizationStatus]; + + if ( author == ALAuthorizationStatusDenied ) { + + return NO; + } + return YES; + } + + PHAuthorizationStatus authorStatus = [PHPhotoLibrary authorizationStatus]; + if ( authorStatus == PHAuthorizationStatusDenied ) { + + return NO; + } + return YES; +} + + ++ (NSString*)convertZXBarcodeFormat:(ZXBarcodeFormat)barCodeFormat +{ + NSString *strAVMetadataObjectType = nil; + + switch (barCodeFormat) { + case kBarcodeFormatQRCode: + strAVMetadataObjectType = AVMetadataObjectTypeQRCode; + break; + case kBarcodeFormatEan13: + strAVMetadataObjectType = AVMetadataObjectTypeEAN13Code; + break; + case kBarcodeFormatEan8: + strAVMetadataObjectType = AVMetadataObjectTypeEAN8Code; + break; + case kBarcodeFormatPDF417: + strAVMetadataObjectType = AVMetadataObjectTypePDF417Code; + break; + case kBarcodeFormatAztec: + strAVMetadataObjectType = AVMetadataObjectTypeAztecCode; + break; + case kBarcodeFormatCode39: + strAVMetadataObjectType = AVMetadataObjectTypeCode39Code; + break; + case kBarcodeFormatCode93: + strAVMetadataObjectType = AVMetadataObjectTypeCode93Code; + break; + case kBarcodeFormatCode128: + strAVMetadataObjectType = AVMetadataObjectTypeCode128Code; + break; + case kBarcodeFormatDataMatrix: + strAVMetadataObjectType = AVMetadataObjectTypeDataMatrixCode; + break; + case kBarcodeFormatITF: + strAVMetadataObjectType = AVMetadataObjectTypeITF14Code; + break; + case kBarcodeFormatRSS14: + break; + case kBarcodeFormatRSSExpanded: + break; + case kBarcodeFormatUPCA: + break; + case kBarcodeFormatUPCE: + strAVMetadataObjectType = AVMetadataObjectTypeUPCECode; + break; + default: + break; + } + + + return strAVMetadataObjectType; +} + ++ (ZXBarcodeFormat)convertCodeFomratToZXBarcodeFormat:(NSString*)strCodeType +{ + + if ([strCodeType isEqualToString:AVMetadataObjectTypeQRCode]) + { + return kBarcodeFormatQRCode; + } + + if ([strCodeType isEqualToString:AVMetadataObjectTypeEAN13Code]) + { + return kBarcodeFormatEan13; + } + + if ([strCodeType isEqualToString:AVMetadataObjectTypeEAN8Code]) + { + return kBarcodeFormatEan8; + } + + if ([strCodeType isEqualToString:AVMetadataObjectTypePDF417Code]) + { + return kBarcodeFormatPDF417; + } + + if ([strCodeType isEqualToString:AVMetadataObjectTypeAztecCode]) + { + return kBarcodeFormatAztec; + } + + + if ([strCodeType isEqualToString:AVMetadataObjectTypeCode39Code]) + { + return kBarcodeFormatCode39; + } + + if ([strCodeType isEqualToString:AVMetadataObjectTypeCode93Code]) + { + return kBarcodeFormatCode93; + } + + //支付宝付款码条形码格式 + if ([strCodeType isEqualToString:AVMetadataObjectTypeCode128Code]) + { + return kBarcodeFormatCode128; + } + + if ([strCodeType isEqualToString:AVMetadataObjectTypeDataMatrixCode]) + { + return kBarcodeFormatDataMatrix; + } + + if ([strCodeType isEqualToString:AVMetadataObjectTypeUPCECode]) + { + return kBarcodeFormatUPCE; + } + + return kBarcodeFormatQRCode; +} + + + + +#pragma mark -生成二维码 + +/*! + * 生成二维码 + * + * @param str 二维码字符串 + * @param size 二维码图片大小 + * + * @return 返回生成的图像 + */ ++ (UIImage*)createQRWithString:(NSString*)str size:(CGSize)size +{ + if ([LBXScanWrapper isSysIos7Later]) { + + return [LBXScanWrapper createNonInterpolatedUIImageFormCIImage:[LBXScanWrapper createQRForString:str] withSize:size.width]; + } + else + return [ZXingWrapper createCodeWithString:str size:size CodeFomart:kBarcodeFormatQRCode]; +} + + ++ (UIImage*)createCodeWithString:(NSString*)str size:(CGSize)size CodeFomart:(NSString*)format +{ + ZXBarcodeFormat zxformat = [LBXScanWrapper convertCodeFomratToZXBarcodeFormat:format]; + + return [ZXingWrapper createCodeWithString:str size:size CodeFomart:zxformat]; +} + + + +/** + @brief 图像中间加logo图片 + @param srcImg 原图像 + @param LogoImage logo图像 + @param logoSize logo图像尺寸 + @return 加Logo的图像 + */ ++ (UIImage*)addImageLogo:(UIImage*)srcImg centerLogoImage:(UIImage*)LogoImage logoSize:(CGSize)logoSize +{ + //UIGraphicsBeginImageContext(srcImg.size); + + UIGraphicsBeginImageContextWithOptions(srcImg.size, NO, [[UIScreen mainScreen] scale]); + + [srcImg drawInRect:CGRectMake(0, 0, srcImg.size.width, srcImg.size.height)]; + + CGRect rect = CGRectMake(srcImg.size.width/2 - logoSize.width/2, srcImg.size.height/2-logoSize.height/2, logoSize.width, logoSize.height); + [LogoImage drawInRect:rect]; + UIImage *resultingImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + return resultingImage; +} + + +/** + * 通过UIImageView形式添加Logo + * + * @param srcImgView 显示二维码的UIImageView + * @param logoView logo的UIImageView + * @param logoSize logo大小 + */ ++ (void)addImageViewLogo:(UIImageView*)srcImgView centerLogoImageView:(UIImageView*)logoView logoSize:(CGSize)logoSize +{ + logoView.center = srcImgView.center; + logoView.bounds = CGRectMake(0, 0, logoSize.width, logoSize.height); + [srcImgView addSubview:logoView]; +} + +#pragma mark --UIImage 圆角 + ++ (UIImage *)roundedCornerImageWithCornerRadius:(CGFloat)cornerRadius srcImg:(UIImage*)srcImg +{ + CGFloat w = srcImg.size.width; + CGFloat h = srcImg.size.height; + CGFloat scale = [UIScreen mainScreen].scale; + // 防止圆角半径小于0,或者大于宽/高中较小值的一半。 + if (cornerRadius < 0) + cornerRadius = 0; + else if (cornerRadius > MIN(w, h)) + cornerRadius = MIN(w, h) / 2.; + + UIImage *image = nil; + CGRect imageFrame = CGRectMake(0., 0., w, h); + UIGraphicsBeginImageContextWithOptions(srcImg.size, NO, scale); + [[UIBezierPath bezierPathWithRoundedRect:imageFrame cornerRadius:cornerRadius] addClip]; + [srcImg drawInRect:imageFrame]; + image = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + return image; +} + + +//下面引用自 https://github.com/yourtion/Demo_CustomQRCode +#pragma mark - InterpolatedUIImage ++ (UIImage *)createNonInterpolatedUIImageFormCIImage:(CIImage *)image withSize:(CGFloat) size { + CGRect extent = CGRectIntegral(image.extent); + CGFloat scale = MIN(size/CGRectGetWidth(extent), size/CGRectGetHeight(extent)); + // 创建bitmap; + size_t width = CGRectGetWidth(extent) * scale; + size_t height = CGRectGetHeight(extent) * scale; + CGColorSpaceRef cs = CGColorSpaceCreateDeviceGray(); + CGContextRef bitmapRef = CGBitmapContextCreate(nil, width, height, 8, 0, cs, (CGBitmapInfo)kCGImageAlphaNone); + CGColorSpaceRelease(cs); + CIContext *context = [CIContext contextWithOptions:nil]; + CGImageRef bitmapImage = [context createCGImage:image fromRect:extent]; + CGContextSetInterpolationQuality(bitmapRef, kCGInterpolationNone); + CGContextScaleCTM(bitmapRef, scale, scale); + CGContextDrawImage(bitmapRef, extent, bitmapImage); + // 保存bitmap到图片 + CGImageRef scaledImage = CGBitmapContextCreateImage(bitmapRef); + CGContextRelease(bitmapRef); + CGImageRelease(bitmapImage); + UIImage *aImage = [UIImage imageWithCGImage:scaledImage]; + CGImageRelease(scaledImage); + return aImage; +} + +#pragma mark - QRCodeGenerator ++ (CIImage *)createQRForString:(NSString *)qrString { + NSData *stringData = [qrString dataUsingEncoding:NSUTF8StringEncoding]; + // 创建filter + CIFilter *qrFilter = [CIFilter filterWithName:@"CIQRCodeGenerator"]; + // 设置内容和纠错级别 + [qrFilter setValue:stringData forKey:@"inputMessage"]; + [qrFilter setValue:@"H" forKey:@"inputCorrectionLevel"]; + // 返回CIImage + return qrFilter.outputImage; +} + +#pragma mark - imageToTransparent +void ProviderReleaseData (void *info, const void *data, size_t size){ + free((void*)data); +} ++ (UIImage*)imageBlackToTransparent:(UIImage*)image withRed:(CGFloat)red andGreen:(CGFloat)green andBlue:(CGFloat)blue{ + const int imageWidth = image.size.width; + const int imageHeight = image.size.height; + size_t bytesPerRow = imageWidth * 4; + uint32_t* rgbImageBuf = (uint32_t*)malloc(bytesPerRow * imageHeight); + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + CGContextRef context = CGBitmapContextCreate(rgbImageBuf, imageWidth, imageHeight, 8, bytesPerRow, colorSpace, + kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipLast); + CGContextDrawImage(context, CGRectMake(0, 0, imageWidth, imageHeight), image.CGImage); + // 遍历像素 + int pixelNum = imageWidth * imageHeight; + uint32_t* pCurPtr = rgbImageBuf; + for (int i = 0; i < pixelNum; i++, pCurPtr++){ + if ((*pCurPtr & 0xFFFFFF00) < 0x99999900) // 将白色变成透明 + { + // 改成下面的代码,会将图片转成想要的颜色 + uint8_t* ptr = (uint8_t*)pCurPtr; + ptr[3] = red; //0~255 + ptr[2] = green; + ptr[1] = blue; + } + else + { + uint8_t* ptr = (uint8_t*)pCurPtr; + ptr[0] = 0; + } + } + // 输出图片 + CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL, rgbImageBuf, bytesPerRow * imageHeight, ProviderReleaseData); + CGImageRef imageRef = CGImageCreate(imageWidth, imageHeight, 8, 32, bytesPerRow, colorSpace, + kCGImageAlphaLast | kCGBitmapByteOrder32Little, dataProvider, + NULL, true, kCGRenderingIntentDefault); + CGDataProviderRelease(dataProvider); + UIImage* resultUIImage = [UIImage imageWithCGImage:imageRef]; + // 清理空间 + CGImageRelease(imageRef); + CGContextRelease(context); + CGColorSpaceRelease(colorSpace); + return resultUIImage; +} + +#pragma mark - 生成二维码,背景色及二维码颜色设置 +//引用自:http://www.jianshu.com/p/e8f7a257b612 ++ (UIImage*)createQRWithString:(NSString*)text QRSize:(CGSize)size QRColor:(UIColor*)qrColor bkColor:(UIColor*)bkColor +{ + + NSData *stringData = [text dataUsingEncoding: NSUTF8StringEncoding]; + + //生成 + CIFilter *qrFilter = [CIFilter filterWithName:@"CIQRCodeGenerator"]; + [qrFilter setValue:stringData forKey:@"inputMessage"]; + [qrFilter setValue:@"H" forKey:@"inputCorrectionLevel"]; + + + //上色 + CIFilter *colorFilter = [CIFilter filterWithName:@"CIFalseColor" + keysAndValues: + @"inputImage",qrFilter.outputImage, + @"inputColor0",[CIColor colorWithCGColor:qrColor.CGColor], + @"inputColor1",[CIColor colorWithCGColor:bkColor.CGColor], + nil]; + + CIImage *qrImage = colorFilter.outputImage; + + //绘制 + CGImageRef cgImage = [[CIContext contextWithOptions:nil] createCGImage:qrImage fromRect:qrImage.extent]; + UIGraphicsBeginImageContext(size); + CGContextRef context = UIGraphicsGetCurrentContext(); + CGContextSetInterpolationQuality(context, kCGInterpolationNone); + CGContextScaleCTM(context, 1.0, -1.0); + CGContextDrawImage(context, CGContextGetClipBoundingBox(context), cgImage); + UIImage *codeImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + CGImageRelease(cgImage); + + return codeImage; +} + + + +/** + @brief 获取摄像机最大拉远镜头 + @return 放大系数 + */ +- (CGFloat)getVideoMaxScale +{ + if (self.scanNativeObj) { + return [self.scanNativeObj getVideoMaxScale]; + } + + return 1.0; +} + +/** + @brief 拉近拉远镜头 + @param scale 系数 + */ +- (void)setVideoScale:(CGFloat)scale +{ + if (self.scanNativeObj) { + [self.scanNativeObj setVideoScale:scale]; + } +} + + +@end diff --git a/iDearQRCode/Tools/LBXScan/LBXZXCapture.h b/iDearQRCode/Tools/LBXScan/LBXZXCapture.h new file mode 100755 index 0000000..7094660 --- /dev/null +++ b/iDearQRCode/Tools/LBXScan/LBXZXCapture.h @@ -0,0 +1,70 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import +//#import "ZXResult.h" +#import "LBXZXCaptureDelegate.h" + +@protocol LBXZXCaptureDelegate, ZXReader; +@class ZXDecodeHints; + +@interface LBXZXCapture : NSObject + +@property (nonatomic, assign) int camera; +@property (nonatomic, strong) AVCaptureDevice *captureDevice; +@property (nonatomic, copy) NSString *captureToFilename; +@property (nonatomic, weak) id delegate; +@property (nonatomic, assign) AVCaptureFocusMode focusMode; +@property (nonatomic, strong) ZXDecodeHints *hints; +@property (nonatomic, assign) CGImageRef lastScannedImage; +@property (nonatomic, assign) BOOL invert; +@property (nonatomic, strong, readonly) CALayer *layer; +@property (nonatomic, assign) BOOL mirror; +@property (nonatomic, strong, readonly) AVCaptureVideoDataOutput *output; +@property (nonatomic, strong) id reader; +@property (nonatomic, assign) CGFloat rotation; +@property (nonatomic, assign, readonly) BOOL running; +@property (nonatomic, assign) CGRect scanRect; +@property (nonatomic, copy) NSString *sessionPreset; +@property (nonatomic, assign) BOOL torch; +@property (nonatomic, assign) CGAffineTransform transform; + +- (int)back; +- (int)front; +- (BOOL)hasBack; +- (BOOL)hasFront; +- (BOOL)hasTorch; + +- (void)setTorch:(BOOL)torch; + +- (void)changeTorch; + +- (CALayer *)binary; +- (void)setBinary:(BOOL)on_off; + +- (CALayer *)luminance; +- (void)setLuminance:(BOOL)on_off; + +- (void)hard_stop; +- (void)order_skip; +- (void)start; +- (void)stop; + + +//+ (ZXResult *)regocnizeImage:(UIImage*)image; + + +@end diff --git a/iDearQRCode/Tools/LBXScan/LBXZXCapture.m b/iDearQRCode/Tools/LBXScan/LBXZXCapture.m new file mode 100755 index 0000000..1f4d703 --- /dev/null +++ b/iDearQRCode/Tools/LBXScan/LBXZXCapture.m @@ -0,0 +1,608 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import +#import "ZXBinaryBitmap.h" +#import "LBXZXCapture.h" +#import "ZXCaptureDelegate.h" +#import "ZXCGImageLuminanceSource.h" +#import "ZXDecodeHints.h" +#import "ZXHybridBinarizer.h" +#import "ZXReader.h" +#import "ZXResult.h" + +@interface LBXZXCapture () + +@property (nonatomic, strong) CALayer *binaryLayer; +@property (nonatomic, assign) BOOL cameraIsReady; +@property (nonatomic, assign) int captureDeviceIndex; +@property (nonatomic, strong) dispatch_queue_t captureQueue; +@property (nonatomic, assign) BOOL hardStop; +@property (nonatomic, strong) AVCaptureDeviceInput *input; +@property (nonatomic, strong) AVCaptureVideoPreviewLayer *layer; +@property (nonatomic, strong) CALayer *luminanceLayer; +@property (nonatomic, assign) int orderInSkip; +@property (nonatomic, assign) int orderOutSkip; +@property (nonatomic, assign) BOOL onScreen; +@property (nonatomic, strong) AVCaptureVideoDataOutput *output; +@property (nonatomic, assign) BOOL running; +@property (nonatomic, strong) AVCaptureSession *session; + +@end + +@implementation LBXZXCapture + +- (LBXZXCapture *)init { + if (self = [super init]) { + _captureDeviceIndex = -1; + _captureQueue = dispatch_queue_create("com.zxing.captureQueue", NULL); + _focusMode = AVCaptureFocusModeContinuousAutoFocus; + _hardStop = NO; + _hints = [ZXDecodeHints hints]; + _lastScannedImage = NULL; + _onScreen = NO; + _orderInSkip = 0; + _orderOutSkip = 0; + + if (NSClassFromString(@"ZXMultiFormatReader")) { + _reader = [NSClassFromString(@"ZXMultiFormatReader") performSelector:@selector(reader)]; + } + + _rotation = 0.0f; + _running = NO; + _sessionPreset = AVCaptureSessionPresetHigh; + _transform = CGAffineTransformIdentity; + _scanRect = CGRectZero; + } + + return self; +} + +- (void)dealloc { + if (_lastScannedImage) { + CGImageRelease(_lastScannedImage); + } + + if (_session && _session.inputs) { + for(AVCaptureInput *input in _session.inputs) { + [_session removeInput:input]; + } + + [self.layer removeFromSuperlayer]; + } + + if (_session && _session.outputs) { + for(AVCaptureOutput *output in _session.outputs) { + [_session removeOutput:output]; + } + } +} + +#pragma mark - Property Getters + +- (CALayer *)layer { + AVCaptureVideoPreviewLayer *layer = (AVCaptureVideoPreviewLayer *)_layer; + if (!_layer) { + layer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.session]; + layer.affineTransform = self.transform; + layer.delegate = self; + layer.videoGravity = AVLayerVideoGravityResizeAspect; + layer.videoGravity = AVLayerVideoGravityResizeAspectFill; + + _layer = layer; + } + return layer; +} + +- (AVCaptureVideoDataOutput *)output { + if (!_output) { + _output = [[AVCaptureVideoDataOutput alloc] init]; + [_output setVideoSettings:@{ + (NSString *)kCVPixelBufferPixelFormatTypeKey : [NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA] + }]; + [_output setAlwaysDiscardsLateVideoFrames:YES]; + [_output setSampleBufferDelegate:self queue:_captureQueue]; + + [self.session addOutput:_output]; + } + + return _output; +} + +#pragma mark - Property Setters + +- (void)setCamera:(int)camera { + if (_camera != camera) { + _camera = camera; + self.captureDeviceIndex = -1; + self.captureDevice = nil; + [self replaceInput]; + } +} + +- (void)setDelegate:(id)delegate { + _delegate = delegate; + + if (delegate) { + self.hardStop = NO; + } + [self startStop]; +} + +- (void)setFocusMode:(AVCaptureFocusMode)focusMode { + if ([self.input.device isFocusModeSupported:focusMode] && self.input.device.focusMode != focusMode) { + _focusMode = focusMode; + + [self.input.device lockForConfiguration:nil]; + self.input.device.focusMode = focusMode; + [self.input.device unlockForConfiguration]; + } +} + +- (void)setLastScannedImage:(CGImageRef)lastScannedImage { + if (_lastScannedImage) { + CGImageRelease(_lastScannedImage); + } + + if (lastScannedImage) { + CGImageRetain(lastScannedImage); + } + + _lastScannedImage = lastScannedImage; +} + +- (void)setMirror:(BOOL)mirror { + if (_mirror != mirror) { + _mirror = mirror; + if (self.layer) { + CGAffineTransform transform = self.transform; + transform.a = - transform.a; + self.transform = transform; + [self.layer setAffineTransform:self.transform]; + } + } +} + +- (void)setTorch:(BOOL)torch { + _torch = torch; + + [self.input.device lockForConfiguration:nil]; + self.input.device.torchMode = self.torch ? AVCaptureTorchModeOn : AVCaptureTorchModeOff; + [self.input.device unlockForConfiguration]; +} + +- (void)changeTorch +{ + AVCaptureTorchMode torch = self.input.device.torchMode; + + switch (self.input.device.torchMode) { + case AVCaptureTorchModeAuto: + break; + case AVCaptureTorchModeOff: + torch = AVCaptureTorchModeOn; + break; + case AVCaptureTorchModeOn: + torch = AVCaptureTorchModeOff; + break; + default: + break; + } + + + [self.input.device lockForConfiguration:nil]; + self.input.device.torchMode = torch; + [self.input.device unlockForConfiguration]; +} + + +- (void)setTransform:(CGAffineTransform)transform { + _transform = transform; + [self.layer setAffineTransform:transform]; +} + +#pragma mark - Back, Front, Torch + +- (int)back { + return 1; +} + +- (int)front { + return 0; +} + +- (BOOL)hasFront { + NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; + return [devices count] > 1; +} + +- (BOOL)hasBack { + NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; + return [devices count] > 0; +} + +- (BOOL)hasTorch { + if ([self device]) { + return [self device].hasTorch; + } else { + return NO; + } +} + +#pragma mark - Binary + +- (CALayer *)binary { + return self.binaryLayer; +} + +- (void)setBinary:(BOOL)on { + if (on && !self.binaryLayer) { + self.binaryLayer = [CALayer layer]; + } else if (!on && self.binaryLayer) { + self.binaryLayer = nil; + } +} + +#pragma mark - Luminance + +- (CALayer *)luminance { + return self.luminanceLayer; +} + +- (void)setLuminance:(BOOL)on { + if (on && !self.luminanceLayer) { + self.luminanceLayer = [CALayer layer]; + } else if (!on && self.luminanceLayer) { + self.luminanceLayer = nil; + } +} + +#pragma mark - Start, Stop + +- (void)hard_stop { + self.hardStop = YES; + + if (self.running) { + [self stop]; + } +} + +- (void)order_skip { + self.orderInSkip = 1; + self.orderOutSkip = 1; +} + +- (void)start { + + if (self.running) { + return; + } + + if (self.hardStop) { + return; + } + + if (self.delegate || self.luminanceLayer || self.binaryLayer) { + (void)[self output]; + } + + if (!self.session.running) { + static int i = 0; + if (++i == -2) { + abort(); + } + + [self.session startRunning]; + } + self.running = YES; +} + +- (void)stop +{ + if (!self.running) { + return; + } + + if (self.session.running) { + // [self.layer removeFromSuperlayer]; + [self.session stopRunning]; + } + self.running = NO; +} + + + +#pragma mark - CAAction + +- (id)actionForLayer:(CALayer *)_layer forKey:(NSString *)event { + [CATransaction setValue:[NSNumber numberWithFloat:0.0f] forKey:kCATransactionAnimationDuration]; + + if ([event isEqualToString:kCAOnOrderIn] || [event isEqualToString:kCAOnOrderOut]) { + return self; + } + + return nil; +} + +- (void)runActionForKey:(NSString *)key object:(id)anObject arguments:(NSDictionary *)dict { + if ([key isEqualToString:kCAOnOrderIn]) { + if (self.orderInSkip) { + self.orderInSkip--; + return; + } + + self.onScreen = YES; + [self startStop]; + } else if ([key isEqualToString:kCAOnOrderOut]) { + if (self.orderOutSkip) { + self.orderOutSkip--; + return; + } + + self.onScreen = NO; + [self startStop]; + } +} + +#pragma mark - AVCaptureVideoDataOutputSampleBufferDelegate + +- (void)captureOutput:(AVCaptureOutput *)captureOutput +didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer + fromConnection:(AVCaptureConnection *)connection { + @autoreleasepool { + if (!self.cameraIsReady) { + self.cameraIsReady = YES; + if ([self.delegate respondsToSelector:@selector(captureCameraIsReady:)]) { + dispatch_async(dispatch_get_main_queue(), ^{ + [self.delegate LBXCaptureCameraIsReady:self]; + }); + } + } + + if (!self.captureToFilename && !self.luminanceLayer && !self.binaryLayer && !self.delegate) { + return; + } + + CVImageBufferRef videoFrame = CMSampleBufferGetImageBuffer(sampleBuffer); + + CGImageRef videoFrameImage = [ZXCGImageLuminanceSource createImageFromBuffer:videoFrame]; + CGImageRef rotatedImage = [self createRotatedImage:videoFrameImage degrees:self.rotation]; + CGImageRelease(videoFrameImage); + + // If scanRect is set, crop the current image to include only the desired rect + if (!CGRectIsEmpty(self.scanRect)) { + CGImageRef croppedImage = CGImageCreateWithImageInRect(rotatedImage, self.scanRect); + CFRelease(rotatedImage); + rotatedImage = croppedImage; + } + + self.lastScannedImage = rotatedImage; + + if (self.captureToFilename) { + NSURL *url = [NSURL fileURLWithPath:self.captureToFilename]; + CGImageDestinationRef dest = CGImageDestinationCreateWithURL((__bridge CFURLRef)url, (__bridge CFStringRef)@"public.png", 1, nil); + CGImageDestinationAddImage(dest, rotatedImage, nil); + CGImageDestinationFinalize(dest); + CFRelease(dest); + self.captureToFilename = nil; + } + + ZXCGImageLuminanceSource *source = [[ZXCGImageLuminanceSource alloc] initWithCGImage:rotatedImage]; + CGImageRelease(rotatedImage); + + if (self.luminanceLayer) { + CGImageRef image = source.image; + CGImageRetain(image); + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0), dispatch_get_main_queue(), ^{ + self.luminanceLayer.contents = (__bridge id)image; + CGImageRelease(image); + }); + } + + + if (self.binaryLayer || self.delegate) + { + ZXHybridBinarizer *binarizer = [[ZXHybridBinarizer alloc] initWithSource:self.invert ? [source invert] : source]; + + if (self.binaryLayer) + { + CGImageRef image = [binarizer createImage]; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0), dispatch_get_main_queue(), ^{ + self.binaryLayer.contents = (__bridge id)image; + CGImageRelease(image); + }); + + + } + + if (self.delegate) + { + ZXBinaryBitmap *bitmap = [[ZXBinaryBitmap alloc] initWithBinarizer:binarizer]; + + NSError *error; + ZXResult *result = [self.reader decode:bitmap hints:self.hints error:&error]; + if (result) { +// CGImageRef iOffscreen = CGBitmapContextCreateImage(context); + UIImage* image = [UIImage imageWithCGImage: _lastScannedImage]; + + dispatch_async(dispatch_get_main_queue(), ^{ + [self.delegate captureResult:self result:result scanImage:image]; + }); + } + } + } + } +} + +//+ (ZXResult *)regocnizeImage:(UIImage*)image +//{ +// ZXCGImageLuminanceSource *source = [[ZXCGImageLuminanceSource alloc] initWithCGImage:image.CGImage]; +// +// ZXHybridBinarizer *binarizer = [[ZXHybridBinarizer alloc] initWithSource: source]; +// +// ZXBinaryBitmap *bitmap = [[ZXBinaryBitmap alloc] initWithBinarizer:binarizer]; +// +// NSError *error; +// +// id reader; +// +// if (NSClassFromString(@"ZXMultiFormatReader")) { +// reader = [NSClassFromString(@"ZXMultiFormatReader") performSelector:@selector(reader)]; +// } +// +// ZXDecodeHints *_hints = [ZXDecodeHints hints]; +// ZXResult *result = [reader decode:bitmap hints:_hints error:&error]; +// +// return result; +//} + + +#pragma mark - Private + +// Adapted from http://blog.coriolis.ch/2009/09/04/arbitrary-rotation-of-a-cgimage/ and https://github.com/JanX2/CreateRotateWriteCGImage +- (CGImageRef)createRotatedImage:(CGImageRef)original degrees:(float)degrees CF_RETURNS_RETAINED { + if (degrees == 0.0f) { + CGImageRetain(original); + return original; + } else { + double radians = degrees * M_PI / 180; + +#if TARGET_OS_EMBEDDED || TARGET_IPHONE_SIMULATOR + radians = -1 * radians; +#endif + + size_t _width = CGImageGetWidth(original); + size_t _height = CGImageGetHeight(original); + + CGRect imgRect = CGRectMake(0, 0, _width, _height); + CGAffineTransform __transform = CGAffineTransformMakeRotation(radians); + CGRect rotatedRect = CGRectApplyAffineTransform(imgRect, __transform); + + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + CGContextRef context = CGBitmapContextCreate(NULL, + rotatedRect.size.width, + rotatedRect.size.height, + CGImageGetBitsPerComponent(original), + 0, + colorSpace, + kCGBitmapAlphaInfoMask & kCGImageAlphaPremultipliedFirst); + CGContextSetAllowsAntialiasing(context, FALSE); + CGContextSetInterpolationQuality(context, kCGInterpolationNone); + CGColorSpaceRelease(colorSpace); + + CGContextTranslateCTM(context, + +(rotatedRect.size.width/2), + +(rotatedRect.size.height/2)); + CGContextRotateCTM(context, radians); + + CGContextDrawImage(context, CGRectMake(-imgRect.size.width/2, + -imgRect.size.height/2, + imgRect.size.width, + imgRect.size.height), + original); + + CGImageRef rotatedImage = CGBitmapContextCreateImage(context); + CFRelease(context); + + return rotatedImage; + } +} + +- (AVCaptureDevice *)device { + if (self.captureDevice) { + return self.captureDevice; + } + + AVCaptureDevice *zxd = nil; + + NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; + + if ([devices count] > 0) { + if (self.captureDeviceIndex == -1) { + AVCaptureDevicePosition position = AVCaptureDevicePositionBack; + if (self.camera == self.front) { + position = AVCaptureDevicePositionFront; + } + + for (unsigned int i = 0; i < [devices count]; ++i) { + AVCaptureDevice *dev = [devices objectAtIndex:i]; + if (dev.position == position) { + self.captureDeviceIndex = i; + zxd = dev; + break; + } + } + } + + if (!zxd && self.captureDeviceIndex != -1) { + zxd = [devices objectAtIndex:self.captureDeviceIndex]; + } + } + + if (!zxd) { + zxd = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; + } + + self.captureDevice = zxd; + + return zxd; +} + +- (void)replaceInput { + [self.session beginConfiguration]; + + if (self.session && self.input) { + [self.session removeInput:self.input]; + self.input = nil; + } + + AVCaptureDevice *zxd = [self device]; + + if (zxd) { + self.input = [AVCaptureDeviceInput deviceInputWithDevice:zxd error:nil]; + self.focusMode = self.focusMode; + } + + if (self.input) { + self.session.sessionPreset = self.sessionPreset; + [self.session addInput:self.input]; + } + + [self.session commitConfiguration]; +} + +- (AVCaptureSession *)session { + if (!_session) { + _session = [[AVCaptureSession alloc] init]; + [self replaceInput]; + } + + return _session; +} + +- (void)startStop { + if ((!self.running && (self.delegate || self.onScreen)) || + (!self.output && + (self.delegate || + (self.onScreen && (self.luminanceLayer || self.binaryLayer))))) { + [self start]; + } + + if (self.running && !self.delegate && !self.onScreen) { + [self stop]; + } +} + +@end diff --git a/iDearQRCode/Tools/LBXScan/LBXZXCaptureDelegate.h b/iDearQRCode/Tools/LBXScan/LBXZXCaptureDelegate.h new file mode 100755 index 0000000..db66882 --- /dev/null +++ b/iDearQRCode/Tools/LBXScan/LBXZXCaptureDelegate.h @@ -0,0 +1,31 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class LBXZXCapture; +@class ZXResult; + +@protocol LBXZXCaptureDelegate + +- (void)captureResult:(LBXZXCapture *)capture result:(ZXResult *)result scanImage:(UIImage*)img; + +@optional +- (void)LBXCaptureSize:(LBXZXCapture *)capture + width:(NSNumber *)width + height:(NSNumber *)height; + +- (void)LBXCaptureCameraIsReady:(LBXZXCapture *)capture; + +@end diff --git a/iDearQRCode/Tools/LBXScan/ZXingWrapper.h b/iDearQRCode/Tools/LBXScan/ZXingWrapper.h new file mode 100755 index 0000000..eeb10cf --- /dev/null +++ b/iDearQRCode/Tools/LBXScan/ZXingWrapper.h @@ -0,0 +1,75 @@ +// +// ZXingWrapper.h +// +// github:https://github.com/MxABC/LBXScan +// Created by lbxia on 15/1/6. +// Copyright (c) 2015年 lbxia. All rights reserved. +// + +#import +#import + +#import "ZXBarcodeFormat.h" + + +/*! + * ZXing扫码封装 + */ +@interface ZXingWrapper : NSObject + + + +- (instancetype)initWithPreView:(UIView*)preView block:(void(^)(ZXBarcodeFormat barcodeFormat,NSString *str,UIImage *scanImg))block; + + +- (void)setScanRect:(CGRect)scanRect; + + + + +/*! + * 开始扫码 + */ +- (void)start; + +/*! + * 停止扫码 + */ +- (void)stop; + +/*! + * 打开关闭闪光灯 + * + * @param on_off YES:打开闪光灯,NO:关闭闪光灯 + */ +- (void)openTorch:(BOOL)on_off; + + +/*! + * 打开关闭闪光灯 + */ +- (void)openOrCloseTorch; + + +/*! + * 生成二维码 + * + * @param str 二维码字符串 + * @param size 二维码图片大小 + * @param format 码的类型 + * @return 返回生成的图像 + */ ++ (UIImage*)createCodeWithString:(NSString*)str size:(CGSize)size CodeFomart:(ZXBarcodeFormat)format; + + +//识别图片上的二维码 + +/*! + * 识别各种码图片 + * + * @param image 图像 + * @param block 返回识别结果 + */ ++ (void)recognizeImage:(UIImage*)image block:(void(^)(ZXBarcodeFormat barcodeFormat,NSString *str))block; + +@end diff --git a/iDearQRCode/Tools/LBXScan/ZXingWrapper.m b/iDearQRCode/Tools/LBXScan/ZXingWrapper.m new file mode 100755 index 0000000..3ad0a4a --- /dev/null +++ b/iDearQRCode/Tools/LBXScan/ZXingWrapper.m @@ -0,0 +1,165 @@ +// +// ZXingWrapper.m +// +// +// Created by lbxia on 15/1/6. +// Copyright (c) 2015年 lbxia. All rights reserved. +// + +#import "ZXingWrapper.h" +#import "ZXingObjC.h" +#import "LBXZXCaptureDelegate.h" +#import "LBXZXCapture.h" + + +typedef void(^blockScan)(ZXBarcodeFormat barcodeFormat,NSString *str,UIImage *scanImg); + +@interface ZXingWrapper() +@property (nonatomic, strong) LBXZXCapture *capture; + +@property (nonatomic,copy)blockScan block; + +@property (nonatomic, assign) BOOL bNeedScanResult; + +@end + +@implementation ZXingWrapper + + +- (id)init +{ + if ( self = [super init] ) + { + self.capture = [[LBXZXCapture alloc] init]; + self.capture.camera = self.capture.back; + self.capture.focusMode = AVCaptureFocusModeContinuousAutoFocus; + self.capture.rotation = 90.0f; + + self.capture.delegate = self; + } + return self; +} + +- (id)initWithPreView:(UIView*)preView block:(void(^)(ZXBarcodeFormat barcodeFormat,NSString *str,UIImage *scanImg))block +{ + if (self = [super init]) { + + self.capture = [[LBXZXCapture alloc] init]; + self.capture.camera = self.capture.back; + self.capture.focusMode = AVCaptureFocusModeContinuousAutoFocus; + self.capture.rotation = 90.0f; + + self.capture.delegate = self; + + self.block = block; + + CGRect rect = preView.frame; + rect.origin = CGPointZero; + + self.capture.layer.frame = rect; + //[preView.layer addSublayer:self.capture.layer]; + + [preView.layer insertSublayer:self.capture.layer atIndex:0]; + + + } + return self; +} + +- (void)setScanRect:(CGRect)scanRect +{ + self.capture.scanRect = scanRect; +} + +- (void)start +{ + [self.capture start]; + self.bNeedScanResult = YES; +} + +- (void)stop +{ + self.bNeedScanResult = NO; + [self.capture stop]; + +} + +- (void)openTorch:(BOOL)on_off +{ + [self.capture setTorch:on_off]; +} +- (void)openOrCloseTorch +{ + [self.capture changeTorch]; +} + + +#pragma mark - ZXCaptureDelegate Methods + +- (void)captureResult:(ZXCapture *)capture result:(ZXResult *)result scanImage:(UIImage *)img { + if (!result) return; + + if (!_bNeedScanResult) { + + return; + } + + if ( _block ) + { + [self stop]; + + _block(result.barcodeFormat,result.text,img); + } +} + + ++ (UIImage*)createCodeWithString:(NSString*)str size:(CGSize)size CodeFomart:(ZXBarcodeFormat)format +{ + ZXMultiFormatWriter *writer = [[ZXMultiFormatWriter alloc] init]; + ZXBitMatrix *result = [writer encode:str + format:format + width:size.width + height:size.width + error:nil]; + + if (result) { + ZXImage *image = [ZXImage imageWithMatrix:result]; + return [UIImage imageWithCGImage:image.cgimage]; + } else { + return nil; + } +} + + ++ (void)recognizeImage:(UIImage*)image block:(void(^)(ZXBarcodeFormat barcodeFormat,NSString *str))block; +{ + ZXCGImageLuminanceSource *source = [[ZXCGImageLuminanceSource alloc] initWithCGImage:image.CGImage]; + + ZXHybridBinarizer *binarizer = [[ZXHybridBinarizer alloc] initWithSource: source]; + + ZXBinaryBitmap *bitmap = [[ZXBinaryBitmap alloc] initWithBinarizer:binarizer]; + + NSError *error; + + id reader; + + if (NSClassFromString(@"ZXMultiFormatReader")) { + reader = [NSClassFromString(@"ZXMultiFormatReader") performSelector:@selector(reader)]; + } + + ZXDecodeHints *_hints = [ZXDecodeHints hints]; + ZXResult *result = [reader decode:bitmap hints:_hints error:&error]; + + if (result == nil) { + + block(kBarcodeFormatQRCode,nil); + return; + } + + block(result.barcodeFormat,result.text); +} + + + + +@end diff --git a/iDearQRCode/Tools/Lib/ViewModelClass.h b/iDearQRCode/Tools/Lib/ViewModelClass.h index 6384412..b575ffe 100644 --- a/iDearQRCode/Tools/Lib/ViewModelClass.h +++ b/iDearQRCode/Tools/Lib/ViewModelClass.h @@ -16,8 +16,8 @@ typedef void (^ErrorCodeBlock) (id errorCode); @interface ViewModelClass : NSObject -@property (strong, nonatomic) ReturnValueBlock returnBlock; -@property (strong, nonatomic) ErrorCodeBlock errorBlock; +@property (copy, nonatomic) ReturnValueBlock returnBlock; +@property (copy, nonatomic) ErrorCodeBlock errorBlock; // 传入交互的Block块 -(void) setBlockWithReturnBlock: (ReturnValueBlock) returnBlock diff --git a/iDearQRCode/Tools/Lib/ZYThirdPartService.m b/iDearQRCode/Tools/Lib/ZYThirdPartService.m index 3783396..ae192d6 100644 --- a/iDearQRCode/Tools/Lib/ZYThirdPartService.m +++ b/iDearQRCode/Tools/Lib/ZYThirdPartService.m @@ -9,6 +9,8 @@ #import "ZYThirdPartService.h" #import "IQKeyboardManager.h" #import "RTNetworking.h" +#import "UserModel.h" +#import "UserManager.h" @implementation ZYThirdPartService +(void)load{ @@ -21,19 +23,21 @@ +(void)load{ [[self class] ls_setKeyBord]; [[self class] ls_testReachableStaus]; + + [[self class] setUserData]; }); } #pragma mark - 初始化coredata + (void)initCoredata { - [RTNetworking updateBaseUrl:@"https://api.shunliandongli.com"]; - [RTNetworking enableInterfaceDebug:YES]; //default NO + [RTNetworking updateBaseUrl:@"http://image.degjsm.cn/EHome/services/api/mobileManager/doQueryActivity"]; + [RTNetworking enableInterfaceDebug:NO]; //default NO [RTNetworking configRequestType:kRTRequestTypeJSON responseType:RTResponseTypeData shouldAutoEncodeUrl:YES callbackOnCancelRequest:NO]; - + } #pragma mark - 键盘回收相关 @@ -52,4 +56,20 @@ + (void)ls_testReachableStaus { } + +#pragma mark - 保存用户信息 + ++ (void)setUserData{ + + UserModel * user = [[UserModel alloc] init]; + user.username = @"Mortimer"; + user.userId = @"007"; + user.avatar = @"https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=720891101,4253860064&fm=23&gp=0.jpg"; + user.nickname = @"没心没肺,没血没泪"; + user.password = @"mmddd"; + + [UserManager sharedInstance].userData = user; + [UserManager saveLocalUserLoginInfo]; +} + @end diff --git a/iDearQRCode/Tools/ZXingObjC/ZXMultiFormatReader.h b/iDearQRCode/Tools/ZXingObjC/ZXMultiFormatReader.h new file mode 100755 index 0000000..d5f47ce --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/ZXMultiFormatReader.h @@ -0,0 +1,41 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXReader.h" + +@class ZXDecodeHints; + +/** + * ZXMultiFormatReader is a convenience class and the main entry point into the library for most uses. + * By default it attempts to decode all barcode formats that the library supports. Optionally, you + * can provide a hints object to request different behavior, for example only decoding QR codes. + */ +@interface ZXMultiFormatReader : NSObject + +@property (nonatomic, strong) ZXDecodeHints *hints; + ++ (id)reader; + +/** + * Decode an image using the state set up by calling setHints() previously. Continuous scan + * clients will get a large speed increase by using this instead of decode(). + * + * @param image The pixel data to decode + * @return The contents of the image or nil if any errors occurred + */ +- (ZXResult *)decodeWithState:(ZXBinaryBitmap *)image error:(NSError **)error; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/ZXMultiFormatReader.m b/iDearQRCode/Tools/ZXingObjC/ZXMultiFormatReader.m new file mode 100755 index 0000000..c3961aa --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/ZXMultiFormatReader.m @@ -0,0 +1,164 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAztecReader.h" +#import "ZXBinaryBitmap.h" +#import "ZXDataMatrixReader.h" +#import "ZXDecodeHints.h" +#import "ZXErrors.h" +#import "ZXMaxiCodeReader.h" +#import "ZXMultiFormatOneDReader.h" +#import "ZXMultiFormatReader.h" +#import "ZXPDF417Reader.h" +#import "ZXQRCodeReader.h" +#import "ZXResult.h" + +@interface ZXMultiFormatReader () + +@property (nonatomic, strong, readonly) NSMutableArray *readers; + +@end + +@implementation ZXMultiFormatReader + +- (id)init { + if (self = [super init]) { + _readers = [NSMutableArray array]; + } + + return self; +} + ++ (id)reader { + return [[ZXMultiFormatReader alloc] init]; +} + +/** + * This version of decode honors the intent of Reader.decode(BinaryBitmap) in that it + * passes null as a hint to the decoders. However, that makes it inefficient to call repeatedly. + * Use setHints() followed by decodeWithState() for continuous scan applications. + * + * @param image The pixel data to decode + * @return The contents of the image or nil if any errors occurred + */ +- (ZXResult *)decode:(ZXBinaryBitmap *)image error:(NSError **)error { + self.hints = nil; + return [self decodeInternal:image error:error]; +} + +/** + * Decode an image using the hints provided. Does not honor existing state. + * + * @param image The pixel data to decode + * @param hints The hints to use, clearing the previous state. + * @return The contents of the image or nil if any errors occurred + */ +- (ZXResult *)decode:(ZXBinaryBitmap *)image hints:(ZXDecodeHints *)hints error:(NSError **)error { + self.hints = hints; + return [self decodeInternal:image error:error]; +} + +- (ZXResult *)decodeWithState:(ZXBinaryBitmap *)image error:(NSError **)error { + if (self.readers == nil) { + self.hints = nil; + } + return [self decodeInternal:image error:error]; +} + +/** + * This method adds state to the MultiFormatReader. By setting the hints once, subsequent calls + * to decodeWithState(image) can reuse the same set of readers without reallocating memory. This + * is important for performance in continuous scan clients. + * + * @param hints The set of hints to use for subsequent calls to decode(image) + */ +- (void)setHints:(ZXDecodeHints *)hints { + _hints = hints; + + BOOL tryHarder = hints != nil && hints.tryHarder; + [self.readers removeAllObjects]; + if (hints != nil) { + BOOL addZXOneDReader = [hints containsFormat:kBarcodeFormatUPCA] || + [hints containsFormat:kBarcodeFormatUPCE] || + [hints containsFormat:kBarcodeFormatEan13] || + [hints containsFormat:kBarcodeFormatEan8] || + [hints containsFormat:kBarcodeFormatCodabar] || + [hints containsFormat:kBarcodeFormatCode39] || + [hints containsFormat:kBarcodeFormatCode93] || + [hints containsFormat:kBarcodeFormatCode128] || + [hints containsFormat:kBarcodeFormatITF] || + [hints containsFormat:kBarcodeFormatRSS14] || + [hints containsFormat:kBarcodeFormatRSSExpanded]; + if (addZXOneDReader && !tryHarder) { + [self.readers addObject:[[ZXMultiFormatOneDReader alloc] initWithHints:hints]]; + } + if ([hints containsFormat:kBarcodeFormatQRCode]) { + [self.readers addObject:[[ZXQRCodeReader alloc] init]]; + } + if ([hints containsFormat:kBarcodeFormatDataMatrix]) { + [self.readers addObject:[[ZXDataMatrixReader alloc] init]]; + } + if ([hints containsFormat:kBarcodeFormatAztec]) { + [self.readers addObject:[[ZXAztecReader alloc] init]]; + } + if ([hints containsFormat:kBarcodeFormatPDF417]) { + [self.readers addObject:[[ZXPDF417Reader alloc] init]]; + } + if ([hints containsFormat:kBarcodeFormatMaxiCode]) { + [self.readers addObject:[[ZXMaxiCodeReader alloc] init]]; + } + if (addZXOneDReader && tryHarder) { + [self.readers addObject:[[ZXMultiFormatOneDReader alloc] initWithHints:hints]]; + } + } + if ([self.readers count] == 0) { + if (!tryHarder) { + [self.readers addObject:[[ZXMultiFormatOneDReader alloc] initWithHints:hints]]; + } + [self.readers addObject:[[ZXQRCodeReader alloc] init]]; + [self.readers addObject:[[ZXDataMatrixReader alloc] init]]; + [self.readers addObject:[[ZXAztecReader alloc] init]]; + [self.readers addObject:[[ZXPDF417Reader alloc] init]]; + [self.readers addObject:[[ZXMaxiCodeReader alloc] init]]; + if (tryHarder) { + [self.readers addObject:[[ZXMultiFormatOneDReader alloc] initWithHints:hints]]; + } + } +} + +- (void)reset { + if (self.readers != nil) { + for (id reader in self.readers) { + [reader reset]; + } + } +} + +- (ZXResult *)decodeInternal:(ZXBinaryBitmap *)image error:(NSError **)error { + if (self.readers != nil) { + for (id reader in self.readers) { + ZXResult *result = [reader decode:image hints:self.hints error:nil]; + if (result) { + return result; + } + } + } + + if (error) *error = ZXNotFoundErrorInstance(); + return nil; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/ZXMultiFormatWriter.h b/iDearQRCode/Tools/ZXingObjC/ZXMultiFormatWriter.h new file mode 100755 index 0000000..356d922 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/ZXMultiFormatWriter.h @@ -0,0 +1,27 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXWriter.h" + +/** + * This is a factory class which finds the appropriate Writer subclass for the BarcodeFormat + * requested and encodes the barcode with the supplied contents. + */ +@interface ZXMultiFormatWriter : NSObject + ++ (id)writer; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/ZXMultiFormatWriter.m b/iDearQRCode/Tools/ZXingObjC/ZXMultiFormatWriter.m new file mode 100755 index 0000000..6a9f056 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/ZXMultiFormatWriter.m @@ -0,0 +1,96 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAztecWriter.h" +#import "ZXBitMatrix.h" +#import "ZXCodaBarWriter.h" +#import "ZXCode39Writer.h" +#import "ZXCode128Writer.h" +#import "ZXDataMatrixWriter.h" +#import "ZXEAN8Writer.h" +#import "ZXEAN13Writer.h" +#import "ZXErrors.h" +#import "ZXITFWriter.h" +#import "ZXMultiFormatWriter.h" +#import "ZXPDF417Writer.h" +#import "ZXQRCodeWriter.h" +#import "ZXUPCAWriter.h" + +@implementation ZXMultiFormatWriter + ++ (id)writer { + return [[ZXMultiFormatWriter alloc] init]; +} + +- (ZXBitMatrix *)encode:(NSString *)contents format:(ZXBarcodeFormat)format width:(int)width height:(int)height error:(NSError **)error { + return [self encode:contents format:format width:width height:height hints:nil error:error]; +} + +- (ZXBitMatrix *)encode:(NSString *)contents format:(ZXBarcodeFormat)format width:(int)width height:(int)height hints:(ZXEncodeHints *)hints error:(NSError **)error { + id writer; + switch (format) { + case kBarcodeFormatEan8: + writer = [[ZXEAN8Writer alloc] init]; + break; + + case kBarcodeFormatEan13: + writer = [[ZXEAN13Writer alloc] init]; + break; + + case kBarcodeFormatUPCA: + writer = [[ZXUPCAWriter alloc] init]; + break; + + case kBarcodeFormatQRCode: + writer = [[ZXQRCodeWriter alloc] init]; + break; + + case kBarcodeFormatCode39: + writer = [[ZXCode39Writer alloc] init]; + break; + + case kBarcodeFormatCode128: + writer = [[ZXCode128Writer alloc] init]; + break; + + case kBarcodeFormatITF: + writer = [[ZXITFWriter alloc] init]; + break; + + case kBarcodeFormatPDF417: + writer = [[ZXPDF417Writer alloc] init]; + break; + + case kBarcodeFormatCodabar: + writer = [[ZXCodaBarWriter alloc] init]; + break; + + case kBarcodeFormatDataMatrix: + writer = [[ZXDataMatrixWriter alloc] init]; + break; + + case kBarcodeFormatAztec: + writer = [[ZXAztecWriter alloc] init]; + break; + + default: + if (error) *error = [NSError errorWithDomain:ZXErrorDomain code:ZXWriterError userInfo:@{NSLocalizedDescriptionKey: @"No encoder available for format"}]; + return nil; + } + return [writer encode:contents format:format width:width height:height hints:hints error:error]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/ZXingObjC.h b/iDearQRCode/Tools/ZXingObjC/ZXingObjC.h new file mode 100755 index 0000000..92c5699 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/ZXingObjC.h @@ -0,0 +1,34 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#ifndef _ZXINGOBJC_ + +#define _ZXINGOBJC_ + +#import "ZXingObjCAztec.h" +#import "ZXingObjCCore.h" +#import "ZXingObjCDataMatrix.h" +#import "ZXingObjCMaxiCode.h" +#import "ZXingObjCOneD.h" +#import "ZXingObjCQRCode.h" +#import "ZXingObjCPDF417.h" + +#import "ZXMultiFormatReader.h" +#import "ZXMultiFormatWriter.h" + +#endif diff --git a/iDearQRCode/Tools/ZXingObjC/aztec/ZXAztecDetectorResult.h b/iDearQRCode/Tools/ZXingObjC/aztec/ZXAztecDetectorResult.h new file mode 100755 index 0000000..d938c94 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/aztec/ZXAztecDetectorResult.h @@ -0,0 +1,32 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitMatrix.h" +#import "ZXDetectorResult.h" + +@interface ZXAztecDetectorResult : ZXDetectorResult + +@property (nonatomic, assign, readonly, getter = isCompact) BOOL compact; +@property (nonatomic, assign, readonly) int nbDatablocks; +@property (nonatomic, assign, readonly) int nbLayers; + +- (id)initWithBits:(ZXBitMatrix *)bits + points:(NSArray *)points + compact:(BOOL)compact + nbDatablocks:(int)nbDatablocks + nbLayers:(int)nbLayers; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/aztec/ZXAztecDetectorResult.m b/iDearQRCode/Tools/ZXingObjC/aztec/ZXAztecDetectorResult.m new file mode 100755 index 0000000..9dd270e --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/aztec/ZXAztecDetectorResult.m @@ -0,0 +1,35 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAztecDetectorResult.h" + +@implementation ZXAztecDetectorResult + +- (id)initWithBits:(ZXBitMatrix *)bits + points:(NSArray *)points + compact:(BOOL)compact + nbDatablocks:(int)nbDatablocks + nbLayers:(int)nbLayers { + if (self = [super initWithBits:bits points:points]) { + _compact = compact; + _nbDatablocks = nbDatablocks; + _nbLayers = nbLayers; + } + + return self; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/aztec/ZXAztecReader.h b/iDearQRCode/Tools/ZXingObjC/aztec/ZXAztecReader.h new file mode 100755 index 0000000..55a95d2 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/aztec/ZXAztecReader.h @@ -0,0 +1,26 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXReader.h" + +@class ZXBinaryBitmap, ZXDecodeHints, ZXResult; + +/** + * This implementation can detect and decode Aztec codes in an image. + */ +@interface ZXAztecReader : NSObject + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/aztec/ZXAztecReader.m b/iDearQRCode/Tools/ZXingObjC/aztec/ZXAztecReader.m new file mode 100755 index 0000000..adf8fd2 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/aztec/ZXAztecReader.m @@ -0,0 +1,89 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAztecDecoder.h" +#import "ZXAztecDetector.h" +#import "ZXAztecDetectorResult.h" +#import "ZXAztecReader.h" +#import "ZXBinaryBitmap.h" +#import "ZXDecodeHints.h" +#import "ZXDecoderResult.h" +#import "ZXReader.h" +#import "ZXResult.h" +#import "ZXResultPointCallback.h" + +@implementation ZXAztecReader + +- (ZXResult *)decode:(ZXBinaryBitmap *)image error:(NSError **)error { + return [self decode:image hints:nil error:error]; +} + +- (ZXResult *)decode:(ZXBinaryBitmap *)image hints:(ZXDecodeHints *)hints error:(NSError **)error { + ZXBitMatrix *matrix = [image blackMatrixWithError:error]; + if (!matrix) { + return nil; + } + + ZXAztecDetector *detector = [[ZXAztecDetector alloc] initWithImage:matrix]; + NSArray *points = nil; + ZXDecoderResult *decoderResult = nil; + + ZXAztecDetectorResult *detectorResult = [detector detectWithMirror:NO error:error]; + if (detectorResult) { + points = detectorResult.points; + decoderResult = [[[ZXAztecDecoder alloc] init] decode:detectorResult error:error]; + } + + if (decoderResult == nil) { + detectorResult = [detector detectWithMirror:YES error:nil]; + points = detectorResult.points; + if (detectorResult) { + decoderResult = [[[ZXAztecDecoder alloc] init] decode:detectorResult error:nil]; + } + } + + if (!decoderResult) { + return nil; + } + + if (hints != nil) { + id rpcb = hints.resultPointCallback; + if (rpcb != nil) { + for (ZXResultPoint *p in points) { + [rpcb foundPossibleResultPoint:p]; + } + } + } + + ZXResult *result = [ZXResult resultWithText:decoderResult.text rawBytes:decoderResult.rawBytes resultPoints:points format:kBarcodeFormatAztec]; + + NSMutableArray *byteSegments = decoderResult.byteSegments; + if (byteSegments != nil) { + [result putMetadata:kResultMetadataTypeByteSegments value:byteSegments]; + } + NSString *ecLevel = decoderResult.ecLevel; + if (ecLevel != nil) { + [result putMetadata:kResultMetadataTypeErrorCorrectionLevel value:ecLevel]; + } + + return result; +} + +- (void)reset { + // do nothing +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/aztec/ZXAztecWriter.h b/iDearQRCode/Tools/ZXingObjC/aztec/ZXAztecWriter.h new file mode 100755 index 0000000..cd032e2 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/aztec/ZXAztecWriter.h @@ -0,0 +1,21 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXWriter.h" + +@interface ZXAztecWriter : NSObject + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/aztec/ZXAztecWriter.m b/iDearQRCode/Tools/ZXingObjC/aztec/ZXAztecWriter.m new file mode 100755 index 0000000..f2d7327 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/aztec/ZXAztecWriter.m @@ -0,0 +1,89 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAztecCode.h" +#import "ZXAztecEncoder.h" +#import "ZXAztecWriter.h" +#import "ZXBitMatrix.h" +#import "ZXByteArray.h" +#import "ZXEncodeHints.h" + +const NSStringEncoding ZX_AZTEC_DEFAULT_ENCODING = NSISOLatin1StringEncoding; + +@implementation ZXAztecWriter + +- (ZXBitMatrix *)encode:(NSString *)contents format:(ZXBarcodeFormat)format width:(int)width height:(int)height error:(NSError **)error { + return [self encode:contents format:format width:width height:height hints:nil error:error]; +} + +- (ZXBitMatrix *)encode:(NSString *)contents format:(ZXBarcodeFormat)format width:(int)width height:(int)height hints:(ZXEncodeHints *)hints error:(NSError **)error { + NSStringEncoding encoding = hints.encoding; + NSNumber *eccPercent = hints.errorCorrectionPercent; + NSNumber *layers = hints.aztecLayers; + + return [self encode:contents + format:format + width:width + height:height + encoding:encoding == 0 ? ZX_AZTEC_DEFAULT_ENCODING : encoding + eccPercent:eccPercent == nil ? ZX_AZTEC_DEFAULT_EC_PERCENT : [eccPercent intValue] + layers:layers == nil ? ZX_AZTEC_DEFAULT_LAYERS : [layers intValue]]; +} + +- (ZXBitMatrix *)encode:(NSString *)contents format:(ZXBarcodeFormat)format width:(int)width + height:(int)height encoding:(NSStringEncoding)encoding eccPercent:(int)eccPercent layers:(int)layers { + if (format != kBarcodeFormatAztec) { + @throw [NSException exceptionWithName:NSInvalidArgumentException + reason:[NSString stringWithFormat:@"Can only encode kBarcodeFormatAztec (%d), but got %d", kBarcodeFormatAztec, format] + userInfo:nil]; + } + + NSData *data = [contents dataUsingEncoding:encoding]; + ZXByteArray *bytes = [[ZXByteArray alloc] initWithLength:(unsigned int)[data length]]; + memcpy(bytes.array, [data bytes], bytes.length * sizeof(int8_t)); + ZXAztecCode *aztec = [ZXAztecEncoder encode:bytes minECCPercent:eccPercent userSpecifiedLayers:layers]; + return [self renderResult:aztec width:width height:height]; +} + +- (ZXBitMatrix *)renderResult:(ZXAztecCode *)aztec width:(int)width height:(int)height { + ZXBitMatrix *input = aztec.matrix; + if (!input) { + return nil; + } + + int inputWidth = input.width; + int inputHeight = input.height; + int outputWidth = MAX(width, inputWidth); + int outputHeight = MAX(height, inputHeight); + + int multiple = MIN(outputWidth / inputWidth, outputHeight / inputHeight); + int leftPadding = (outputWidth - (inputWidth * multiple)) / 2; + int topPadding = (outputHeight - (inputHeight * multiple)) / 2; + + ZXBitMatrix *output = [[ZXBitMatrix alloc] initWithWidth:outputWidth height:outputHeight]; + + for (int inputY = 0, outputY = topPadding; inputY < inputHeight; inputY++, outputY += multiple) { + // Write the contents of this row of the barcode + for (int inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX += multiple) { + if ([input getX:inputX y:inputY]) { + [output setRegionAtLeft:outputX top:outputY width:multiple height:multiple]; + } + } + } + return output; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/aztec/ZXingObjCAztec.h b/iDearQRCode/Tools/ZXingObjC/aztec/ZXingObjCAztec.h new file mode 100755 index 0000000..14edb28 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/aztec/ZXingObjCAztec.h @@ -0,0 +1,32 @@ +/* + * Copyright 2014 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXingObjCCore.h" + +#ifndef _ZXINGOBJC_AZTEC_ + +#define _ZXINGOBJC_AZTEC_ + +#import "ZXAztecCode.h" +#import "ZXAztecDecoder.h" +#import "ZXAztecDetector.h" +#import "ZXAztecDetectorResult.h" +#import "ZXAztecEncoder.h" +#import "ZXAztecHighLevelEncoder.h" +#import "ZXAztecReader.h" +#import "ZXAztecWriter.h" + +#endif diff --git a/iDearQRCode/Tools/ZXingObjC/aztec/decoder/ZXAztecDecoder.h b/iDearQRCode/Tools/ZXingObjC/aztec/decoder/ZXAztecDecoder.h new file mode 100755 index 0000000..491f1c9 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/aztec/decoder/ZXAztecDecoder.h @@ -0,0 +1,30 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXAztecDetectorResult, ZXBoolArray, ZXDecoderResult; + +/** + * The main class which implements Aztec Code decoding -- as opposed to locating and extracting + * the Aztec Code from an image. + */ +@interface ZXAztecDecoder : NSObject + +- (ZXDecoderResult *)decode:(ZXAztecDetectorResult *)detectorResult error:(NSError **)error; + +// This method is used for testing the high-level encoder ++ (NSString *)highLevelDecode:(ZXBoolArray *)correctedBits; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/aztec/decoder/ZXAztecDecoder.m b/iDearQRCode/Tools/ZXingObjC/aztec/decoder/ZXAztecDecoder.m new file mode 100755 index 0000000..f38a6a6 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/aztec/decoder/ZXAztecDecoder.m @@ -0,0 +1,351 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAztecDecoder.h" +#import "ZXAztecDetectorResult.h" +#import "ZXBitMatrix.h" +#import "ZXBoolArray.h" +#import "ZXDecoderResult.h" +#import "ZXErrors.h" +#import "ZXGenericGF.h" +#import "ZXIntArray.h" +#import "ZXReedSolomonDecoder.h" + +typedef enum { + ZXAztecTableUpper = 0, + ZXAztecTableLower, + ZXAztecTableMixed, + ZXAztecTableDigit, + ZXAztecTablePunct, + ZXAztecTableBinary +} ZXAztecTable; + +static NSString *ZX_AZTEC_UPPER_TABLE[] = { + @"CTRL_PS", @" ", @"A", @"B", @"C", @"D", @"E", @"F", @"G", @"H", @"I", @"J", @"K", @"L", @"M", @"N", @"O", @"P", + @"Q", @"R", @"S", @"T", @"U", @"V", @"W", @"X", @"Y", @"Z", @"CTRL_LL", @"CTRL_ML", @"CTRL_DL", @"CTRL_BS" +}; + +static NSString *ZX_AZTEC_LOWER_TABLE[] = { + @"CTRL_PS", @" ", @"a", @"b", @"c", @"d", @"e", @"f", @"g", @"h", @"i", @"j", @"k", @"l", @"m", @"n", @"o", @"p", + @"q", @"r", @"s", @"t", @"u", @"v", @"w", @"x", @"y", @"z", @"CTRL_US", @"CTRL_ML", @"CTRL_DL", @"CTRL_BS" +}; + +static NSString *ZX_AZTEC_MIXED_TABLE[] = { + @"CTRL_PS", @" ", @"\1", @"\2", @"\3", @"\4", @"\5", @"\6", @"\7", @"\b", @"\t", @"\n", + @"\13", @"\f", @"\r", @"\33", @"\34", @"\35", @"\36", @"\37", @"@", @"\\", @"^", @"_", + @"`", @"|", @"~", @"\177", @"CTRL_LL", @"CTRL_UL", @"CTRL_PL", @"CTRL_BS" +}; + +static NSString *ZX_AZTEC_PUNCT_TABLE[] = { + @"", @"\r", @"\r\n", @". ", @", ", @": ", @"!", @"\"", @"#", @"$", @"%", @"&", @"'", @"(", @")", + @"*", @"+", @",", @"-", @".", @"/", @":", @";", @"<", @"=", @">", @"?", @"[", @"]", @"{", @"}", @"CTRL_UL" +}; + +static NSString *ZX_AZTEC_DIGIT_TABLE[] = { + @"CTRL_PS", @" ", @"0", @"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9", @",", @".", @"CTRL_UL", @"CTRL_US" +}; + +@interface ZXAztecDecoder () + +@property (nonatomic, strong) ZXAztecDetectorResult *ddata; + +@end + +@implementation ZXAztecDecoder + +- (ZXDecoderResult *)decode:(ZXAztecDetectorResult *)detectorResult error:(NSError **)error { + self.ddata = detectorResult; + ZXBitMatrix *matrix = [detectorResult bits]; + ZXBoolArray *rawbits = [self extractBits:matrix]; + if (!rawbits) { + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + + ZXBoolArray *correctedBits = [self correctBits:rawbits error:error]; + if (!correctedBits) { + return nil; + } + + NSString *result = [[self class] encodedData:correctedBits]; + return [[ZXDecoderResult alloc] initWithRawBytes:nil text:result byteSegments:nil ecLevel:nil]; +} + ++ (NSString *)highLevelDecode:(ZXBoolArray *)correctedBits { + return [self encodedData:correctedBits]; +} + +/** + * Gets the string encoded in the aztec code bits + * + * @return the decoded string + */ ++ (NSString *)encodedData:(ZXBoolArray *)correctedBits { + int endIndex = (int)correctedBits.length; + ZXAztecTable latchTable = ZXAztecTableUpper; // table most recently latched to + ZXAztecTable shiftTable = ZXAztecTableUpper; // table to use for the next read + NSMutableString *result = [NSMutableString stringWithCapacity:20]; + int index = 0; + while (index < endIndex) { + if (shiftTable == ZXAztecTableBinary) { + if (endIndex - index < 5) { + break; + } + int length = [self readCode:correctedBits startIndex:index length:5]; + index += 5; + if (length == 0) { + if (endIndex - index < 11) { + break; + } + + length = [self readCode:correctedBits startIndex:index length:11] + 31; + index += 11; + } + for (int charCount = 0; charCount < length; charCount++) { + if (endIndex - index < 8) { + index = endIndex; // Force outer loop to exit + break; + } + + int code = [self readCode:correctedBits startIndex:index length:8]; + [result appendFormat:@"%C", (unichar)code]; + index += 8; + } + // Go back to whatever mode we had been in + shiftTable = latchTable; + } else { + int size = shiftTable == ZXAztecTableDigit ? 4 : 5; + if (endIndex - index < size) { + break; + } + int code = [self readCode:correctedBits startIndex:index length:size]; + index += size; + NSString *str = [self character:shiftTable code:code]; + if ([str hasPrefix:@"CTRL_"]) { + // Table changes + shiftTable = [self table:[str characterAtIndex:5]]; + if ([str characterAtIndex:6] == 'L') { + latchTable = shiftTable; + } + } else { + [result appendString:str]; + // Go back to whatever mode we had been in + shiftTable = latchTable; + } + } + } + return [NSString stringWithString:result]; +} + +/** + * gets the table corresponding to the char passed + */ ++ (ZXAztecTable)table:(unichar)t { + switch (t) { + case 'L': + return ZXAztecTableLower; + case 'P': + return ZXAztecTablePunct; + case 'M': + return ZXAztecTableMixed; + case 'D': + return ZXAztecTableDigit; + case 'B': + return ZXAztecTableBinary; + case 'U': + default: + return ZXAztecTableUpper; + } +} + +/** + * Gets the character (or string) corresponding to the passed code in the given table + * + * @param table the table used + * @param code the code of the character + */ ++ (NSString *)character:(ZXAztecTable)table code:(int)code { + switch (table) { + case ZXAztecTableUpper: + return ZX_AZTEC_UPPER_TABLE[code]; + case ZXAztecTableLower: + return ZX_AZTEC_LOWER_TABLE[code]; + case ZXAztecTableMixed: + return ZX_AZTEC_MIXED_TABLE[code]; + case ZXAztecTablePunct: + return ZX_AZTEC_PUNCT_TABLE[code]; + case ZXAztecTableDigit: + return ZX_AZTEC_DIGIT_TABLE[code]; + default: + // Should not reach here. + @throw [NSException exceptionWithName:@"IllegalStateException" reason:@"Bad table" userInfo:nil]; + } +} + +/** + *

Performs RS error correction on an array of bits.

+ * + * @return the number of corrected bits, or 0 if the input contains too many errors + */ +- (ZXBoolArray *)correctBits:(ZXBoolArray *)rawbits error:(NSError **)error { + ZXGenericGF *gf; + int codewordSize; + + if ([self.ddata nbLayers] <= 2) { + codewordSize = 6; + gf = [ZXGenericGF AztecData6]; + } else if ([self.ddata nbLayers] <= 8) { + codewordSize = 8; + gf = [ZXGenericGF AztecData8]; + } else if ([self.ddata nbLayers] <= 22) { + codewordSize = 10; + gf = [ZXGenericGF AztecData10]; + } else { + codewordSize = 12; + gf = [ZXGenericGF AztecData12]; + } + + int numDataCodewords = [self.ddata nbDatablocks]; + int numCodewords = rawbits.length / codewordSize; + if (numCodewords < numDataCodewords) { + if (error) *error = ZXFormatErrorInstance(); + return 0; + } + int offset = rawbits.length % codewordSize; + int numECCodewords = numCodewords - numDataCodewords; + + ZXIntArray *dataWords = [[ZXIntArray alloc] initWithLength:numCodewords]; + for (int i = 0; i < numCodewords; i++, offset += codewordSize) { + dataWords.array[i] = [[self class] readCode:rawbits startIndex:offset length:codewordSize]; + } + + ZXReedSolomonDecoder *rsDecoder = [[ZXReedSolomonDecoder alloc] initWithField:gf]; + NSError *decodeError = nil; + if (![rsDecoder decode:dataWords twoS:numECCodewords error:&decodeError]) { + if (decodeError.code == ZXReedSolomonError) { + if (error) *error = ZXFormatErrorInstance(); + } else { + if (error) *error = decodeError; + } + return 0; + } + + // Now perform the unstuffing operation. + // First, count how many bits are going to be thrown out as stuffing + int mask = (1 << codewordSize) - 1; + int stuffedBits = 0; + for (int i = 0; i < numDataCodewords; i++) { + int32_t dataWord = dataWords.array[i]; + if (dataWord == 0 || dataWord == mask) { + if (error) *error = ZXFormatErrorInstance(); + return 0; + } else if (dataWord == 1 || dataWord == mask - 1) { + stuffedBits++; + } + } + + // Now, actually unpack the bits and remove the stuffing + ZXBoolArray *correctedBits = [[ZXBoolArray alloc] initWithLength:numDataCodewords * codewordSize - stuffedBits]; + int index = 0; + for (int i = 0; i < numDataCodewords; i++) { + int dataWord = dataWords.array[i]; + if (dataWord == 1 || dataWord == mask - 1) { + // next codewordSize-1 bits are all zeros or all ones + memset(correctedBits.array + index * sizeof(BOOL), dataWord > 1, codewordSize - 1); + index += codewordSize - 1; + } else { + for (int bit = codewordSize - 1; bit >= 0; --bit) { + correctedBits.array[index++] = (dataWord & (1 << bit)) != 0; + } + } + } + return correctedBits; +} + +/** + * Gets the array of bits from an Aztec Code matrix + * + * @return the size of the array of bits + */ +- (ZXBoolArray *)extractBits:(ZXBitMatrix *)matrix { + BOOL compact = self.ddata.isCompact; + int layers = self.ddata.nbLayers; + int baseMatrixSize = compact ? 11 + layers * 4 : 14 + layers * 4; // not including alignment lines + ZXIntArray *alignmentMap = [[ZXIntArray alloc] initWithLength:baseMatrixSize]; + ZXBoolArray *rawbits = [[ZXBoolArray alloc] initWithLength:[self totalBitsInLayer:layers compact:compact]]; + + if (compact) { + for (int i = 0; i < alignmentMap.length; i++) { + alignmentMap.array[i] = i; + } + } else { + int matrixSize = baseMatrixSize + 1 + 2 * ((baseMatrixSize / 2 - 1) / 15); + int origCenter = baseMatrixSize / 2; + int center = matrixSize / 2; + for (int i = 0; i < origCenter; i++) { + int newOffset = i + i / 15; + alignmentMap.array[origCenter - i - 1] = (int32_t)(center - newOffset - 1); + alignmentMap.array[origCenter + i] = (int32_t)(center + newOffset + 1); + } + } + for (int i = 0, rowOffset = 0; i < layers; i++) { + int rowSize = compact ? (layers - i) * 4 + 9 : (layers - i) * 4 + 12; + // The top-left most point of this layer is (not including alignment lines) + int low = i * 2; + // The bottom-right most point of this layer is (not including alignment lines) + int high = baseMatrixSize - 1 - low; + // We pull bits from the two 2 x rowSize columns and two rowSize x 2 rows + for (int j = 0; j < rowSize; j++) { + int columnOffset = j * 2; + for (int k = 0; k < 2; k++) { + // left column + rawbits.array[rowOffset + columnOffset + k] = + [matrix getX:alignmentMap.array[low + k] y:alignmentMap.array[low + j]]; + // bottom row + rawbits.array[rowOffset + 2 * rowSize + columnOffset + k] = + [matrix getX:alignmentMap.array[low + j] y:alignmentMap.array[high - k]]; + // right column + rawbits.array[rowOffset + 4 * rowSize + columnOffset + k] = + [matrix getX:alignmentMap.array[high - k] y:alignmentMap.array[high - j]]; + // top row + rawbits.array[rowOffset + 6 * rowSize + columnOffset + k] = + [matrix getX:alignmentMap.array[high - j] y:alignmentMap.array[low + k]]; + } + } + rowOffset += rowSize * 8; + } + return rawbits; +} + +/** + * Reads a code of given length and at given index in an array of bits + */ ++ (int)readCode:(ZXBoolArray *)rawbits startIndex:(int)startIndex length:(int)length { + int res = 0; + for (int i = startIndex; i < startIndex + length; i++) { + res <<= 1; + if (rawbits.array[i]) { + res |= 0x01; + } + } + return res; +} + +- (int)totalBitsInLayer:(int)layers compact:(BOOL)compact { + return ((compact ? 88 : 112) + 16 * layers) * layers; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/aztec/detector/ZXAztecDetector.h b/iDearQRCode/Tools/ZXingObjC/aztec/detector/ZXAztecDetector.h new file mode 100755 index 0000000..31aad24 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/aztec/detector/ZXAztecDetector.h @@ -0,0 +1,45 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@interface ZXAztecPoint : NSObject + +@property (nonatomic, assign, readonly) int x; +@property (nonatomic, assign, readonly) int y; + +- (id)initWithX:(int)x y:(int)y; + +@end + +@class ZXAztecDetectorResult, ZXBitMatrix; + +/** + * Encapsulates logic that can detect an Aztec Code in an image, even if the Aztec Code + * is rotated or skewed, or partially obscured. + */ +@interface ZXAztecDetector : NSObject + +- (id)initWithImage:(ZXBitMatrix *)image; + +- (ZXAztecDetectorResult *)detectWithError:(NSError **)error; + +/** + * Detects an Aztec Code in an image. + * + * @return ZXAztecDetectorResult encapsulating results of detecting an Aztec Code, or nil if no Aztec Code can be found + */ +- (ZXAztecDetectorResult *)detectWithMirror:(BOOL)isMirror error:(NSError **)error; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/aztec/detector/ZXAztecDetector.m b/iDearQRCode/Tools/ZXingObjC/aztec/detector/ZXAztecDetector.m new file mode 100755 index 0000000..30c13fd --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/aztec/detector/ZXAztecDetector.m @@ -0,0 +1,619 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAztecDetector.h" +#import "ZXAztecDetectorResult.h" +#import "ZXErrors.h" +#import "ZXGenericGF.h" +#import "ZXGridSampler.h" +#import "ZXIntArray.h" +#import "ZXMathUtils.h" +#import "ZXReedSolomonDecoder.h" +#import "ZXResultPoint.h" +#import "ZXWhiteRectangleDetector.h" + +@implementation ZXAztecPoint + +- (id)initWithX:(int)x y:(int)y { + if (self = [super init]) { + _x = x; + _y = y; + } + return self; +} + +- (ZXResultPoint *)toResultPoint { + return [[ZXResultPoint alloc] initWithX:self.x y:self.y]; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"<%d %d>", self.x, self.y]; +} + +@end + +@interface ZXAztecDetector () + +@property (nonatomic, assign, getter = isCompact) BOOL compact; +@property (nonatomic, strong) ZXBitMatrix *image; +@property (nonatomic, assign) int nbCenterLayers; +@property (nonatomic, assign) int nbDataBlocks; +@property (nonatomic, assign) int nbLayers; +@property (nonatomic, assign) int shift; + +@end + +@implementation ZXAztecDetector + +- (id)initWithImage:(ZXBitMatrix *)image { + if (self = [super init]) { + _image = image; + } + return self; +} + +- (ZXAztecDetectorResult *)detectWithError:(NSError **)error { + return [self detectWithMirror:NO error:error]; +} + +- (ZXAztecDetectorResult *)detectWithMirror:(BOOL)isMirror error:(NSError **)error { + // 1. Get the center of the aztec matrix + ZXAztecPoint *pCenter = [self matrixCenter]; + if (!pCenter) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + + // 2. Get the center points of the four diagonal points just outside the bull's eye + // [topRight, bottomRight, bottomLeft, topLeft] + NSMutableArray *bullsEyeCorners = [self bullsEyeCorners:pCenter]; + if (!bullsEyeCorners) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + + if (isMirror) { + ZXResultPoint *temp = bullsEyeCorners[0]; + bullsEyeCorners[0] = bullsEyeCorners[2]; + bullsEyeCorners[2] = temp; + } + + // 3. Get the size of the matrix and other parameters from the bull's eye + if (![self extractParameters:bullsEyeCorners]) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + + // 4. Sample the grid + ZXBitMatrix *bits = [self sampleGrid:self.image + topLeft:bullsEyeCorners[self.shift % 4] + topRight:bullsEyeCorners[(self.shift + 1) % 4] + bottomRight:bullsEyeCorners[(self.shift + 2) % 4] + bottomLeft:bullsEyeCorners[(self.shift + 3) % 4]]; + if (!bits) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + + // 5. Get the corners of the matrix. + NSArray *corners = [self matrixCornerPoints:bullsEyeCorners]; + if (!corners) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + + return [[ZXAztecDetectorResult alloc] initWithBits:bits + points:corners + compact:self.compact + nbDatablocks:self.nbDataBlocks + nbLayers:self.nbLayers]; +} + + +/** + * Extracts the number of data layers and data blocks from the layer around the bull's eye + */ +- (BOOL)extractParameters:(NSArray *)bullsEyeCorners { + ZXResultPoint *p0 = bullsEyeCorners[0]; + ZXResultPoint *p1 = bullsEyeCorners[1]; + ZXResultPoint *p2 = bullsEyeCorners[2]; + ZXResultPoint *p3 = bullsEyeCorners[3]; + + if (![self isValid:p0] || ![self isValid:p1] || + ![self isValid:p2] || ![self isValid:p3]) { + return NO; + } + int length = 2 * self.nbCenterLayers; + // Get the bits around the bull's eye + int sides[] = { + [self sampleLine:p0 p2:p1 size:length], // Right side + [self sampleLine:p1 p2:p2 size:length], // Bottom + [self sampleLine:p2 p2:p3 size:length], // Left side + [self sampleLine:p3 p2:p0 size:length] // Top + }; + + // bullsEyeCorners[shift] is the corner of the bulls'eye that has three + // orientation marks. + // sides[shift] is the row/column that goes from the corner with three + // orientation marks to the corner with two. + int shift = [self rotationForSides:sides length:length]; + if (shift == -1) { + return NO; + } + self.shift = shift; + + // Flatten the parameter bits into a single 28- or 40-bit long + long parameterData = 0; + for (int i = 0; i < 4; i++) { + int side = sides[(self.shift + i) % 4]; + if (self.isCompact) { + // Each side of the form ..XXXXXXX. where Xs are parameter data + parameterData <<= 7; + parameterData += (side >> 1) & 0x7F; + } else { + // Each side of the form ..XXXXX.XXXXX. where Xs are parameter data + parameterData <<= 10; + parameterData += ((side >> 2) & (0x1f << 5)) + ((side >> 1) & 0x1F); + } + } + + // Corrects parameter data using RS. Returns just the data portion + // without the error correction. + int correctedData = [self correctedParameterData:parameterData compact:self.isCompact]; + if (correctedData == -1) { + return NO; + } + + if (self.isCompact) { + // 8 bits: 2 bits layers and 6 bits data blocks + self.nbLayers = (correctedData >> 6) + 1; + self.nbDataBlocks = (correctedData & 0x3F) + 1; + } else { + // 16 bits: 5 bits layers and 11 bits data blocks + self.nbLayers = (correctedData >> 11) + 1; + self.nbDataBlocks = (correctedData & 0x7FF) + 1; + } + + return YES; +} + +int expectedCornerBits[] = { + 0xee0, // 07340 XXX .XX X.. ... + 0x1dc, // 00734 ... XXX .XX X.. + 0x83b, // 04073 X.. ... XXX .XX + 0x707, // 03407 .XX X.. ... XXX +}; + +int bitCount(uint32_t i) { + i = i - ((i >> 1) & 0x55555555); + i = (i & 0x33333333) + ((i >> 2) & 0x33333333); + return (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24; +} + +- (int)rotationForSides:(const int[])sides length:(int)length { + // In a normal pattern, we expect to See + // ** .* D A + // * * + // + // . * + // .. .. C B + // + // Grab the 3 bits from each of the sides the form the locator pattern and concatenate + // into a 12-bit integer. Start with the bit at A + int cornerBits = 0; + for (int i = 0; i < 4; i++) { + int side = sides[i]; + // XX......X where X's are orientation marks + int t = ((side >> (length - 2)) << 1) + (side & 1); + cornerBits = (cornerBits << 3) + t; + } + // Mov the bottom bit to the top, so that the three bits of the locator pattern at A are + // together. cornerBits is now: + // 3 orientation bits at A || 3 orientation bits at B || ... || 3 orientation bits at D + cornerBits = ((cornerBits & 1) << 11) + (cornerBits >> 1); + // The result shift indicates which element of BullsEyeCorners[] goes into the top-left + // corner. Since the four rotation values have a Hamming distance of 8, we + // can easily tolerate two errors. + for (int shift = 0; shift < 4; shift++) { + if (bitCount(cornerBits ^ expectedCornerBits[shift]) <= 2) { + return shift; + } + } + return -1; +} + +/** + * Corrects the parameter bits using Reed-Solomon algorithm. + * + * @param parameterData parameter bits + * @param compact true if this is a compact Aztec code + * @return -1 if the array contains too many errors + */ +- (int)correctedParameterData:(long)parameterData compact:(BOOL)compact { + int numCodewords; + int numDataCodewords; + + if (compact) { + numCodewords = 7; + numDataCodewords = 2; + } else { + numCodewords = 10; + numDataCodewords = 4; + } + + int numECCodewords = numCodewords - numDataCodewords; + ZXIntArray *parameterWords = [[ZXIntArray alloc] initWithLength:numCodewords]; + for (int i = numCodewords - 1; i >= 0; --i) { + parameterWords.array[i] = (int32_t) parameterData & 0xF; + parameterData >>= 4; + } + + ZXReedSolomonDecoder *rsDecoder = [[ZXReedSolomonDecoder alloc] initWithField:[ZXGenericGF AztecParam]]; + if (![rsDecoder decode:parameterWords twoS:numECCodewords error:nil]) { + return NO; + } + // Toss the error correction. Just return the data as an integer + int result = 0; + for (int i = 0; i < numDataCodewords; i++) { + result = (result << 4) + parameterWords.array[i]; + } + return result; +} + +/** + * Finds the corners of a bull-eye centered on the passed point. + * This returns the centers of the diagonal points just outside the bull's eye + * Returns [topRight, bottomRight, bottomLeft, topLeft] + * + * @param pCenter Center point + * @return The corners of the bull-eye, or nil if no valid bull-eye can be found + */ +- (NSMutableArray *)bullsEyeCorners:(ZXAztecPoint *)pCenter { + ZXAztecPoint *pina = pCenter; + ZXAztecPoint *pinb = pCenter; + ZXAztecPoint *pinc = pCenter; + ZXAztecPoint *pind = pCenter; + + BOOL color = YES; + + for (self.nbCenterLayers = 1; self.nbCenterLayers < 9; self.nbCenterLayers++) { + ZXAztecPoint *pouta = [self firstDifferent:pina color:color dx:1 dy:-1]; + ZXAztecPoint *poutb = [self firstDifferent:pinb color:color dx:1 dy:1]; + ZXAztecPoint *poutc = [self firstDifferent:pinc color:color dx:-1 dy:1]; + ZXAztecPoint *poutd = [self firstDifferent:pind color:color dx:-1 dy:-1]; + + //d a + // + //c b + + if (self.nbCenterLayers > 2) { + float q = [self distance:poutd b:pouta] * self.nbCenterLayers / ([self distance:pind b:pina] * (self.nbCenterLayers + 2)); + if (q < 0.75 || q > 1.25 || ![self isWhiteOrBlackRectangle:pouta p2:poutb p3:poutc p4:poutd]) { + break; + } + } + + pina = pouta; + pinb = poutb; + pinc = poutc; + pind = poutd; + + color = !color; + } + + if (self.nbCenterLayers != 5 && self.nbCenterLayers != 7) { + return nil; + } + + self.compact = self.nbCenterLayers == 5; + + // Expand the square by .5 pixel in each direction so that we're on the border + // between the white square and the black square + ZXResultPoint *pinax = [[ZXResultPoint alloc] initWithX:pina.x + 0.5f y:pina.y - 0.5f]; + ZXResultPoint *pinbx = [[ZXResultPoint alloc] initWithX:pinb.x + 0.5f y:pinb.y + 0.5f]; + ZXResultPoint *pincx = [[ZXResultPoint alloc] initWithX:pinc.x - 0.5f y:pinc.y + 0.5f]; + ZXResultPoint *pindx = [[ZXResultPoint alloc] initWithX:pind.x - 0.5f y:pind.y - 0.5f]; + + // Expand the square so that its corners are the centers of the points + // just outside the bull's eye. + return [[self expandSquare:@[pinax, pinbx, pincx, pindx] + oldSide:2 * self.nbCenterLayers - 3 + newSide:2 * self.nbCenterLayers] mutableCopy]; +} + +/** + * Finds a candidate center point of an Aztec code from an image + */ +- (ZXAztecPoint *)matrixCenter { + ZXResultPoint *pointA; + ZXResultPoint *pointB; + ZXResultPoint *pointC; + ZXResultPoint *pointD; + + ZXWhiteRectangleDetector *detector = [[ZXWhiteRectangleDetector alloc] initWithImage:self.image error:nil]; + NSArray *cornerPoints = [detector detectWithError:nil]; + + if (cornerPoints) { + pointA = cornerPoints[0]; + pointB = cornerPoints[1]; + pointC = cornerPoints[2]; + pointD = cornerPoints[3]; + } else { + // This exception can be in case the initial rectangle is white + // In that case, surely in the bull's eye, we try to expand the rectangle. + int cx = self.image.width / 2; + int cy = self.image.height / 2; + pointA = [[self firstDifferent:[[ZXAztecPoint alloc] initWithX:cx + 7 y:cy - 7] color:NO dx:1 dy:-1] toResultPoint]; + pointB = [[self firstDifferent:[[ZXAztecPoint alloc] initWithX:cx + 7 y:cy + 7] color:NO dx:1 dy:1] toResultPoint]; + pointC = [[self firstDifferent:[[ZXAztecPoint alloc] initWithX:cx - 7 y:cy + 7] color:NO dx:-1 dy:1] toResultPoint]; + pointD = [[self firstDifferent:[[ZXAztecPoint alloc] initWithX:cx - 7 y:cy - 7] color:NO dx:-1 dy:-1] toResultPoint]; + } + + //Compute the center of the rectangle + int cx = [ZXMathUtils round:([pointA x] + [pointD x] + [pointB x] + [pointC x]) / 4.0f]; + int cy = [ZXMathUtils round:([pointA y] + [pointD y] + [pointB y] + [pointC y]) / 4.0f]; + + // Redetermine the white rectangle starting from previously computed center. + // This will ensure that we end up with a white rectangle in center bull's eye + // in order to compute a more accurate center. + detector = [[ZXWhiteRectangleDetector alloc] initWithImage:self.image initSize:15 x:cx y:cy error:nil]; + cornerPoints = [detector detectWithError:nil]; + + if (cornerPoints) { + pointA = cornerPoints[0]; + pointB = cornerPoints[1]; + pointC = cornerPoints[2]; + pointD = cornerPoints[3]; + } else { + // This exception can be in case the initial rectangle is white + // In that case we try to expand the rectangle. + pointA = [[self firstDifferent:[[ZXAztecPoint alloc] initWithX:cx + 7 y:cy - 7] color:NO dx:1 dy:-1] toResultPoint]; + pointB = [[self firstDifferent:[[ZXAztecPoint alloc] initWithX:cx + 7 y:cy + 7] color:NO dx:1 dy:1] toResultPoint]; + pointC = [[self firstDifferent:[[ZXAztecPoint alloc] initWithX:cx - 7 y:cy + 7] color:NO dx:-1 dy:1] toResultPoint]; + pointD = [[self firstDifferent:[[ZXAztecPoint alloc] initWithX:cx - 7 y:cy - 7] color:NO dx:-1 dy:-1] toResultPoint]; + } + + cx = [ZXMathUtils round:([pointA x] + [pointD x] + [pointB x] + [pointC x]) / 4]; + cy = [ZXMathUtils round:([pointA y] + [pointD y] + [pointB y] + [pointC y]) / 4]; + + // Recompute the center of the rectangle + return [[ZXAztecPoint alloc] initWithX:cx y:cy]; +} + +/** + * Gets the Aztec code corners from the bull's eye corners and the parameters. + * + * @param bullsEyeCorners the array of bull's eye corners + * @return the array of aztec code corners, or nil if the corner points do not fit in the image + */ +- (NSArray *)matrixCornerPoints:(NSArray *)bullsEyeCorners { + return [self expandSquare:bullsEyeCorners oldSide:2 * self.nbCenterLayers newSide:[self dimension]]; +} + +/** + * Creates a BitMatrix by sampling the provided image. + * topLeft, topRight, bottomRight, and bottomLeft are the centers of the squares on the + * diagonal just outside the bull's eye. + */ +- (ZXBitMatrix *)sampleGrid:(ZXBitMatrix *)anImage + topLeft:(ZXResultPoint *)topLeft + topRight:(ZXResultPoint *)topRight + bottomRight:(ZXResultPoint *)bottomRight + bottomLeft:(ZXResultPoint *)bottomLeft { + ZXGridSampler *sampler = [ZXGridSampler instance]; + int dimension = [self dimension]; + + float low = dimension / 2.0f - self.nbCenterLayers; + float high = dimension / 2.0f + self.nbCenterLayers; + + return [sampler sampleGrid:anImage + dimensionX:dimension + dimensionY:dimension + p1ToX:low p1ToY:low // topleft + p2ToX:high p2ToY:low // topright + p3ToX:high p3ToY:high // bottomright + p4ToX:low p4ToY:high // bottomleft + p1FromX:topLeft.x p1FromY:topLeft.y + p2FromX:topRight.x p2FromY:topRight.y + p3FromX:bottomRight.x p3FromY:bottomRight.y + p4FromX:bottomLeft.x p4FromY:bottomLeft.y + error:nil]; +} + +/** + * Samples a line. + * + * @param p1 start point (inclusive) + * @param p2 end point (exclusive) + * @param size number of bits + * @return the array of bits as an int (first bit is high-order bit of result) + */ +- (int)sampleLine:(ZXResultPoint *)p1 p2:(ZXResultPoint *)p2 size:(int)size { + int result = 0; + + float d = [self resultDistance:p1 b:p2]; + float moduleSize = d / size; + float px = p1.x; + float py = p1.y; + float dx = moduleSize * (p2.x - p1.x) / d; + float dy = moduleSize * (p2.y - p1.y) / d; + for (int i = 0; i < size; i++) { + if ([self.image getX:[ZXMathUtils round:px + i * dx] y:[ZXMathUtils round:py + i * dy]]) { + result |= 1 << (size - i - 1); + } + } + + return result; +} + +/** + * @return true if the border of the rectangle passed in parameter is compound of white points only + * or black points only + */ +- (BOOL)isWhiteOrBlackRectangle:(ZXAztecPoint *)p1 p2:(ZXAztecPoint *)p2 p3:(ZXAztecPoint *)p3 p4:(ZXAztecPoint *)p4 { + int corr = 3; + + p1 = [[ZXAztecPoint alloc] initWithX:p1.x - corr y:p1.y + corr]; + p2 = [[ZXAztecPoint alloc] initWithX:p2.x - corr y:p2.y - corr]; + p3 = [[ZXAztecPoint alloc] initWithX:p3.x + corr y:p3.y - corr]; + p4 = [[ZXAztecPoint alloc] initWithX:p4.x + corr y:p4.y + corr]; + + int cInit = [self color:p4 p2:p1]; + + if (cInit == 0) { + return NO; + } + + int c = [self color:p1 p2:p2]; + + if (c != cInit) { + return NO; + } + + c = [self color:p2 p2:p3]; + + if (c != cInit) { + return NO; + } + + c = [self color:p3 p2:p4]; + + return c == cInit; +} + +/** + * Gets the color of a segment + * + * @return 1 if segment more than 90% black, -1 if segment is more than 90% white, 0 else + */ +- (int)color:(ZXAztecPoint *)p1 p2:(ZXAztecPoint *)p2 { + float d = [self distance:p1 b:p2]; + float dx = (p2.x - p1.x) / d; + float dy = (p2.y - p1.y) / d; + int error = 0; + + float px = p1.x; + float py = p1.y; + + BOOL colorModel = [self.image getX:p1.x y:p1.y]; + + for (int i = 0; i < d; i++) { + px += dx; + py += dy; + if ([self.image getX:[ZXMathUtils round:px] y:[ZXMathUtils round:py]] != colorModel) { + error++; + } + } + + float errRatio = (float)error / d; + + if (errRatio > 0.1f && errRatio < 0.9f) { + return 0; + } + + return (errRatio <= 0.1f) == colorModel ? 1 : -1; +} + +/** + * Gets the coordinate of the first point with a different color in the given direction + */ +- (ZXAztecPoint *)firstDifferent:(ZXAztecPoint *)init color:(BOOL)color dx:(int)dx dy:(int)dy { + int x = init.x + dx; + int y = init.y + dy; + + while ([self isValidX:x y:y] && [self.image getX:x y:y] == color) { + x += dx; + y += dy; + } + + x -= dx; + y -= dy; + + while ([self isValidX:x y:y] && [self.image getX:x y:y] == color) { + x += dx; + } + x -= dx; + + while ([self isValidX:x y:y] && [self.image getX:x y:y] == color) { + y += dy; + } + y -= dy; + + return [[ZXAztecPoint alloc] initWithX:x y:y]; +} + +/** + * Expand the square represented by the corner points by pushing out equally in all directions + * + * @param cornerPoints the corners of the square, which has the bull's eye at its center + * @param oldSide the original length of the side of the square in the target bit matrix + * @param newSide the new length of the size of the square in the target bit matrix + * @return the corners of the expanded square + */ +- (NSArray *)expandSquare:(NSArray *)cornerPoints oldSide:(float)oldSide newSide:(float)newSide { + ZXResultPoint *cornerPoints0 = (ZXResultPoint *)cornerPoints[0]; + ZXResultPoint *cornerPoints1 = (ZXResultPoint *)cornerPoints[1]; + ZXResultPoint *cornerPoints2 = (ZXResultPoint *)cornerPoints[2]; + ZXResultPoint *cornerPoints3 = (ZXResultPoint *)cornerPoints[3]; + + float ratio = newSide / (2 * oldSide); + float dx = cornerPoints0.x - cornerPoints2.x; + float dy = cornerPoints0.y - cornerPoints2.y; + float centerx = (cornerPoints0.x + cornerPoints2.x) / 2.0f; + float centery = (cornerPoints0.y + cornerPoints2.y) / 2.0f; + + ZXResultPoint *result0 = [[ZXResultPoint alloc] initWithX:centerx + ratio * dx y:centery + ratio * dy]; + ZXResultPoint *result2 = [[ZXResultPoint alloc] initWithX:centerx - ratio * dx y:centery - ratio * dy]; + + dx = cornerPoints1.x - cornerPoints3.x; + dy = cornerPoints1.y - cornerPoints3.y; + centerx = (cornerPoints1.x + cornerPoints3.x) / 2.0f; + centery = (cornerPoints1.y + cornerPoints3.y) / 2.0f; + ZXResultPoint *result1 = [[ZXResultPoint alloc] initWithX:centerx + ratio * dx y:centery + ratio * dy]; + ZXResultPoint *result3 = [[ZXResultPoint alloc] initWithX:centerx - ratio * dx y:centery - ratio * dy]; + + return @[result0, result1, result2, result3]; +} + +- (BOOL)isValidX:(int)x y:(int)y { + return x >= 0 && x < self.image.width && y > 0 && y < self.image.height; +} + +- (BOOL)isValid:(ZXResultPoint *)point { + int x = [ZXMathUtils round:point.x]; + int y = [ZXMathUtils round:point.y]; + return [self isValidX:x y:y]; +} + +- (float)distance:(ZXAztecPoint *)a b:(ZXAztecPoint *)b { + return [ZXMathUtils distance:a.x aY:a.y bX:b.x bY:b.y]; +} + +- (float)resultDistance:(ZXResultPoint *)a b:(ZXResultPoint *)b { + return [ZXMathUtils distance:a.x aY:a.y bX:b.x bY:b.y]; +} + +- (int)dimension { + if (self.compact) { + return 4 * self.nbLayers + 11; + } + if (self.nbLayers <= 4) { + return 4 * self.nbLayers + 15; + } + return 4 * self.nbLayers + 2 * ((self.nbLayers-4)/8 + 1) + 15; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecBinaryShiftToken.h b/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecBinaryShiftToken.h new file mode 100755 index 0000000..9bf4095 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecBinaryShiftToken.h @@ -0,0 +1,23 @@ +/* + * Copyright 2014 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAztecToken.h" + +@interface ZXAztecBinaryShiftToken : ZXAztecToken + +- (id)initWithPrevious:(ZXAztecToken *)previous binaryShiftStart:(int)binaryShiftStart binaryShiftByteCount:(int)binaryShiftByteCount; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecBinaryShiftToken.m b/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecBinaryShiftToken.m new file mode 100755 index 0000000..2ca14ce --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecBinaryShiftToken.m @@ -0,0 +1,59 @@ +/* + * Copyright 2014 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAztecBinaryShiftToken.h" +#import "ZXBitArray.h" +#import "ZXByteArray.h" + +@interface ZXAztecBinaryShiftToken () + +@property (nonatomic, assign, readonly) int16_t binaryShiftStart; +@property (nonatomic, assign, readonly) int16_t binaryShiftByteCount; + +@end + +@implementation ZXAztecBinaryShiftToken + +- (id)initWithPrevious:(ZXAztecToken *)previous binaryShiftStart:(int)binaryShiftStart binaryShiftByteCount:(int)binaryShiftByteCount { + if (self = [super initWithPrevious:previous]) { + _binaryShiftStart = (int16_t) binaryShiftStart; + _binaryShiftByteCount = (int16_t) binaryShiftByteCount; + } + + return self; +} + +- (void)appendTo:(ZXBitArray *)bitArray text:(ZXByteArray *)text { + for (int i = 0; i < self.binaryShiftByteCount; i++) { + if (i == 0 || (i == 31 && self.binaryShiftByteCount <= 62)) { + // We need a header before the first character, and before + // character 31 when the total byte code is <= 62 + [bitArray appendBits:31 numBits:5]; // BINARY_SHIFT + if (self.binaryShiftByteCount > 62) { + [bitArray appendBits:self.binaryShiftByteCount - 31 numBits:16]; + } else if (i == 0) { + // 1 <= binaryShiftByteCode <= 62 + [bitArray appendBits:MIN(self.binaryShiftByteCount, 31) numBits:5]; + } else { + // 32 <= binaryShiftCount <= 62 and i == 31 + [bitArray appendBits:self.binaryShiftByteCount - 31 numBits:5]; + } + } + [bitArray appendBits:text.array[self.binaryShiftStart + i] numBits:8]; + } +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecCode.h b/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecCode.h new file mode 100755 index 0000000..41a086e --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecCode.h @@ -0,0 +1,49 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXBitMatrix; + +/** + * Aztec 2D code representation + */ +@interface ZXAztecCode : NSObject + +/** + * Number of data codewords + */ +@property (nonatomic, assign) int codeWords; + +/** + * Compact or full symbol indicator + */ +@property (nonatomic, assign, getter = isCompact) BOOL compact; + +/** + * Number of levels + */ +@property (nonatomic, assign) int layers; + +/** + * The symbol image + */ +@property (nonatomic, strong) ZXBitMatrix *matrix; + +/** + * Size in pixels (width and height) + */ +@property (nonatomic, assign) int size; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecCode.m b/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecCode.m new file mode 100755 index 0000000..c7054d5 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecCode.m @@ -0,0 +1,21 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAztecCode.h" + +@implementation ZXAztecCode + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecEncoder.h b/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecEncoder.h new file mode 100755 index 0000000..549ffdd --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecEncoder.h @@ -0,0 +1,48 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +extern const int ZX_AZTEC_DEFAULT_EC_PERCENT; +extern const int ZX_AZTEC_DEFAULT_LAYERS; + +@class ZXAztecCode, ZXBitArray, ZXByteArray, ZXGenericGF; + +/** + * Generates Aztec 2D barcodes. + */ +@interface ZXAztecEncoder : NSObject + +/** + * Encodes the given binary content as an Aztec symbol + * + * @param data input data string + * @return Aztec symbol matrix with metadata + */ ++ (ZXAztecCode *)encode:(ZXByteArray *)data; + +/** + * Encodes the given binary content as an Aztec symbol + * + * @param data input data string + * @param minECCPercent minimal percentage of error check words (According to ISO/IEC 24778:2008, + * a minimum of 23% + 3 words is recommended) + * @param userSpecifiedLayers if non-zero, a user-specified value for the number of layers + * @return Aztec symbol matrix with metadata + */ ++ (ZXAztecCode *)encode:(ZXByteArray *)data + minECCPercent:(int)minECCPercent + userSpecifiedLayers:(int)userSpecifiedLayers; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecEncoder.m b/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecEncoder.m new file mode 100755 index 0000000..ef0c0e9 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecEncoder.m @@ -0,0 +1,335 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAztecCode.h" +#import "ZXAztecEncoder.h" +#import "ZXAztecHighLevelEncoder.h" +#import "ZXBitArray.h" +#import "ZXBitMatrix.h" +#import "ZXByteArray.h" +#import "ZXGenericGF.h" +#import "ZXIntArray.h" +#import "ZXReedSolomonEncoder.h" + +const int ZX_AZTEC_DEFAULT_EC_PERCENT = 33; // default minimal percentage of error check words +const int ZX_AZTEC_DEFAULT_LAYERS = 0; +const int ZX_AZTEC_MAX_NB_BITS = 32; +const int ZX_AZTEC_MAX_NB_BITS_COMPACT = 4; + +const int ZX_AZTEC_WORD_SIZE[] = { + 4, 6, 6, 8, 8, 8, 8, 8, 8, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12 +}; + +@implementation ZXAztecEncoder + ++ (ZXAztecCode *)encode:(ZXByteArray *)data { + return [self encode:data minECCPercent:ZX_AZTEC_DEFAULT_EC_PERCENT userSpecifiedLayers:ZX_AZTEC_DEFAULT_LAYERS]; +} + ++ (ZXAztecCode *)encode:(ZXByteArray *)data minECCPercent:(int)minECCPercent userSpecifiedLayers:(int)userSpecifiedLayers { + // High-level encode + ZXBitArray *bits = [[[ZXAztecHighLevelEncoder alloc] initWithText:data] encode]; + + // stuff bits and choose symbol size + int eccBits = bits.size * minECCPercent / 100 + 11; + int totalSizeBits = bits.size + eccBits; + BOOL compact; + int layers; + int totalBitsInLayer; + int wordSize = ZX_AZTEC_WORD_SIZE[0]; + ZXBitArray *stuffedBits; + if (userSpecifiedLayers != ZX_AZTEC_DEFAULT_LAYERS) { + compact = userSpecifiedLayers < 0; + layers = abs(userSpecifiedLayers); + if (layers > (compact ? ZX_AZTEC_MAX_NB_BITS_COMPACT : ZX_AZTEC_MAX_NB_BITS)) { + @throw [NSException exceptionWithName:@"IllegalArgumentException" + reason:[NSString stringWithFormat:@"Illegal value %d for layers", userSpecifiedLayers] + userInfo:nil]; + } + totalBitsInLayer = [self totalBitsInLayer:layers compact:compact]; + wordSize = ZX_AZTEC_WORD_SIZE[layers]; + int usableBitsInLayers = totalBitsInLayer - (totalBitsInLayer % wordSize); + stuffedBits = [self stuffBits:bits wordSize:wordSize]; + if (stuffedBits.size + eccBits > usableBitsInLayers) { + @throw [NSException exceptionWithName:@"IllegalArgumentException" + reason:@"Data too large for user specified layer" + userInfo:nil]; + } + if (compact && stuffedBits.size > wordSize * 64) { + // Compact format only allows 64 data words, though C4 can hold more words than that + @throw [NSException exceptionWithName:@"IllegalArgumentException" + reason:@"Data too large for user specified layer" + userInfo:nil]; + } + } else { + // We look at the possible table sizes in the order Compact1, Compact2, Compact3, + // Compact4, Normal4,... Normal(i) for i < 4 isn't typically used since Compact(i+1) + // is the same size, but has more data. + for (int i = 0; ; i++) { + if (i > ZX_AZTEC_MAX_NB_BITS) { + @throw [NSException exceptionWithName:@"IllegalArgumentException" + reason:@"Data too large for an Aztec code" + userInfo:nil]; + } + compact = i <= 3; + layers = compact ? i + 1 : i; + totalBitsInLayer = [self totalBitsInLayer:layers compact:compact]; + if (totalSizeBits > totalBitsInLayer) { + continue; + } + // [Re]stuff the bits if this is the first opportunity, or if the + // wordSize has changed + if (wordSize != ZX_AZTEC_WORD_SIZE[layers]) { + wordSize = ZX_AZTEC_WORD_SIZE[layers]; + stuffedBits = [self stuffBits:bits wordSize:wordSize]; + } + int usableBitsInLayers = totalBitsInLayer - (totalBitsInLayer % wordSize); + if (compact && stuffedBits.size > wordSize * 64) { + // Compact format only allows 64 data words, though C4 can hold more words than that + continue; + } + if (stuffedBits.size + eccBits <= usableBitsInLayers) { + break; + } + } + } + ZXBitArray *messageBits = [self generateCheckWords:stuffedBits totalBits:totalBitsInLayer wordSize:wordSize]; + + // generate check words + int messageSizeInWords = stuffedBits.size / wordSize; + ZXBitArray *modeMessage = [self generateModeMessageCompact:compact layers:layers messageSizeInWords:messageSizeInWords]; + + // allocate symbol + int baseMatrixSize = compact ? 11 + layers * 4 : 14 + layers * 4; // not including alignment lines + int alignmentMap[baseMatrixSize]; + memset(alignmentMap, 0, baseMatrixSize * sizeof(int)); + int matrixSize; + if (compact) { + // no alignment marks in compact mode, alignmentMap is a no-op + matrixSize = baseMatrixSize; + for (int i = 0; i < baseMatrixSize; i++) { + alignmentMap[i] = i; + } + } else { + matrixSize = baseMatrixSize + 1 + 2 * ((baseMatrixSize / 2 - 1) / 15); + int origCenter = baseMatrixSize / 2; + int center = matrixSize / 2; + for (int i = 0; i < origCenter; i++) { + int newOffset = i + i / 15; + alignmentMap[origCenter - i - 1] = center - newOffset - 1; + alignmentMap[origCenter + i] = center + newOffset + 1; + } + } + ZXBitMatrix *matrix = [[ZXBitMatrix alloc] initWithDimension:matrixSize]; + + // draw data bits + for (int i = 0, rowOffset = 0; i < layers; i++) { + int rowSize = compact ? (layers - i) * 4 + 9 : (layers - i) * 4 + 12; + for (int j = 0; j < rowSize; j++) { + int columnOffset = j * 2; + for (int k = 0; k < 2; k++) { + if ([messageBits get:rowOffset + columnOffset + k]) { + [matrix setX:alignmentMap[i * 2 + k] y:alignmentMap[i * 2 + j]]; + } + if ([messageBits get:rowOffset + rowSize * 2 + columnOffset + k]) { + [matrix setX:alignmentMap[i * 2 + j] y:alignmentMap[baseMatrixSize - 1 - i * 2 - k]]; + } + if ([messageBits get:rowOffset + rowSize * 4 + columnOffset + k]) { + [matrix setX:alignmentMap[baseMatrixSize - 1 - i * 2 - k] y:alignmentMap[baseMatrixSize - 1 - i * 2 - j]]; + } + if ([messageBits get:rowOffset + rowSize * 6 + columnOffset + k]) { + [matrix setX:alignmentMap[baseMatrixSize - 1 - i * 2 - j] y:alignmentMap[i * 2 + k]]; + } + } + } + rowOffset += rowSize * 8; + } + + // draw mode message + [self drawModeMessage:matrix compact:compact matrixSize:matrixSize modeMessage:modeMessage]; + + // draw alignment marks + if (compact) { + [self drawBullsEye:matrix center:matrixSize / 2 size:5]; + } else { + [self drawBullsEye:matrix center:matrixSize / 2 size:7]; + for (int i = 0, j = 0; i < baseMatrixSize / 2 - 1; i += 15, j += 16) { + for (int k = (matrixSize / 2) & 1; k < matrixSize; k += 2) { + [matrix setX:matrixSize / 2 - j y:k]; + [matrix setX:matrixSize / 2 + j y:k]; + [matrix setX:k y:matrixSize / 2 - j]; + [matrix setX:k y:matrixSize / 2 + j]; + } + } + } + + ZXAztecCode *aztec = [[ZXAztecCode alloc] init]; + aztec.compact = compact; + aztec.size = matrixSize; + aztec.layers = layers; + aztec.codeWords = messageSizeInWords; + aztec.matrix = matrix; + return aztec; +} + ++ (void)drawBullsEye:(ZXBitMatrix *)matrix center:(int)center size:(int)size { + for (int i = 0; i < size; i += 2) { + for (int j = center - i; j <= center + i; j++) { + [matrix setX:j y:center - i]; + [matrix setX:j y:center + i]; + [matrix setX:center - i y:j]; + [matrix setX:center + i y:j]; + } + } + [matrix setX:center - size y:center - size]; + [matrix setX:center - size + 1 y:center - size]; + [matrix setX:center - size y:center - size + 1]; + [matrix setX:center + size y:center - size]; + [matrix setX:center + size y:center - size + 1]; + [matrix setX:center + size y:center + size - 1]; +} + ++ (ZXBitArray *)generateModeMessageCompact:(BOOL)compact layers:(int)layers messageSizeInWords:(int)messageSizeInWords { + ZXBitArray *modeMessage = [[ZXBitArray alloc] init]; + if (compact) { + [modeMessage appendBits:layers - 1 numBits:2]; + [modeMessage appendBits:messageSizeInWords - 1 numBits:6]; + modeMessage = [self generateCheckWords:modeMessage totalBits:28 wordSize:4]; + } else { + [modeMessage appendBits:layers - 1 numBits:5]; + [modeMessage appendBits:messageSizeInWords - 1 numBits:11]; + modeMessage = [self generateCheckWords:modeMessage totalBits:40 wordSize:4]; + } + return modeMessage; +} + ++ (void)drawModeMessage:(ZXBitMatrix *)matrix compact:(BOOL)compact matrixSize:(int)matrixSize modeMessage:(ZXBitArray *)modeMessage { + int center = matrixSize / 2; + if (compact) { + for (int i = 0; i < 7; i++) { + int offset = center - 3 + i; + if ([modeMessage get:i]) { + [matrix setX:offset y:center - 5]; + } + if ([modeMessage get:i + 7]) { + [matrix setX:center + 5 y:offset]; + } + if ([modeMessage get:20 - i]) { + [matrix setX:offset y:center + 5]; + } + if ([modeMessage get:27 - i]) { + [matrix setX:center - 5 y:offset]; + } + } + } else { + for (int i = 0; i < 10; i++) { + int offset = center - 5 + i + i / 5; + if ([modeMessage get:i]) { + [matrix setX:offset y:center - 7]; + } + if ([modeMessage get:i + 10]) { + [matrix setX:center + 7 y:offset]; + } + if ([modeMessage get:29 - i]) { + [matrix setX:offset y:center + 7]; + } + if ([modeMessage get:39 - i]) { + [matrix setX:center - 7 y:offset]; + } + } + } +} + ++ (ZXBitArray *)generateCheckWords:(ZXBitArray *)bitArray totalBits:(int)totalBits wordSize:(int)wordSize { + // bitArray is guaranteed to be a multiple of the wordSize, so no padding needed + int messageSizeInWords = bitArray.size / wordSize; + ZXReedSolomonEncoder *rs = [[ZXReedSolomonEncoder alloc] initWithField:[self getGF:wordSize]]; + int totalWords = totalBits / wordSize; + + ZXIntArray *messageWords = [self bitsToWords:bitArray wordSize:wordSize totalWords:totalWords]; + [rs encode:messageWords ecBytes:totalWords - messageSizeInWords]; + int startPad = totalBits % wordSize; + ZXBitArray *messageBits = [[ZXBitArray alloc] init]; + [messageBits appendBits:0 numBits:startPad]; + for (int i = 0; i < totalWords; i++) { + [messageBits appendBits:messageWords.array[i] numBits:wordSize]; + } + return messageBits; +} + ++ (ZXIntArray *)bitsToWords:(ZXBitArray *)stuffedBits wordSize:(int)wordSize totalWords:(int)totalWords { + ZXIntArray *message = [[ZXIntArray alloc] initWithLength:totalWords]; + int i; + int n; + for (i = 0, n = stuffedBits.size / wordSize; i < n; i++) { + int32_t value = 0; + for (int j = 0; j < wordSize; j++) { + value |= [stuffedBits get:i * wordSize + j] ? (1 << (wordSize - j - 1)) : 0; + } + message.array[i] = value; + } + return message; +} + ++ (ZXGenericGF *)getGF:(int)wordSize { + switch (wordSize) { + case 4: + return [ZXGenericGF AztecParam]; + case 6: + return [ZXGenericGF AztecData6]; + case 8: + return [ZXGenericGF AztecData8]; + case 10: + return [ZXGenericGF AztecData10]; + case 12: + return [ZXGenericGF AztecData12]; + default: + return nil; + } +} + ++ (ZXBitArray *)stuffBits:(ZXBitArray *)bits wordSize:(int)wordSize { + ZXBitArray *arrayOut = [[ZXBitArray alloc] init]; + + int n = bits.size; + int mask = (1 << wordSize) - 2; + for (int i = 0; i < n; i += wordSize) { + int word = 0; + for (int j = 0; j < wordSize; j++) { + if (i + j >= n || [bits get:i + j]) { + word |= 1 << (wordSize - 1 - j); + } + } + if ((word & mask) == mask) { + [arrayOut appendBits:word & mask numBits:wordSize]; + i--; + } else if ((word & mask) == 0) { + [arrayOut appendBits:word | 1 numBits:wordSize]; + i--; + } else { + [arrayOut appendBits:word numBits:wordSize]; + } + } + + return arrayOut; +} + ++ (int)totalBitsInLayer:(int)layers compact:(BOOL)compact { + return ((compact ? 88 : 112) + 16 * layers) * layers; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecHighLevelEncoder.h b/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecHighLevelEncoder.h new file mode 100755 index 0000000..9355b86 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecHighLevelEncoder.h @@ -0,0 +1,50 @@ +/* + * Copyright 2014 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +extern NSArray *ZX_AZTEC_MODE_NAMES; + +extern const int ZX_AZTEC_MODE_UPPER; +extern const int ZX_AZTEC_MODE_LOWER; +extern const int ZX_AZTEC_MODE_DIGIT; +extern const int ZX_AZTEC_MODE_MIXED; +extern const int ZX_AZTEC_MODE_PUNCT; + +extern const int ZX_AZTEC_LATCH_TABLE[][5]; + +#define ZX_AZTEC_SHIFT_TABLE_SIZE 6 +extern int ZX_AZTEC_SHIFT_TABLE[ZX_AZTEC_SHIFT_TABLE_SIZE][ZX_AZTEC_SHIFT_TABLE_SIZE]; + +@class ZXBitArray, ZXByteArray; + +/** + * This produces nearly optimal encodings of text into the first-level of + * encoding used by Aztec code. + * + * It uses a dynamic algorithm. For each prefix of the string, it determines + * a set of encodings that could lead to this prefix. We repeatedly add a + * character and generate a new set of optimal encodings until we have read + * through the entire input. + */ +@interface ZXAztecHighLevelEncoder : NSObject + +- (id)initWithText:(ZXByteArray *)text; + +/** + * Convert the text represented by this High Level Encoder into a BitArray. + */ +- (ZXBitArray *)encode; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecHighLevelEncoder.m b/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecHighLevelEncoder.m new file mode 100755 index 0000000..119ff81 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecHighLevelEncoder.m @@ -0,0 +1,294 @@ +/* + * Copyright 2014 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAztecHighLevelEncoder.h" +#import "ZXAztecState.h" +#import "ZXByteArray.h" + +NSArray *ZX_AZTEC_MODE_NAMES = nil; + +const int ZX_AZTEC_MODE_UPPER = 0; // 5 bits +const int ZX_AZTEC_MODE_LOWER = 1; // 5 bits +const int ZX_AZTEC_MODE_DIGIT = 2; // 4 bits +const int ZX_AZTEC_MODE_MIXED = 3; // 5 bits +const int ZX_AZTEC_MODE_PUNCT = 4; // 5 bits + +// The Latch Table shows, for each pair of Modes, the optimal method for +// getting from one mode to another. In the worst possible case, this can +// be up to 14 bits. In the best possible case, we are already there! +// The high half-word of each entry gives the number of bits. +// The low half-word of each entry are the actual bits necessary to change +const int ZX_AZTEC_LATCH_TABLE[][5] = { + { + 0, + (5 << 16) + 28, // UPPER -> LOWER + (5 << 16) + 30, // UPPER -> DIGIT + (5 << 16) + 29, // UPPER -> MIXED + (10 << 16) + (29 << 5) + 30, // UPPER -> MIXED -> PUNCT + }, + { + (9 << 16) + (30 << 4) + 14, // LOWER -> DIGIT -> UPPER + 0, + (5 << 16) + 30, // LOWER -> DIGIT + (5 << 16) + 29, // LOWER -> MIXED + (10 << 16) + (29 << 5) + 30, // LOWER -> MIXED -> PUNCT + }, + { + (4 << 16) + 14, // DIGIT -> UPPER + (9 << 16) + (14 << 5) + 28, // DIGIT -> UPPER -> LOWER + 0, + (9 << 16) + (14 << 5) + 29, // DIGIT -> UPPER -> MIXED + (14 << 16) + (14 << 10) + (29 << 5) + 30, + // DIGIT -> UPPER -> MIXED -> PUNCT + }, + { + (5 << 16) + 29, // MIXED -> UPPER + (5 << 16) + 28, // MIXED -> LOWER + (10 << 16) + (29 << 5) + 30, // MIXED -> UPPER -> DIGIT + 0, + (5 << 16) + 30, // MIXED -> PUNCT + }, + { + (5 << 16) + 31, // PUNCT -> UPPER + (10 << 16) + (31 << 5) + 28, // PUNCT -> UPPER -> LOWER + (10 << 16) + (31 << 5) + 30, // PUNCT -> UPPER -> DIGIT + (10 << 16) + (31 << 5) + 29, // PUNCT -> UPPER -> MIXED + 0, + }, +}; + +// A reverse mapping from [mode][char] to the encoding for that character +// in that mode. An entry of 0 indicates no mapping exists. +const int ZX_AZTEC_CHAR_MAP_HEIGHT = 5; +const int ZX_AZTEC_CHAR_MAP_WIDTH = 256; +static int ZX_AZTEC_CHAR_MAP[ZX_AZTEC_CHAR_MAP_HEIGHT][ZX_AZTEC_CHAR_MAP_WIDTH]; + +// A map showing the available shift codes. (The shifts to BINARY are not +// shown +int ZX_AZTEC_SHIFT_TABLE[ZX_AZTEC_SHIFT_TABLE_SIZE][ZX_AZTEC_SHIFT_TABLE_SIZE]; + +@interface ZXAztecHighLevelEncoder () + +@property (nonatomic, assign, readonly) ZXByteArray *text; + +@end + +@implementation ZXAztecHighLevelEncoder + ++ (void)load { + ZX_AZTEC_MODE_NAMES = @[@"UPPER", @"LOWER", @"DIGIT", @"MIXED", @"PUNCT"]; + + memset(ZX_AZTEC_CHAR_MAP, 0, ZX_AZTEC_CHAR_MAP_HEIGHT * ZX_AZTEC_CHAR_MAP_WIDTH * sizeof(int)); + ZX_AZTEC_CHAR_MAP[ZX_AZTEC_MODE_UPPER][' '] = 1; + for (int c = 'A'; c <= 'Z'; c++) { + ZX_AZTEC_CHAR_MAP[ZX_AZTEC_MODE_UPPER][c] = c - 'A' + 2; + } + ZX_AZTEC_CHAR_MAP[ZX_AZTEC_MODE_LOWER][' '] = 1; + for (int c = 'a'; c <= 'z'; c++) { + ZX_AZTEC_CHAR_MAP[ZX_AZTEC_MODE_LOWER][c] = c - 'a' + 2; + } + ZX_AZTEC_CHAR_MAP[ZX_AZTEC_MODE_DIGIT][' '] = 1; + for (int c = '0'; c <= '9'; c++) { + ZX_AZTEC_CHAR_MAP[ZX_AZTEC_MODE_DIGIT][c] = c - '0' + 2; + } + ZX_AZTEC_CHAR_MAP[ZX_AZTEC_MODE_DIGIT][','] = 12; + ZX_AZTEC_CHAR_MAP[ZX_AZTEC_MODE_DIGIT]['.'] = 13; + + const int mixedTable[] = { + '\0', ' ', '\1', '\2', '\3', '\4', '\5', '\6', '\7', '\b', '\t', '\n', + '\13', '\f', '\r', '\33', '\34', '\35', '\36', '\37', '@', '\\', '^', + '_', '`', '|', '~', '\177' + }; + for (int i = 0; i < sizeof(mixedTable) / sizeof(int); i++) { + ZX_AZTEC_CHAR_MAP[ZX_AZTEC_MODE_MIXED][mixedTable[i]] = i; + } + + const int punctTable[] = { + '\0', '\r', '\0', '\0', '\0', '\0', '!', '\'', '#', '$', '%', '&', '\'', + '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', + '[', ']', '{', '}' + }; + for (int i = 0; i < sizeof(punctTable) / sizeof(int); i++) { + if (punctTable[i] > 0) { + ZX_AZTEC_CHAR_MAP[ZX_AZTEC_MODE_PUNCT][punctTable[i]] = i; + } + } + + memset(ZX_AZTEC_SHIFT_TABLE, -1, ZX_AZTEC_SHIFT_TABLE_SIZE * ZX_AZTEC_SHIFT_TABLE_SIZE * sizeof(int)); + ZX_AZTEC_SHIFT_TABLE[ZX_AZTEC_MODE_UPPER][ZX_AZTEC_MODE_PUNCT] = 0; + + ZX_AZTEC_SHIFT_TABLE[ZX_AZTEC_MODE_LOWER][ZX_AZTEC_MODE_PUNCT] = 0; + ZX_AZTEC_SHIFT_TABLE[ZX_AZTEC_MODE_LOWER][ZX_AZTEC_MODE_UPPER] = 28; + + ZX_AZTEC_SHIFT_TABLE[ZX_AZTEC_MODE_MIXED][ZX_AZTEC_MODE_PUNCT] = 0; + + ZX_AZTEC_SHIFT_TABLE[ZX_AZTEC_MODE_DIGIT][ZX_AZTEC_MODE_PUNCT] = 0; + ZX_AZTEC_SHIFT_TABLE[ZX_AZTEC_MODE_DIGIT][ZX_AZTEC_MODE_UPPER] = 15; +} + +- (id)initWithText:(ZXByteArray *)text { + if (self = [super init]) { + _text = text; + } + + return self; +} + +- (ZXBitArray *)encode { + NSArray *states = @[[ZXAztecState initialState]]; + for (int index = 0; index < self.text.length; index++) { + int pairCode; + int nextChar = index + 1 < self.text.length ? self.text.array[index + 1] : 0; + switch (self.text.array[index]) { + case '\r': + pairCode = nextChar == '\n' ? 2 : 0; + break; + case '.' : + pairCode = nextChar == ' ' ? 3 : 0; + break; + case ',' : + pairCode = nextChar == ' ' ? 4 : 0; + break; + case ':' : + pairCode = nextChar == ' ' ? 5 : 0; + break; + default: + pairCode = 0; + } + if (pairCode > 0) { + // We have one of the four special PUNCT pairs. Treat them specially. + // Get a new set of states for the two new characters. + states = [self updateStateListForPair:states index:index pairCode:pairCode]; + index++; + } else { + // Get a new set of states for the new character. + states = [self updateStateListForChar:states index:index]; + } + } + // We are left with a set of states. Find the shortest one. + ZXAztecState *minState = [[states sortedArrayUsingComparator:^NSComparisonResult(ZXAztecState *a, ZXAztecState *b) { + return a.bitCount - b.bitCount; + }] firstObject]; + // Convert it to a bit array, and return. + return [minState toBitArray:self.text]; +} + +// We update a set of states for a new character by updating each state +// for the new character, merging the results, and then removing the +// non-optimal states. +- (NSArray *)updateStateListForChar:(NSArray *)states index:(int)index { + NSMutableArray *result = [NSMutableArray array]; + for (ZXAztecState *state in states) { + [self updateStateForChar:state index:index result:result]; + } + return [self simplifyStates:result]; +} + +// Return a set of states that represent the possible ways of updating this +// state for the next character. The resulting set of states are added to +// the "result" list. +- (void)updateStateForChar:(ZXAztecState *)state index:(int)index result:(NSMutableArray *)result { + unichar ch = (unichar) (self.text.array[index] & 0xFF); + BOOL charInCurrentTable = ZX_AZTEC_CHAR_MAP[state.mode][ch] > 0; + ZXAztecState *stateNoBinary = nil; + for (int mode = 0; mode <= ZX_AZTEC_MODE_PUNCT; mode++) { + int charInMode = ZX_AZTEC_CHAR_MAP[mode][ch]; + if (charInMode > 0) { + if (!stateNoBinary) { + // Only create stateNoBinary the first time it's required. + stateNoBinary = [state endBinaryShift:index]; + } + // Try generating the character by latching to its mode + if (!charInCurrentTable || mode == state.mode || mode == ZX_AZTEC_MODE_DIGIT) { + // If the character is in the current table, we don't want to latch to + // any other mode except possibly digit (which uses only 4 bits). Any + // other latch would be equally successful *after* this character, and + // so wouldn't save any bits. + ZXAztecState *latch_state = [stateNoBinary latchAndAppend:mode value:charInMode]; + [result addObject:latch_state]; + } + // Try generating the character by switching to its mode. + if (!charInCurrentTable && ZX_AZTEC_SHIFT_TABLE[state.mode][mode] >= 0) { + // It never makes sense to temporarily shift to another mode if the + // character exists in the current mode. That can never save bits. + ZXAztecState *shift_state = [stateNoBinary shiftAndAppend:mode value:charInMode]; + [result addObject:shift_state]; + } + } + } + if (state.binaryShiftByteCount > 0 || ZX_AZTEC_CHAR_MAP[state.mode][ch] == 0) { + // It's never worthwhile to go into binary shift mode if you're not already + // in binary shift mode, and the character exists in your current mode. + // That can never save bits over just outputting the char in the current mode. + ZXAztecState *binaryState = [state addBinaryShiftChar:index]; + [result addObject:binaryState]; + } +} + +- (NSArray *)updateStateListForPair:(NSArray *)states index:(int)index pairCode:(int)pairCode { + NSMutableArray *result = [NSMutableArray array]; + for (ZXAztecState *state in states) { + [self updateStateForPair:state index:index pairCode:pairCode result:result]; + } + return [self simplifyStates:result]; +} + +- (void)updateStateForPair:(ZXAztecState *)state index:(int)index pairCode:(int)pairCode result:(NSMutableArray *)result { + ZXAztecState *stateNoBinary = [state endBinaryShift:index]; + // Possibility 1. Latch to ZX_AZTEC_MODE_PUNCT, and then append this code + [result addObject:[stateNoBinary latchAndAppend:ZX_AZTEC_MODE_PUNCT value:pairCode]]; + if (state.mode != ZX_AZTEC_MODE_PUNCT) { + // Possibility 2. Shift to ZX_AZTEC_MODE_PUNCT, and then append this code. + // Every state except ZX_AZTEC_MODE_PUNCT (handled above) can shift + [result addObject:[stateNoBinary shiftAndAppend:ZX_AZTEC_MODE_PUNCT value:pairCode]]; + } + if (pairCode == 3 || pairCode == 4) { + // both characters are in DIGITS. Sometimes better to just add two digits + ZXAztecState *digit_state = [[stateNoBinary + latchAndAppend:ZX_AZTEC_MODE_DIGIT value:16 - pairCode] // period or comma in DIGIT + latchAndAppend:ZX_AZTEC_MODE_DIGIT value:1]; // space in DIGIT + [result addObject:digit_state]; + } + if (state.binaryShiftByteCount > 0) { + // It only makes sense to do the characters as binary if we're already + // in binary mode. + ZXAztecState *binaryState = [[state addBinaryShiftChar:index] addBinaryShiftChar:index + 1]; + [result addObject:binaryState]; + } +} + +- (NSArray *)simplifyStates:(NSArray *)states { + NSMutableArray *result = [NSMutableArray array]; + for (ZXAztecState *newState in states) { + BOOL add = YES; + NSArray *resultCopy = [NSArray arrayWithArray:result]; + for (ZXAztecState *oldState in resultCopy) { + if ([oldState isBetterThanOrEqualTo:newState]) { + add = NO; + break; + } + if ([newState isBetterThanOrEqualTo:oldState]) { + [result removeObject:oldState]; + } + } + if (add) { + [result addObject:newState]; + } + } + return result; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecSimpleToken.h b/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecSimpleToken.h new file mode 100755 index 0000000..ab9ac11 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecSimpleToken.h @@ -0,0 +1,23 @@ +/* + * Copyright 2014 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAztecToken.h" + +@interface ZXAztecSimpleToken : ZXAztecToken + +- (id)initWithPrevious:(ZXAztecToken *)previous value:(int)value bitCount:(int)bitCount; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecSimpleToken.m b/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecSimpleToken.m new file mode 100755 index 0000000..d22e3ce --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecSimpleToken.m @@ -0,0 +1,55 @@ +/* + * Copyright 2014 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAztecSimpleToken.h" +#import "ZXBitArray.h" + +@interface ZXAztecSimpleToken () + +// For normal words, indicates value and bitCount +@property (nonatomic, assign, readonly) int16_t value; +@property (nonatomic, assign, readonly) int16_t bitCount; + +@end + +@implementation ZXAztecSimpleToken + +- (id)initWithPrevious:(ZXAztecToken *)previous value:(int)value bitCount:(int)bitCount { + if (self = [super initWithPrevious:previous]) { + _value = (int16_t)value; + _bitCount = (int16_t)bitCount; + } + + return self; +} + +- (void)appendTo:(ZXBitArray *)bitArray text:(ZXByteArray *)text { + [bitArray appendBits:self.value numBits:self.bitCount]; +} + +- (NSString *)description { + int value = self.value & ((1 << self.bitCount) - 1); + value |= 1 << self.bitCount; + + NSMutableString *str = [NSMutableString string]; + for (int i = value | (1 << self.bitCount); i > 0; i >>= 1) { + [str insertString:((i & 1) ? @"1" : @"0") atIndex:0]; + } + + return [NSString stringWithFormat:@"<%@>", [str substringFromIndex:1]]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecState.h b/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecState.h new file mode 100755 index 0000000..36eb6e0 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecState.h @@ -0,0 +1,49 @@ +/* + * Copyright 2014 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXAztecToken, ZXBitArray, ZXByteArray; + +/** + * State represents all information about a sequence necessary to generate the current output. + * Note that a state is immutable. + */ +@interface ZXAztecState : NSObject + +// The current mode of the encoding (or the mode to which we'll return if +// we're in Binary Shift mode. +@property (nonatomic, assign, readonly) int mode; + +// The list of tokens that we output. If we are in Binary Shift mode, this +// token list does *not* yet included the token for those bytes +@property (nonatomic, strong, readonly) ZXAztecToken *token; + +// If non-zero, the number of most recent bytes that should be output +// in Binary Shift mode. +@property (nonatomic, assign, readonly) int binaryShiftByteCount; + +// The total number of bits generated (including Binary Shift). +@property (nonatomic, assign, readonly) int bitCount; + +- (id)initWithToken:(ZXAztecToken *)token mode:(int)mode binaryBytes:(int)binaryBytes bitCount:(int)bitCount; ++ (ZXAztecState *)initialState; +- (ZXAztecState *)latchAndAppend:(int)mode value:(int)value; +- (ZXAztecState *)shiftAndAppend:(int)mode value:(int)value; +- (ZXAztecState *)addBinaryShiftChar:(int)index; +- (ZXAztecState *)endBinaryShift:(int)index; +- (BOOL)isBetterThanOrEqualTo:(ZXAztecState *)other; +- (ZXBitArray *)toBitArray:(ZXByteArray *)text; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecState.m b/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecState.m new file mode 100755 index 0000000..4a7ad50 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecState.m @@ -0,0 +1,132 @@ +/* + * Copyright 2014 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAztecHighLevelEncoder.h" +#import "ZXAztecState.h" +#import "ZXAztecToken.h" +#import "ZXBitArray.h" +#import "ZXByteArray.h" + +@implementation ZXAztecState + +- (id)initWithToken:(ZXAztecToken *)token mode:(int)mode binaryBytes:(int)binaryBytes bitCount:(int)bitCount { + if (self = [super init]) { + _token = token; + _mode = mode; + _binaryShiftByteCount = binaryBytes; + _bitCount = bitCount; + } + + return self; +} + ++ (ZXAztecState *)initialState { + return [[ZXAztecState alloc] initWithToken:[ZXAztecToken empty] mode:ZX_AZTEC_MODE_UPPER binaryBytes:0 bitCount:0]; +} + +// Create a new state representing this state with a latch to a (not +// necessary different) mode, and then a code. +- (ZXAztecState *)latchAndAppend:(int)mode value:(int)value { + int bitCount = self.bitCount; + ZXAztecToken *token = self.token; + if (mode != self.mode) { + int latch = ZX_AZTEC_LATCH_TABLE[self.mode][mode]; + token = [token add:latch & 0xFFFF bitCount:latch >> 16]; + bitCount += latch >> 16; + } + int latchModeBitCount = mode == ZX_AZTEC_MODE_DIGIT ? 4 : 5; + token = [token add:value bitCount:latchModeBitCount]; + return [[ZXAztecState alloc] initWithToken:token mode:mode binaryBytes:0 bitCount:bitCount + latchModeBitCount]; +} + +// Create a new state representing this state, with a temporary shift +// to a different mode to output a single value. +- (ZXAztecState *)shiftAndAppend:(int)mode value:(int)value { + //assert binaryShiftByteCount == 0 && this.mode != mode; + ZXAztecToken *token = self.token; + int thisModeBitCount = self.mode == ZX_AZTEC_MODE_DIGIT ? 4 : 5; + // Shifts exist only to UPPER and PUNCT, both with tokens size 5. + token = [token add:ZX_AZTEC_SHIFT_TABLE[self.mode][mode] bitCount:thisModeBitCount]; + token = [token add:value bitCount:5]; + return [[ZXAztecState alloc] initWithToken:token mode:self.mode binaryBytes:0 bitCount:self.bitCount + thisModeBitCount + 5]; +} + +// Create a new state representing this state, but an additional character +// output in Binary Shift mode. +- (ZXAztecState *)addBinaryShiftChar:(int)index { + ZXAztecToken *token = self.token; + int mode = self.mode; + int bitCount = self.bitCount; + if (self.mode == ZX_AZTEC_MODE_PUNCT || self.mode == ZX_AZTEC_MODE_DIGIT) { + int latch = ZX_AZTEC_LATCH_TABLE[mode][ZX_AZTEC_MODE_UPPER]; + token = [token add:latch & 0xFFFF bitCount:latch >> 16]; + bitCount += latch >> 16; + mode = ZX_AZTEC_MODE_UPPER; + } + int deltaBitCount = + (self.binaryShiftByteCount == 0 || self.binaryShiftByteCount == 31) ? 18 : + (self.binaryShiftByteCount == 62) ? 9 : 8; + ZXAztecState *result = [[ZXAztecState alloc] initWithToken:token mode:mode binaryBytes:self.binaryShiftByteCount + 1 bitCount:bitCount + deltaBitCount]; + if (result.binaryShiftByteCount == 2047 + 31) { + // The string is as long as it's allowed to be. We should end it. + result = [result endBinaryShift:index + 1]; + } + return result; +} + +// Create the state identical to this one, but we are no longer in +// Binary Shift mode. +- (ZXAztecState *)endBinaryShift:(int)index { + if (self.binaryShiftByteCount == 0) { + return self; + } + ZXAztecToken *token = self.token; + token = [token addBinaryShift:index - self.binaryShiftByteCount byteCount:self.binaryShiftByteCount]; + return [[ZXAztecState alloc] initWithToken:token mode:self.mode binaryBytes:0 bitCount:self.bitCount]; +} + +// Returns true if "this" state is better (or equal) to be in than "that" +// state under all possible circumstances. +- (BOOL)isBetterThanOrEqualTo:(ZXAztecState *)other { + int mySize = self.bitCount + (ZX_AZTEC_LATCH_TABLE[self.mode][other.mode] >> 16); + if (other.binaryShiftByteCount > 0 && + (self.binaryShiftByteCount == 0 || self.binaryShiftByteCount > other.binaryShiftByteCount)) { + mySize += 10; // Cost of entering Binary Shift mode. + } + return mySize <= other.bitCount; +} + +- (ZXBitArray *)toBitArray:(ZXByteArray *)text { + // Reverse the tokens, so that they are in the order that they should + // be output + NSMutableArray *symbols = [NSMutableArray array]; + for (ZXAztecToken *token = [self endBinaryShift:text.length].token; token != nil; token = token.previous) { + [symbols insertObject:token atIndex:0]; + } + ZXBitArray *bitArray = [[ZXBitArray alloc] init]; + // Add each token to the result. + for (ZXAztecToken *symbol in symbols) { + [symbol appendTo:bitArray text:text]; + } + return bitArray; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"%@ bits=%d bytes=%d", ZX_AZTEC_MODE_NAMES[self.mode], + self.bitCount, self.binaryShiftByteCount]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecToken.h b/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecToken.h new file mode 100755 index 0000000..a95ff32 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecToken.h @@ -0,0 +1,29 @@ +/* + * Copyright 2014 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXBitArray, ZXByteArray; + +@interface ZXAztecToken : NSObject + +@property (nonatomic, strong, readonly) ZXAztecToken *previous; + +- (id)initWithPrevious:(ZXAztecToken *)previous; ++ (ZXAztecToken *)empty; +- (ZXAztecToken *)add:(int)value bitCount:(int)bitCount; +- (ZXAztecToken *)addBinaryShift:(int)start byteCount:(int)byteCount; +- (void)appendTo:(ZXBitArray *)bitArray text:(ZXByteArray *)text; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecToken.m b/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecToken.m new file mode 100755 index 0000000..5e1d810 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/aztec/encoder/ZXAztecToken.m @@ -0,0 +1,51 @@ +/* + * Copyright 2014 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAztecBinaryShiftToken.h" +#import "ZXAztecSimpleToken.h" +#import "ZXAztecToken.h" +#import "ZXBitArray.h" + +@implementation ZXAztecToken + +- (id)initWithPrevious:(ZXAztecToken *)previous { + if (self = [super init]) { + _previous = previous; + } + + return self; +} + ++ (ZXAztecToken *)empty { + return [[ZXAztecSimpleToken alloc] initWithPrevious:nil value:0 bitCount:0]; +} + +- (ZXAztecToken *)add:(int)value bitCount:(int)bitCount { + return [[ZXAztecSimpleToken alloc] initWithPrevious:self value:value bitCount:bitCount]; +} + +- (ZXAztecToken *)addBinaryShift:(int)start byteCount:(int)byteCount { +// int bitCount = (byteCount * 8) + (byteCount <= 31 ? 10 : byteCount <= 62 ? 20 : 21); + return [[ZXAztecBinaryShiftToken alloc] initWithPrevious:self binaryShiftStart:start binaryShiftByteCount:byteCount]; +} + +- (void)appendTo:(ZXBitArray *)bitArray text:(ZXByteArray *)text { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)] + userInfo:nil]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/ZXCGImageLuminanceSource.h b/iDearQRCode/Tools/ZXingObjC/client/ZXCGImageLuminanceSource.h new file mode 100755 index 0000000..cfee4fb --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/ZXCGImageLuminanceSource.h @@ -0,0 +1,57 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import +#import "ZXLuminanceSource.h" + +@class ZXImage; + +@interface ZXCGImageLuminanceSource : ZXLuminanceSource + ++ (CGImageRef)createImageFromBuffer:(CVImageBufferRef)buffer CF_RETURNS_RETAINED; ++ (CGImageRef)createImageFromBuffer:(CVImageBufferRef)buffer + left:(size_t)left + top:(size_t)top + width:(size_t)width + height:(size_t)height CF_RETURNS_RETAINED; + +- (id)initWithZXImage:(ZXImage *)image + left:(size_t)left + top:(size_t)top + width:(size_t)width + height:(size_t)height; + +- (id)initWithZXImage:(ZXImage *)image; + +- (id)initWithCGImage:(CGImageRef)image + left:(size_t)left + top:(size_t)top + width:(size_t)width + height:(size_t)height; + +- (id)initWithCGImage:(CGImageRef)image; + +- (id)initWithBuffer:(CVPixelBufferRef)buffer + left:(size_t)left + top:(size_t)top + width:(size_t)width + height:(size_t)height; + +- (id)initWithBuffer:(CVPixelBufferRef)buffer; + +- (CGImageRef)image; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/ZXCGImageLuminanceSource.m b/iDearQRCode/Tools/ZXingObjC/client/ZXCGImageLuminanceSource.m new file mode 100755 index 0000000..2f65e9a --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/ZXCGImageLuminanceSource.m @@ -0,0 +1,308 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import +#import "ZXByteArray.h" +#import "ZXCGImageLuminanceSource.h" +#import "ZXImage.h" + +@interface ZXCGImageLuminanceSource () + +@property (nonatomic, assign, readonly) CGImageRef image; +@property (nonatomic, assign, readonly) int8_t *data; +@property (nonatomic, assign, readonly) size_t left; +@property (nonatomic, assign, readonly) size_t top; + +@end + +@implementation ZXCGImageLuminanceSource + ++ (CGImageRef)createImageFromBuffer:(CVImageBufferRef)buffer CF_RETURNS_RETAINED { + return [self createImageFromBuffer:buffer + left:0 + top:0 + width:CVPixelBufferGetWidth(buffer) + height:CVPixelBufferGetHeight(buffer)]; +} + ++ (CGImageRef)createImageFromBuffer:(CVImageBufferRef)buffer + left:(size_t)left + top:(size_t)top + width:(size_t)width + height:(size_t)height CF_RETURNS_RETAINED { + size_t bytesPerRow = CVPixelBufferGetBytesPerRow(buffer); + size_t dataWidth = CVPixelBufferGetWidth(buffer); + size_t dataHeight = CVPixelBufferGetHeight(buffer); + + if (left + width > dataWidth || + top + height > dataHeight) { + [NSException raise:NSInvalidArgumentException format:@"Crop rectangle does not fit within image data."]; + } + + size_t newBytesPerRow = ((width*4+0xf)>>4)<<4; + + CVPixelBufferLockBaseAddress(buffer,0); + + int8_t *baseAddress = (int8_t *)CVPixelBufferGetBaseAddress(buffer); + + size_t size = newBytesPerRow*height; + int8_t *bytes = (int8_t *)malloc(size * sizeof(int8_t)); + if (newBytesPerRow == bytesPerRow) { + memcpy(bytes, baseAddress+top*bytesPerRow, size * sizeof(int8_t)); + } else { + for (int y=0; y= self.height) { + [NSException raise:NSInvalidArgumentException format:@"Requested row is outside the image: %d", y]; + } + + if (!row || row.length < self.width) { + row = [[ZXByteArray alloc] initWithLength:self.width]; + } + int offset = y * self.width; + memcpy(row.array, self.data + offset, self.width * sizeof(int8_t)); + return row; +} + +- (ZXByteArray *)matrix { + int area = self.width * self.height; + + ZXByteArray *matrix = [[ZXByteArray alloc] initWithLength:area]; + memcpy(matrix.array, self.data, area * sizeof(int8_t)); + return matrix; +} + +- (void)initializeWithImage:(CGImageRef)cgimage left:(size_t)left top:(size_t)top width:(size_t)width height:(size_t)height { + _data = 0; + _image = CGImageRetain(cgimage); + _left = left; + _top = top; + size_t sourceWidth = CGImageGetWidth(cgimage); + size_t sourceHeight = CGImageGetHeight(cgimage); + size_t selfWidth = self.width; + size_t selfHeight= self.height; + + if (left + selfWidth > sourceWidth || + top + selfHeight > sourceHeight) { + [NSException raise:NSInvalidArgumentException format:@"Crop rectangle does not fit within image data."]; + } + + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + CGContextRef context = CGBitmapContextCreate(NULL, selfWidth, selfHeight, 8, selfWidth * 4, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedLast); + CGColorSpaceRelease(colorSpace); + + CGContextSetAllowsAntialiasing(context, FALSE); + CGContextSetInterpolationQuality(context, kCGInterpolationNone); + + if (top || left) { + CGContextClipToRect(context, CGRectMake(0, 0, selfWidth, selfHeight)); + } + + CGContextDrawImage(context, CGRectMake(-left, -top, selfWidth, selfHeight), self.image); + + uint32_t *pixelData = CGBitmapContextGetData(context); + + _data = (int8_t *)malloc(selfWidth * selfHeight * sizeof(int8_t)); + + dispatch_apply(selfHeight, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^(size_t idx) { + size_t stripe_start = idx * selfWidth; + size_t stripe_stop = stripe_start + selfWidth; + + for (size_t i = stripe_start; i < stripe_stop; i++) { + uint32_t rgbPixelIn = pixelData[i]; + uint32_t rgbPixelOut = 0; + + uint32_t red = (rgbPixelIn >> 24) & 0xFF; + uint32_t green = (rgbPixelIn >> 16) & 0xFF; + uint32_t blue = (rgbPixelIn >> 8) & 0xFF; + uint32_t alpha = (rgbPixelIn & 0xFF); + + // ImageIO premultiplies all PNGs, so we have to "un-premultiply them": + // http://code.google.com/p/cocos2d-iphone/issues/detail?id=697#c26 + if (alpha != 0xFF) { + red = red > 0 ? ((red << 20) / (alpha << 2)) >> 10 : 0; + green = green > 0 ? ((green << 20) / (alpha << 2)) >> 10 : 0; + blue = blue > 0 ? ((blue << 20) / (alpha << 2)) >> 10 : 0; + } + + if (red == green && green == blue) { + rgbPixelOut = red; + } else { + rgbPixelOut = (306 * red + + 601 * green + + 117 * blue + + (0x200)) >> 10; // 0x200 = 1<<9, half an lsb of the result to force rounding + } + + if (rgbPixelOut > 255) { + rgbPixelOut = 255; + } + + _data[i] = rgbPixelOut; + } + }); + + CGContextRelease(context); + + _top = top; + _left = left; +} + +- (BOOL)rotateSupported { + return YES; +} + +- (ZXLuminanceSource *)rotateCounterClockwise { + double radians = 270.0f * M_PI / 180; + +#if TARGET_OS_EMBEDDED || TARGET_IPHONE_SIMULATOR + radians = -1 * radians; +#endif + + int sourceWidth = self.width; + int sourceHeight = self.height; + + CGRect imgRect = CGRectMake(0, 0, sourceWidth, sourceHeight); + CGAffineTransform transform = CGAffineTransformMakeRotation(radians); + CGRect rotatedRect = CGRectApplyAffineTransform(imgRect, transform); + + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + CGContextRef context = CGBitmapContextCreate(NULL, + rotatedRect.size.width, + rotatedRect.size.height, + CGImageGetBitsPerComponent(self.image), + 0, + colorSpace, + kCGBitmapAlphaInfoMask & kCGImageAlphaPremultipliedFirst); + CGContextSetAllowsAntialiasing(context, FALSE); + CGContextSetInterpolationQuality(context, kCGInterpolationNone); + CGColorSpaceRelease(colorSpace); + + CGContextTranslateCTM(context, + +(rotatedRect.size.width/2), + +(rotatedRect.size.height/2)); + CGContextRotateCTM(context, radians); + + CGContextDrawImage(context, CGRectMake(-imgRect.size.width/2, + -imgRect.size.height/2, + imgRect.size.width, + imgRect.size.height), + self.image); + + CGImageRef rotatedImage = CGBitmapContextCreateImage(context); + + CFRelease(context); + + ZXCGImageLuminanceSource *result = [[ZXCGImageLuminanceSource alloc] initWithCGImage:rotatedImage + left:self.top + top:sourceWidth - (self.left + self.width) + width:self.height + height:self.width]; + + CGImageRelease(rotatedImage); + + return result; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/ZXCapture.h b/iDearQRCode/Tools/ZXingObjC/client/ZXCapture.h new file mode 100755 index 0000000..d8e529d --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/ZXCapture.h @@ -0,0 +1,60 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@protocol ZXCaptureDelegate, ZXReader; +@class ZXDecodeHints; + +@interface ZXCapture : NSObject + +@property (nonatomic, assign) int camera; +@property (nonatomic, strong) AVCaptureDevice *captureDevice; +@property (nonatomic, copy) NSString *captureToFilename; +@property (nonatomic, weak) id delegate; +@property (nonatomic, assign) AVCaptureFocusMode focusMode; +@property (nonatomic, strong) ZXDecodeHints *hints; +@property (nonatomic, assign) CGImageRef lastScannedImage; +@property (nonatomic, assign) BOOL invert; +@property (nonatomic, strong, readonly) CALayer *layer; +@property (nonatomic, assign) BOOL mirror; +@property (nonatomic, strong, readonly) AVCaptureVideoDataOutput *output; +@property (nonatomic, strong) id reader; +@property (nonatomic, assign) CGFloat rotation; +@property (nonatomic, assign, readonly) BOOL running; +@property (nonatomic, assign) CGRect scanRect; +@property (nonatomic, copy) NSString *sessionPreset; +@property (nonatomic, assign) BOOL torch; +@property (nonatomic, assign) CGAffineTransform transform; + +- (int)back; +- (int)front; +- (BOOL)hasBack; +- (BOOL)hasFront; +- (BOOL)hasTorch; + +- (CALayer *)binary; +- (void)setBinary:(BOOL)on_off; + +- (CALayer *)luminance; +- (void)setLuminance:(BOOL)on_off; + +- (void)hard_stop; +- (void)order_skip; +- (void)start; +- (void)stop; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/ZXCapture.m b/iDearQRCode/Tools/ZXingObjC/client/ZXCapture.m new file mode 100755 index 0000000..ec7139c --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/ZXCapture.m @@ -0,0 +1,544 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import +#import "ZXBinaryBitmap.h" +#import "ZXCapture.h" +#import "ZXCaptureDelegate.h" +#import "ZXCGImageLuminanceSource.h" +#import "ZXDecodeHints.h" +#import "ZXHybridBinarizer.h" +#import "ZXReader.h" +#import "ZXResult.h" + +@interface ZXCapture () + +@property (nonatomic, strong) CALayer *binaryLayer; +@property (nonatomic, assign) BOOL cameraIsReady; +@property (nonatomic, assign) int captureDeviceIndex; +@property (nonatomic, strong) dispatch_queue_t captureQueue; +@property (nonatomic, assign) BOOL hardStop; +@property (nonatomic, strong) AVCaptureDeviceInput *input; +@property (nonatomic, strong) AVCaptureVideoPreviewLayer *layer; +@property (nonatomic, strong) CALayer *luminanceLayer; +@property (nonatomic, assign) int orderInSkip; +@property (nonatomic, assign) int orderOutSkip; +@property (nonatomic, assign) BOOL onScreen; +@property (nonatomic, strong) AVCaptureVideoDataOutput *output; +@property (nonatomic, assign) BOOL running; +@property (nonatomic, strong) AVCaptureSession *session; + +@end + +@implementation ZXCapture + +- (ZXCapture *)init { + if (self = [super init]) { + _captureDeviceIndex = -1; + _captureQueue = dispatch_queue_create("com.zxing.captureQueue", NULL); + _focusMode = AVCaptureFocusModeContinuousAutoFocus; + _hardStop = NO; + _hints = [ZXDecodeHints hints]; + _lastScannedImage = NULL; + _onScreen = NO; + _orderInSkip = 0; + _orderOutSkip = 0; + + if (NSClassFromString(@"ZXMultiFormatReader")) { + _reader = [NSClassFromString(@"ZXMultiFormatReader") performSelector:@selector(reader)]; + } + + _rotation = 0.0f; + _running = NO; + _sessionPreset = AVCaptureSessionPresetMedium; + _transform = CGAffineTransformIdentity; + _scanRect = CGRectZero; + } + + return self; +} + +- (void)dealloc { + if (_lastScannedImage) { + CGImageRelease(_lastScannedImage); + } + + if (_session && _session.inputs) { + for (AVCaptureInput *input in _session.inputs) { + [_session removeInput:input]; + } + } + + if (_session && _session.outputs) { + for (AVCaptureOutput *output in _session.outputs) { + [_session removeOutput:output]; + } + } +} + +#pragma mark - Property Getters + +- (CALayer *)layer { + AVCaptureVideoPreviewLayer *layer = (AVCaptureVideoPreviewLayer *)_layer; + if (!_layer) { + layer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.session]; + layer.affineTransform = self.transform; + layer.delegate = self; + layer.videoGravity = AVLayerVideoGravityResizeAspect; + layer.videoGravity = AVLayerVideoGravityResizeAspectFill; + + _layer = layer; + } + return layer; +} + +- (AVCaptureVideoDataOutput *)output { + if (!_output) { + _output = [[AVCaptureVideoDataOutput alloc] init]; + [_output setVideoSettings:@{ + (NSString *)kCVPixelBufferPixelFormatTypeKey : [NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA] + }]; + [_output setAlwaysDiscardsLateVideoFrames:YES]; + [_output setSampleBufferDelegate:self queue:_captureQueue]; + + [self.session addOutput:_output]; + } + + return _output; +} + +#pragma mark - Property Setters + +- (void)setCamera:(int)camera { + if (_camera != camera) { + _camera = camera; + self.captureDeviceIndex = -1; + self.captureDevice = nil; + [self replaceInput]; + } +} + +- (void)setDelegate:(id)delegate { + _delegate = delegate; + + if (delegate) { + self.hardStop = NO; + } + [self startStop]; +} + +- (void)setFocusMode:(AVCaptureFocusMode)focusMode { + if ([self.input.device isFocusModeSupported:focusMode] && self.input.device.focusMode != focusMode) { + _focusMode = focusMode; + + [self.input.device lockForConfiguration:nil]; + self.input.device.focusMode = focusMode; + [self.input.device unlockForConfiguration]; + } +} + +- (void)setLastScannedImage:(CGImageRef)lastScannedImage { + if (_lastScannedImage) { + CGImageRelease(_lastScannedImage); + } + + if (lastScannedImage) { + CGImageRetain(lastScannedImage); + } + + _lastScannedImage = lastScannedImage; +} + +- (void)setMirror:(BOOL)mirror { + if (_mirror != mirror) { + _mirror = mirror; + if (self.layer) { + CGAffineTransform transform = self.transform; + transform.a = - transform.a; + self.transform = transform; + [self.layer setAffineTransform:self.transform]; + } + } +} + +- (void)setTorch:(BOOL)torch { + _torch = torch; + + [self.input.device lockForConfiguration:nil]; + self.input.device.torchMode = self.torch ? AVCaptureTorchModeOn : AVCaptureTorchModeOff; + [self.input.device unlockForConfiguration]; +} + +- (void)setTransform:(CGAffineTransform)transform { + _transform = transform; + [self.layer setAffineTransform:transform]; +} + +#pragma mark - Back, Front, Torch + +- (int)back { + return 1; +} + +- (int)front { + return 0; +} + +- (BOOL)hasFront { + NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; + return [devices count] > 1; +} + +- (BOOL)hasBack { + NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; + return [devices count] > 0; +} + +- (BOOL)hasTorch { + if ([self device]) { + return [self device].hasTorch; + } else { + return NO; + } +} + +#pragma mark - Binary + +- (CALayer *)binary { + return self.binaryLayer; +} + +- (void)setBinary:(BOOL)on { + if (on && !self.binaryLayer) { + self.binaryLayer = [CALayer layer]; + } else if (!on && self.binaryLayer) { + self.binaryLayer = nil; + } +} + +#pragma mark - Luminance + +- (CALayer *)luminance { + return self.luminanceLayer; +} + +- (void)setLuminance:(BOOL)on { + if (on && !self.luminanceLayer) { + self.luminanceLayer = [CALayer layer]; + } else if (!on && self.luminanceLayer) { + self.luminanceLayer = nil; + } +} + +#pragma mark - Start, Stop + +- (void)hard_stop { + self.hardStop = YES; + + if (self.running) { + [self stop]; + } +} + +- (void)order_skip { + self.orderInSkip = 1; + self.orderOutSkip = 1; +} + +- (void)start { + if (self.hardStop) { + return; + } + + if (self.delegate || self.luminanceLayer || self.binaryLayer) { + (void)[self output]; + } + + if (!self.session.running) { + static int i = 0; + if (++i == -2) { + abort(); + } + + [self.session startRunning]; + } + self.running = YES; +} + +- (void)stop { + if (!self.running) { + return; + } + + if (self.session.running) { + [self.session stopRunning]; + } + + self.running = NO; +} + +#pragma mark - CAAction + +- (id)actionForLayer:(CALayer *)_layer forKey:(NSString *)event { + [CATransaction setValue:[NSNumber numberWithFloat:0.0f] forKey:kCATransactionAnimationDuration]; + + if ([event isEqualToString:kCAOnOrderIn] || [event isEqualToString:kCAOnOrderOut]) { + return self; + } + + return nil; +} + +- (void)runActionForKey:(NSString *)key object:(id)anObject arguments:(NSDictionary *)dict { + if ([key isEqualToString:kCAOnOrderIn]) { + if (self.orderInSkip) { + self.orderInSkip--; + return; + } + + self.onScreen = YES; + [self startStop]; + } else if ([key isEqualToString:kCAOnOrderOut]) { + if (self.orderOutSkip) { + self.orderOutSkip--; + return; + } + + self.onScreen = NO; + [self startStop]; + } +} + +#pragma mark - AVCaptureVideoDataOutputSampleBufferDelegate + +- (void)captureOutput:(AVCaptureOutput *)captureOutput +didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer + fromConnection:(AVCaptureConnection *)connection { + if (!self.running) return; + + @autoreleasepool { + if (!self.cameraIsReady) { + self.cameraIsReady = YES; + if ([self.delegate respondsToSelector:@selector(captureCameraIsReady:)]) { + dispatch_async(dispatch_get_main_queue(), ^{ + [self.delegate captureCameraIsReady:self]; + }); + } + } + + if (!self.captureToFilename && !self.luminanceLayer && !self.binaryLayer && !self.delegate) { + return; + } + + CVImageBufferRef videoFrame = CMSampleBufferGetImageBuffer(sampleBuffer); + + CGImageRef videoFrameImage = [ZXCGImageLuminanceSource createImageFromBuffer:videoFrame]; + CGImageRef rotatedImage = [self createRotatedImage:videoFrameImage degrees:self.rotation]; + CGImageRelease(videoFrameImage); + + // If scanRect is set, crop the current image to include only the desired rect + if (!CGRectIsEmpty(self.scanRect)) { + CGImageRef croppedImage = CGImageCreateWithImageInRect(rotatedImage, self.scanRect); + CFRelease(rotatedImage); + rotatedImage = croppedImage; + } + + self.lastScannedImage = rotatedImage; + + if (self.captureToFilename) { + NSURL *url = [NSURL fileURLWithPath:self.captureToFilename]; + CGImageDestinationRef dest = CGImageDestinationCreateWithURL((__bridge CFURLRef)url, (__bridge CFStringRef)@"public.png", 1, nil); + CGImageDestinationAddImage(dest, rotatedImage, nil); + CGImageDestinationFinalize(dest); + CFRelease(dest); + self.captureToFilename = nil; + } + + ZXCGImageLuminanceSource *source = [[ZXCGImageLuminanceSource alloc] initWithCGImage:rotatedImage]; + CGImageRelease(rotatedImage); + + if (self.luminanceLayer) { + CGImageRef image = source.image; + CGImageRetain(image); + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0), dispatch_get_main_queue(), ^{ + self.luminanceLayer.contents = (__bridge id)image; + CGImageRelease(image); + }); + } + + if (self.binaryLayer || self.delegate) { + ZXHybridBinarizer *binarizer = [[ZXHybridBinarizer alloc] initWithSource:self.invert ? [source invert] : source]; + + if (self.binaryLayer) { + CGImageRef image = [binarizer createImage]; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0), dispatch_get_main_queue(), ^{ + self.binaryLayer.contents = (__bridge id)image; + CGImageRelease(image); + }); + } + + if (self.delegate) { + ZXBinaryBitmap *bitmap = [[ZXBinaryBitmap alloc] initWithBinarizer:binarizer]; + + NSError *error; + ZXResult *result = [self.reader decode:bitmap hints:self.hints error:&error]; + if (result) { + dispatch_async(dispatch_get_main_queue(), ^{ + [self.delegate captureResult:self result:result]; + }); + } + } + } + } +} + +#pragma mark - Private + +// Adapted from http://blog.coriolis.ch/2009/09/04/arbitrary-rotation-of-a-cgimage/ and https://github.com/JanX2/CreateRotateWriteCGImage +- (CGImageRef)createRotatedImage:(CGImageRef)original degrees:(float)degrees CF_RETURNS_RETAINED { + if (degrees == 0.0f) { + CGImageRetain(original); + return original; + } else { + double radians = degrees * M_PI / 180; + +#if TARGET_OS_EMBEDDED || TARGET_IPHONE_SIMULATOR + radians = -1 * radians; +#endif + + size_t _width = CGImageGetWidth(original); + size_t _height = CGImageGetHeight(original); + + CGRect imgRect = CGRectMake(0, 0, _width, _height); + CGAffineTransform __transform = CGAffineTransformMakeRotation(radians); + CGRect rotatedRect = CGRectApplyAffineTransform(imgRect, __transform); + + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + CGContextRef context = CGBitmapContextCreate(NULL, + rotatedRect.size.width, + rotatedRect.size.height, + CGImageGetBitsPerComponent(original), + 0, + colorSpace, + kCGBitmapAlphaInfoMask & kCGImageAlphaPremultipliedFirst); + CGContextSetAllowsAntialiasing(context, FALSE); + CGContextSetInterpolationQuality(context, kCGInterpolationNone); + CGColorSpaceRelease(colorSpace); + + CGContextTranslateCTM(context, + +(rotatedRect.size.width/2), + +(rotatedRect.size.height/2)); + CGContextRotateCTM(context, radians); + + CGContextDrawImage(context, CGRectMake(-imgRect.size.width/2, + -imgRect.size.height/2, + imgRect.size.width, + imgRect.size.height), + original); + + CGImageRef rotatedImage = CGBitmapContextCreateImage(context); + CFRelease(context); + + return rotatedImage; + } +} + +- (AVCaptureDevice *)device { + if (self.captureDevice) { + return self.captureDevice; + } + + AVCaptureDevice *zxd = nil; + + NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; + + if ([devices count] > 0) { + if (self.captureDeviceIndex == -1) { + AVCaptureDevicePosition position = AVCaptureDevicePositionBack; + if (self.camera == self.front) { + position = AVCaptureDevicePositionFront; + } + + for (unsigned int i = 0; i < [devices count]; ++i) { + AVCaptureDevice *dev = [devices objectAtIndex:i]; + if (dev.position == position) { + self.captureDeviceIndex = i; + zxd = dev; + break; + } + } + } + + if (!zxd && self.captureDeviceIndex != -1) { + zxd = [devices objectAtIndex:self.captureDeviceIndex]; + } + } + + if (!zxd) { + zxd = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; + } + + self.captureDevice = zxd; + + return zxd; +} + +- (void)replaceInput { + [self.session beginConfiguration]; + + if (self.session && self.input) { + [self.session removeInput:self.input]; + self.input = nil; + } + + AVCaptureDevice *zxd = [self device]; + + if (zxd) { + self.input = [AVCaptureDeviceInput deviceInputWithDevice:zxd error:nil]; + self.focusMode = self.focusMode; + } + + if (self.input) { + self.session.sessionPreset = self.sessionPreset; + [self.session addInput:self.input]; + } + + [self.session commitConfiguration]; +} + +- (AVCaptureSession *)session { + if (!_session) { + _session = [[AVCaptureSession alloc] init]; + [self replaceInput]; + } + + return _session; +} + +- (void)startStop { + if ((!self.running && (self.delegate || self.onScreen)) || + (!self.output && + (self.delegate || + (self.onScreen && (self.luminanceLayer || self.binaryLayer))))) { + [self start]; + } + + if (self.running && !self.delegate && !self.onScreen) { + [self stop]; + } +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/ZXCaptureDelegate.h b/iDearQRCode/Tools/ZXingObjC/client/ZXCaptureDelegate.h new file mode 100755 index 0000000..33a7f48 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/ZXCaptureDelegate.h @@ -0,0 +1,31 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXCapture; +@class ZXResult; + +@protocol ZXCaptureDelegate + +- (void)captureResult:(ZXCapture *)capture result:(ZXResult *)result; + +@optional +- (void)captureSize:(ZXCapture *)capture + width:(NSNumber *)width + height:(NSNumber *)height; + +- (void)captureCameraIsReady:(ZXCapture *)capture; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/ZXImage.h b/iDearQRCode/Tools/ZXingObjC/client/ZXImage.h new file mode 100755 index 0000000..03600c2 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/ZXImage.h @@ -0,0 +1,32 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class ZXBitMatrix; + +@interface ZXImage : NSObject + +@property (nonatomic, assign, readonly) CGImageRef cgimage; + +- (ZXImage *)initWithCGImageRef:(CGImageRef)image; +- (ZXImage *)initWithURL:(NSURL const *)url; +- (size_t)width; +- (size_t)height; ++ (ZXImage *)imageWithMatrix:(ZXBitMatrix *)matrix; ++ (ZXImage *)imageWithMatrix:(ZXBitMatrix *)matrix onColor:(CGColorRef)onColor offColor:(CGColorRef)offColor; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/ZXImage.m b/iDearQRCode/Tools/ZXingObjC/client/ZXImage.m new file mode 100755 index 0000000..7c09d6b --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/ZXImage.m @@ -0,0 +1,135 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitMatrix.h" +#import "ZXImage.h" + +#if TARGET_OS_EMBEDDED || TARGET_IPHONE_SIMULATOR +#import +#endif + +@implementation ZXImage + +- (ZXImage *)initWithCGImageRef:(CGImageRef)image { + if (self = [super init]) { + _cgimage = CGImageRetain(image); + } + + return self; +} + +- (ZXImage *)initWithURL:(NSURL const *)url { + if (self = [super init]) { + CGDataProviderRef provider = CGDataProviderCreateWithURL((__bridge CFURLRef)url); + + if (provider) { + CGImageSourceRef source = CGImageSourceCreateWithDataProvider(provider, 0); + + if (source) { + _cgimage = CGImageSourceCreateImageAtIndex(source, 0, 0); + CFRelease(source); + } + + CGDataProviderRelease(provider); + } + } + + return self; +} + +- (size_t)width { + return CGImageGetWidth(self.cgimage); +} + +- (size_t)height { + return CGImageGetHeight(self.cgimage); +} + +- (void)dealloc { + if (_cgimage) { + CGImageRelease(_cgimage); + } +} + ++ (ZXImage *)imageWithMatrix:(ZXBitMatrix *)matrix { + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray(); + + CGFloat blackComponents[] = {0.0f, 1.0f}; + CGColorRef black = CGColorCreate(colorSpace, blackComponents); + CGFloat whiteComponents[] = {1.0f, 1.0f}; + CGColorRef white = CGColorCreate(colorSpace, whiteComponents); + + CFRelease(colorSpace); + + ZXImage *result = [self imageWithMatrix:matrix onColor:black offColor:white]; + + CGColorRelease(white); + CGColorRelease(black); + + return result; +} + ++ (ZXImage *)imageWithMatrix:(ZXBitMatrix *)matrix onColor:(CGColorRef)onColor offColor:(CGColorRef)offColor { + int8_t onIntensities[4], offIntensities[4]; + + [self setColorIntensities:onIntensities color:onColor]; + [self setColorIntensities:offIntensities color:offColor]; + + int width = matrix.width; + int height = matrix.height; + int8_t *bytes = (int8_t *)malloc(width * height * 4); + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + BOOL bit = [matrix getX:x y:y]; + for (int i = 0; i < 4; i++) { + int8_t intensity = bit ? onIntensities[i] : offIntensities[i]; + bytes[y * width * 4 + x * 4 + i] = intensity; + } + } + } + + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + CGContextRef c = CGBitmapContextCreate(bytes, width, height, 8, 4 * width, colorSpace, kCGBitmapAlphaInfoMask & kCGImageAlphaPremultipliedLast); + CFRelease(colorSpace); + CGImageRef image = CGBitmapContextCreateImage(c); + CFRelease(c); + free(bytes); + + ZXImage *zxImage = [[ZXImage alloc] initWithCGImageRef:image]; + + CFRelease(image); + return zxImage; +} + ++ (void)setColorIntensities:(int8_t *)intensities color:(CGColorRef)color { + memset(intensities, 0, 4); + + size_t numberOfComponents = CGColorGetNumberOfComponents(color); + const CGFloat *components = CGColorGetComponents(color); + + if (numberOfComponents == 4) { + for (int i = 0; i < 4; i++) { + intensities[i] = components[i] * 255; + } + } else if (numberOfComponents == 2) { + for (int i = 0; i < 3; i++) { + intensities[i] = components[0] * 255; + } + intensities[3] = components[1] * 255; + } +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXAbstractDoCoMoResultParser.h b/iDearQRCode/Tools/ZXingObjC/client/result/ZXAbstractDoCoMoResultParser.h new file mode 100755 index 0000000..c1d10f7 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXAbstractDoCoMoResultParser.h @@ -0,0 +1,28 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXResultParser.h" + +/** + * See DoCoMo's documentation http://www.nttdocomo.co.jp/english/service/imode/make/content/barcode/about/s2.html + * about the result types represented by subclasses of this class. + */ +@interface ZXAbstractDoCoMoResultParser : ZXResultParser + ++ (NSArray *)matchDoCoMoPrefixedField:(NSString *)prefix rawText:(NSString *)rawText trim:(BOOL)trim; ++ (NSString *)matchSingleDoCoMoPrefixedField:(NSString *)prefix rawText:(NSString *)rawText trim:(BOOL)trim; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXAbstractDoCoMoResultParser.m b/iDearQRCode/Tools/ZXingObjC/client/result/ZXAbstractDoCoMoResultParser.m new file mode 100755 index 0000000..fc881b4 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXAbstractDoCoMoResultParser.m @@ -0,0 +1,29 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAbstractDoCoMoResultParser.h" + +@implementation ZXAbstractDoCoMoResultParser + ++ (NSArray *)matchDoCoMoPrefixedField:(NSString *)prefix rawText:(NSString *)rawText trim:(BOOL)trim { + return [self matchPrefixedField:prefix rawText:rawText endChar:';' trim:trim]; +} + ++ (NSString *)matchSingleDoCoMoPrefixedField:(NSString *)prefix rawText:(NSString *)rawText trim:(BOOL)trim { + return [self matchSinglePrefixedField:prefix rawText:rawText endChar:';' trim:trim]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXAddressBookAUResultParser.h b/iDearQRCode/Tools/ZXingObjC/client/result/ZXAddressBookAUResultParser.h new file mode 100755 index 0000000..33700ab --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXAddressBookAUResultParser.h @@ -0,0 +1,25 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXResultParser.h" + +/** + * Implements KDDI AU's address book format. See http://www.au.kddi.com/ezfactory/tec/two_dimensions/index.html. + * (Thanks to Yuzo for translating!) + */ +@interface ZXAddressBookAUResultParser : ZXResultParser + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXAddressBookAUResultParser.m b/iDearQRCode/Tools/ZXingObjC/client/result/ZXAddressBookAUResultParser.m new file mode 100755 index 0000000..4c9f7d8 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXAddressBookAUResultParser.m @@ -0,0 +1,80 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAddressBookAUResultParser.h" +#import "ZXAddressBookParsedResult.h" +#import "ZXResult.h" + +@implementation ZXAddressBookAUResultParser + +- (ZXParsedResult *)parse:(ZXResult *)result { + NSString *rawText = [ZXResultParser massagedText:result]; + + if ([rawText rangeOfString:@"MEMORY"].location == NSNotFound || + [rawText rangeOfString:@"\r\n"].location == NSNotFound) { + return nil; + } + + NSString *name = [[self class] matchSinglePrefixedField:@"NAME1:" rawText:rawText endChar:'\r' trim:YES]; + NSString *pronunciation = [[self class] matchSinglePrefixedField:@"NAME2:" rawText:rawText endChar:'\r' trim:YES]; + NSArray *phoneNumbers = [self matchMultipleValuePrefix:@"TEL" max:3 rawText:rawText trim:YES]; + NSArray *emails = [self matchMultipleValuePrefix:@"MAIL" max:3 rawText:rawText trim:YES]; + NSString *note = [[self class] matchSinglePrefixedField:@"MEMORY:" rawText:rawText endChar:'\r' trim:NO]; + NSString *address = [[self class] matchSinglePrefixedField:@"ADD:" rawText:rawText endChar:'\r' trim:YES]; + NSArray *addresses = address == nil ? nil : @[address]; + + return [ZXAddressBookParsedResult addressBookParsedResultWithNames:[self maybeWrap:name] + nicknames:nil + pronunciation:pronunciation + phoneNumbers:phoneNumbers + phoneTypes:nil + emails:emails + emailTypes:nil + instantMessenger:nil + note:note + addresses:addresses + addressTypes:nil + org:nil + birthday:nil + title:nil + urls:nil + geo:nil]; +} + +- (NSArray *)matchMultipleValuePrefix:(NSString *)prefix max:(int)max rawText:(NSString *)rawText trim:(BOOL)trim { + NSMutableArray *values = nil; + + for (int i = 1; i <= max; i++) { + NSString *value = [[self class] matchSinglePrefixedField:[NSString stringWithFormat:@"%@%d:", prefix, i] + rawText:rawText + endChar:'\r' + trim:trim]; + if (value == nil) { + break; + } + if (values == nil) { + values = [[NSMutableArray alloc] initWithCapacity:max]; + } + [values addObject:value]; + } + + if (values == nil) { + return nil; + } + return values; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXAddressBookDoCoMoResultParser.h b/iDearQRCode/Tools/ZXingObjC/client/result/ZXAddressBookDoCoMoResultParser.h new file mode 100755 index 0000000..daabf68 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXAddressBookDoCoMoResultParser.h @@ -0,0 +1,35 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAbstractDoCoMoResultParser.h" +#import "ZXResult.h" + +/** + * Implements the "MECARD" address book entry format. + * + * Supported keys: N, SOUND, TEL, EMAIL, NOTE, ADR, BDAY, URL, plus ORG + * Unsupported keys: TEL-AV, NICKNAME + * + * Except for TEL, multiple values for keys are also not supported; + * the first one found takes precedence. + * + * Our understanding of the MECARD format is based on this document: + * + * http://www.mobicode.org.tw/files/OMIA%20Mobile%20Bar%20Code%20Standard%20v3.2.1.doc + */ +@interface ZXAddressBookDoCoMoResultParser : ZXAbstractDoCoMoResultParser + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXAddressBookDoCoMoResultParser.m b/iDearQRCode/Tools/ZXingObjC/client/result/ZXAddressBookDoCoMoResultParser.m new file mode 100755 index 0000000..7357473 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXAddressBookDoCoMoResultParser.m @@ -0,0 +1,75 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAddressBookDoCoMoResultParser.h" +#import "ZXAddressBookParsedResult.h" +#import "ZXResult.h" + +@implementation ZXAddressBookDoCoMoResultParser + +- (ZXParsedResult *)parse:(ZXResult *)result { + NSString *rawText = [ZXResultParser massagedText:result]; + if (![rawText hasPrefix:@"MECARD:"]) { + return nil; + } + NSArray *rawName = [[self class] matchDoCoMoPrefixedField:@"N:" rawText:rawText trim:YES]; + if (rawName == nil) { + return nil; + } + NSString *name = [self parseName:rawName[0]]; + NSString *pronunciation = [[self class] matchSingleDoCoMoPrefixedField:@"SOUND:" rawText:rawText trim:YES]; + NSArray *phoneNumbers = [[self class] matchDoCoMoPrefixedField:@"TEL:" rawText:rawText trim:YES]; + NSArray *emails = [[self class] matchDoCoMoPrefixedField:@"EMAIL:" rawText:rawText trim:YES]; + NSString *note = [[self class] matchSingleDoCoMoPrefixedField:@"NOTE:" rawText:rawText trim:NO]; + NSArray *addresses = [[self class] matchDoCoMoPrefixedField:@"ADR:" rawText:rawText trim:YES]; + NSString *birthday = [[self class] matchSingleDoCoMoPrefixedField:@"BDAY:" rawText:rawText trim:YES]; + if (![[self class] isStringOfDigits:birthday length:8]) { + birthday = nil; + } + NSArray *urls = [[self class] matchDoCoMoPrefixedField:@"URL:" rawText:rawText trim:YES]; + + // Although ORG may not be strictly legal in MECARD, it does exist in VCARD and we might as well + // honor it when found in the wild. + NSString *org = [[self class] matchSingleDoCoMoPrefixedField:@"ORG:" rawText:rawText trim:YES]; + + return [ZXAddressBookParsedResult addressBookParsedResultWithNames:[self maybeWrap:name] + nicknames:nil + pronunciation:pronunciation + phoneNumbers:phoneNumbers + phoneTypes:nil + emails:emails + emailTypes:nil + instantMessenger:nil + note:note + addresses:addresses + addressTypes:nil + org:org + birthday:birthday + title:nil + urls:urls + geo:nil]; +} + +- (NSString *)parseName:(NSString *)name { + NSUInteger comma = [name rangeOfString:@","].location; + if (comma != NSNotFound) { + // Format may be last,first; switch it around + return [NSString stringWithFormat:@"%@ %@", [name substringFromIndex:comma + 1], [name substringToIndex:comma]]; + } + return name; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXAddressBookParsedResult.h b/iDearQRCode/Tools/ZXingObjC/client/result/ZXAddressBookParsedResult.h new file mode 100755 index 0000000..b05748f --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXAddressBookParsedResult.h @@ -0,0 +1,93 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXParsedResult.h" + +@interface ZXAddressBookParsedResult : ZXParsedResult + +@property (nonatomic, readonly, strong) NSArray *names; +@property (nonatomic, readonly, strong) NSArray *nicknames; + +/** + * In Japanese, the name is written in kanji, which can have multiple readings. Therefore a hint + * is often provided, called furigana, which spells the name phonetically. + * + * @return The pronunciation of the names property, often in hiragana or katakana. + */ +@property (nonatomic, readonly, copy) NSString *pronunciation; + +@property (nonatomic, readonly, strong) NSArray *phoneNumbers; + +/** + * @return optional descriptions of the type of each phone number. It could be like "HOME", but, + * there is no guaranteed or standard format. + */ +@property (nonatomic, readonly, strong) NSArray *phoneTypes; + +@property (nonatomic, readonly, strong) NSArray *emails; + +/** + * @return optional descriptions of the type of each e-mail. It could be like "WORK", but, + * there is no guaranteed or standard format. + */ +@property (nonatomic, readonly, strong) NSArray *emailTypes; + +@property (nonatomic, readonly, copy) NSString *instantMessenger; +@property (nonatomic, readonly, copy) NSString *note; +@property (nonatomic, readonly, strong) NSArray *addresses; + +/** + * @return optional descriptions of the type of each e-mail. It could be like "WORK", but, + * there is no guaranteed or standard format. + */ +@property (nonatomic, readonly, strong) NSArray *addressTypes; + +@property (nonatomic, readonly, copy) NSString *title; +@property (nonatomic, readonly, copy) NSString *org; +@property (nonatomic, readonly, strong) NSArray *urls; + +/** + * @return birthday formatted as yyyyMMdd (e.g. 19780917) + */ +@property (nonatomic, readonly, copy) NSString *birthday; + +/** + * @return a location as a latitude/longitude pair + */ +@property (nonatomic, readonly, strong) NSArray *geo; + +- (id)initWithNames:(NSArray *)names phoneNumbers:(NSArray *)phoneNumbers + phoneTypes:(NSArray *)phoneTypes emails:(NSArray *)emails emailTypes:(NSArray *)emailTypes + addresses:(NSArray *)addresses addressTypes:(NSArray *)addressTypes; + +- (id)initWithNames:(NSArray *)names nicknames:(NSArray *)nicknames pronunciation:(NSString *)pronunciation + phoneNumbers:(NSArray *)phoneNumbers phoneTypes:(NSArray *)phoneTypes emails:(NSArray *)emails + emailTypes:(NSArray *)emailTypes instantMessenger:(NSString *)instantMessenger note:(NSString *)note + addresses:(NSArray *)addresses addressTypes:(NSArray *)addressTypes org:(NSString *)org + birthday:(NSString *)birthday title:(NSString *)title urls:(NSArray *)urls geo:(NSArray *)geo; + ++ (id)addressBookParsedResultWithNames:(NSArray *)names phoneNumbers:(NSArray *)phoneNumbers + phoneTypes:(NSArray *)phoneTypes emails:(NSArray *)emails emailTypes:(NSArray *)emailTypes + addresses:(NSArray *)addresses addressTypes:(NSArray *)addressTypes; + ++ (id)addressBookParsedResultWithNames:(NSArray *)names nicknames:(NSArray *)nicknames + pronunciation:(NSString *)pronunciation phoneNumbers:(NSArray *)phoneNumbers + phoneTypes:(NSArray *)phoneTypes emails:(NSArray *)emails emailTypes:(NSArray *)emailTypes + instantMessenger:(NSString *)instantMessenger note:(NSString *)note addresses:(NSArray *)addresses + addressTypes:(NSArray *)addressTypes org:(NSString *)org birthday:(NSString *)birthday + title:(NSString *)title urls:(NSArray *)urls geo:(NSArray *)geo; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXAddressBookParsedResult.m b/iDearQRCode/Tools/ZXingObjC/client/result/ZXAddressBookParsedResult.m new file mode 100755 index 0000000..13a5e24 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXAddressBookParsedResult.m @@ -0,0 +1,94 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAddressBookParsedResult.h" +#import "ZXParsedResultType.h" + +@implementation ZXAddressBookParsedResult + +- (id)initWithNames:(NSArray *)names phoneNumbers:(NSArray *)phoneNumbers + phoneTypes:(NSArray *)phoneTypes emails:(NSArray *)emails emailTypes:(NSArray *)emailTypes + addresses:(NSArray *)addresses addressTypes:(NSArray *)addressTypes { + return [self initWithNames:names nicknames:nil pronunciation:nil phoneNumbers:phoneNumbers phoneTypes:phoneNumbers + emails:emails emailTypes:_emailTypes instantMessenger:nil note:nil addresses:addresses + addressTypes:addressTypes org:nil birthday:nil title:nil urls:nil geo:nil]; +} + +- (id)initWithNames:(NSArray *)names nicknames:(NSArray *)nicknames pronunciation:(NSString *)pronunciation + phoneNumbers:(NSArray *)phoneNumbers phoneTypes:(NSArray *)phoneTypes emails:(NSArray *)emails + emailTypes:(NSArray *)emailTypes instantMessenger:(NSString *)instantMessenger note:(NSString *)note + addresses:(NSArray *)addresses addressTypes:(NSArray *)addressTypes org:(NSString *)org + birthday:(NSString *)birthday title:(NSString *)title urls:(NSArray *)urls geo:(NSArray *)geo { + if (self = [super initWithType:kParsedResultTypeAddressBook]) { + _names = names; + _nicknames = nicknames; + _pronunciation = pronunciation; + _phoneNumbers = phoneNumbers; + _phoneTypes = phoneTypes; + _emails = emails; + _emailTypes = emailTypes; + _instantMessenger = instantMessenger; + _note = note; + _addresses = addresses; + _addressTypes = addressTypes; + _org = org; + _birthday = birthday; + _title = title; + _urls = urls; + _geo = geo; + } + + return self; +} + ++ (id)addressBookParsedResultWithNames:(NSArray *)names phoneNumbers:(NSArray *)phoneNumbers + phoneTypes:(NSArray *)phoneTypes emails:(NSArray *)emails emailTypes:(NSArray *)emailTypes + addresses:(NSArray *)addresses addressTypes:(NSArray *)addressTypes { + return [[self alloc] initWithNames:names phoneNumbers:phoneNumbers phoneTypes:phoneTypes emails:emails + emailTypes:emailTypes addresses:addresses addressTypes:addressTypes]; +} + ++ (id)addressBookParsedResultWithNames:(NSArray *)names nicknames:(NSArray *)nicknames + pronunciation:(NSString *)pronunciation phoneNumbers:(NSArray *)phoneNumbers + phoneTypes:(NSArray *)phoneTypes emails:(NSArray *)emails emailTypes:(NSArray *)emailTypes + instantMessenger:(NSString *)instantMessenger note:(NSString *)note addresses:(NSArray *)addresses + addressTypes:(NSArray *)addressTypes org:(NSString *)org birthday:(NSString *)birthday + title:(NSString *)title urls:(NSArray *)urls geo:(NSArray *)geo { + return [[self alloc] initWithNames:names nicknames:nicknames pronunciation:pronunciation phoneNumbers:phoneNumbers + phoneTypes:phoneTypes emails:emails emailTypes:emailTypes instantMessenger:instantMessenger + note:note addresses:addresses addressTypes:addressTypes org:org birthday:birthday + title:title urls:urls geo:geo]; +} + +- (NSString *)displayResult { + NSMutableString *result = [NSMutableString string]; + [ZXParsedResult maybeAppendArray:self.names result:result]; + [ZXParsedResult maybeAppendArray:self.nicknames result:result]; + [ZXParsedResult maybeAppend:self.pronunciation result:result]; + [ZXParsedResult maybeAppend:self.title result:result]; + [ZXParsedResult maybeAppend:self.org result:result]; + [ZXParsedResult maybeAppendArray:self.addresses result:result]; + [ZXParsedResult maybeAppendArray:self.phoneNumbers result:result]; + [ZXParsedResult maybeAppendArray:self.emails result:result]; + [ZXParsedResult maybeAppend:self.instantMessenger result:result]; + [ZXParsedResult maybeAppendArray:self.urls result:result]; + [ZXParsedResult maybeAppend:self.birthday result:result]; + [ZXParsedResult maybeAppendArray:self.geo result:result]; + [ZXParsedResult maybeAppend:self.note result:result]; + return result; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXBizcardResultParser.h b/iDearQRCode/Tools/ZXingObjC/client/result/ZXBizcardResultParser.h new file mode 100755 index 0000000..00eae58 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXBizcardResultParser.h @@ -0,0 +1,26 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAbstractDoCoMoResultParser.h" + +/** + * Implements the "BIZCARD" address book entry format, though this has been + * largely reverse-engineered from examples observed in the wild -- still + * looking for a definitive reference. + */ +@interface ZXBizcardResultParser : ZXAbstractDoCoMoResultParser + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXBizcardResultParser.m b/iDearQRCode/Tools/ZXingObjC/client/result/ZXBizcardResultParser.m new file mode 100755 index 0000000..f6a297c --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXBizcardResultParser.m @@ -0,0 +1,87 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAddressBookParsedResult.h" +#import "ZXBizcardResultParser.h" +#import "ZXResult.h" + +@implementation ZXBizcardResultParser + +- (ZXParsedResult *)parse:(ZXResult *)result { + NSString *rawText = [ZXResultParser massagedText:result]; + if (![rawText hasPrefix:@"BIZCARD:"]) { + return nil; + } + NSString *firstName = [[self class] matchSingleDoCoMoPrefixedField:@"N:" rawText:rawText trim:YES]; + NSString *lastName = [[self class] matchSingleDoCoMoPrefixedField:@"X:" rawText:rawText trim:YES]; + NSString *fullName = [self buildName:firstName lastName:lastName]; + NSString *title = [[self class] matchSingleDoCoMoPrefixedField:@"T:" rawText:rawText trim:YES]; + NSString *org = [[self class] matchSingleDoCoMoPrefixedField:@"C:" rawText:rawText trim:YES]; + NSArray *addresses = [[self class] matchDoCoMoPrefixedField:@"A:" rawText:rawText trim:YES]; + NSString *phoneNumber1 = [[self class] matchSingleDoCoMoPrefixedField:@"B:" rawText:rawText trim:YES]; + NSString *phoneNumber2 = [[self class] matchSingleDoCoMoPrefixedField:@"M:" rawText:rawText trim:YES]; + NSString *phoneNumber3 = [[self class] matchSingleDoCoMoPrefixedField:@"F:" rawText:rawText trim:YES]; + NSString *email = [[self class] matchSingleDoCoMoPrefixedField:@"E:" rawText:rawText trim:YES]; + + return [ZXAddressBookParsedResult addressBookParsedResultWithNames:[self maybeWrap:fullName] + nicknames:nil + pronunciation:nil + phoneNumbers:[self buildPhoneNumbers:phoneNumber1 number2:phoneNumber2 number3:phoneNumber3] + phoneTypes:nil + emails:[self maybeWrap:email] + emailTypes:nil + instantMessenger:nil + note:nil + addresses:addresses + addressTypes:nil + org:org + birthday:nil + title:title + urls:nil + geo:nil]; +} + +- (NSArray *)buildPhoneNumbers:(NSString *)number1 number2:(NSString *)number2 number3:(NSString *)number3 { + NSMutableArray *numbers = [NSMutableArray arrayWithCapacity:3]; + if (number1 != nil) { + [numbers addObject:number1]; + } + if (number2 != nil) { + [numbers addObject:number2]; + } + if (number3 != nil) { + [numbers addObject:number3]; + } + NSUInteger size = [numbers count]; + if (size == 0) { + return nil; + } + NSMutableArray *result = [NSMutableArray arrayWithCapacity:size]; + for (int i = 0; i < size; i++) { + [result addObject:numbers[i]]; + } + return result; +} + +- (NSString *)buildName:(NSString *)firstName lastName:(NSString *)lastName { + if (firstName == nil) { + return lastName; + } else { + return lastName == nil ? firstName : [[firstName stringByAppendingString:@" "] stringByAppendingString:lastName]; + } +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXBookmarkDoCoMoResultParser.h b/iDearQRCode/Tools/ZXingObjC/client/result/ZXBookmarkDoCoMoResultParser.h new file mode 100755 index 0000000..bb9ca2d --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXBookmarkDoCoMoResultParser.h @@ -0,0 +1,21 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAbstractDoCoMoResultParser.h" + +@interface ZXBookmarkDoCoMoResultParser : ZXAbstractDoCoMoResultParser + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXBookmarkDoCoMoResultParser.m b/iDearQRCode/Tools/ZXingObjC/client/result/ZXBookmarkDoCoMoResultParser.m new file mode 100755 index 0000000..50f50a5 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXBookmarkDoCoMoResultParser.m @@ -0,0 +1,41 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBookmarkDoCoMoResultParser.h" +#import "ZXResult.h" +#import "ZXURIParsedResult.h" +#import "ZXURIResultParser.h" + +@implementation ZXBookmarkDoCoMoResultParser + +- (ZXParsedResult *)parse:(ZXResult *)result { + NSString *rawText = [result text]; + if (![rawText hasPrefix:@"MEBKM:"]) { + return nil; + } + NSString *title = [[self class] matchSingleDoCoMoPrefixedField:@"TITLE:" rawText:rawText trim:YES]; + NSArray *rawUri = [[self class] matchDoCoMoPrefixedField:@"URL:" rawText:rawText trim:YES]; + if (rawUri == nil) { + return nil; + } + NSString *uri = rawUri[0]; + if (![ZXURIResultParser isBasicallyValidURI:uri]) { + return nil; + } + return [ZXURIParsedResult uriParsedResultWithUri:uri title:title]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXCalendarParsedResult.h b/iDearQRCode/Tools/ZXingObjC/client/result/ZXCalendarParsedResult.h new file mode 100755 index 0000000..c9f665e --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXCalendarParsedResult.h @@ -0,0 +1,43 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXParsedResult.h" + +@interface ZXCalendarParsedResult : ZXParsedResult + +@property (nonatomic, copy, readonly) NSString *summary; +@property (nonatomic, strong, readonly) NSDate *start; +@property (nonatomic, assign, readonly) BOOL startAllDay; +@property (nonatomic, strong, readonly) NSDate *end; +@property (nonatomic, assign, readonly) BOOL endAllDay; +@property (nonatomic, copy, readonly) NSString *location; +@property (nonatomic, copy, readonly) NSString *organizer; +@property (nonatomic, strong, readonly) NSArray *attendees; +@property (nonatomic, copy, readonly) NSString *resultDescription; +@property (nonatomic, assign, readonly) double latitude; +@property (nonatomic, assign, readonly) double longitude; + +- (id)initWithSummary:(NSString *)summary startString:(NSString *)startString endString:(NSString *)endString + durationString:(NSString *)durationString location:(NSString *)location organizer:(NSString *)organizer + attendees:(NSArray *)attendees description:(NSString *)description latitude:(double)latitude + longitude:(double)longitude; ++ (id)calendarParsedResultWithSummary:(NSString *)summary startString:(NSString *)startString + endString:(NSString *)endString durationString:(NSString *)durationString + location:(NSString *)location organizer:(NSString *)organizer + attendees:(NSArray *)attendees description:(NSString *)description latitude:(double)latitude + longitude:(double)longitude; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXCalendarParsedResult.m b/iDearQRCode/Tools/ZXingObjC/client/result/ZXCalendarParsedResult.m new file mode 100755 index 0000000..d439c3a --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXCalendarParsedResult.m @@ -0,0 +1,164 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXCalendarParsedResult.h" + +static NSRegularExpression *ZX_DATE_TIME = nil; +static NSRegularExpression *ZX_RFC2445_DURATION = nil; + +const long ZX_RFC2445_DURATION_FIELD_UNITS[] = { + 7 * 24 * 60 * 60 * 1000, // 1 week + 24 * 60 * 60 * 1000, // 1 day + 60 * 60 * 1000, // 1 hour + 60 * 1000, // 1 minute + 1000, // 1 second +}; + +@implementation ZXCalendarParsedResult + ++ (void)initialize { + if ([self class] != [ZXCalendarParsedResult class]) return; + + ZX_DATE_TIME = [[NSRegularExpression alloc] initWithPattern:@"[0-9]{8}(T[0-9]{6}Z?)?" + options:0 + error:nil]; + + ZX_RFC2445_DURATION = [[NSRegularExpression alloc] initWithPattern:@"P(?:(\\d+)W)?(?:(\\d+)D)?(?:T(?:(\\d+)H)?(?:(\\d+)M)?(?:(\\d+)S)?)?" + options:NSRegularExpressionCaseInsensitive + error:nil]; +} + +- (id)initWithSummary:(NSString *)summary startString:(NSString *)startString endString:(NSString *)endString + durationString:(NSString *)durationString location:(NSString *)location organizer:(NSString *)organizer + attendees:(NSArray *)attendees description:(NSString *)description latitude:(double)latitude + longitude:(double)longitude { + if (self = [super initWithType:kParsedResultTypeCalendar]) { + _summary = summary; + _start = [self parseDate:startString]; + + if (endString == nil) { + long durationMS = [self parseDurationMS:durationString]; + _end = durationMS < 0 ? nil : [NSDate dateWithTimeIntervalSince1970:[_start timeIntervalSince1970] + durationMS / 1000]; + } else { + _end = [self parseDate:endString]; + } + + _startAllDay = startString.length == 8; + _endAllDay = endString != nil && endString.length == 8; + + _location = location; + _organizer = organizer; + _attendees = attendees; + _resultDescription = description; + _latitude = latitude; + _longitude = longitude; + } + return self; +} + ++ (id)calendarParsedResultWithSummary:(NSString *)summary startString:(NSString *)startString + endString:(NSString *)endString durationString:(NSString *)durationString + location:(NSString *)location organizer:(NSString *)organizer + attendees:(NSArray *)attendees description:(NSString *)description latitude:(double)latitude + longitude:(double)longitude { + return [[self alloc] initWithSummary:summary startString:startString endString:endString durationString:durationString + location:location organizer:organizer attendees:attendees description:description + latitude:latitude longitude:longitude]; +} + +- (NSString *)displayResult { + NSMutableString *result = [NSMutableString stringWithCapacity:100]; + [ZXParsedResult maybeAppend:self.summary result:result]; + [ZXParsedResult maybeAppend:[self format:self.startAllDay date:self.start] result:result]; + [ZXParsedResult maybeAppend:[self format:self.endAllDay date:self.end] result:result]; + [ZXParsedResult maybeAppend:self.location result:result]; + [ZXParsedResult maybeAppend:self.organizer result:result]; + [ZXParsedResult maybeAppendArray:self.attendees result:result]; + [ZXParsedResult maybeAppend:self.description result:result]; + return result; +} + +/** + * Parses a string as a date. RFC 2445 allows the start and end fields to be of type DATE (e.g. 20081021) + * or DATE-TIME (e.g. 20081021T123000 for local time, or 20081021T123000Z for UTC). + */ +- (NSDate *)parseDate:(NSString *)when { + NSArray *matches = [ZX_DATE_TIME matchesInString:when options:0 range:NSMakeRange(0, when.length)]; + if (matches.count == 0) { + [NSException raise:NSInvalidArgumentException + format:@"Invalid date"]; + } + if (when.length == 8) { + // Show only year/month/day + return [[self buildDateFormat] dateFromString:when]; + } else { + // The when string can be local time, or UTC if it ends with a Z + if (when.length == 16 && [when characterAtIndex:15] == 'Z') { + return [[self buildDateTimeFormat] dateFromString:[when substringToIndex:15]]; + } else { + return [[self buildDateTimeFormat] dateFromString:when]; + } + } +} + +- (NSString *)format:(BOOL)allDay date:(NSDate *)date { + if (date == nil) { + return nil; + } + NSDateFormatter *format = [[NSDateFormatter alloc] init]; + format.dateFormat = allDay ? @"MMM d, yyyy" : @"MMM d, yyyy hh:mm:ss a"; + return [format stringFromDate:date]; +} + +- (long)parseDurationMS:(NSString *)durationString { + if (durationString == nil) { + return -1; + } + NSArray *m = [ZX_RFC2445_DURATION matchesInString:durationString options:0 range:NSMakeRange(0, durationString.length)]; + if (m.count == 0) { + return -1; + } + long durationMS = 0; + NSTextCheckingResult *match = m[0]; + for (int i = 0; i < sizeof(ZX_RFC2445_DURATION_FIELD_UNITS) / sizeof(long); i++) { + if ([match rangeAtIndex:i + 1].location != NSNotFound) { + NSString *fieldValue = [durationString substringWithRange:[match rangeAtIndex:i + 1]]; + if (fieldValue != nil) { + durationMS += ZX_RFC2445_DURATION_FIELD_UNITS[i] * [fieldValue intValue]; + } + } + } + return durationMS; +} + +- (NSDateFormatter *)buildDateFormat { + NSDateFormatter *format = [[NSDateFormatter alloc] init]; + format.dateFormat = @"yyyyMMdd"; + format.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"]; + return format; +} + +- (NSDateFormatter *)buildDateTimeFormat { + NSDateFormatter *format = [[NSDateFormatter alloc] init]; + format.dateFormat = @"yyyyMMdd'T'HHmmss"; + return format; +} + +- (NSString *)description { + return self.resultDescription; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXEmailAddressParsedResult.h b/iDearQRCode/Tools/ZXingObjC/client/result/ZXEmailAddressParsedResult.h new file mode 100755 index 0000000..0dd30ff --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXEmailAddressParsedResult.h @@ -0,0 +1,46 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXParsedResult.h" + +@interface ZXEmailAddressParsedResult : ZXParsedResult + +@property (nonatomic, copy, readonly) NSArray *tos; +@property (nonatomic, copy, readonly) NSArray *ccs; +@property (nonatomic, copy, readonly) NSArray *bccs; +@property (nonatomic, copy, readonly) NSString *subject; +@property (nonatomic, copy, readonly) NSString *body; + +/** + * @return first elements of tos or nil if none + * @deprecated use tos + */ +@property (nonatomic, copy, readonly) NSString *emailAddress DEPRECATED_ATTRIBUTE; + +/** + * @return "mailto:" + * @deprecated without replacement + */ +@property (nonatomic, copy, readonly) NSString *mailtoURI DEPRECATED_ATTRIBUTE; + +- (id)initWithTo:(NSString *)to; +- (id)initWithTos:(NSArray *)tos + ccs:(NSArray *)ccs + bccs:(NSArray *)bccs + subject:(NSString *)subject + body:(NSString *)body; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXEmailAddressParsedResult.m b/iDearQRCode/Tools/ZXingObjC/client/result/ZXEmailAddressParsedResult.m new file mode 100755 index 0000000..f56f215 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXEmailAddressParsedResult.m @@ -0,0 +1,60 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXEmailAddressParsedResult.h" +#import "ZXParsedResultType.h" + +@implementation ZXEmailAddressParsedResult + +- (id)initWithTo:(NSString *)to { + return [self initWithTos:@[to] ccs:nil bccs:nil subject:nil body:nil]; +} + +- (id)initWithTos:(NSArray *)tos + ccs:(NSArray *)ccs + bccs:(NSArray *)bccs + subject:(NSString *)subject + body:(NSString *)body { + if (self = [super initWithType:kParsedResultTypeEmailAddress]) { + _tos = tos; + _ccs = ccs; + _bccs = bccs; + _subject = subject; + _body = body; + } + + return self; +} + +- (NSString *)emailAddress { + return !self.tos || self.tos.count == 0 ? nil : self.tos[0]; +} + +- (NSString *)mailtoURI { + return @"mailto:"; +} + +- (NSString *)displayResult { + NSMutableString *result = [NSMutableString stringWithCapacity:30]; + [ZXParsedResult maybeAppendArray:self.tos result:result]; + [ZXParsedResult maybeAppendArray:self.ccs result:result]; + [ZXParsedResult maybeAppendArray:self.bccs result:result]; + [ZXParsedResult maybeAppend:self.subject result:result]; + [ZXParsedResult maybeAppend:self.body result:result]; + return result; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXEmailAddressResultParser.h b/iDearQRCode/Tools/ZXingObjC/client/result/ZXEmailAddressResultParser.h new file mode 100755 index 0000000..2e7e765 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXEmailAddressResultParser.h @@ -0,0 +1,25 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXResultParser.h" + +/** + * Represents a result that encodes an e-mail address, either as a plain address + * like "joe@example.org" or a mailto: URL like "mailto:joe@example.org". + */ +@interface ZXEmailAddressResultParser : ZXResultParser + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXEmailAddressResultParser.m b/iDearQRCode/Tools/ZXingObjC/client/result/ZXEmailAddressResultParser.m new file mode 100755 index 0000000..9bfb324 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXEmailAddressResultParser.m @@ -0,0 +1,78 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXEmailAddressParsedResult.h" +#import "ZXEmailAddressResultParser.h" +#import "ZXEmailDoCoMoResultParser.h" +#import "ZXResult.h" + +static NSCharacterSet *ZX_EMAIL_ADDRESS_RESULT_COMMA = nil; + +@implementation ZXEmailAddressResultParser + ++ (void)initialize { + if ([self class] != [ZXEmailAddressResultParser class]) return; + + ZX_EMAIL_ADDRESS_RESULT_COMMA = [NSCharacterSet characterSetWithCharactersInString:@","]; +} + +- (ZXParsedResult *)parse:(ZXResult *)result { + NSString *rawText = [ZXResultParser massagedText:result]; + if ([rawText hasPrefix:@"mailto:"] || [rawText hasPrefix:@"MAILTO:"]) { + // If it starts with mailto:, assume it is definitely trying to be an email address + NSString *hostEmail = [rawText substringFromIndex:7]; + NSUInteger queryStart = [hostEmail rangeOfString:@"?"].location; + if (queryStart != NSNotFound) { + hostEmail = [hostEmail substringToIndex:queryStart]; + } + hostEmail = [[self class] urlDecode:hostEmail]; + NSArray *tos; + if (hostEmail.length > 0) { + tos = [hostEmail componentsSeparatedByCharactersInSet:ZX_EMAIL_ADDRESS_RESULT_COMMA]; + } + NSMutableDictionary *nameValues = [self parseNameValuePairs:rawText]; + NSArray *ccs; + NSArray *bccs; + NSString *subject = nil; + NSString *body = nil; + if (nameValues != nil) { + if (!tos) { + NSString *tosString = nameValues[@"to"]; + if (tosString) { + tos = [tosString componentsSeparatedByCharactersInSet:ZX_EMAIL_ADDRESS_RESULT_COMMA]; + } + } + NSString *ccString = nameValues[@"cc"]; + if (ccString) { + ccs = [ccString componentsSeparatedByCharactersInSet:ZX_EMAIL_ADDRESS_RESULT_COMMA]; + } + NSString *bccString = nameValues[@"bcc"]; + if (bccString) { + bccs = [bccString componentsSeparatedByCharactersInSet:ZX_EMAIL_ADDRESS_RESULT_COMMA]; + } + subject = nameValues[@"subject"]; + body = nameValues[@"body"]; + } + return [[ZXEmailAddressParsedResult alloc] initWithTos:tos ccs:ccs bccs:bccs subject:subject body:body]; + } else { + if (![ZXEmailDoCoMoResultParser isBasicallyValidEmailAddress:rawText]) { + return nil; + } + return [[ZXEmailAddressParsedResult alloc] initWithTo:rawText]; + } +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXEmailDoCoMoResultParser.h b/iDearQRCode/Tools/ZXingObjC/client/result/ZXEmailDoCoMoResultParser.h new file mode 100755 index 0000000..631be8e --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXEmailDoCoMoResultParser.h @@ -0,0 +1,34 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAbstractDoCoMoResultParser.h" + +/** + * Implements the "MATMSG" email message entry format. + * + * Supported keys: TO, SUB, BODY + */ +@interface ZXEmailDoCoMoResultParser : ZXAbstractDoCoMoResultParser + +/** + * This implements only the most basic checking for an email address's validity -- that it contains + * an '@' and contains no characters disallowed by RFC 2822. This is an overly lenient definition of + * validity. We want to generally be lenient here since this class is only intended to encapsulate what's + * in a barcode, not "judge" it. + */ ++ (BOOL)isBasicallyValidEmailAddress:(NSString *)email; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXEmailDoCoMoResultParser.m b/iDearQRCode/Tools/ZXingObjC/client/result/ZXEmailDoCoMoResultParser.m new file mode 100755 index 0000000..c8ca5d3 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXEmailDoCoMoResultParser.m @@ -0,0 +1,56 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXEmailAddressParsedResult.h" +#import "ZXEmailDoCoMoResultParser.h" +#import "ZXResult.h" + +static NSRegularExpression *ZX_ATEXT_ALPHANUMERIC = nil; + +@implementation ZXEmailDoCoMoResultParser + ++ (void)initialize { + if ([self class] != [ZXEmailDoCoMoResultParser class]) return; + + ZX_ATEXT_ALPHANUMERIC = [[NSRegularExpression alloc] initWithPattern:@"^[a-zA-Z0-9@.!#$%&'*+\\-/=?^_`{|}~]+$" + options:0 error:nil]; +} + +- (ZXParsedResult *)parse:(ZXResult *)result { + NSString *rawText = [ZXResultParser massagedText:result]; + if (![rawText hasPrefix:@"MATMSG:"]) { + return nil; + } + NSArray *tos = [[self class] matchDoCoMoPrefixedField:@"TO:" rawText:rawText trim:YES]; + if (tos == nil) { + return nil; + } + for (NSString *to in tos) { + if (![[self class] isBasicallyValidEmailAddress:to]) { + return nil; + } + } + NSString *subject = [[self class] matchSingleDoCoMoPrefixedField:@"SUB:" rawText:rawText trim:NO]; + NSString *body = [[self class] matchSingleDoCoMoPrefixedField:@"BODY:" rawText:rawText trim:NO]; + + return [[ZXEmailAddressParsedResult alloc] initWithTos:tos ccs:nil bccs:nil subject:subject body:body]; +} + ++ (BOOL)isBasicallyValidEmailAddress:(NSString *)email { + return email != nil && [ZX_ATEXT_ALPHANUMERIC numberOfMatchesInString:email options:0 range:NSMakeRange(0, email.length)] > 0 && [email rangeOfString:@"@"].location != NSNotFound; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXExpandedProductParsedResult.h b/iDearQRCode/Tools/ZXingObjC/client/result/ZXExpandedProductParsedResult.h new file mode 100755 index 0000000..3341d6d --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXExpandedProductParsedResult.h @@ -0,0 +1,54 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXParsedResult.h" + +extern NSString * const ZX_KILOGRAM; +extern NSString * const ZX_POUND; + +@interface ZXExpandedProductParsedResult : ZXParsedResult + +@property (nonatomic, copy, readonly) NSString *rawText; +@property (nonatomic, copy, readonly) NSString *productID; +@property (nonatomic, copy, readonly) NSString *sscc; +@property (nonatomic, copy, readonly) NSString *lotNumber; +@property (nonatomic, copy, readonly) NSString *productionDate; +@property (nonatomic, copy, readonly) NSString *packagingDate; +@property (nonatomic, copy, readonly) NSString *bestBeforeDate; +@property (nonatomic, copy, readonly) NSString *expirationDate; +@property (nonatomic, copy, readonly) NSString *weight; +@property (nonatomic, copy, readonly) NSString *weightType; +@property (nonatomic, copy, readonly) NSString *weightIncrement; +@property (nonatomic, copy, readonly) NSString *price; +@property (nonatomic, copy, readonly) NSString *priceIncrement; +@property (nonatomic, copy, readonly) NSString *priceCurrency; +@property (nonatomic, strong, readonly) NSMutableDictionary *uncommonAIs; + +- (id)initWithRawText:(NSString *)rawText productID:(NSString *)productID sscc:(NSString *)sscc + lotNumber:(NSString *)lotNumber productionDate:(NSString *)productionDate + packagingDate:(NSString *)packagingDate bestBeforeDate:(NSString *)bestBeforeDate + expirationDate:(NSString *)expirationDate weight:(NSString *)weight weightType:(NSString *)weightType + weightIncrement:(NSString *)weightIncrement price:(NSString *)price priceIncrement:(NSString *)priceIncrement + priceCurrency:(NSString *)priceCurrency uncommonAIs:(NSMutableDictionary *)uncommonAIs; ++ (id)expandedProductParsedResultWithRawText:(NSString *)rawText productID:(NSString *)productID sscc:(NSString *)sscc + lotNumber:(NSString *)lotNumber productionDate:(NSString *)productionDate + packagingDate:(NSString *)packagingDate bestBeforeDate:(NSString *)bestBeforeDate + expirationDate:(NSString *)expirationDate weight:(NSString *)weight + weightType:(NSString *)weightType weightIncrement:(NSString *)weightIncrement + price:(NSString *)price priceIncrement:(NSString *)priceIncrement + priceCurrency:(NSString *)priceCurrency uncommonAIs:(NSMutableDictionary *)uncommonAIs; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXExpandedProductParsedResult.m b/iDearQRCode/Tools/ZXingObjC/client/result/ZXExpandedProductParsedResult.m new file mode 100755 index 0000000..f217dc8 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXExpandedProductParsedResult.m @@ -0,0 +1,119 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXExpandedProductParsedResult.h" + +NSString * const ZX_KILOGRAM = @"KG"; +NSString * const ZX_POUND = @"LB"; + +@implementation ZXExpandedProductParsedResult + +- (id)init { + return [self initWithRawText:@"" productID:@"" sscc:@"" lotNumber:@"" productionDate:@"" packagingDate:@"" + bestBeforeDate:@"" expirationDate:@"" weight:@"" weightType:@"" weightIncrement:@"" price:@"" + priceIncrement:@"" priceCurrency:@"" uncommonAIs:[NSMutableDictionary dictionary]]; +} + +- (id)initWithRawText:(NSString *)rawText productID:(NSString *)productID sscc:(NSString *)sscc + lotNumber:(NSString *)lotNumber productionDate:(NSString *)productionDate + packagingDate:(NSString *)packagingDate bestBeforeDate:(NSString *)bestBeforeDate + expirationDate:(NSString *)expirationDate weight:(NSString *)weight weightType:(NSString *)weightType + weightIncrement:(NSString *)weightIncrement price:(NSString *)price priceIncrement:(NSString *)priceIncrement + priceCurrency:(NSString *)priceCurrency uncommonAIs:(NSMutableDictionary *)uncommonAIs { + if (self = [super initWithType:kParsedResultTypeProduct]) { + _rawText = rawText; + _productID = productID; + _sscc = sscc; + _lotNumber = lotNumber; + _productionDate = productionDate; + _packagingDate = packagingDate; + _bestBeforeDate = bestBeforeDate; + _expirationDate = expirationDate; + _weight = weight; + _weightType = weightType; + _weightIncrement = weightIncrement; + _price = price; + _priceIncrement = priceIncrement; + _priceCurrency = priceCurrency; + _uncommonAIs = uncommonAIs; + } + + return self; +} + ++ (id)expandedProductParsedResultWithRawText:(NSString *)rawText productID:(NSString *)productID sscc:(NSString *)sscc + lotNumber:(NSString *)lotNumber productionDate:(NSString *)productionDate + packagingDate:(NSString *)packagingDate bestBeforeDate:(NSString *)bestBeforeDate + expirationDate:(NSString *)expirationDate weight:(NSString *)weight + weightType:(NSString *)weightType weightIncrement:(NSString *)weightIncrement + price:(NSString *)price priceIncrement:(NSString *)priceIncrement + priceCurrency:(NSString *)priceCurrency uncommonAIs:(NSMutableDictionary *)uncommonAIs { + return [[self alloc] initWithRawText:rawText productID:productID sscc:sscc lotNumber:lotNumber + productionDate:productionDate packagingDate:packagingDate bestBeforeDate:bestBeforeDate + expirationDate:expirationDate weight:weight weightType:weightType + weightIncrement:weightIncrement price:price priceIncrement:priceIncrement + priceCurrency:priceCurrency uncommonAIs:uncommonAIs]; +} + +- (BOOL)isEqual:(id)o { + if (![o isKindOfClass:[self class]]) { + return NO; + } + + ZXExpandedProductParsedResult *other = (ZXExpandedProductParsedResult *)o; + + return [self equalsOrNil:self.productID o2:other.productID] + && [self equalsOrNil:self.sscc o2:other.sscc] + && [self equalsOrNil:self.lotNumber o2:other.lotNumber] + && [self equalsOrNil:self.productionDate o2:other.productionDate] + && [self equalsOrNil:self.bestBeforeDate o2:other.bestBeforeDate] + && [self equalsOrNil:self.expirationDate o2:other.expirationDate] + && [self equalsOrNil:self.weight o2:other.weight] + && [self equalsOrNil:self.weightType o2:other.weightType] + && [self equalsOrNil:self.weightIncrement o2:other.weightIncrement] + && [self equalsOrNil:self.price o2:other.price] + && [self equalsOrNil:self.priceIncrement o2:other.priceIncrement] + && [self equalsOrNil:self.priceCurrency o2:other.priceCurrency] + && [self equalsOrNil:self.uncommonAIs o2:other.uncommonAIs]; +} + +- (BOOL)equalsOrNil:(id)o1 o2:(id)o2 { + return o1 == nil ? o2 == nil : [o1 isEqual:o2]; +} + +- (NSUInteger)hash { + int hash = 0; + hash ^= [self.productID hash]; + hash ^= [self.sscc hash]; + hash ^= [self.lotNumber hash]; + hash ^= [self.productionDate hash]; + hash ^= [self.bestBeforeDate hash]; + hash ^= [self.expirationDate hash]; + hash ^= [self.weight hash]; + hash ^= [self.weightType hash]; + hash ^= [self.weightIncrement hash]; + hash ^= [self.price hash]; + hash ^= [self.priceIncrement hash]; + hash ^= [self.priceCurrency hash]; + hash ^= [self.uncommonAIs hash]; + return hash; +} + +- (NSString *)displayResult { + return self.rawText; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXExpandedProductResultParser.h b/iDearQRCode/Tools/ZXingObjC/client/result/ZXExpandedProductResultParser.h new file mode 100755 index 0000000..195c82d --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXExpandedProductResultParser.h @@ -0,0 +1,24 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXResultParser.h" + +/** + * Parses strings of digits that represent a RSS Extended code. + */ +@interface ZXExpandedProductResultParser : ZXResultParser + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXExpandedProductResultParser.m b/iDearQRCode/Tools/ZXingObjC/client/result/ZXExpandedProductResultParser.m new file mode 100755 index 0000000..4b76560 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXExpandedProductResultParser.m @@ -0,0 +1,162 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXExpandedProductResultParser.h" +#import "ZXExpandedProductParsedResult.h" +#import "ZXResult.h" + +@implementation ZXExpandedProductResultParser + +- (ZXParsedResult *)parse:(ZXResult *)result { + ZXBarcodeFormat format = [result barcodeFormat]; + if (kBarcodeFormatRSSExpanded != format) { + // ExtendedProductParsedResult NOT created. Not a RSS Expanded barcode + return nil; + } + NSString *rawText = [ZXResultParser massagedText:result]; + + NSString *productID = nil; + NSString *sscc = nil; + NSString *lotNumber = nil; + NSString *productionDate = nil; + NSString *packagingDate = nil; + NSString *bestBeforeDate = nil; + NSString *expirationDate = nil; + NSString *weight = nil; + NSString *weightType = nil; + NSString *weightIncrement = nil; + NSString *price = nil; + NSString *priceIncrement = nil; + NSString *priceCurrency = nil; + NSMutableDictionary *uncommonAIs = [NSMutableDictionary dictionary]; + + int i = 0; + + while (i < [rawText length]) { + NSString *ai = [self findAIvalue:i rawText:rawText]; + if (ai == nil) { + // Error. Code doesn't match with RSS expanded pattern + // ExtendedProductParsedResult NOT created. Not match with RSS Expanded pattern + return nil; + } + i += [ai length] + 2; + NSString *value = [self findValue:i rawText:rawText]; + i += [value length]; + + if ([@"00" isEqualToString:ai]) { + sscc = value; + } else if ([@"01" isEqualToString:ai]) { + productID = value; + } else if ([@"10" isEqualToString:ai]) { + lotNumber = value; + } else if ([@"11" isEqualToString:ai]) { + productionDate = value; + } else if ([@"13" isEqualToString:ai]) { + packagingDate = value; + } else if ([@"15" isEqualToString:ai]) { + bestBeforeDate = value; + } else if ([@"17" isEqualToString:ai]) { + expirationDate = value; + } else if ([@"3100" isEqualToString:ai] || [@"3101" isEqualToString:ai] || [@"3102" isEqualToString:ai] || [@"3103" isEqualToString:ai] || [@"3104" isEqualToString:ai] || [@"3105" isEqualToString:ai] || [@"3106" isEqualToString:ai] || [@"3107" isEqualToString:ai] || [@"3108" isEqualToString:ai] || [@"3109" isEqualToString:ai]) { + weight = value; + weightType = ZX_KILOGRAM; + weightIncrement = [ai substringFromIndex:3]; + } else if ([@"3200" isEqualToString:ai] || [@"3201" isEqualToString:ai] || [@"3202" isEqualToString:ai] || [@"3203" isEqualToString:ai] || [@"3204" isEqualToString:ai] || [@"3205" isEqualToString:ai] || [@"3206" isEqualToString:ai] || [@"3207" isEqualToString:ai] || [@"3208" isEqualToString:ai] || [@"3209" isEqualToString:ai]) { + weight = value; + weightType = ZX_POUND; + weightIncrement = [ai substringFromIndex:3]; + } else if ([@"3920" isEqualToString:ai] || [@"3921" isEqualToString:ai] || [@"3922" isEqualToString:ai] || [@"3923" isEqualToString:ai]) { + price = value; + priceIncrement = [ai substringFromIndex:3]; + } else if ([@"3930" isEqualToString:ai] || [@"3931" isEqualToString:ai] || [@"3932" isEqualToString:ai] || [@"3933" isEqualToString:ai]) { + if ([value length] < 4) { + // The value must have more of 3 symbols (3 for currency and + // 1 at least for the price) + // ExtendedProductParsedResult NOT created. Not match with RSS Expanded pattern + return nil; + } + price = [value substringFromIndex:3]; + priceCurrency = [value substringToIndex:3]; + priceIncrement = [ai substringFromIndex:3]; + } else { + // No match with common AIs + uncommonAIs[ai] = value; + } + } + + return [ZXExpandedProductParsedResult expandedProductParsedResultWithRawText:rawText + productID:productID + sscc:sscc + lotNumber:lotNumber + productionDate:productionDate + packagingDate:packagingDate + bestBeforeDate:bestBeforeDate + expirationDate:expirationDate + weight:weight + weightType:weightType + weightIncrement:weightIncrement + price:price + priceIncrement:priceIncrement + priceCurrency:priceCurrency + uncommonAIs:uncommonAIs]; +} + +- (NSString *)findAIvalue:(int)i rawText:(NSString *)rawText { + unichar c = [rawText characterAtIndex:i]; + // First character must be a open parenthesis.If not, ERROR + if (c != '(') { + return nil; + } + + NSString *rawTextAux = [rawText substringFromIndex:i + 1]; + + NSMutableString *buf = [NSMutableString string]; + for (int index = 0; index < [rawTextAux length]; index++) { + unichar currentChar = [rawTextAux characterAtIndex:index]; + if (currentChar == ')') { + return buf; + } else if (currentChar >= '0' && currentChar <= '9') { + [buf appendFormat:@"%C", currentChar]; + } else { + return nil; + } + } + return buf; +} + +- (NSString *)findValue:(int)i rawText:(NSString *)rawText { + NSMutableString *buf = [NSMutableString string]; + NSString *rawTextAux = [rawText substringFromIndex:i]; + + for (int index = 0; index < [rawTextAux length]; index++) { + unichar c = [rawTextAux characterAtIndex:index]; + if (c == '(') { + // We look for a new AI. If it doesn't exist (ERROR), we coninue + // with the iteration + if ([self findAIvalue:index rawText:rawTextAux] == nil) { + [buf appendString:@"("]; + } else { + break; + } + } else { + [buf appendFormat:@"%C", c]; + } + } + + return buf; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXGeoParsedResult.h b/iDearQRCode/Tools/ZXingObjC/client/result/ZXGeoParsedResult.h new file mode 100755 index 0000000..3f4c354 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXGeoParsedResult.h @@ -0,0 +1,45 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXParsedResult.h" + +@interface ZXGeoParsedResult : ZXParsedResult + +/** + * @return latitude in degrees + */ +@property (nonatomic, assign, readonly) double latitude; + +/** + * @return longitude in degrees + */ +@property (nonatomic, assign, readonly) double longitude; + +/** + * @return altitude in meters. If not specified, in the geo URI, returns 0.0 + */ +@property (nonatomic, assign, readonly) double altitude; + +/** + * @return query string associated with geo URI or null if none exists + */ +@property (nonatomic, copy, readonly) NSString *query; + +- (id)initWithLatitude:(double)latitude longitude:(double)longitude altitude:(double)altitude query:(NSString *)query; ++ (id)geoParsedResultWithLatitude:(double)latitude longitude:(double)longitude altitude:(double)altitude query:(NSString *)query; +- (NSString *)geoURI; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXGeoParsedResult.m b/iDearQRCode/Tools/ZXingObjC/client/result/ZXGeoParsedResult.m new file mode 100755 index 0000000..d2ec38b --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXGeoParsedResult.m @@ -0,0 +1,62 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXGeoParsedResult.h" +#import "ZXParsedResultType.h" + +@implementation ZXGeoParsedResult + +- (id)initWithLatitude:(double)latitude longitude:(double)longitude altitude:(double)altitude query:(NSString *)query { + if (self = [super initWithType:kParsedResultTypeGeo]) { + _latitude = latitude; + _longitude = longitude; + _altitude = altitude; + _query = query; + } + + return self; +} + ++ (id)geoParsedResultWithLatitude:(double)latitude longitude:(double)longitude altitude:(double)altitude query:(NSString *)query { + return [[self alloc] initWithLatitude:latitude longitude:longitude altitude:altitude query:query]; +} + +- (NSString *)geoURI { + NSMutableString *result = [NSMutableString string]; + [result appendFormat:@"geo:%f,%f", self.latitude, self.longitude]; + if (self.altitude > 0) { + [result appendFormat:@",%f", self.altitude]; + } + if (self.query != nil) { + [result appendFormat:@"?%@", self.query]; + } + return result; +} + +- (NSString *)displayResult { + NSMutableString *result = [NSMutableString string]; + [result appendFormat:@"%f, %f", self.latitude, self.longitude]; + if (self.altitude > 0.0) { + [result appendFormat:@", %f", self.altitude]; + [result appendString:@"m"]; + } + if (self.query != nil) { + [result appendFormat:@" (%@)", self.query]; + } + return result; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXGeoResultParser.h b/iDearQRCode/Tools/ZXingObjC/client/result/ZXGeoResultParser.h new file mode 100755 index 0000000..9b16e3d --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXGeoResultParser.h @@ -0,0 +1,26 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXResultParser.h" + +/** + * Parses a "geo:" URI result, which specifies a location on the surface of + * the Earth as well as an optional altitude above the surface. See + * http://tools.ietf.org/html/draft-mayrhofer-geo-uri-00. + */ +@interface ZXGeoResultParser : ZXResultParser + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXGeoResultParser.m b/iDearQRCode/Tools/ZXingObjC/client/result/ZXGeoResultParser.m new file mode 100755 index 0000000..732a63d --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXGeoResultParser.m @@ -0,0 +1,70 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXGeoParsedResult.h" +#import "ZXGeoResultParser.h" + +static NSRegularExpression *ZX_GEO_URL_PATTERN = nil; + +@implementation ZXGeoResultParser + ++ (void)initialize { + if ([self class] != [ZXGeoResultParser class]) return; + + ZX_GEO_URL_PATTERN = [[NSRegularExpression alloc] initWithPattern:@"geo:([\\-0-9.]+),([\\-0-9.]+)(?:,([\\-0-9.]+))?(?:\\?(.*))?" + options:NSRegularExpressionCaseInsensitive error:nil]; + +} + +- (ZXParsedResult *)parse:(ZXResult *)result { + NSString *rawText = [ZXResultParser massagedText:result]; + if (rawText == nil || (![rawText hasPrefix:@"geo:"] && ![rawText hasPrefix:@"GEO:"])) { + return nil; + } + + NSArray *matches = [ZX_GEO_URL_PATTERN matchesInString:rawText options:0 range:NSMakeRange(0, rawText.length)]; + if (matches.count == 0) { + return nil; + } + + NSTextCheckingResult *match = matches[0]; + NSString *query = nil; + if ([match rangeAtIndex:4].location != NSNotFound) { + query = [rawText substringWithRange:[match rangeAtIndex:4]]; + } + + double latitude = [[rawText substringWithRange:[match rangeAtIndex:1]] doubleValue]; + if (latitude > 90.0 || latitude < -90.0) { + return nil; + } + double longitude = [[rawText substringWithRange:[match rangeAtIndex:2]] doubleValue]; + if (longitude > 180.0 || longitude < -180.0) { + return nil; + } + double altitude; + if ([match rangeAtIndex:3].location == NSNotFound) { + altitude = 0.0; + } else { + altitude = [[rawText substringWithRange:[match rangeAtIndex:3]] doubleValue]; + if (altitude < 0.0) { + return nil; + } + } + + return [ZXGeoParsedResult geoParsedResultWithLatitude:latitude longitude:longitude altitude:altitude query:query]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXISBNParsedResult.h b/iDearQRCode/Tools/ZXingObjC/client/result/ZXISBNParsedResult.h new file mode 100755 index 0000000..76adecb --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXISBNParsedResult.h @@ -0,0 +1,26 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXParsedResult.h" + +@interface ZXISBNParsedResult : ZXParsedResult + +@property (nonatomic, copy, readonly) NSString *isbn; + +- (id)initWithIsbn:(NSString *)isbn; ++ (id)isbnParsedResultWithIsbn:(NSString *)isbn; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXISBNParsedResult.m b/iDearQRCode/Tools/ZXingObjC/client/result/ZXISBNParsedResult.m new file mode 100755 index 0000000..22f2aab --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXISBNParsedResult.m @@ -0,0 +1,37 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXISBNParsedResult.h" + +@implementation ZXISBNParsedResult + +- (id)initWithIsbn:(NSString *)isbn { + if (self = [super initWithType:kParsedResultTypeISBN]) { + _isbn = isbn; + } + + return self; +} + ++ (id)isbnParsedResultWithIsbn:(NSString *)isbn { + return [[self alloc] initWithIsbn:isbn]; +} + +- (NSString *)displayResult { + return self.isbn; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXISBNResultParser.h b/iDearQRCode/Tools/ZXingObjC/client/result/ZXISBNResultParser.h new file mode 100755 index 0000000..d364e1e --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXISBNResultParser.h @@ -0,0 +1,24 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXResultParser.h" + +/** + * Parses strings of digits that represent a ISBN. + */ +@interface ZXISBNResultParser : ZXResultParser + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXISBNResultParser.m b/iDearQRCode/Tools/ZXingObjC/client/result/ZXISBNResultParser.m new file mode 100755 index 0000000..696d70d --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXISBNResultParser.m @@ -0,0 +1,41 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXISBNParsedResult.h" +#import "ZXISBNResultParser.h" + +@implementation ZXISBNResultParser + +/** + * See ISBN-13 For Dummies + */ +- (ZXParsedResult *)parse:(ZXResult *)result { + ZXBarcodeFormat format = [result barcodeFormat]; + if (format != kBarcodeFormatEan13) { + return nil; + } + NSString *rawText = [ZXResultParser massagedText:result]; + NSUInteger length = [rawText length]; + if (length != 13) { + return nil; + } + if (![rawText hasPrefix:@"978"] && ![rawText hasPrefix:@"979"]) { + return nil; + } + return [ZXISBNParsedResult isbnParsedResultWithIsbn:rawText]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXParsedResult.h b/iDearQRCode/Tools/ZXingObjC/client/result/ZXParsedResult.h new file mode 100755 index 0000000..50691cf --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXParsedResult.h @@ -0,0 +1,39 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXParsedResultType.h" +#import "ZXResult.h" + +/** + * Abstract class representing the result of decoding a barcode, as more than + * a String -- as some type of structured data. This might be a subclass which represents + * a URL, or an e-mail address. parseResult() will turn a raw + * decoded string into the most appropriate type of structured representation. + * + * Thanks to Jeff Griffin for proposing rewrite of these classes that relies less + * on exception-based mechanisms during parsing. + */ +@interface ZXParsedResult : NSObject + +@property (nonatomic, assign, readonly) ZXParsedResultType type; + +- (id)initWithType:(ZXParsedResultType)type; ++ (id)parsedResultWithType:(ZXParsedResultType)type; +- (NSString *)displayResult; ++ (void)maybeAppend:(NSString *)value result:(NSMutableString *)result; ++ (void)maybeAppendArray:(NSArray *)value result:(NSMutableString *)result; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXParsedResult.m b/iDearQRCode/Tools/ZXingObjC/client/result/ZXParsedResult.m new file mode 100755 index 0000000..5a363a1 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXParsedResult.m @@ -0,0 +1,61 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXParsedResult.h" + +@implementation ZXParsedResult + +- (id)initWithType:(ZXParsedResultType)type { + if (self = [super init]) { + _type = type; + } + + return self; +} + ++ (id)parsedResultWithType:(ZXParsedResultType)type { + return [[ZXParsedResult alloc] initWithType:type]; +} + +- (NSString *)displayResult { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)] + userInfo:nil]; +} + +- (NSString *)description { + return [self displayResult]; +} + ++ (void)maybeAppend:(NSString *)value result:(NSMutableString *)result { + if (value != nil && (id)value != [NSNull null] && [value length] > 0) { + // Don't add a newline before the first value + if ([result length] > 0) { + [result appendString:@"\n"]; + } + [result appendString:value]; + } +} + ++ (void)maybeAppendArray:(NSArray *)values result:(NSMutableString *)result { + if (values != nil) { + for (NSString *value in values) { + [self maybeAppend:value result:result]; + } + } +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXParsedResultType.h b/iDearQRCode/Tools/ZXingObjC/client/result/ZXParsedResultType.h new file mode 100755 index 0000000..cdb375c --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXParsedResultType.h @@ -0,0 +1,37 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Represents the type of data encoded by a barcode -- from plain text, to a + * URI, to an e-mail address, etc. + */ +typedef enum { + kParsedResultTypeAddressBook, + kParsedResultTypeEmailAddress, + kParsedResultTypeProduct, + kParsedResultTypeURI, + kParsedResultTypeText, + kParsedResultTypeAndroidIntent, + kParsedResultTypeGeo, + kParsedResultTypeTel, + kParsedResultTypeSMS, + kParsedResultTypeCalendar, + kParsedResultTypeWifi, + kParsedResultTypeNDEFSMartPoster, + kParsedResultTypeMobiletagRichWeb, + kParsedResultTypeISBN, + kParsedResultTypeVIN +} ZXParsedResultType; diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXProductParsedResult.h b/iDearQRCode/Tools/ZXingObjC/client/result/ZXProductParsedResult.h new file mode 100755 index 0000000..b2039c0 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXProductParsedResult.h @@ -0,0 +1,29 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXParsedResult.h" + +@interface ZXProductParsedResult : ZXParsedResult + +@property (nonatomic, copy, readonly) NSString *normalizedProductID; +@property (nonatomic, copy, readonly) NSString *productID; + +- (id)initWithProductID:(NSString *)productID; +- (id)initWithProductID:(NSString *)productID normalizedProductID:(NSString *)normalizedProductID; ++ (id)productParsedResultWithProductID:(NSString *)productID; ++ (id)productParsedResultWithProductID:(NSString *)productID normalizedProductID:(NSString *)normalizedProductID; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXProductParsedResult.m b/iDearQRCode/Tools/ZXingObjC/client/result/ZXProductParsedResult.m new file mode 100755 index 0000000..5fa5371 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXProductParsedResult.m @@ -0,0 +1,46 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXProductParsedResult.h" + +@implementation ZXProductParsedResult + +- (id)initWithProductID:(NSString *)productID { + return [self initWithProductID:productID normalizedProductID:productID]; +} + +- (id)initWithProductID:(NSString *)productID normalizedProductID:(NSString *)normalizedProductID { + if (self = [super initWithType:kParsedResultTypeProduct]) { + _normalizedProductID = normalizedProductID; + _productID = productID; + } + + return self; +} + ++ (id)productParsedResultWithProductID:(NSString *)productID { + return [[self alloc] initWithProductID:productID]; +} + ++ (id)productParsedResultWithProductID:(NSString *)productID normalizedProductID:(NSString *)normalizedProductID { + return [[self alloc] initWithProductID:productID normalizedProductID:normalizedProductID]; +} + +- (NSString *)displayResult { + return self.productID; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXProductResultParser.h b/iDearQRCode/Tools/ZXingObjC/client/result/ZXProductResultParser.h new file mode 100755 index 0000000..4954a40 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXProductResultParser.h @@ -0,0 +1,24 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXResultParser.h" + +/** + * Parses strings of digits that represent a UPC code. + */ +@interface ZXProductResultParser : ZXResultParser + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXProductResultParser.m b/iDearQRCode/Tools/ZXingObjC/client/result/ZXProductResultParser.m new file mode 100755 index 0000000..a20446d --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXProductResultParser.m @@ -0,0 +1,45 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBarcodeFormat.h" +#import "ZXProductParsedResult.h" +#import "ZXProductResultParser.h" +#import "ZXUPCEReader.h" + +@implementation ZXProductResultParser + +// Treat all UPC and EAN variants as UPCs, in the sense that they are all product barcodes. +- (ZXParsedResult *)parse:(ZXResult *)result { + ZXBarcodeFormat format = [result barcodeFormat]; + if (!(format == kBarcodeFormatUPCA || format == kBarcodeFormatUPCE || format == kBarcodeFormatEan8 || format == kBarcodeFormatEan13)) { + return nil; + } + NSString *rawText = [ZXResultParser massagedText:result]; + if (![[self class] isStringOfDigits:rawText length:(unsigned int)[rawText length]]) { + return nil; + } + // Not actually checking the checksum again here + + NSString *normalizedProductID; + if (format == kBarcodeFormatUPCE && [rawText length] == 8) { + normalizedProductID = [ZXUPCEReader convertUPCEtoUPCA:rawText]; + } else { + normalizedProductID = rawText; + } + return [ZXProductParsedResult productParsedResultWithProductID:rawText normalizedProductID:normalizedProductID]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXResultParser.h b/iDearQRCode/Tools/ZXingObjC/client/result/ZXResultParser.h new file mode 100755 index 0000000..688a438 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXResultParser.h @@ -0,0 +1,50 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXParsedResult, ZXResult; + +/** + * Abstract class representing the result of decoding a barcode, as more than + * a String -- as some type of structured data. This might be a subclass which represents + * a URL, or an e-mail address. parseResult() will turn a raw + * decoded string into the most appropriate type of structured representation. + * + * Thanks to Jeff Griffin for proposing rewrite of these classes that relies less + * on exception-based mechanisms during parsing. + */ +@interface ZXResultParser : NSObject + +/** + * Attempts to parse the raw ZXResult's contents as a particular type + * of information (email, URL, etc.) and return a ZXParsedResult encapsulating + * the result of parsing. + */ +- (ZXParsedResult *)parse:(ZXResult *)result; + ++ (NSString *)massagedText:(ZXResult *)result; ++ (ZXParsedResult *)parseResult:(ZXResult *)theResult; +- (void)maybeAppend:(NSString *)value result:(NSMutableString *)result; +- (void)maybeAppendArray:(NSArray *)value result:(NSMutableString *)result; +- (NSArray *)maybeWrap:(NSString *)value; ++ (BOOL)isStringOfDigits:(NSString *)value length:(unsigned int)length; ++ (BOOL)isSubstringOfDigits:(NSString *)value offset:(int)offset length:(int)length; ++ (int)parseHexDigit:(unichar)c; +- (NSMutableDictionary *)parseNameValuePairs:(NSString *)uri; ++ (NSString *)urlDecode:(NSString *)encoded; ++ (NSArray *)matchPrefixedField:(NSString *)prefix rawText:(NSString *)rawText endChar:(unichar)endChar trim:(BOOL)trim; ++ (NSString *)matchSinglePrefixedField:(NSString *)prefix rawText:(NSString *)rawText endChar:(unichar)endChar trim:(BOOL)trim; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXResultParser.m b/iDearQRCode/Tools/ZXingObjC/client/result/ZXResultParser.m new file mode 100755 index 0000000..8981f7e --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXResultParser.m @@ -0,0 +1,317 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAddressBookAUResultParser.h" +#import "ZXAddressBookDoCoMoResultParser.h" +#import "ZXAddressBookParsedResult.h" +#import "ZXBizcardResultParser.h" +#import "ZXBookmarkDoCoMoResultParser.h" +#import "ZXCalendarParsedResult.h" +#import "ZXEmailAddressParsedResult.h" +#import "ZXEmailAddressResultParser.h" +#import "ZXEmailDoCoMoResultParser.h" +#import "ZXExpandedProductParsedResult.h" +#import "ZXExpandedProductResultParser.h" +#import "ZXGeoParsedResult.h" +#import "ZXGeoResultParser.h" +#import "ZXISBNParsedResult.h" +#import "ZXISBNResultParser.h" +#import "ZXParsedResult.h" +#import "ZXProductParsedResult.h" +#import "ZXProductResultParser.h" +#import "ZXResult.h" +#import "ZXResultParser.h" +#import "ZXSMSMMSResultParser.h" +#import "ZXSMSParsedResult.h" +#import "ZXSMSTOMMSTOResultParser.h" +#import "ZXSMTPResultParser.h" +#import "ZXTelParsedResult.h" +#import "ZXTelResultParser.h" +#import "ZXTextParsedResult.h" +#import "ZXURIParsedResult.h" +#import "ZXURIResultParser.h" +#import "ZXURLTOResultParser.h" +#import "ZXVCardResultParser.h" +#import "ZXVEventResultParser.h" +#import "ZXVINResultParser.h" +#import "ZXWifiParsedResult.h" +#import "ZXWifiResultParser.h" + +static NSArray *ZX_PARSERS = nil; +static NSRegularExpression *ZX_DIGITS = nil; +static NSString *ZX_AMPERSAND = @"&"; +static NSString *ZX_EQUALS = @"="; +static unichar ZX_BYTE_ORDER_MARK = L'\ufeff'; + +@implementation ZXResultParser + ++ (void)initialize { + if ([self class] != [ZXResultParser class]) return; + + ZX_PARSERS = @[[[ZXBookmarkDoCoMoResultParser alloc] init], + [[ZXAddressBookDoCoMoResultParser alloc] init], + [[ZXEmailDoCoMoResultParser alloc] init], + [[ZXAddressBookAUResultParser alloc] init], + [[ZXVCardResultParser alloc] init], + [[ZXBizcardResultParser alloc] init], + [[ZXVEventResultParser alloc] init], + [[ZXEmailAddressResultParser alloc] init], + [[ZXSMTPResultParser alloc] init], + [[ZXTelResultParser alloc] init], + [[ZXSMSMMSResultParser alloc] init], + [[ZXSMSTOMMSTOResultParser alloc] init], + [[ZXGeoResultParser alloc] init], + [[ZXWifiResultParser alloc] init], + [[ZXURLTOResultParser alloc] init], + [[ZXURIResultParser alloc] init], + [[ZXISBNResultParser alloc] init], + [[ZXProductResultParser alloc] init], + [[ZXExpandedProductResultParser alloc] init], + [[ZXVINResultParser alloc] init]]; + ZX_DIGITS = [[NSRegularExpression alloc] initWithPattern:@"^\\d+$" options:0 error:nil]; +} + +- (ZXParsedResult *)parse:(ZXResult *)result { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)] + userInfo:nil]; +} + ++ (NSString *)massagedText:(ZXResult *)result { + NSString *text = result.text; + if (text.length > 0 && [text characterAtIndex:0] == ZX_BYTE_ORDER_MARK) { + text = [text substringFromIndex:1]; + } + return text; +} + ++ (ZXParsedResult *)parseResult:(ZXResult *)theResult { + for (ZXResultParser *parser in ZX_PARSERS) { + ZXParsedResult *result = [parser parse:theResult]; + if (result != nil) { + return result; + } + } + return [ZXTextParsedResult textParsedResultWithText:[theResult text] language:nil]; +} + +- (void)maybeAppend:(NSString *)value result:(NSMutableString *)result { + if (value != nil) { + [result appendFormat:@"\n%@", value]; + } +} + +- (void)maybeAppendArray:(NSArray *)value result:(NSMutableString *)result { + if (value != nil) { + for (NSString *s in value) { + [result appendFormat:@"\n%@", s]; + } + } +} + +- (NSArray *)maybeWrap:(NSString *)value { + return value == nil ? nil : @[value]; +} + ++ (NSString *)unescapeBackslash:(NSString *)escaped { + NSUInteger backslash = [escaped rangeOfString:@"\\"].location; + if (backslash == NSNotFound) { + return escaped; + } + NSUInteger max = [escaped length]; + NSMutableString *unescaped = [NSMutableString stringWithCapacity:max - 1]; + [unescaped appendString:[escaped substringToIndex:backslash]]; + BOOL nextIsEscaped = NO; + for (int i = (int)backslash; i < max; i++) { + unichar c = [escaped characterAtIndex:i]; + if (nextIsEscaped || c != '\\') { + [unescaped appendFormat:@"%C", c]; + nextIsEscaped = NO; + } else { + nextIsEscaped = YES; + } + } + return unescaped; +} + ++ (int)parseHexDigit:(unichar)c { + if (c >= '0' && c <= '9') { + return c - '0'; + } + if (c >= 'a' && c <= 'f') { + return 10 + (c - 'a'); + } + if (c >= 'A' && c <= 'F') { + return 10 + (c - 'A'); + } + return -1; +} + ++ (BOOL)isStringOfDigits:(NSString *)value length:(unsigned int)length { + return value != nil && length > 0 && length == value.length && [ZX_DIGITS numberOfMatchesInString:value options:0 range:NSMakeRange(0, value.length)] > 0; +} + +- (NSString *)urlDecode:(NSString *)escaped { + if (escaped == nil) { + return nil; + } + + int first = [self findFirstEscape:escaped]; + if (first == -1) { + return escaped; + } + + NSUInteger max = [escaped length]; + NSMutableString *unescaped = [NSMutableString stringWithCapacity:max - 2]; + [unescaped appendString:[escaped substringToIndex:first]]; + + for (int i = first; i < max; i++) { + unichar c = [escaped characterAtIndex:i]; + switch (c) { + case '+': + [unescaped appendString:@" "]; + break; + case '%': + if (i >= max - 2) { + [unescaped appendString:@"%"]; + } else { + int firstDigitValue = [[self class] parseHexDigit:[escaped characterAtIndex:++i]]; + int secondDigitValue = [[self class] parseHexDigit:[escaped characterAtIndex:++i]]; + if (firstDigitValue < 0 || secondDigitValue < 0) { + [unescaped appendFormat:@"%%%C%C", [escaped characterAtIndex:i - 1], [escaped characterAtIndex:i]]; + } + [unescaped appendFormat:@"%C", (unichar)((firstDigitValue << 4) + secondDigitValue)]; + } + break; + default: + [unescaped appendFormat:@"%C", c]; + break; + } + } + + return unescaped; +} + +- (int)findFirstEscape:(NSString *)escaped { + NSUInteger max = [escaped length]; + for (int i = 0; i < max; i++) { + unichar c = [escaped characterAtIndex:i]; + if (c == '+' || c == '%') { + return i; + } + } + + return -1; +} + ++ (BOOL)isSubstringOfDigits:(NSString *)value offset:(int)offset length:(int)length { + if (value == nil || length <= 0) { + return NO; + } + int max = offset + length; + return value.length >= max && [ZX_DIGITS numberOfMatchesInString:value options:0 range:NSMakeRange(offset, max - offset)] > 0; +} + +- (NSMutableDictionary *)parseNameValuePairs:(NSString *)uri { + NSUInteger paramStart = [uri rangeOfString:@"?"].location; + if (paramStart == NSNotFound) { + return nil; + } + NSMutableDictionary *result = [NSMutableDictionary dictionaryWithCapacity:3]; + for (NSString *keyValue in [[uri substringFromIndex:paramStart + 1] componentsSeparatedByString:ZX_AMPERSAND]) { + [self appendKeyValue:keyValue result:result]; + } + return result; +} + +- (void)appendKeyValue:(NSString *)keyValue result:(NSMutableDictionary *)result { + NSRange equalsRange = [keyValue rangeOfString:ZX_EQUALS]; + if (equalsRange.location != NSNotFound) { + NSString *key = [keyValue substringToIndex:equalsRange.location]; + NSString *value = [keyValue substringFromIndex:equalsRange.location + 1]; + value = [self urlDecode:value]; + result[key] = value; + } +} + ++ (NSString *)urlDecode:(NSString *)encoded { + NSString *result = [encoded stringByReplacingOccurrencesOfString:@"+" withString:@" "]; + result = [result stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + return result; +} + ++ (NSArray *)matchPrefixedField:(NSString *)prefix rawText:(NSString *)rawText endChar:(unichar)endChar trim:(BOOL)trim { + NSMutableArray *matches = nil; + NSUInteger i = 0; + NSUInteger max = [rawText length]; + while (i < max) { + i = [rawText rangeOfString:prefix options:NSLiteralSearch range:NSMakeRange(i, [rawText length] - i - 1)].location; + if (i == NSNotFound) { + break; + } + i += [prefix length]; // Skip past this prefix we found to start + NSUInteger start = i; // Found the start of a match here + BOOL more = YES; + while (more) { + i = [rawText rangeOfString:[NSString stringWithFormat:@"%C", endChar] options:NSLiteralSearch range:NSMakeRange(i, [rawText length] - i)].location; + if (i == NSNotFound) { + // No terminating end character? uh, done. Set i such that loop terminates and break + i = [rawText length]; + more = NO; + } else if ([self countPrecedingBackslashes:rawText pos:i] % 2 != 0) { + // semicolon was escaped (odd count of preceding backslashes) so continue + i++; + } else { + // found a match + if (matches == nil) { + matches = [NSMutableArray arrayWithCapacity:3]; // lazy init + } + NSString *element = [self unescapeBackslash:[rawText substringWithRange:NSMakeRange(start, i - start)]]; + if (trim) { + element = [element stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + } + if (element.length > 0) { + [matches addObject:element]; + } + i++; + more = NO; + } + } + } + if (matches == nil || [matches count] == 0) { + return nil; + } + return matches; +} + ++ (int)countPrecedingBackslashes:(NSString *)s pos:(NSInteger)pos { + int count = 0; + for (NSInteger i = pos - 1; i >= 0; i--) { + if ([s characterAtIndex:i] == '\\') { + count++; + } else { + break; + } + } + return count; +} + ++ (NSString *)matchSinglePrefixedField:(NSString *)prefix rawText:(NSString *)rawText endChar:(unichar)endChar trim:(BOOL)trim { + NSArray *matches = [self matchPrefixedField:prefix rawText:rawText endChar:endChar trim:trim]; + return matches == nil ? nil : matches[0]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXSMSMMSResultParser.h b/iDearQRCode/Tools/ZXingObjC/client/result/ZXSMSMMSResultParser.h new file mode 100755 index 0000000..be2ec7f --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXSMSMMSResultParser.h @@ -0,0 +1,34 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXResultParser.h" + +/** + * Parses an "sms:" URI result, which specifies a number to SMS. + * See http://tools.ietf.org/html/rfc5724 on this. + * + * This class supports "via" syntax for numbers, which is not part of the spec. + * For example "+12125551212;via=+12124440101" may appear as a number. + * It also supports a "subject" query parameter, which is not mentioned in the spec. + * These are included since they were mentioned in earlier IETF drafts and might be + * used. + * + * This actually also parses URIs starting with "mms:" and treats them all the same way, + * and effectively converts them to an "sms:" URI for purposes of forwarding to the platform. + */ +@interface ZXSMSMMSResultParser : ZXResultParser + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXSMSMMSResultParser.m b/iDearQRCode/Tools/ZXingObjC/client/result/ZXSMSMMSResultParser.m new file mode 100755 index 0000000..6510b50 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXSMSMMSResultParser.m @@ -0,0 +1,83 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXResult.h" +#import "ZXSMSMMSResultParser.h" +#import "ZXSMSParsedResult.h" + +@implementation ZXSMSMMSResultParser + +- (ZXParsedResult *)parse:(ZXResult *)result { + NSString *rawText = [ZXResultParser massagedText:result]; + if (!([rawText hasPrefix:@"sms:"] || [rawText hasPrefix:@"SMS:"] || [rawText hasPrefix:@"mms:"] || [rawText hasPrefix:@"MMS:"])) { + return nil; + } + + // Check up front if this is a URI syntax string with query arguments + NSMutableDictionary *nameValuePairs = [self parseNameValuePairs:rawText]; + NSString *subject = nil; + NSString *body = nil; + BOOL querySyntax = NO; + if (nameValuePairs != nil && [nameValuePairs count] > 0) { + subject = nameValuePairs[@"subject"]; + body = nameValuePairs[@"body"]; + querySyntax = YES; + } + + // Drop sms, query portion + NSUInteger queryStart = [rawText rangeOfString:@"?" options:NSLiteralSearch range:NSMakeRange(4, [rawText length] - 4)].location; + NSString *smsURIWithoutQuery; + // If it's not query syntax, the question mark is part of the subject or message + if (queryStart == NSNotFound || !querySyntax) { + smsURIWithoutQuery = [rawText substringFromIndex:4]; + } else { + smsURIWithoutQuery = [rawText substringWithRange:NSMakeRange(4, queryStart - 4)]; + } + + int lastComma = -1; + NSInteger comma; + NSMutableArray *numbers = [NSMutableArray arrayWithCapacity:1]; + NSMutableArray *vias = [NSMutableArray arrayWithCapacity:1]; + while ((comma = [smsURIWithoutQuery rangeOfString:@"," options:NSLiteralSearch range:NSMakeRange(lastComma + 1, (int)[smsURIWithoutQuery length] - lastComma - 1)].location) > lastComma && comma != NSNotFound) { + NSString *numberPart = [smsURIWithoutQuery substringWithRange:NSMakeRange(lastComma + 1, comma - lastComma - 1)]; + [self addNumberVia:numbers vias:vias numberPart:numberPart]; + lastComma = (int)comma; + } + [self addNumberVia:numbers vias:vias numberPart:[smsURIWithoutQuery substringFromIndex:lastComma + 1]]; + + return [ZXSMSParsedResult smsParsedResultWithNumbers:numbers + vias:vias + subject:subject + body:body]; +} + +- (void)addNumberVia:(NSMutableArray *)numbers vias:(NSMutableArray *)vias numberPart:(NSString *)numberPart { + NSUInteger numberEnd = [numberPart rangeOfString:@";"].location; + if (numberEnd == NSNotFound) { + [numbers addObject:numberPart]; + [vias addObject:[NSNull null]]; + } else { + [numbers addObject:[numberPart substringToIndex:numberEnd]]; + NSString *maybeVia = [numberPart substringFromIndex:numberEnd + 1]; + if ([maybeVia hasPrefix:@"via="]) { + [vias addObject:[maybeVia substringFromIndex:4]]; + } else { + [vias addObject:[NSNull null]]; + } + } +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXSMSParsedResult.h b/iDearQRCode/Tools/ZXingObjC/client/result/ZXSMSParsedResult.h new file mode 100755 index 0000000..0f594ff --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXSMSParsedResult.h @@ -0,0 +1,32 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXParsedResult.h" + +@interface ZXSMSParsedResult : ZXParsedResult + +@property (nonatomic, strong, readonly) NSArray *numbers; +@property (nonatomic, strong, readonly) NSArray *vias; +@property (nonatomic, copy, readonly) NSString *subject; +@property (nonatomic, copy, readonly) NSString *body; + +- (id)initWithNumber:(NSString *)number via:(NSString *)via subject:(NSString *)subject body:(NSString *)body; +- (id)initWithNumbers:(NSArray *)numbers vias:(NSArray *)vias subject:(NSString *)subject body:(NSString *)body; ++ (id)smsParsedResultWithNumber:(NSString *)number via:(NSString *)via subject:(NSString *)subject body:(NSString *)body; ++ (id)smsParsedResultWithNumbers:(NSArray *)numbers vias:(NSArray *)vias subject:(NSString *)subject body:(NSString *)body; +- (NSString *)sMSURI; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXSMSParsedResult.m b/iDearQRCode/Tools/ZXingObjC/client/result/ZXSMSParsedResult.m new file mode 100755 index 0000000..6d4510e --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXSMSParsedResult.m @@ -0,0 +1,97 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXSMSParsedResult.h" + +@implementation ZXSMSParsedResult + +- (id)initWithNumber:(NSString *)number via:(NSString *)via subject:(NSString *)subject body:(NSString *)body { + NSArray *numbers; + if (number) { + numbers = @[number]; + } + + NSArray *vias; + if (via) { + vias = @[via]; + } + + return [self initWithNumbers:numbers vias:vias subject:subject body:body]; +} + +- (id)initWithNumbers:(NSArray *)numbers vias:(NSArray *)vias subject:(NSString *)subject body:(NSString *)body { + if (self = [super initWithType:kParsedResultTypeSMS]) { + _numbers = numbers; + _vias = vias; + _subject = subject; + _body = body; + } + + return self; +} + ++ (id)smsParsedResultWithNumber:(NSString *)number via:(NSString *)via subject:(NSString *)subject body:(NSString *)body { + return [[self alloc] initWithNumber:number via:via subject:subject body:body]; +} + ++ (id)smsParsedResultWithNumbers:(NSArray *)numbers vias:(NSArray *)vias subject:(NSString *)subject body:(NSString *)body { + return [[self alloc] initWithNumbers:numbers vias:vias subject:subject body:body]; +} + +- (NSString *)sMSURI { + NSMutableString *result = [NSMutableString stringWithString:@"sms:"]; + BOOL first = YES; + for (int i = 0; i < self.numbers.count; i++) { + if (first) { + first = NO; + } else { + [result appendString:@","]; + } + [result appendString:self.numbers[i]]; + if (self.vias != nil && self.vias[i] != [NSNull null]) { + [result appendString:@";via="]; + [result appendString:self.vias[i]]; + } + } + + BOOL hasBody = self.body != nil; + BOOL hasSubject = self.subject != nil; + if (hasBody || hasSubject) { + [result appendString:@"?"]; + if (hasBody) { + [result appendString:@"body="]; + [result appendString:self.body]; + } + if (hasSubject) { + if (hasBody) { + [result appendString:@"&"]; + } + [result appendString:@"subject="]; + [result appendString:self.subject]; + } + } + return result; +} + +- (NSString *)displayResult { + NSMutableString *result = [NSMutableString stringWithCapacity:100]; + [ZXParsedResult maybeAppendArray:self.numbers result:result]; + [ZXParsedResult maybeAppend:self.subject result:result]; + [ZXParsedResult maybeAppend:self.body result:result]; + return result; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXSMSTOMMSTOResultParser.h b/iDearQRCode/Tools/ZXingObjC/client/result/ZXSMSTOMMSTOResultParser.h new file mode 100755 index 0000000..2408e67 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXSMSTOMMSTOResultParser.h @@ -0,0 +1,29 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXResultParser.h" + +/** + * Parses an "smsto:" URI result, whose format is not standardized but appears to be like: + * smsto:number(:body). + * + * This actually also parses URIs starting with "smsto:", "mmsto:", "SMSTO:", and + * "MMSTO:", and treats them all the same way, and effectively converts them to an "sms:" URI + * for purposes of forwarding to the platform. + */ +@interface ZXSMSTOMMSTOResultParser : ZXResultParser + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXSMSTOMMSTOResultParser.m b/iDearQRCode/Tools/ZXingObjC/client/result/ZXSMSTOMMSTOResultParser.m new file mode 100755 index 0000000..832c931 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXSMSTOMMSTOResultParser.m @@ -0,0 +1,40 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXResult.h" +#import "ZXSMSTOMMSTOResultParser.h" +#import "ZXSMSParsedResult.h" + +@implementation ZXSMSTOMMSTOResultParser + +- (ZXParsedResult *)parse:(ZXResult *)result { + NSString *rawText = [ZXResultParser massagedText:result]; + if (!([rawText hasPrefix:@"smsto:"] || [rawText hasPrefix:@"SMSTO:"] || [rawText hasPrefix:@"mmsto:"] || [rawText hasPrefix:@"MMSTO:"])) { + return nil; + } + // Thanks to dominik.wild for suggesting this enhancement to support + // smsto:number:body URIs + NSString *number = [rawText substringFromIndex:6]; + NSString *body = nil; + NSUInteger bodyStart = [number rangeOfString:@":"].location; + if (bodyStart != NSNotFound) { + body = [number substringFromIndex:bodyStart + 1]; + number = [number substringToIndex:bodyStart]; + } + return [ZXSMSParsedResult smsParsedResultWithNumber:number via:nil subject:nil body:body]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXSMTPResultParser.h b/iDearQRCode/Tools/ZXingObjC/client/result/ZXSMTPResultParser.h new file mode 100755 index 0000000..9897c72 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXSMTPResultParser.h @@ -0,0 +1,25 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXResultParser.h" + +/** + * Parses an "smtp:" URI result, whose format is not standardized but appears to be like: + * smtp[:subject[:body]]. + */ +@interface ZXSMTPResultParser : ZXResultParser + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXSMTPResultParser.m b/iDearQRCode/Tools/ZXingObjC/client/result/ZXSMTPResultParser.m new file mode 100755 index 0000000..f6b593b --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXSMTPResultParser.m @@ -0,0 +1,44 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXEmailAddressParsedResult.h" +#import "ZXResult.h" +#import "ZXSMTPResultParser.h" + +@implementation ZXSMTPResultParser + +- (ZXParsedResult *)parse:(ZXResult *)result { + NSString *rawText = [ZXResultParser massagedText:result]; + if (!([rawText hasPrefix:@"smtp:"] || [rawText hasPrefix:@"SMTP:"])) { + return nil; + } + NSString *emailAddress = [rawText substringFromIndex:5]; + NSString *subject = nil; + NSString *body = nil; + NSUInteger colon = [emailAddress rangeOfString:@":"].location; + if (colon != NSNotFound) { + subject = [emailAddress substringFromIndex:colon + 1]; + emailAddress = [emailAddress substringToIndex:colon]; + colon = [subject rangeOfString:@":"].location; + if (colon != NSNotFound) { + body = [subject substringFromIndex:colon + 1]; + subject = [subject substringToIndex:colon]; + } + } + return [[ZXEmailAddressParsedResult alloc] initWithTos:@[emailAddress] ccs:nil bccs:nil subject:subject body:body]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXTelParsedResult.h b/iDearQRCode/Tools/ZXingObjC/client/result/ZXTelParsedResult.h new file mode 100755 index 0000000..7c5d2d1 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXTelParsedResult.h @@ -0,0 +1,28 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXParsedResult.h" + +@interface ZXTelParsedResult : ZXParsedResult + +@property (nonatomic, copy, readonly) NSString *number; +@property (nonatomic, copy, readonly) NSString *telURI; +@property (nonatomic, copy, readonly) NSString *title; + +- (id)initWithNumber:(NSString *)number telURI:(NSString *)telURI title:(NSString *)title; ++ (id)telParsedResultWithNumber:(NSString *)number telURI:(NSString *)telURI title:(NSString *)title; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXTelParsedResult.m b/iDearQRCode/Tools/ZXingObjC/client/result/ZXTelParsedResult.m new file mode 100755 index 0000000..aed1b28 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXTelParsedResult.m @@ -0,0 +1,42 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXTelParsedResult.h" + +@implementation ZXTelParsedResult + +- (id)initWithNumber:(NSString *)number telURI:(NSString *)telURI title:(NSString *)title { + if (self = [super initWithType:kParsedResultTypeTel]) { + _number = number; + _telURI = telURI; + _title = title; + } + + return self; +} + ++ (id)telParsedResultWithNumber:(NSString *)number telURI:(NSString *)telURI title:(NSString *)title { + return [[self alloc] initWithNumber:number telURI:telURI title:title]; +} + +- (NSString *)displayResult { + NSMutableString *result = [NSMutableString stringWithCapacity:20]; + [ZXParsedResult maybeAppend:self.number result:result]; + [ZXParsedResult maybeAppend:self.title result:result]; + return result; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXTelResultParser.h b/iDearQRCode/Tools/ZXingObjC/client/result/ZXTelResultParser.h new file mode 100755 index 0000000..39c1e0a --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXTelResultParser.h @@ -0,0 +1,24 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXResultParser.h" + +/** + * Parses a "tel:" URI result, which specifies a phone number. + */ +@interface ZXTelResultParser : ZXResultParser + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXTelResultParser.m b/iDearQRCode/Tools/ZXingObjC/client/result/ZXTelResultParser.m new file mode 100755 index 0000000..529a934 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXTelResultParser.m @@ -0,0 +1,35 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXTelParsedResult.h" +#import "ZXTelResultParser.h" + +@implementation ZXTelResultParser + +- (ZXParsedResult *)parse:(ZXResult *)result { + NSString *rawText = [ZXResultParser massagedText:result]; + if (![rawText hasPrefix:@"tel:"] && ![rawText hasPrefix:@"TEL:"]) { + return nil; + } + // Normalize "TEL:" to "tel:" + NSString *telURI = [rawText hasPrefix:@"TEL:"] ? [@"tel:" stringByAppendingString:[rawText substringFromIndex:4]] : rawText; + // Drop tel, query portion + NSUInteger queryStart = [rawText rangeOfString:@"?" options:NSLiteralSearch range:NSMakeRange(4, [rawText length] - 4)].location; + NSString *number = queryStart == NSNotFound ? [rawText substringFromIndex:4] : [rawText substringWithRange:NSMakeRange(4, [rawText length] - queryStart)]; + return [ZXTelParsedResult telParsedResultWithNumber:number telURI:telURI title:nil]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXTextParsedResult.h b/iDearQRCode/Tools/ZXingObjC/client/result/ZXTextParsedResult.h new file mode 100755 index 0000000..deb211f --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXTextParsedResult.h @@ -0,0 +1,31 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXParsedResult.h" + +/** + * A simple result type encapsulating a string that has no further + * interpretation. + */ +@interface ZXTextParsedResult : ZXParsedResult + +@property (nonatomic, copy, readonly) NSString *text; +@property (nonatomic, copy, readonly) NSString *language; + +- (id)initWithText:(NSString *)text language:(NSString *)language; ++ (id)textParsedResultWithText:(NSString *)text language:(NSString *)language; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXTextParsedResult.m b/iDearQRCode/Tools/ZXingObjC/client/result/ZXTextParsedResult.m new file mode 100755 index 0000000..059fae0 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXTextParsedResult.m @@ -0,0 +1,39 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXParsedResultType.h" +#import "ZXTextParsedResult.h" + +@implementation ZXTextParsedResult + +- (id)initWithText:(NSString *)text language:(NSString *)language { + if (self = [super initWithType:kParsedResultTypeText]) { + _text = text; + _language = language; + } + + return self; +} + ++ (id)textParsedResultWithText:(NSString *)text language:(NSString *)language { + return [[self alloc] initWithText:text language:language]; +} + +- (NSString *)displayResult { + return self.text; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXURIParsedResult.h b/iDearQRCode/Tools/ZXingObjC/client/result/ZXURIParsedResult.h new file mode 100755 index 0000000..8443e6e --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXURIParsedResult.h @@ -0,0 +1,37 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXParsedResult.h" + +@interface ZXURIParsedResult : ZXParsedResult + +@property (nonatomic, copy, readonly) NSString *uri; +@property (nonatomic, copy, readonly) NSString *title; + +- (id)initWithUri:(NSString *)uri title:(NSString *)title; ++ (id)uriParsedResultWithUri:(NSString *)uri title:(NSString *)title; + +/** + * @return true if the URI contains suspicious patterns that may suggest it intends to + * mislead the user about its true nature. At the moment this looks for the presence + * of user/password syntax in the host/authority portion of a URI which may be used + * in attempts to make the URI's host appear to be other than it is. Example: + * http://yourbank.com@phisher.com This URI connects to phisher.com but may appear + * to connect to yourbank.com at first glance. + */ +- (BOOL)possiblyMaliciousURI; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXURIParsedResult.m b/iDearQRCode/Tools/ZXingObjC/client/result/ZXURIParsedResult.m new file mode 100755 index 0000000..3e66a76 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXURIParsedResult.m @@ -0,0 +1,80 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXResultParser.h" +#import "ZXURIParsedResult.h" + +static NSRegularExpression *ZX_USER_IN_HOST = nil; + +@implementation ZXURIParsedResult + ++ (void)initialize { + if ([self class] != [ZXURIParsedResult class]) return; + + ZX_USER_IN_HOST = [[NSRegularExpression alloc] initWithPattern:@":/*([^/@]+)@[^/]+" options:0 error:nil]; +} + +- (id)initWithUri:(NSString *)uri title:(NSString *)title { + if (self = [super initWithType:kParsedResultTypeURI]) { + _uri = [self massageURI:uri]; + _title = title; + } + + return self; +} + ++ (id)uriParsedResultWithUri:(NSString *)uri title:(NSString *)title { + return [[self alloc] initWithUri:uri title:title]; +} + +- (BOOL)possiblyMaliciousURI { + return [ZX_USER_IN_HOST numberOfMatchesInString:self.uri options:0 range:NSMakeRange(0, self.uri.length)] > 0; +} + +- (NSString *)displayResult { + NSMutableString *result = [NSMutableString stringWithCapacity:30]; + [ZXParsedResult maybeAppend:self.title result:result]; + [ZXParsedResult maybeAppend:self.uri result:result]; + return result; +} + +/** + * Transforms a string that represents a URI into something more proper, by adding or canonicalizing + * the protocol. + */ +- (NSString *)massageURI:(NSString *)uri { + NSString *massagedUri = [uri stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + NSUInteger protocolEnd = [massagedUri rangeOfString:@":"].location; + if (protocolEnd == NSNotFound) { + // No protocol, assume http + massagedUri = [NSString stringWithFormat:@"http://%@", massagedUri]; + } else if ([self isColonFollowedByPortNumber:massagedUri protocolEnd:(int)protocolEnd]) { + // Found a colon, but it looks like it is after the host, so the protocol is still missing + massagedUri = [NSString stringWithFormat:@"http://%@", massagedUri]; + } + return massagedUri; +} + +- (BOOL)isColonFollowedByPortNumber:(NSString *)uri protocolEnd:(int)protocolEnd { + int start = protocolEnd + 1; + NSUInteger nextSlash = [uri rangeOfString:@"/" options:0 range:NSMakeRange(start, [uri length] - start)].location; + if (nextSlash == NSNotFound) { + nextSlash = [uri length]; + } + return [ZXResultParser isSubstringOfDigits:uri offset:start length:(int)nextSlash - start]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXURIResultParser.h b/iDearQRCode/Tools/ZXingObjC/client/result/ZXURIResultParser.h new file mode 100755 index 0000000..6b17f8a --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXURIResultParser.h @@ -0,0 +1,26 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXResultParser.h" + +/** + * Tries to parse results that are a URI of some kind. + */ +@interface ZXURIResultParser : ZXResultParser + ++ (BOOL)isBasicallyValidURI:(NSString *)uri; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXURIResultParser.m b/iDearQRCode/Tools/ZXingObjC/client/result/ZXURIResultParser.m new file mode 100755 index 0000000..b1b4403 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXURIResultParser.m @@ -0,0 +1,66 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXURIResultParser.h" +#import "ZXResult.h" +#import "ZXURIParsedResult.h" + +static NSRegularExpression *ZX_URL_WITH_PROTOCOL_PATTERN = nil; +static NSRegularExpression *ZX_URL_WITHOUT_PROTOCOL_PATTERN = nil; + +@implementation ZXURIResultParser + ++ (void)initialize { + if ([self class] != [ZXURIResultParser class]) return; + + // See http://www.ietf.org/rfc/rfc2396.txt + ZX_URL_WITH_PROTOCOL_PATTERN = [[NSRegularExpression alloc] initWithPattern:@"^[a-zA-Z][a-zA-Z0-9+-.]+:" + options:0 + error:nil]; + ZX_URL_WITHOUT_PROTOCOL_PATTERN = [[NSRegularExpression alloc] initWithPattern: + [[@"([a-zA-Z0-9\\-]+\\.)+[a-zA-Z]{2,}" // host name elements + stringByAppendingString:@"(:\\d{1,5})?"] // maybe port + stringByAppendingString:@"(/|\\?|$)"] // query, path or nothing + options:0 + error:nil]; +} + +- (ZXParsedResult *)parse:(ZXResult *)result { + NSString *rawText = [ZXResultParser massagedText:result]; + // We specifically handle the odd "URL" scheme here for simplicity and add "URI" for fun + // Assume anything starting this way really means to be a URI + if ([rawText hasPrefix:@"URL:"] || [rawText hasPrefix:@"URI:"]) { + return [[ZXURIParsedResult alloc] initWithUri:[[rawText substringFromIndex:4] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] + title:nil]; + } + rawText = [rawText stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + return [[self class] isBasicallyValidURI:rawText] ? [ZXURIParsedResult uriParsedResultWithUri:rawText title:nil] : nil; +} + + ++ (BOOL)isBasicallyValidURI:(NSString *)uri { + if ([uri rangeOfString:@" "].location != NSNotFound) { + // Quick hack check for a common case + return NO; + } + + if ([ZX_URL_WITH_PROTOCOL_PATTERN numberOfMatchesInString:uri options:NSMatchingWithoutAnchoringBounds range:NSMakeRange(0, uri.length)] > 0) { // match at start only + return YES; + } + return [ZX_URL_WITHOUT_PROTOCOL_PATTERN numberOfMatchesInString:uri options:NSMatchingWithoutAnchoringBounds range:NSMakeRange(0, uri.length)] > 0; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXURLTOResultParser.h b/iDearQRCode/Tools/ZXingObjC/client/result/ZXURLTOResultParser.h new file mode 100755 index 0000000..dd1c01a --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXURLTOResultParser.h @@ -0,0 +1,26 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXResultParser.h" + +/** + * Parses the "URLTO" result format, which is of the form "URLTO:[title]:[url]". + * This seems to be used sometimes, but I am not able to find documentation + * on its origin or official format? + */ +@interface ZXURLTOResultParser : ZXResultParser + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXURLTOResultParser.m b/iDearQRCode/Tools/ZXingObjC/client/result/ZXURLTOResultParser.m new file mode 100755 index 0000000..b95b884 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXURLTOResultParser.m @@ -0,0 +1,37 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXResult.h" +#import "ZXURIParsedResult.h" +#import "ZXURLTOResultParser.h" + +@implementation ZXURLTOResultParser + +- (ZXParsedResult *)parse:(ZXResult *)result { + NSString *rawText = [ZXResultParser massagedText:result]; + if (![rawText hasPrefix:@"urlto:"] && ![rawText hasPrefix:@"URLTO:"]) { + return nil; + } + NSUInteger titleEnd = [rawText rangeOfString:@":" options:NSLiteralSearch range:NSMakeRange(6, [rawText length] - 6)].location; + if (titleEnd == NSNotFound) { + return nil; + } + NSString *title = titleEnd <= 6 ? nil : [rawText substringWithRange:NSMakeRange(6, titleEnd - 6)]; + NSString *uri = [rawText substringFromIndex:titleEnd + 1]; + return [ZXURIParsedResult uriParsedResultWithUri:uri title:title]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXVCardResultParser.h b/iDearQRCode/Tools/ZXingObjC/client/result/ZXVCardResultParser.h new file mode 100755 index 0000000..c1d946b --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXVCardResultParser.h @@ -0,0 +1,28 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXResultParser.h" + +/** + * Parses contact information formatted according to the VCard (2.1) format. This is not a complete + * implementation but should parse information as commonly encoded in 2D barcodes. + */ +@interface ZXVCardResultParser : ZXResultParser + ++ (NSArray *)matchSingleVCardPrefixedField:(NSString *)prefix rawText:(NSString *)rawText trim:(BOOL)trim parseFieldDivider:(BOOL)parseFieldDivider; ++ (NSMutableArray *)matchVCardPrefixedField:(NSString *)prefix rawText:(NSString *)rawText trim:(BOOL)trim parseFieldDivider:(BOOL)parseFieldDivider; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXVCardResultParser.m b/iDearQRCode/Tools/ZXingObjC/client/result/ZXVCardResultParser.m new file mode 100755 index 0000000..f82f104 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXVCardResultParser.m @@ -0,0 +1,356 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAddressBookParsedResult.h" +#import "ZXResult.h" +#import "ZXVCardResultParser.h" + +static NSRegularExpression *ZX_BEGIN_VCARD = nil; +static NSRegularExpression *ZX_VCARD_LIKE_DATE = nil; +static NSRegularExpression *ZX_CR_LF_SPACE_TAB = nil; +static NSRegularExpression *ZX_NEWLINE_ESCAPE = nil; +static NSRegularExpression *ZX_VCARD_ESCAPES = nil; +static NSString *ZX_EQUALS = @"="; +static NSString *ZX_SEMICOLON = @";"; +static NSRegularExpression *ZX_UNESCAPED_SEMICOLONS = nil; +static NSCharacterSet *ZX_COMMA = nil; +static NSCharacterSet *ZX_SEMICOLON_OR_COMMA = nil; + +@implementation ZXVCardResultParser + ++ (void)initialize { + if ([self class] != [ZXVCardResultParser class]) return; + + ZX_BEGIN_VCARD = [[NSRegularExpression alloc] initWithPattern:@"BEGIN:VCARD" options:NSRegularExpressionCaseInsensitive error:nil]; + ZX_VCARD_LIKE_DATE = [[NSRegularExpression alloc] initWithPattern:@"\\d{4}-?\\d{2}-?\\d{2}" options:0 error:nil]; + ZX_CR_LF_SPACE_TAB = [[NSRegularExpression alloc] initWithPattern:@"\r\n[ \t]" options:0 error:nil]; + ZX_NEWLINE_ESCAPE = [[NSRegularExpression alloc] initWithPattern:@"\\\\[nN]" options:0 error:nil]; + ZX_VCARD_ESCAPES = [[NSRegularExpression alloc] initWithPattern:@"\\\\([,;\\\\])" options:0 error:nil]; + ZX_UNESCAPED_SEMICOLONS = [[NSRegularExpression alloc] initWithPattern:@"(? 0) { + i--; // Find from i-1 not i since looking at the preceding character + } + NSArray *regexMatches = [regex matchesInString:rawText options:0 range:NSMakeRange(i, rawText.length - i)]; + if (regexMatches.count == 0) { + break; + } + NSRange matchRange = [regexMatches[0] range]; + i = matchRange.location + matchRange.length; + + NSString *metadataString = nil; + if ([regexMatches[0] rangeAtIndex:1].location != NSNotFound) { + metadataString = [rawText substringWithRange:[regexMatches[0] rangeAtIndex:1]]; + } + NSMutableArray *metadata = nil; + BOOL quotedPrintable = NO; + NSString *quotedPrintableCharset = nil; + if (metadataString != nil) { + for (NSString *metadatum in [metadataString componentsSeparatedByString:ZX_SEMICOLON]) { + if (metadata == nil) { + metadata = [NSMutableArray array]; + } + [metadata addObject:metadatum]; + NSUInteger equals = [metadatum rangeOfString:ZX_EQUALS].location; + if (equals != NSNotFound) { + NSString *key = [metadatum substringToIndex:equals]; + NSString *value = [metadatum substringFromIndex:equals + 1]; + if ([@"ENCODING" caseInsensitiveCompare:key] == NSOrderedSame && + [@"QUOTED-PRINTABLE" caseInsensitiveCompare:value] == NSOrderedSame) { + quotedPrintable = YES; + } else if ([@"CHARSET" caseInsensitiveCompare:key] == NSOrderedSame) { + quotedPrintableCharset = value; + } + } + } + } + + NSUInteger matchStart = i; // Found the start of a match here + + while ((NSUInteger)(i = [rawText rangeOfString:@"\n" options:NSLiteralSearch range:NSMakeRange(i, [rawText length] - i)].location) != NSNotFound) { // Really, end in \r\n + if (i < [rawText length] - 1 && // But if followed by tab or space, + ([rawText characterAtIndex:i + 1] == ' ' || // this is only a continuation + [rawText characterAtIndex:i + 1] == '\t')) { + i += 2; // Skip \n and continutation whitespace + } else if (quotedPrintable && // If preceded by = in quoted printable + ((i >= 1 && [rawText characterAtIndex:i - 1] == '=') || // this is a continuation + (i >= 2 && [rawText characterAtIndex:i - 2] == '='))) { + i++; // Skip \n + } else { + break; + } + } + + if (i == NSNotFound) { + // No terminating end character? uh, done. Set i such that loop terminates and break + i = max; + } else if (i > matchStart) { + // found a match + if (matches == nil) { + matches = [NSMutableArray arrayWithCapacity:1]; + } + if (i >= 1 && [rawText characterAtIndex:i-1] == '\r') { + i--; // Back up over \r, which really should be there + } + NSString *element = [rawText substringWithRange:NSMakeRange(matchStart, i - matchStart)]; + if (trim) { + element = [element stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + } + if (quotedPrintable) { + element = [self decodeQuotedPrintable:element charset:quotedPrintableCharset]; + if (parseFieldDivider) { + element = [[ZX_UNESCAPED_SEMICOLONS stringByReplacingMatchesInString:element options:0 range:NSMakeRange(0, element.length) withTemplate:@"\n"] + stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + } + } else { + if (parseFieldDivider) { + element = [[ZX_UNESCAPED_SEMICOLONS stringByReplacingMatchesInString:element options:0 range:NSMakeRange(0, element.length) withTemplate:@"\n"] + stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + } + element = [ZX_CR_LF_SPACE_TAB stringByReplacingMatchesInString:element options:0 range:NSMakeRange(0, element.length) withTemplate:@""]; + element = [ZX_NEWLINE_ESCAPE stringByReplacingMatchesInString:element options:0 range:NSMakeRange(0, element.length) withTemplate:@"\n"]; + element = [ZX_VCARD_ESCAPES stringByReplacingMatchesInString:element options:0 range:NSMakeRange(0, element.length) withTemplate:@"$1"]; + } + if (metadata == nil) { + NSMutableArray *match = [NSMutableArray arrayWithObject:element]; + [match addObject:element]; + [matches addObject:match]; + } else { + [metadata insertObject:element atIndex:0]; + [matches addObject:metadata]; + } + i++; + } else { + i++; + } + } + + return matches; +} + ++ (NSString *)decodeQuotedPrintable:(NSString *)value charset:(NSString *)charset { + NSUInteger length = [value length]; + NSMutableString *result = [NSMutableString stringWithCapacity:length]; + NSMutableData *fragmentBuffer = [NSMutableData data]; + + for (int i = 0; i < length; i++) { + unichar c = [value characterAtIndex:i]; + + switch (c) { + case '\r': + case '\n': + break; + case '=': + if (i < length - 2) { + unichar nextChar = [value characterAtIndex:i + 1]; + if (nextChar != '\r' && nextChar != '\n') { + unichar nextNextChar = [value characterAtIndex:i + 2]; + int firstDigit = [self parseHexDigit:nextChar]; + int secondDigit = [self parseHexDigit:nextNextChar]; + if (firstDigit >= 0 && secondDigit >= 0) { + int encodedByte = (firstDigit << 4) + secondDigit; + [fragmentBuffer appendBytes:&encodedByte length:1]; + } // else ignore it, assume it was incorrectly encoded + i += 2; + } + } + break; + default: + [self maybeAppendFragment:fragmentBuffer charset:charset result:result]; + [result appendFormat:@"%C", c]; + } + } + + [self maybeAppendFragment:fragmentBuffer charset:charset result:result]; + return result; +} + ++ (void)maybeAppendFragment:(NSMutableData *)fragmentBuffer charset:(NSString *)charset result:(NSMutableString *)result { + if ([fragmentBuffer length] > 0) { + NSString *fragment; + if (charset == nil || CFStringConvertIANACharSetNameToEncoding((CFStringRef)charset) == kCFStringEncodingInvalidId) { + fragment = [[NSString alloc] initWithData:fragmentBuffer encoding:NSUTF8StringEncoding]; + } else { + fragment = [[NSString alloc] initWithData:fragmentBuffer encoding:CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding((CFStringRef)charset))]; + if (!fragment) { + fragment = [[NSString alloc] initWithData:fragmentBuffer encoding:NSUTF8StringEncoding]; + } + } + [fragmentBuffer setLength:0]; + [result appendString:fragment]; + } +} + ++ (NSArray *)matchSingleVCardPrefixedField:(NSString *)prefix rawText:(NSString *)rawText trim:(BOOL)trim parseFieldDivider:(BOOL)parseFieldDivider { + NSArray *values = [self matchVCardPrefixedField:prefix rawText:rawText trim:trim parseFieldDivider:parseFieldDivider]; + return values == nil ? nil : values[0]; +} + +- (NSString *)toPrimaryValue:(NSArray *)list { + return list == nil || list.count == 0 ? nil : list[0]; +} + +- (NSArray *)toPrimaryValues:(NSArray *)lists { + if (lists == nil || lists.count == 0) { + return nil; + } + NSMutableArray *result = [NSMutableArray arrayWithCapacity:lists.count]; + for (NSArray *list in lists) { + NSString *value = list[0]; + if (value != nil && value.length > 0) { + [result addObject:value]; + } + } + return result; +} + +- (NSArray *)toTypes:(NSArray *)lists { + if (lists == nil || lists.count == 0) { + return nil; + } + NSMutableArray *result = [NSMutableArray arrayWithCapacity:lists.count]; + for (NSArray *list in lists) { + NSString *type = nil; + for (int i = 1; i < list.count; i++) { + NSString *metadatum = list[i]; + NSUInteger equals = [metadatum rangeOfString:@"=" options:NSCaseInsensitiveSearch].location; + if (equals == NSNotFound) { + // take the whole thing as a usable label + type = metadatum; + break; + } + if ([@"TYPE" isEqualToString:[[metadatum substringToIndex:equals] uppercaseString]]) { + type = [metadatum substringFromIndex:equals + 1]; + break; + } + } + + if (type) { + [result addObject:type]; + } else { + [result addObject:[NSNull null]]; + } + } + return result; +} + +- (BOOL)isLikeVCardDate:(NSString *)value { + return value == nil || [ZX_VCARD_LIKE_DATE numberOfMatchesInString:value options:0 range:NSMakeRange(0, value.length)] > 0; +} + +/** + * Formats name fields of the form "Public;John;Q.;Reverend;III" into a form like + * "Reverend John Q. Public III". + * + * @param names name values to format, in place + */ +- (void)formatNames:(NSMutableArray *)names { + if (names != nil) { + for (NSMutableArray *list in names) { + NSString *name = list[0]; + NSArray *allComponents = [name componentsSeparatedByString:@";"]; + NSMutableArray *components = [NSMutableArray array]; + for (NSString *component in allComponents) { + if ([component length] > 0) { + [components addObject:component]; + } + } + + NSMutableString *newName = [NSMutableString stringWithCapacity:100]; + [self maybeAppendComponent:components i:3 newName:newName]; + [self maybeAppendComponent:components i:1 newName:newName]; + [self maybeAppendComponent:components i:2 newName:newName]; + [self maybeAppendComponent:components i:0 newName:newName]; + [self maybeAppendComponent:components i:4 newName:newName]; + list[0] = [newName stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + } + } +} + +- (void)maybeAppendComponent:(NSArray *)components i:(int)i newName:(NSMutableString *)newName { + if ([components count] > i && components[i] && [(NSString *)components[i] length] > 0) { + if ([newName length] > 0) { + [newName appendString:@" "]; + } + [newName appendString:components[i]]; + } +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXVEventResultParser.h b/iDearQRCode/Tools/ZXingObjC/client/result/ZXVEventResultParser.h new file mode 100755 index 0000000..bedc558 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXVEventResultParser.h @@ -0,0 +1,25 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXResultParser.h" + +/** + * Partially implements the iCalendar format's "VEVENT" format for specifying a + * calendar event. See RFC 2445. This supports SUMMARY, LOCATION, GEO, DTSTART and DTEND fields. + */ +@interface ZXVEventResultParser : ZXResultParser + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXVEventResultParser.m b/iDearQRCode/Tools/ZXingObjC/client/result/ZXVEventResultParser.m new file mode 100755 index 0000000..f564087 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXVEventResultParser.m @@ -0,0 +1,108 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXCalendarParsedResult.h" +#import "ZXResult.h" +#import "ZXVCardResultParser.h" +#import "ZXVEventResultParser.h" + +@implementation ZXVEventResultParser + +- (ZXParsedResult *)parse:(ZXResult *)result { + NSString *rawText = [ZXResultParser massagedText:result]; + if (rawText == nil) { + return nil; + } + NSUInteger vEventStart = [rawText rangeOfString:@"BEGIN:VEVENT"].location; + if (vEventStart == NSNotFound) { + return nil; + } + + NSString *summary = [self matchSingleVCardPrefixedField:@"SUMMARY" rawText:rawText trim:YES]; + NSString *start = [self matchSingleVCardPrefixedField:@"DTSTART" rawText:rawText trim:YES]; + if (start == nil) { + return nil; + } + NSString *end = [self matchSingleVCardPrefixedField:@"DTEND" rawText:rawText trim:YES]; + NSString *duration = [self matchSingleVCardPrefixedField:@"DURATION" rawText:rawText trim:YES]; + NSString *location = [self matchSingleVCardPrefixedField:@"LOCATION" rawText:rawText trim:YES]; + NSString *organizer = [self stripMailto:[self matchSingleVCardPrefixedField:@"ORGANIZER" rawText:rawText trim:YES]]; + + NSMutableArray *attendees = [self matchVCardPrefixedField:@"ATTENDEE" rawText:rawText trim:YES]; + if (attendees != nil) { + for (int i = 0; i < attendees.count; i++) { + attendees[i] = [self stripMailto:attendees[i]]; + } + } + NSString *description = [self matchSingleVCardPrefixedField:@"DESCRIPTION" rawText:rawText trim:YES]; + + NSString *geoString = [self matchSingleVCardPrefixedField:@"GEO" rawText:rawText trim:YES]; + double latitude; + double longitude; + if (geoString == nil) { + latitude = NAN; + longitude = NAN; + } else { + NSUInteger semicolon = [geoString rangeOfString:@";"].location; + if (semicolon == NSNotFound) { + return nil; + } + latitude = [[geoString substringToIndex:semicolon] doubleValue]; + longitude = [[geoString substringFromIndex:semicolon + 1] doubleValue]; + } + + @try { + return [ZXCalendarParsedResult calendarParsedResultWithSummary:summary + startString:start + endString:end + durationString:duration + location:location + organizer:organizer + attendees:attendees + description:description + latitude:latitude + longitude:longitude]; + } @catch (NSException *iae) { + return nil; + } +} + +- (NSString *)matchSingleVCardPrefixedField:(NSString *)prefix rawText:(NSString *)rawText trim:(BOOL)trim { + NSArray *values = [ZXVCardResultParser matchSingleVCardPrefixedField:prefix rawText:rawText trim:trim parseFieldDivider:NO]; + return values == nil || values.count == 0 ? nil : values[0]; +} + +- (NSMutableArray *)matchVCardPrefixedField:(NSString *)prefix rawText:(NSString *)rawText trim:(BOOL)trim { + NSMutableArray *values = [ZXVCardResultParser matchVCardPrefixedField:prefix rawText:rawText trim:trim parseFieldDivider:NO]; + if (values == nil || values.count == 0) { + return nil; + } + NSUInteger size = values.count; + NSMutableArray *result = [NSMutableArray arrayWithCapacity:size]; + for (int i = 0; i < size; i++) { + [result addObject:values[i][0]]; + } + return result; +} + +- (NSString *)stripMailto:(NSString *)s { + if (s != nil && ([s hasPrefix:@"mailto:"] || [s hasPrefix:@"MAILTO:"])) { + s = [s substringFromIndex:7]; + } + return s; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXVINParsedResult.h b/iDearQRCode/Tools/ZXingObjC/client/result/ZXVINParsedResult.h new file mode 100755 index 0000000..e312462 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXVINParsedResult.h @@ -0,0 +1,37 @@ +/* + * Copyright 2014 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXParsedResult.h" + +@interface ZXVINParsedResult : ZXParsedResult + +@property (nonatomic, copy, readonly) NSString *vin; +@property (nonatomic, copy, readonly) NSString *worldManufacturerID; +@property (nonatomic, copy, readonly) NSString *vehicleDescriptorSection; +@property (nonatomic, copy, readonly) NSString *vehicleIdentifierSection; +@property (nonatomic, copy, readonly) NSString *countryCode; +@property (nonatomic, copy, readonly) NSString *vehicleAttributes; +@property (nonatomic, assign, readonly) int modelYear; +@property (nonatomic, assign, readonly) unichar plantCode; +@property (nonatomic, copy, readonly) NSString *sequentialNumber; + +- (id)initWithVIN:(NSString *)vin worldManufacturerID:(NSString *)worldManufacturerID + vehicleDescriptorSection:(NSString *)vehicleDescriptorSection vehicleIdentifierSection:(NSString *)vehicleIdentifierSection + countryCode:(NSString *)countryCode vehicleAttributes:(NSString *)vehicleAttributes modelYear:(int)modelYear + plantCode:(unichar)plantCode sequentialNumber:(NSString *)sequentialNumber; + + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXVINParsedResult.m b/iDearQRCode/Tools/ZXingObjC/client/result/ZXVINParsedResult.m new file mode 100755 index 0000000..1baea36 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXVINParsedResult.m @@ -0,0 +1,54 @@ +/* + * Copyright 2014 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXVINParsedResult.h" + +@implementation ZXVINParsedResult + +- (id)initWithVIN:(NSString *)vin worldManufacturerID:(NSString *)worldManufacturerID +vehicleDescriptorSection:(NSString *)vehicleDescriptorSection vehicleIdentifierSection:(NSString *)vehicleIdentifierSection + countryCode:(NSString *)countryCode vehicleAttributes:(NSString *)vehicleAttributes modelYear:(int)modelYear + plantCode:(unichar)plantCode sequentialNumber:(NSString *)sequentialNumber { + if (self = [super initWithType:kParsedResultTypeVIN]) { + _vin = vin; + _worldManufacturerID = worldManufacturerID; + _vehicleDescriptorSection = vehicleDescriptorSection; + _vehicleIdentifierSection = vehicleIdentifierSection; + _countryCode = countryCode; + _vehicleAttributes = vehicleAttributes; + _modelYear = modelYear; + _plantCode = plantCode; + _sequentialNumber = sequentialNumber; + } + + return self; +} + +- (NSString *)displayResult { + NSMutableString *result = [NSMutableString stringWithCapacity:50]; + [result appendFormat:@"%@ ", self.worldManufacturerID]; + [result appendFormat:@"%@ ", self.vehicleDescriptorSection]; + [result appendFormat:@"%@\n", self.vehicleIdentifierSection]; + if (self.countryCode) { + [result appendFormat:@"%@ ", self.countryCode]; + } + [result appendFormat:@"%d ", self.modelYear]; + [result appendFormat:@"%C ", self.plantCode]; + [result appendFormat:@"%@\n", self.sequentialNumber]; + return [NSString stringWithString:result]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXVINResultParser.h b/iDearQRCode/Tools/ZXingObjC/client/result/ZXVINResultParser.h new file mode 100755 index 0000000..73f5b3b --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXVINResultParser.h @@ -0,0 +1,24 @@ +/* + * Copyright 2014 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXResultParser.h" + +/** + * Detects a result that is likely a vehicle identification number. + */ +@interface ZXVINResultParser : ZXResultParser + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXVINResultParser.m b/iDearQRCode/Tools/ZXingObjC/client/result/ZXVINResultParser.m new file mode 100755 index 0000000..6865792 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXVINResultParser.m @@ -0,0 +1,219 @@ +/* + * Copyright 2014 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXVINParsedResult.h" +#import "ZXVINResultParser.h" + +static NSRegularExpression *ZX_IOQ = nil; +static NSRegularExpression *ZX_AZ09 = nil; + +@implementation ZXVINResultParser + ++ (void)initialize { + if ([self class] != [ZXVINResultParser class]) return; + + ZX_IOQ = [[NSRegularExpression alloc] initWithPattern:@"[IOQ]" options:0 error:nil]; + ZX_AZ09 = [[NSRegularExpression alloc] initWithPattern:@"[A-Z0-9]{17}" options:0 error:nil]; +} + +- (ZXVINParsedResult *)parse:(ZXResult *)result { + if (result.barcodeFormat != kBarcodeFormatCode39) { + return nil; + } + NSString *rawText = result.text; + rawText = [[ZX_IOQ stringByReplacingMatchesInString:rawText options:0 range:NSMakeRange(0, rawText.length) withTemplate:@""] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + if ([ZX_AZ09 matchesInString:rawText options:0 range:NSMakeRange(0, rawText.length)] == 0) { + return nil; + } + if (![self checkChecksum:rawText]) { + return nil; + } + + int modelYear = [self modelYear:[rawText characterAtIndex:9]]; + if (modelYear == -1) { + return nil; + } + + NSString *wmi = [rawText substringToIndex:3]; + return [[ZXVINParsedResult alloc] initWithVIN:rawText + worldManufacturerID:wmi + vehicleDescriptorSection:[rawText substringWithRange:NSMakeRange(3, 6)] + vehicleIdentifierSection:[rawText substringWithRange:NSMakeRange(9, 8)] + countryCode:[self countryCode:wmi] + vehicleAttributes:[rawText substringWithRange:NSMakeRange(3, 5)] + modelYear:modelYear + plantCode:[rawText characterAtIndex:10] + sequentialNumber:[rawText substringFromIndex:11]]; +} + +- (BOOL)checkChecksum:(NSString *)vin { + int sum = 0; + for (int i = 0; i < [vin length]; i++) { + int vinPositionWeight = [self vinPositionWeight:i + 1]; + if (vinPositionWeight == -1) { + return NO; + } + int vinCharValue = [self vinCharValue:[vin characterAtIndex:i]]; + if (vinCharValue == -1) { + return NO; + } + sum += vinPositionWeight * vinCharValue; + } + unichar checkChar = [vin characterAtIndex:8]; + if (checkChar == '\0') { + return NO; + } + unichar expectedCheckChar = [self checkChar:sum % 11]; + return checkChar == expectedCheckChar; +} + +- (int)vinCharValue:(unichar)c { + if (c >= 'A' && c <= 'I') { + return (c - 'A') + 1; + } + if (c >= 'J' && c <= 'R') { + return (c - 'J') + 1; + } + if (c >= 'S' && c <= 'Z') { + return (c - 'S') + 2; + } + if (c >= '0' && c <= '9') { + return c - '0'; + } + return -1; +} + +- (int)vinPositionWeight:(int)position { + if (position >= 1 && position <= 7) { + return 9 - position; + } + if (position == 8) { + return 10; + } + if (position == 9) { + return 0; + } + if (position >= 10 && position <= 17) { + return 19 - position; + } + return -1; +} + +- (unichar)checkChar:(int)remainder { + if (remainder < 10) { + return (unichar) ('0' + remainder); + } + if (remainder == 10) { + return 'X'; + } + return '\0'; +} + +- (int)modelYear:(unichar)c { + if (c >= 'E' && c <= 'H') { + return (c - 'E') + 1984; + } + if (c >= 'J' && c <= 'N') { + return (c - 'J') + 1988; + } + if (c == 'P') { + return 1993; + } + if (c >= 'R' && c <= 'T') { + return (c - 'R') + 1994; + } + if (c >= 'V' && c <= 'Y') { + return (c - 'V') + 1997; + } + if (c >= '1' && c <= '9') { + return (c - '1') + 2001; + } + if (c >= 'A' && c <= 'D') { + return (c - 'A') + 2010; + } + return -1; +} + +- (NSString *)countryCode:(NSString *)wmi { + unichar c1 = [wmi characterAtIndex:0]; + unichar c2 = [wmi characterAtIndex:1]; + switch (c1) { + case '1': + case '4': + case '5': + return @"US"; + case '2': + return @"CA"; + case '3': + if (c2 >= 'A' && c2 <= 'W') { + return @"MX"; + } + break; + case '9': + if ((c2 >= 'A' && c2 <= 'E') || (c2 >= '3' && c2 <= '9')) { + return @"BR"; + } + break; + case 'J': + if (c2 >= 'A' && c2 <= 'T') { + return @"JP"; + } + break; + case 'K': + if (c2 >= 'L' && c2 <= 'R') { + return @"KO"; + } + break; + case 'L': + return @"CN"; + case 'M': + if (c2 >= 'A' && c2 <= 'E') { + return @"IN"; + } + break; + case 'S': + if (c2 >= 'A' && c2 <= 'M') { + return @"UK"; + } + if (c2 >= 'N' && c2 <= 'T') { + return @"DE"; + } + break; + case 'V': + if (c2 >= 'F' && c2 <= 'R') { + return @"FR"; + } + if (c2 >= 'S' && c2 <= 'W') { + return @"ES"; + } + break; + case 'W': + return @"DE"; + case 'X': + if (c2 == '0' || (c2 >= '3' && c2 <= '9')) { + return @"RU"; + } + break; + case 'Z': + if (c2 >= 'A' && c2 <= 'R') { + return @"IT"; + } + break; + } + return nil; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXWifiParsedResult.h b/iDearQRCode/Tools/ZXingObjC/client/result/ZXWifiParsedResult.h new file mode 100755 index 0000000..708a1df --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXWifiParsedResult.h @@ -0,0 +1,31 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXParsedResult.h" + +@interface ZXWifiParsedResult : ZXParsedResult + +@property (nonatomic, copy, readonly) NSString *ssid; +@property (nonatomic, copy, readonly) NSString *networkEncryption; +@property (nonatomic, copy, readonly) NSString *password; +@property (nonatomic, assign, readonly) BOOL hidden; + +- (id)initWithNetworkEncryption:(NSString *)networkEncryption ssid:(NSString *)ssid password:(NSString *)password; +- (id)initWithNetworkEncryption:(NSString *)networkEncryption ssid:(NSString *)ssid password:(NSString *)password hidden:(BOOL)hidden; ++ (id)wifiParsedResultWithNetworkEncryption:(NSString *)networkEncryption ssid:(NSString *)ssid password:(NSString *)password; ++ (id)wifiParsedResultWithNetworkEncryption:(NSString *)networkEncryption ssid:(NSString *)ssid password:(NSString *)password hidden:(BOOL)hidden; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXWifiParsedResult.m b/iDearQRCode/Tools/ZXingObjC/client/result/ZXWifiParsedResult.m new file mode 100755 index 0000000..cc6e655 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXWifiParsedResult.m @@ -0,0 +1,54 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXParsedResultType.h" +#import "ZXWifiParsedResult.h" + +@implementation ZXWifiParsedResult + +- (id)initWithNetworkEncryption:(NSString *)networkEncryption ssid:(NSString *)ssid password:(NSString *)password { + return [self initWithNetworkEncryption:networkEncryption ssid:ssid password:password]; +} + +- (id)initWithNetworkEncryption:(NSString *)networkEncryption ssid:(NSString *)ssid password:(NSString *)password hidden:(BOOL)hidden { + if (self = [super initWithType:kParsedResultTypeWifi]) { + _ssid = ssid; + _networkEncryption = networkEncryption; + _password = password; + _hidden = hidden; + } + + return self; +} + ++ (id)wifiParsedResultWithNetworkEncryption:(NSString *)networkEncryption ssid:(NSString *)ssid password:(NSString *)password { + return [[self alloc] initWithNetworkEncryption:networkEncryption ssid:ssid password:password]; +} + ++ (id)wifiParsedResultWithNetworkEncryption:(NSString *)networkEncryption ssid:(NSString *)ssid password:(NSString *)password hidden:(BOOL)hidden { + return [[self alloc] initWithNetworkEncryption:networkEncryption ssid:ssid password:password hidden:hidden]; +} + +- (NSString *)displayResult { + NSMutableString *result = [NSMutableString stringWithCapacity:80]; + [ZXParsedResult maybeAppend:self.ssid result:result]; + [ZXParsedResult maybeAppend:self.networkEncryption result:result]; + [ZXParsedResult maybeAppend:self.password result:result]; + [ZXParsedResult maybeAppend:[@(self.hidden) stringValue] result:result]; + return result; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXWifiResultParser.h b/iDearQRCode/Tools/ZXingObjC/client/result/ZXWifiResultParser.h new file mode 100755 index 0000000..9c85c9a --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXWifiResultParser.h @@ -0,0 +1,28 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXResultParser.h" + +/** + * Parses a WIFI configuration string. Strings will be of the form: + * + * WIFI:T:[network type];S:[SSID];P:[network password];H:[hidden?];; + * + * The fields can appear in any order. Only "S:" is required. + */ +@interface ZXWifiResultParser : ZXResultParser + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/client/result/ZXWifiResultParser.m b/iDearQRCode/Tools/ZXingObjC/client/result/ZXWifiResultParser.m new file mode 100755 index 0000000..3b70ed2 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/client/result/ZXWifiResultParser.m @@ -0,0 +1,42 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXResult.h" +#import "ZXWifiResultParser.h" +#import "ZXWifiParsedResult.h" + +@implementation ZXWifiResultParser + +- (ZXParsedResult *)parse:(ZXResult *)result { + NSString *rawText = [ZXResultParser massagedText:result]; + if (![rawText hasPrefix:@"WIFI:"]) { + return nil; + } + NSString *ssid = [[self class] matchSinglePrefixedField:@"S:" rawText:rawText endChar:';' trim:NO]; + if (ssid == nil || ssid.length == 0) { + return nil; + } + NSString *pass = [[self class] matchSinglePrefixedField:@"P:" rawText:rawText endChar:';' trim:NO]; + NSString *type = [[self class] matchSinglePrefixedField:@"T:" rawText:rawText endChar:';' trim:NO]; + if (type == nil) { + type = @"nopass"; + } + + BOOL hidden = [[[self class] matchSinglePrefixedField:@"H:" rawText:rawText endChar:';' trim:NO] boolValue]; + return [ZXWifiParsedResult wifiParsedResultWithNetworkEncryption:type ssid:ssid password:pass hidden:hidden]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/ZXBitArray.h b/iDearQRCode/Tools/ZXingObjC/common/ZXBitArray.h new file mode 100755 index 0000000..0243264 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/ZXBitArray.h @@ -0,0 +1,132 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXByteArray, ZXIntArray; + +/** + * A simple, fast array of bits, represented compactly by an array of ints internally. + */ +@interface ZXBitArray : NSObject + +/** + * @return underlying array of ints. The first element holds the first 32 bits, and the least + * significant bit is bit 0. + */ +@property (nonatomic, assign, readonly) int32_t *bits; + +@property (nonatomic, assign, readonly) int size; + +- (id)initWithSize:(int)size; + +- (int)sizeInBytes; + +/** + * @param i bit to get + * @return true iff bit i is set + */ +- (BOOL)get:(int)i; + +/** + * Sets bit i. + * + * @param i bit to set + */ +- (void)set:(int)i; + +/** + * Flips bit i. + * + * @param i bit to set + */ +- (void)flip:(int)i; + +/** + * @param from first bit to check + * @return index of first bit that is set, starting from the given index, or size if none are set + * at or beyond this given index + */ +- (int)nextSet:(int)from; + +- (int)nextUnset:(int)from; + +/** + * Sets a block of 32 bits, starting at bit i. + * + * @param i first bit to set + * @param newBits the new value of the next 32 bits. Note again that the least-significant bit + * corresponds to bit i, the next-least-significant to i+1, and so on. + */ +- (void)setBulk:(int)i newBits:(int32_t)newBits; + +/** + * Sets a range of bits. + * + * @param start start of range, inclusive. + * @param end end of range, exclusive + */ +- (void)setRange:(int)start end:(int)end; + +/** + * Clears all bits (sets to false). + */ +- (void)clear; + +/** + * Efficient method to check if a range of bits is set, or not set. + * + * @param start start of range, inclusive. + * @param end end of range, exclusive + * @param value if true, checks that bits in range are set, otherwise checks that they are not set + * @return true iff all bits are set or not set in range, according to value argument + * @throws NSInvalidArgumentException if end is less than or equal to start + */ +- (BOOL)isRange:(int)start end:(int)end value:(BOOL)value; + +- (void)appendBit:(BOOL)bit; + +/** + * Appends the least-significant bits, from value, in order from most-significant to + * least-significant. For example, appending 6 bits from 0x000001E will append the bits + * 0, 1, 1, 1, 1, 0 in that order. + */ +- (void)appendBits:(int32_t)value numBits:(int)numBits; + +- (void)appendBitArray:(ZXBitArray *)other; + +- (void)xor:(ZXBitArray *)other; + +/** + * + * @param bitOffset first bit to start writing + * @param array array to write into. Bytes are written most-significant byte first. This is the opposite + * of the internal representation, which is exposed by {@link #getBitArray()} + * @param offset position in array to start writing + * @param numBytes how many bytes to write + */ +- (void)toBytes:(int)bitOffset array:(ZXByteArray *)array offset:(int)offset numBytes:(int)numBytes; + +/** + * @return underlying array of ints. The first element holds the first 32 bits, and the least + * significant bit is bit 0. + */ +- (ZXIntArray *)bitArray; + +/** + * Reverses all bits in the array. + */ +- (void)reverse; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/ZXBitArray.m b/iDearQRCode/Tools/ZXingObjC/common/ZXBitArray.m new file mode 100755 index 0000000..9e415d3 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/ZXBitArray.m @@ -0,0 +1,348 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitArray.h" +#import "ZXByteArray.h" +#import "ZXIntArray.h" + +@interface ZXBitArray () + +@property (nonatomic, assign) int32_t *bits; +@property (nonatomic, assign) int bitsLength; +@property (nonatomic, assign) int size; + +@end + +@implementation ZXBitArray + +- (id)init { + if (self = [super init]) { + _size = 0; + _bits = (int32_t *)calloc(1, sizeof(int32_t)); + _bitsLength = 1; + } + + return self; +} + +// For testing only +- (id)initWithBits:(ZXIntArray *)bits size:(int)size { + if (self = [self initWithSize:size]) { + _bits = bits.array; + _bits = (int32_t *)malloc(bits.length * sizeof(int32_t)); + memcpy(_bits, bits.array, bits.length * sizeof(int32_t)); + _bitsLength = bits.length; + } + + return self; +} + +- (id)initWithSize:(int)size { + if (self = [super init]) { + _size = size; + _bitsLength = (size + 31) / 32; + _bits = (int32_t *)calloc(_bitsLength, sizeof(int32_t)); + } + + return self; +} + +- (void)dealloc { + if (_bits != NULL) { + free(_bits); + _bits = NULL; + } +} + +- (int)sizeInBytes { + return (self.size + 7) / 8; +} + +- (void)ensureCapacity:(int)size { + if (size > self.bitsLength * 32) { + int newBitsLength = (size + 31) / 32; + self.bits = realloc(self.bits, newBitsLength * sizeof(int32_t)); + memset(self.bits + self.bitsLength, 0, (newBitsLength - self.bitsLength) * sizeof(int32_t)); + + self.bitsLength = newBitsLength; + } +} + +- (BOOL)get:(int)i { + return (_bits[i / 32] & (1 << (i & 0x1F))) != 0; +} + +- (void)set:(int)i { + _bits[i / 32] |= 1 << (i & 0x1F); +} + +- (void)flip:(int)i { + _bits[i / 32] ^= 1 << (i & 0x1F); +} + +- (int)nextSet:(int)from { + if (from >= self.size) { + return self.size; + } + int bitsOffset = from / 32; + int32_t currentBits = self.bits[bitsOffset]; + // mask off lesser bits first + currentBits &= ~((1 << (from & 0x1F)) - 1); + while (currentBits == 0) { + if (++bitsOffset == self.bitsLength) { + return self.size; + } + currentBits = self.bits[bitsOffset]; + } + int result = (bitsOffset * 32) + [self numberOfTrailingZeros:currentBits]; + return result > self.size ? self.size : result; +} + +- (int)nextUnset:(int)from { + if (from >= self.size) { + return self.size; + } + int bitsOffset = from / 32; + int32_t currentBits = ~self.bits[bitsOffset]; + // mask off lesser bits first + currentBits &= ~((1 << (from & 0x1F)) - 1); + while (currentBits == 0) { + if (++bitsOffset == self.bitsLength) { + return self.size; + } + currentBits = ~self.bits[bitsOffset]; + } + int result = (bitsOffset * 32) + [self numberOfTrailingZeros:currentBits]; + return result > self.size ? self.size : result; +} + +- (void)setBulk:(int)i newBits:(int32_t)newBits { + _bits[i / 32] = newBits; +} + +- (void)setRange:(int)start end:(int)end { + if (end < start) { + @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Start greater than end" userInfo:nil]; + } + if (end == start) { + return; + } + end--; // will be easier to treat this as the last actually set bit -- inclusive + int firstInt = start / 32; + int lastInt = end / 32; + for (int i = firstInt; i <= lastInt; i++) { + int firstBit = i > firstInt ? 0 : start & 0x1F; + int lastBit = i < lastInt ? 31 : end & 0x1F; + int32_t mask; + if (lastBit > 31) { + @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Bit-shift operand does not support more than 31 bits" userInfo:nil]; + } + if (firstBit == 0 && lastBit == 31) { + mask = -1; + } else { + mask = 0; + for (int j = firstBit; j <= lastBit; j++) { + mask |= 1 << j; + } + } + _bits[i] |= mask; + } +} + +- (void)clear { + memset(self.bits, 0, self.bitsLength * sizeof(int32_t)); +} + +- (BOOL)isRange:(int)start end:(int)end value:(BOOL)value { + if (end < start) { + @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Start greater than end" userInfo:nil]; + } + if (end == start) { + return YES; // empty range matches + } + end--; // will be easier to treat this as the last actually set bit -- inclusive + int firstInt = start / 32; + int lastInt = end / 32; + for (int i = firstInt; i <= lastInt; i++) { + int firstBit = i > firstInt ? 0 : start & 0x1F; + int lastBit = i < lastInt ? 31 : end & 0x1F; + int32_t mask; + if (lastBit > 31) { + @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Bit-shift operand does not support more than 31 bits" userInfo:nil]; + } + if (firstBit == 0 && lastBit == 31) { + mask = -1; + } else { + mask = 0; + for (int j = firstBit; j <= lastBit; j++) { + mask |= 1 << j; + } + } + + // Return false if we're looking for 1s and the masked bits[i] isn't all 1s (that is, + // equals the mask, or we're looking for 0s and the masked portion is not all 0s + if ((_bits[i] & mask) != (value ? mask : 0)) { + return NO; + } + } + + return YES; +} + +- (void)appendBit:(BOOL)bit { + [self ensureCapacity:self.size + 1]; + if (bit) { + self.bits[self.size / 32] |= 1 << (self.size & 0x1F); + } + self.size++; +} + +- (void)appendBits:(int32_t)value numBits:(int)numBits { + if (numBits < 0 || numBits > 32) { + @throw [NSException exceptionWithName:NSInvalidArgumentException + reason:@"Num bits must be between 0 and 32" + userInfo:nil]; + } + [self ensureCapacity:self.size + numBits]; + for (int numBitsLeft = numBits; numBitsLeft > 0; numBitsLeft--) { + [self appendBit:((value >> (numBitsLeft - 1)) & 0x01) == 1]; + } +} + +- (void)appendBitArray:(ZXBitArray *)other { + int otherSize = [other size]; + [self ensureCapacity:self.size + otherSize]; + + for (int i = 0; i < otherSize; i++) { + [self appendBit:[other get:i]]; + } +} + +- (void)xor:(ZXBitArray *)other { + if (self.bitsLength != other.bitsLength) { + @throw [NSException exceptionWithName:NSInvalidArgumentException + reason:@"Sizes don't match" + userInfo:nil]; + } + + for (int i = 0; i < self.bitsLength; i++) { + // The last byte could be incomplete (i.e. not have 8 bits in + // it) but there is no problem since 0 XOR 0 == 0. + self.bits[i] ^= other.bits[i]; + } +} + +- (void)toBytes:(int)bitOffset array:(ZXByteArray *)array offset:(int)offset numBytes:(int)numBytes { + for (int i = 0; i < numBytes; i++) { + int32_t theByte = 0; + for (int j = 0; j < 8; j++) { + if ([self get:bitOffset]) { + theByte |= 1 << (7 - j); + } + bitOffset++; + } + array.array[offset + i] = (int8_t) theByte; + } +} + +- (ZXIntArray *)bitArray { + ZXIntArray *array = [[ZXIntArray alloc] initWithLength:self.bitsLength]; + memcpy(array.array, self.bits, array.length * sizeof(int32_t)); + return array; +} + +- (BOOL)isEqual:(id)o { + if (![o isKindOfClass:[ZXBitArray class]]) { + return NO; + } + ZXBitArray *other = (ZXBitArray *)o; + return self.size == other.size && memcmp(self.bits, other.bits, self.bitsLength) != 0; +} + +- (NSUInteger)hash { + return 31 * self.size; +} + +- (void)reverse { + int32_t *newBits = (int32_t *)calloc(self.bitsLength, sizeof(int32_t)); + int size = self.size; + + // reverse all int's first + int len = ((size-1) / 32); + int oldBitsLen = len + 1; + for (int i = 0; i < oldBitsLen; i++) { + long x = (long) self.bits[i]; + x = ((x >> 1) & 0x55555555L) | ((x & 0x55555555L) << 1); + x = ((x >> 2) & 0x33333333L) | ((x & 0x33333333L) << 2); + x = ((x >> 4) & 0x0f0f0f0fL) | ((x & 0x0f0f0f0fL) << 4); + x = ((x >> 8) & 0x00ff00ffL) | ((x & 0x00ff00ffL) << 8); + x = ((x >> 16) & 0x0000ffffL) | ((x & 0x0000ffffL) << 16); + newBits[len - i] = (int32_t) x; + } + // now correct the int's if the bit size isn't a multiple of 32 + if (size != oldBitsLen * 32) { + int leftOffset = oldBitsLen * 32 - size; + int mask = 1; + for (int i = 0; i < 31 - leftOffset; i++) { + mask = (mask << 1) | 1; + } + int32_t currentInt = (newBits[0] >> leftOffset) & mask; + for (int i = 1; i < oldBitsLen; i++) { + int32_t nextInt = newBits[i]; + currentInt |= nextInt << (32 - leftOffset); + newBits[i - 1] = currentInt; + currentInt = (nextInt >> leftOffset) & mask; + } + newBits[oldBitsLen - 1] = currentInt; + } + if (self.bits != NULL) { + free(self.bits); + } + self.bits = newBits; +} + +- (NSString *)description { + NSMutableString *result = [NSMutableString string]; + + for (int i = 0; i < self.size; i++) { + if ((i & 0x07) == 0) { + [result appendString:@" "]; + } + [result appendString:[self get:i] ? @"X" : @"."]; + } + + return result; +} + +// Ported from OpenJDK Integer.numberOfTrailingZeros implementation +- (int32_t)numberOfTrailingZeros:(int32_t)i { + int32_t y; + if (i == 0) return 32; + int32_t n = 31; + y = i <<16; if (y != 0) { n = n -16; i = y; } + y = i << 8; if (y != 0) { n = n - 8; i = y; } + y = i << 4; if (y != 0) { n = n - 4; i = y; } + y = i << 2; if (y != 0) { n = n - 2; i = y; } + return n - (int32_t)((uint32_t)(i << 1) >> 31); +} + +- (id)copyWithZone:(NSZone *)zone { + ZXBitArray *copy = [[ZXBitArray allocWithZone:zone] initWithSize:self.size]; + memcpy(copy.bits, self.bits, self.size * sizeof(int32_t)); + return copy; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/ZXBitMatrix.h b/iDearQRCode/Tools/ZXingObjC/common/ZXBitMatrix.h new file mode 100755 index 0000000..be65fcf --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/ZXBitMatrix.h @@ -0,0 +1,153 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXBitArray, ZXIntArray; + +/** + * Represents a 2D matrix of bits. In function arguments below, and throughout the common + * module, x is the column position, and y is the row position. The ordering is always x, y. + * The origin is at the top-left. + * + * Internally the bits are represented in a 1-D array of 32-bit ints. However, each row begins + * with a new NSInteger. This is done intentionally so that we can copy out a row into a BitArray very + * efficiently. + * + * The ordering of bits is row-major. Within each NSInteger, the least significant bits are used first, + * meaning they represent lower x values. This is compatible with BitArray's implementation. + */ +@interface ZXBitMatrix : NSObject + +/** + * @return The width of the matrix + */ +@property (nonatomic, assign, readonly) int width; + +/** + * @return The height of the matrix + */ +@property (nonatomic, assign, readonly) int height; + +@property (nonatomic, assign, readonly) int32_t *bits; + +/** + * @return The row size of the matrix + */ +@property (nonatomic, assign, readonly) int rowSize; + +// A helper to construct a square matrix. +- (id)initWithDimension:(int)dimension; +- (id)initWithWidth:(int)width height:(int)height; + ++ (ZXBitMatrix *)parse:(NSString *)stringRepresentation + setString:(NSString *)setString + unsetString:(NSString *)unsetString; + +/** + * Gets the requested bit, where true means black. + * + * @param x The horizontal component (i.e. which column) + * @param y The vertical component (i.e. which row) + * @return value of given bit in matrix + */ +- (BOOL)getX:(int)x y:(int)y; + +/** + * Sets the given bit to true. + * + * @param x The horizontal component (i.e. which column) + * @param y The vertical component (i.e. which row) + */ +- (void)setX:(int)x y:(int)y; + +- (void)unsetX:(int)x y:(int)y; + +/** + * Flips the given bit. + * + * @param x The horizontal component (i.e. which column) + * @param y The vertical component (i.e. which row) + */ +- (void)flipX:(int)x y:(int)y; + +/** + * Exclusive-or (XOR): Flip the bit in this ZXBitMatrix if the corresponding + * mask bit is set. + * + * @param mask XOR mask + */ +- (void)xor:(ZXBitMatrix *)mask; + +/** + * Clears all bits (sets to false). + */ +- (void)clear; + +/** + * Sets a square region of the bit matrix to true. + * + * @param left The horizontal position to begin at (inclusive) + * @param top The vertical position to begin at (inclusive) + * @param width The width of the region + * @param height The height of the region + */ +- (void)setRegionAtLeft:(int)left top:(int)top width:(int)width height:(int)height; + +/** + * A fast method to retrieve one row of data from the matrix as a ZXBitArray. + * + * @param y The row to retrieve + * @param row An optional caller-allocated BitArray, will be allocated if null or too small + * @return The resulting BitArray - this reference should always be used even when passing + * your own row + */ +- (ZXBitArray *)rowAtY:(int)y row:(ZXBitArray *)row; + +/** + * @param y row to set + * @param row ZXBitArray to copy from + */ +- (void)setRowAtY:(int)y row:(ZXBitArray *)row; + +/** + * Modifies this ZXBitMatrix to represent the same but rotated 180 degrees + */ +- (void)rotate180; + +/** + * This is useful in detecting the enclosing rectangle of a 'pure' barcode. + * + * @return {left,top,width,height} enclosing rectangle of all 1 bits, or null if it is all white + */ +- (ZXIntArray *)enclosingRectangle; + +/** + * This is useful in detecting a corner of a 'pure' barcode. + * + * @return {x,y} coordinate of top-left-most 1 bit, or null if it is all white + */ +- (ZXIntArray *)topLeftOnBit; + +- (ZXIntArray *)bottomRightOnBit; + +- (NSString *)descriptionWithSetString:(NSString *)setString unsetString:(NSString *)unsetString; + +/** + * @deprecated call descriptionWithSetString:unsetString: only, which uses \n line separator always + */ +- (NSString *)descriptionWithSetString:(NSString *)setString unsetString:(NSString *)unsetString + lineSeparator:(NSString *)lineSeparator DEPRECATED_ATTRIBUTE; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/ZXBitMatrix.m b/iDearQRCode/Tools/ZXingObjC/common/ZXBitMatrix.m new file mode 100755 index 0000000..4e03103 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/ZXBitMatrix.m @@ -0,0 +1,377 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitArray.h" +#import "ZXBitMatrix.h" +#import "ZXBoolArray.h" +#import "ZXIntArray.h" + +@interface ZXBitMatrix () + +@property (nonatomic, assign, readonly) int bitsSize; + +@end + +@implementation ZXBitMatrix + +- (id)initWithDimension:(int)dimension { + return [self initWithWidth:dimension height:dimension]; +} + +- (id)initWithWidth:(int)width height:(int)height { + if (self = [super init]) { + if (width < 1 || height < 1) { + @throw [NSException exceptionWithName:NSInvalidArgumentException + reason:@"Both dimensions must be greater than 0" + userInfo:nil]; + } + _width = width; + _height = height; + _rowSize = (_width + 31) / 32; + _bitsSize = _rowSize * _height; + _bits = (int32_t *)malloc(_bitsSize * sizeof(int32_t)); + [self clear]; + } + + return self; +} + +- (id)initWithWidth:(int)width height:(int)height rowSize:(int)rowSize bits:(int32_t *)bits { + if (self = [super init]) { + _width = width; + _height = height; + _rowSize = rowSize; + _bitsSize = _rowSize * _height; + _bits = (int32_t *)malloc(_bitsSize * sizeof(int32_t)); + memcpy(_bits, bits, _bitsSize * sizeof(int32_t)); + } + + return self; +} + +- (void)dealloc { + if (_bits != NULL) { + free(_bits); + _bits = NULL; + } +} + ++ (ZXBitMatrix *)parse:(NSString *)stringRepresentation + setString:(NSString *)setString + unsetString:(NSString *)unsetString { + if (!stringRepresentation) { + @throw [NSException exceptionWithName:@"IllegalArgumentException" + reason:@"stringRepresentation is required" + userInfo:nil]; + } + + ZXBoolArray *bits = [[ZXBoolArray alloc] initWithLength:(unsigned int)stringRepresentation.length]; + int bitsPos = 0; + int rowStartPos = 0; + int rowLength = -1; + int nRows = 0; + int pos = 0; + while (pos < stringRepresentation.length) { + if ([stringRepresentation characterAtIndex:pos] == '\n' || + [stringRepresentation characterAtIndex:pos] == '\r') { + if (bitsPos > rowStartPos) { + if(rowLength == -1) { + rowLength = bitsPos - rowStartPos; + } else if (bitsPos - rowStartPos != rowLength) { + @throw [NSException exceptionWithName:@"IllegalArgumentException" + reason:@"row lengths do not match" + userInfo:nil]; + } + rowStartPos = bitsPos; + nRows++; + } + pos++; + } else if ([[stringRepresentation substringWithRange:NSMakeRange(pos, setString.length)] isEqualToString:setString]) { + pos += setString.length; + bits.array[bitsPos] = YES; + bitsPos++; + } else if ([[stringRepresentation substringWithRange:NSMakeRange(pos, unsetString.length)] isEqualToString:unsetString]) { + pos += unsetString.length; + bits.array[bitsPos] = NO; + bitsPos++; + } else { + @throw [NSException exceptionWithName:@"IllegalArgumentException" + reason:[NSString stringWithFormat:@"illegal character encountered: %@", [stringRepresentation substringFromIndex:pos]] + userInfo:nil]; + } + } + + // no EOL at end? + if (bitsPos > rowStartPos) { + if (rowLength == -1) { + rowLength = bitsPos - rowStartPos; + } else if (bitsPos - rowStartPos != rowLength) { + @throw [NSException exceptionWithName:@"IllegalArgumentException" + reason:@"row lengths do not match" + userInfo:nil]; + } + nRows++; + } + + ZXBitMatrix *matrix = [[ZXBitMatrix alloc] initWithWidth:rowLength height:nRows]; + for (int i = 0; i < bitsPos; i++) { + if (bits.array[i]) { + [matrix setX:i % rowLength y:i / rowLength]; + } + } + return matrix; +} + +- (BOOL)getX:(int)x y:(int)y { + NSInteger offset = y * self.rowSize + (x / 32); + return ((_bits[offset] >> (x & 0x1f)) & 1) != 0; +} + +- (void)setX:(int)x y:(int)y { + NSInteger offset = y * self.rowSize + (x / 32); + _bits[offset] |= 1 << (x & 0x1f); +} + +- (void)unsetX:(int)x y:(int)y { + int offset = y * self.rowSize + (x / 32); + _bits[offset] &= ~(1 << (x & 0x1f)); +} + +- (void)flipX:(int)x y:(int)y { + NSUInteger offset = y * self.rowSize + (x / 32); + _bits[offset] ^= 1 << (x & 0x1f); +} + +- (void)xor:(ZXBitMatrix *)mask { + if (self.width != mask.width || self.height != mask.height + || self.rowSize != mask.rowSize) { + @throw [NSException exceptionWithName:NSInvalidArgumentException + reason:@"input matrix dimensions do not match" + userInfo:nil]; + } + ZXBitArray *rowArray = [[ZXBitArray alloc] initWithSize:self.width]; + for (int y = 0; y < self.height; y++) { + int offset = y * self.rowSize; + int32_t *row = [mask rowAtY:y row:rowArray].bits; + for (int x = 0; x < self.rowSize; x++) { + self.bits[offset + x] ^= row[x]; + } + } +} + +- (void)clear { + NSInteger max = self.bitsSize; + memset(_bits, 0, max * sizeof(int32_t)); +} + +- (void)setRegionAtLeft:(int)left top:(int)top width:(int)aWidth height:(int)aHeight { + if (aHeight < 1 || aWidth < 1) { + @throw [NSException exceptionWithName:NSInvalidArgumentException + reason:@"Height and width must be at least 1" + userInfo:nil]; + } + NSUInteger right = left + aWidth; + NSUInteger bottom = top + aHeight; + if (bottom > self.height || right > self.width) { + @throw [NSException exceptionWithName:NSInvalidArgumentException + reason:@"The region must fit inside the matrix" + userInfo:nil]; + } + for (NSUInteger y = top; y < bottom; y++) { + NSUInteger offset = y * self.rowSize; + for (NSInteger x = left; x < right; x++) { + _bits[offset + (x / 32)] |= 1 << (x & 0x1f); + } + } +} + +- (ZXBitArray *)rowAtY:(int)y row:(ZXBitArray *)row { + if (row == nil || [row size] < self.width) { + row = [[ZXBitArray alloc] initWithSize:self.width]; + } else { + [row clear]; + } + int offset = y * self.rowSize; + for (int x = 0; x < self.rowSize; x++) { + [row setBulk:x * 32 newBits:_bits[offset + x]]; + } + + return row; +} + +- (void)setRowAtY:(int)y row:(ZXBitArray *)row { + for (NSUInteger i = 0; i < self.rowSize; i++) { + _bits[(y * self.rowSize) + i] = row.bits[i]; + } +} + +- (void)rotate180 { + int width = self.width; + int height = self.height; + ZXBitArray *topRow = [[ZXBitArray alloc] initWithSize:width]; + ZXBitArray *bottomRow = [[ZXBitArray alloc] initWithSize:width]; + for (int i = 0; i < (height+1) / 2; i++) { + topRow = [self rowAtY:i row:topRow]; + bottomRow = [self rowAtY:height - 1 - i row:bottomRow]; + [topRow reverse]; + [bottomRow reverse]; + [self setRowAtY:i row:bottomRow]; + [self setRowAtY:height - 1 - i row:topRow]; + } +} + +- (ZXIntArray *)enclosingRectangle { + int left = self.width; + int top = self.height; + int right = -1; + int bottom = -1; + + for (int y = 0; y < self.height; y++) { + for (int x32 = 0; x32 < self.rowSize; x32++) { + int32_t theBits = _bits[y * self.rowSize + x32]; + if (theBits != 0) { + if (y < top) { + top = y; + } + if (y > bottom) { + bottom = y; + } + if (x32 * 32 < left) { + int32_t bit = 0; + while ((theBits << (31 - bit)) == 0) { + bit++; + } + if ((x32 * 32 + bit) < left) { + left = x32 * 32 + bit; + } + } + if (x32 * 32 + 31 > right) { + int bit = 31; + while ((theBits >> bit) == 0) { + bit--; + } + if ((x32 * 32 + bit) > right) { + right = x32 * 32 + bit; + } + } + } + } + } + + NSInteger width = right - left; + NSInteger height = bottom - top; + + if (width < 0 || height < 0) { + return nil; + } + + return [[ZXIntArray alloc] initWithInts:left, top, width, height, -1]; +} + +- (ZXIntArray *)topLeftOnBit { + int bitsOffset = 0; + while (bitsOffset < self.bitsSize && _bits[bitsOffset] == 0) { + bitsOffset++; + } + if (bitsOffset == self.bitsSize) { + return nil; + } + int y = bitsOffset / self.rowSize; + int x = (bitsOffset % self.rowSize) * 32; + + int32_t theBits = _bits[bitsOffset]; + int32_t bit = 0; + while ((theBits << (31 - bit)) == 0) { + bit++; + } + x += bit; + return [[ZXIntArray alloc] initWithInts:x, y, -1]; +} + +- (ZXIntArray *)bottomRightOnBit { + int bitsOffset = self.bitsSize - 1; + while (bitsOffset >= 0 && _bits[bitsOffset] == 0) { + bitsOffset--; + } + if (bitsOffset < 0) { + return nil; + } + + int y = bitsOffset / self.rowSize; + int x = (bitsOffset % self.rowSize) * 32; + + int32_t theBits = _bits[bitsOffset]; + int32_t bit = 31; + while ((theBits >> bit) == 0) { + bit--; + } + x += bit; + + return [[ZXIntArray alloc] initWithInts:x, y, -1]; +} + +- (BOOL)isEqual:(NSObject *)o { + if (!([o isKindOfClass:[ZXBitMatrix class]])) { + return NO; + } + ZXBitMatrix *other = (ZXBitMatrix *)o; + for (int i = 0; i < self.bitsSize; i++) { + if (_bits[i] != other.bits[i]) { + return NO; + } + } + return self.width == other.width && self.height == other.height && self.rowSize == other.rowSize && self.bitsSize == other.bitsSize; +} + +- (NSUInteger)hash { + NSInteger hash = self.width; + hash = 31 * hash + self.width; + hash = 31 * hash + self.height; + hash = 31 * hash + self.rowSize; + for (NSUInteger i = 0; i < self.bitsSize; i++) { + hash = 31 * hash + _bits[i]; + } + return hash; +} + +- (NSString *)description { + return [self descriptionWithSetString:@"X " unsetString:@" "]; +} + +- (NSString *)descriptionWithSetString:(NSString *)setString unsetString:(NSString *)unsetString { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + return [self descriptionWithSetString:setString unsetString:unsetString lineSeparator:@"\n"]; +#pragma GCC diagnostic pop +} + +- (NSString *)descriptionWithSetString:(NSString *)setString unsetString:(NSString *)unsetString + lineSeparator:(NSString *)lineSeparator { + NSMutableString *result = [NSMutableString stringWithCapacity:self.height * (self.width + 1)]; + for (int y = 0; y < self.height; y++) { + for (int x = 0; x < self.width; x++) { + [result appendString:[self getX:x y:y] ? setString : unsetString]; + } + [result appendString:lineSeparator]; + } + return result; +} + +- (id)copyWithZone:(NSZone *)zone { + return [[ZXBitMatrix allocWithZone:zone] initWithWidth:self.width height:self.height rowSize:self.rowSize bits:self.bits]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/ZXBitSource.h b/iDearQRCode/Tools/ZXingObjC/common/ZXBitSource.h new file mode 100755 index 0000000..6cc0d5e --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/ZXBitSource.h @@ -0,0 +1,57 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXByteArray; + +/** + * This provides an easy abstraction to read bits at a time from a sequence of bytes, where the + * number of bits read is not often a multiple of 8. + * + * This class is thread-safe but not reentrant -- unless the caller modifies the bytes array + * it passed in, in which case all bets are off. + */ +@interface ZXBitSource : NSObject + +/** + * @return index of next bit in current byte which would be read by the next call to {@link #readBits(int)}. + */ +@property (nonatomic, assign, readonly) int bitOffset; + +/** + * @return index of next byte in input byte array which would be read by the next call to {@link #readBits(int)}. + */ +@property (nonatomic, assign, readonly) int byteOffset; + +/** + * @param bytes bytes from which this will read bits. Bits will be read from the first byte first. + * Bits are read within a byte from most-significant to least-significant bit. + */ +- (id)initWithBytes:(ZXByteArray *)bytes; + +/** + * @param numBits number of bits to read + * @return int representing the bits read. The bits will appear as the least-significant + * bits of the int + * @throws NSInvalidArgumentException if numBits isn't in [1,32] or more than is available + */ +- (int)readBits:(int)numBits; + +/** + * @return number of bits that can be read successfully + */ +- (int)available; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/ZXBitSource.m b/iDearQRCode/Tools/ZXingObjC/common/ZXBitSource.m new file mode 100755 index 0000000..9453f32 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/ZXBitSource.m @@ -0,0 +1,84 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitSource.h" +#import "ZXByteArray.h" + +@interface ZXBitSource () + +@property (nonatomic, strong, readonly) ZXByteArray *bytes; +@property (nonatomic, assign) int byteOffset; +@property (nonatomic, assign) int bitOffset; + +@end + +@implementation ZXBitSource + +- (id)initWithBytes:(ZXByteArray *)bytes { + if (self = [super init]) { + _bytes = bytes; + } + + return self; +} + +- (int)readBits:(int)numBits { + if (numBits < 1 || numBits > 32 || numBits > self.available) { + [NSException raise:NSInvalidArgumentException format:@"Invalid number of bits: %d", numBits]; + } + + int result = 0; + + // First, read remainder from current byte + if (self.bitOffset > 0) { + int bitsLeft = 8 - self.bitOffset; + int toRead = numBits < bitsLeft ? numBits : bitsLeft; + int bitsToNotRead = bitsLeft - toRead; + int mask = (0xFF >> (8 - toRead)) << bitsToNotRead; + result = (self.bytes.array[self.byteOffset] & mask) >> bitsToNotRead; + numBits -= toRead; + self.bitOffset += toRead; + if (self.bitOffset == 8) { + self.bitOffset = 0; + self.byteOffset++; + } + } + + // Next read whole bytes + if (numBits > 0) { + while (numBits >= 8) { + result = (result << 8) | (self.bytes.array[self.byteOffset] & 0xFF); + self.byteOffset++; + numBits -= 8; + } + + // Finally read a partial byte + if (numBits > 0) { + int bitsToNotRead = 8 - numBits; + int mask = (0xFF >> bitsToNotRead) << bitsToNotRead; + result = (result << numBits) | ((self.bytes.array[self.byteOffset] & mask) >> bitsToNotRead); + self.bitOffset += numBits; + } + } + + return result; +} + +- (int)available { + return 8 * (self.bytes.length - self.byteOffset) - self.bitOffset; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/ZXBoolArray.h b/iDearQRCode/Tools/ZXingObjC/common/ZXBoolArray.h new file mode 100755 index 0000000..582d3a3 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/ZXBoolArray.h @@ -0,0 +1,24 @@ +/* + * Copyright 2014 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@interface ZXBoolArray : NSObject + +@property (nonatomic, assign, readonly) BOOL *array; +@property (nonatomic, assign, readonly) unsigned int length; + +- (id)initWithLength:(unsigned int)length; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/ZXBoolArray.m b/iDearQRCode/Tools/ZXingObjC/common/ZXBoolArray.m new file mode 100755 index 0000000..9639f87 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/ZXBoolArray.m @@ -0,0 +1,36 @@ +/* + * Copyright 2014 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBoolArray.h" + +@implementation ZXBoolArray + +- (id)initWithLength:(unsigned int)length { + if (self = [super init]) { + _array = (BOOL *)calloc(length, sizeof(BOOL)); + _length = length; + } + + return self; +} + +- (void)dealloc { + if (_array) { + free(_array); + } +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/ZXByteArray.h b/iDearQRCode/Tools/ZXingObjC/common/ZXByteArray.h new file mode 100755 index 0000000..e837cc6 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/ZXByteArray.h @@ -0,0 +1,25 @@ +/* + * Copyright 2014 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@interface ZXByteArray : NSObject + +@property (nonatomic, assign, readonly) int8_t *array; +@property (nonatomic, assign, readonly) unsigned int length; + +- (id)initWithLength:(unsigned int)length; +- (id)initWithBytes:(int8_t)byte1, ...; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/ZXByteArray.m b/iDearQRCode/Tools/ZXingObjC/common/ZXByteArray.m new file mode 100755 index 0000000..8c4ca58 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/ZXByteArray.m @@ -0,0 +1,76 @@ +/* + * Copyright 2014 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXByteArray.h" + +@implementation ZXByteArray + +- (id)initWithLength:(unsigned int)length { + if (self = [super init]) { + if (length > 0) { + _array = (int8_t *)calloc(length, sizeof(int8_t)); + } else { + _array = NULL; + } + _length = length; + } + + return self; +} + +- (id)initWithBytes:(int8_t)byte1, ... { + va_list args; + va_start(args, byte1); + unsigned int length = 0; + for (int8_t byte = byte1; byte != -1; byte = va_arg(args, int)) { + length++; + } + va_end(args); + + if ((self = [self initWithLength:length]) && (length > 0)) { + va_list args; + va_start(args, byte1); + int i = 0; + for (int8_t byte = byte1; byte != -1; byte = va_arg(args, int)) { + _array[i++] = byte; + } + va_end(args); + } + + return self; +} + +- (void)dealloc { + if (_array) { + free(_array); + } +} + +- (NSString *)description { + NSMutableString *s = [NSMutableString stringWithFormat:@"length=%u, array=(", self.length]; + + for (int i = 0; i < self.length; i++) { + [s appendFormat:@"%d", self.array[i]]; + if (i < self.length - 1) { + [s appendString:@", "]; + } + } + + [s appendString:@")"]; + return s; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/ZXCharacterSetECI.h b/iDearQRCode/Tools/ZXingObjC/common/ZXCharacterSetECI.h new file mode 100755 index 0000000..ea855f2 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/ZXCharacterSetECI.h @@ -0,0 +1,40 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Encapsulates a Character Set ECI, according to "Extended Channel Interpretations" 5.3.1.1 + * of ISO 18004. + */ +@interface ZXCharacterSetECI : NSObject + +@property (nonatomic, assign, readonly) NSStringEncoding encoding; +@property (nonatomic, assign, readonly) int value; + +/** + * @param value character set ECI value + * @return CharacterSetECI representing ECI of given value, or nil if it is legal but + * unsupported + */ ++ (ZXCharacterSetECI *)characterSetECIByValue:(int)value; + +/** + * @param name character set ECI encoding name + * @return CharacterSetECI representing ECI for character encoding, or nil if it is legal + * but unsupported + */ ++ (ZXCharacterSetECI *)characterSetECIByEncoding:(NSStringEncoding)encoding; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/ZXCharacterSetECI.m b/iDearQRCode/Tools/ZXingObjC/common/ZXCharacterSetECI.m new file mode 100755 index 0000000..6d2398f --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/ZXCharacterSetECI.m @@ -0,0 +1,94 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXCharacterSetECI.h" +#import "ZXErrors.h" + +static NSMutableDictionary *VALUE_TO_ECI = nil; +static NSMutableDictionary *ENCODING_TO_ECI = nil; + +@implementation ZXCharacterSetECI + ++ (void)initialize { + if ([self class] != [ZXCharacterSetECI class]) return; + + VALUE_TO_ECI = [[NSMutableDictionary alloc] initWithCapacity:29]; + ENCODING_TO_ECI = [[NSMutableDictionary alloc] initWithCapacity:29]; + [self addCharacterSet:0 encoding:(NSStringEncoding) 0x80000400]; + [self addCharacterSet:1 encoding:NSISOLatin1StringEncoding]; + [self addCharacterSet:2 encoding:(NSStringEncoding) 0x80000400]; + [self addCharacterSet:3 encoding:NSISOLatin1StringEncoding]; + [self addCharacterSet:4 encoding:NSISOLatin2StringEncoding]; + [self addCharacterSet:5 encoding:(NSStringEncoding) 0x80000203]; + [self addCharacterSet:6 encoding:(NSStringEncoding) 0x80000204]; + [self addCharacterSet:7 encoding:(NSStringEncoding) 0x80000205]; + [self addCharacterSet:8 encoding:(NSStringEncoding) 0x80000206]; + [self addCharacterSet:9 encoding:(NSStringEncoding) 0x80000207]; + [self addCharacterSet:10 encoding:(NSStringEncoding) 0x80000208]; + [self addCharacterSet:11 encoding:(NSStringEncoding) 0x80000209]; + [self addCharacterSet:12 encoding:(NSStringEncoding) 0x8000020A]; + [self addCharacterSet:13 encoding:(NSStringEncoding) 0x8000020B]; + [self addCharacterSet:15 encoding:(NSStringEncoding) 0x8000020D]; + [self addCharacterSet:16 encoding:(NSStringEncoding) 0x8000020E]; + [self addCharacterSet:17 encoding:(NSStringEncoding) 0x8000020F]; + [self addCharacterSet:18 encoding:(NSStringEncoding) 0x80000210]; + [self addCharacterSet:20 encoding:NSShiftJISStringEncoding]; + [self addCharacterSet:21 encoding:NSWindowsCP1250StringEncoding]; + [self addCharacterSet:22 encoding:NSWindowsCP1251StringEncoding]; + [self addCharacterSet:23 encoding:NSWindowsCP1252StringEncoding]; + [self addCharacterSet:24 encoding:(NSStringEncoding) 0x80000505]; + [self addCharacterSet:25 encoding:NSUTF16BigEndianStringEncoding]; + [self addCharacterSet:26 encoding:NSUTF8StringEncoding]; + [self addCharacterSet:27 encoding:NSASCIIStringEncoding]; + [self addCharacterSet:28 encoding:(NSStringEncoding) 0x80000A03]; + [self addCharacterSet:29 encoding:(NSStringEncoding) 0x80000632]; + [self addCharacterSet:30 encoding:(NSStringEncoding) 0x80000940]; + [self addCharacterSet:170 encoding:NSASCIIStringEncoding]; +} + +- (id)initWithValue:(int)value encoding:(NSStringEncoding)encoding { + if (self = [super init]) { + _value = value; + _encoding = encoding; + } + + return self; +} + ++ (void)addCharacterSet:(int)value encoding:(NSStringEncoding)encoding { + ZXCharacterSetECI *eci = [[ZXCharacterSetECI alloc] initWithValue:value encoding:encoding]; + VALUE_TO_ECI[@(value)] = eci; + ENCODING_TO_ECI[@(encoding)] = eci; +} + ++ (ZXCharacterSetECI *)characterSetECIByValue:(int)value { + if (VALUE_TO_ECI == nil) { + [self initialize]; + } + if (value < 0 || value >= 900) { + return nil; + } + return VALUE_TO_ECI[@(value)]; +} + ++ (ZXCharacterSetECI *)characterSetECIByEncoding:(NSStringEncoding)encoding { + if (ENCODING_TO_ECI == nil) { + [self initialize]; + } + return ENCODING_TO_ECI[@(encoding)]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/ZXDecoderResult.h b/iDearQRCode/Tools/ZXingObjC/common/ZXDecoderResult.h new file mode 100755 index 0000000..4d92c3a --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/ZXDecoderResult.h @@ -0,0 +1,45 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXByteArray; + +/** + * Encapsulates the result of decoding a matrix of bits. This typically + * applies to 2D barcode formats. For now it contains the raw bytes obtained, + * as well as a String interpretation of those bytes, if applicable. + */ +@interface ZXDecoderResult : NSObject + +@property (nonatomic, strong, readonly) ZXByteArray *rawBytes; +@property (nonatomic, copy, readonly) NSString *text; +@property (nonatomic, strong, readonly) NSMutableArray *byteSegments; +@property (nonatomic, copy, readonly) NSString *ecLevel; +@property (nonatomic, copy) NSNumber *errorsCorrected; +@property (nonatomic, copy) NSNumber *erasures; +@property (nonatomic, strong) id other; +@property (nonatomic, assign, readonly) int structuredAppendParity; +@property (nonatomic, assign, readonly) int structuredAppendSequenceNumber; + +- (id)initWithRawBytes:(ZXByteArray *)rawBytes text:(NSString *)text + byteSegments:(NSMutableArray *)byteSegments ecLevel:(NSString *)ecLevel; + +- (id)initWithRawBytes:(ZXByteArray *)rawBytes text:(NSString *)text + byteSegments:(NSMutableArray *)byteSegments ecLevel:(NSString *)ecLevel + saSequence:(int)saSequence saParity:(int)saParity; + +- (BOOL)hasStructuredAppend; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/ZXDecoderResult.m b/iDearQRCode/Tools/ZXingObjC/common/ZXDecoderResult.m new file mode 100755 index 0000000..3e60556 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/ZXDecoderResult.m @@ -0,0 +1,45 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXDecoderResult.h" + +@implementation ZXDecoderResult + +- (id)initWithRawBytes:(ZXByteArray *)rawBytes text:(NSString *)text + byteSegments:(NSMutableArray *)byteSegments ecLevel:(NSString *)ecLevel { + return [self initWithRawBytes:rawBytes text:text byteSegments:byteSegments ecLevel:ecLevel saSequence:-1 saParity:-1]; +} + +- (id)initWithRawBytes:(ZXByteArray *)rawBytes text:(NSString *)text + byteSegments:(NSMutableArray *)byteSegments ecLevel:(NSString *)ecLevel + saSequence:(int)saSequence saParity:(int)saParity { + if (self = [super init]) { + _rawBytes = rawBytes; + _text = text; + _byteSegments = byteSegments; + _ecLevel = ecLevel; + _structuredAppendParity = saParity; + _structuredAppendSequenceNumber = saSequence; + } + + return self; +} + +- (BOOL)hasStructuredAppend { + return self.structuredAppendParity >= 0 && self.structuredAppendSequenceNumber >= 0; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/ZXDefaultGridSampler.h b/iDearQRCode/Tools/ZXingObjC/common/ZXDefaultGridSampler.h new file mode 100755 index 0000000..b7776cc --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/ZXDefaultGridSampler.h @@ -0,0 +1,23 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXGridSampler.h" + +@class ZXBitMatrix, ZXPerspectiveTransform; + +@interface ZXDefaultGridSampler : ZXGridSampler + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/ZXDefaultGridSampler.m b/iDearQRCode/Tools/ZXingObjC/common/ZXDefaultGridSampler.m new file mode 100755 index 0000000..c4445c5 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/ZXDefaultGridSampler.m @@ -0,0 +1,91 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitMatrix.h" +#import "ZXDefaultGridSampler.h" +#import "ZXErrors.h" +#import "ZXPerspectiveTransform.h" + +@implementation ZXDefaultGridSampler + +- (ZXBitMatrix *)sampleGrid:(ZXBitMatrix *)image + dimensionX:(int)dimensionX + dimensionY:(int)dimensionY + p1ToX:(float)p1ToX p1ToY:(float)p1ToY + p2ToX:(float)p2ToX p2ToY:(float)p2ToY + p3ToX:(float)p3ToX p3ToY:(float)p3ToY + p4ToX:(float)p4ToX p4ToY:(float)p4ToY + p1FromX:(float)p1FromX p1FromY:(float)p1FromY + p2FromX:(float)p2FromX p2FromY:(float)p2FromY + p3FromX:(float)p3FromX p3FromY:(float)p3FromY + p4FromX:(float)p4FromX p4FromY:(float)p4FromY + error:(NSError **)error { + ZXPerspectiveTransform *transform = + [ZXPerspectiveTransform quadrilateralToQuadrilateral:p1ToX y0:p1ToY + x1:p2ToX y1:p2ToY + x2:p3ToX y2:p3ToY + x3:p4ToX y3:p4ToY + x0p:p1FromX y0p:p1FromY + x1p:p2FromX y1p:p2FromY + x2p:p3FromX y2p:p3FromY + x3p:p4FromX y3p:p4FromY]; + return [self sampleGrid:image dimensionX:dimensionX dimensionY:dimensionY transform:transform error:error]; +} + +- (ZXBitMatrix *)sampleGrid:(ZXBitMatrix *)image + dimensionX:(int)dimensionX + dimensionY:(int)dimensionY + transform:(ZXPerspectiveTransform *)transform + error:(NSError **)error { + if (dimensionX <= 0 || dimensionY <= 0) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + ZXBitMatrix *bits = [[ZXBitMatrix alloc] initWithWidth:dimensionX height:dimensionY]; + int pointsLen = 2 * dimensionX; + float pointsf[pointsLen]; + memset(pointsf, 0, pointsLen * sizeof(float)); + + for (int y = 0; y < dimensionY; y++) { + int max = dimensionX << 1; + float iValue = (float)y + 0.5f; + for (int x = 0; x < max; x += 2) { + pointsf[x] = (float) (x / 2) + 0.5f; + pointsf[x + 1] = iValue; + } + [transform transformPoints:pointsf pointsLen:pointsLen]; + + if (![ZXGridSampler checkAndNudgePoints:image points:pointsf pointsLen:pointsLen error:error]) { + return nil; + } + for (int x = 0; x < max; x += 2) { + int xx = (int)pointsf[x]; + int yy = (int)pointsf[x + 1]; + if (xx < 0 || yy < 0 || xx >= image.width || yy >= image.height) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + + if ([image getX:xx y:yy]) { + [bits setX:x / 2 y:y]; + } + } + } + + return bits; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/ZXDetectorResult.h b/iDearQRCode/Tools/ZXingObjC/common/ZXDetectorResult.h new file mode 100755 index 0000000..91428b1 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/ZXDetectorResult.h @@ -0,0 +1,31 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXBitMatrix; + +/** + * Encapsulates the result of detecting a barcode in an image. This includes the raw + * matrix of black/white pixels corresponding to the barcode, and possibly points of interest + * in the image, like the location of finder patterns or corners of the barcode in the image. + */ +@interface ZXDetectorResult : NSObject + +@property (nonatomic, strong, readonly) ZXBitMatrix *bits; +@property (nonatomic, strong, readonly) NSArray *points; + +- (id)initWithBits:(ZXBitMatrix *)bits points:(NSArray *)points; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/ZXDetectorResult.m b/iDearQRCode/Tools/ZXingObjC/common/ZXDetectorResult.m new file mode 100755 index 0000000..edd9d25 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/ZXDetectorResult.m @@ -0,0 +1,31 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitMatrix.h" +#import "ZXDetectorResult.h" + +@implementation ZXDetectorResult + +- (id)initWithBits:(ZXBitMatrix *)bits points:(NSArray *)points { + if (self = [super init]) { + _bits = bits; + _points = points; + } + + return self; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/ZXGlobalHistogramBinarizer.h b/iDearQRCode/Tools/ZXingObjC/common/ZXGlobalHistogramBinarizer.h new file mode 100755 index 0000000..8166353 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/ZXGlobalHistogramBinarizer.h @@ -0,0 +1,37 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBinarizer.h" + +@class ZXBitArray, ZXBitMatrix, ZXLuminanceSource; + +/** + * This Binarizer implementation uses the old ZXing global histogram approach. It is suitable + * for low-end mobile devices which don't have enough CPU or memory to use a local thresholding + * algorithm. However, because it picks a global black point, it cannot handle difficult shadows + * and gradients. + * + * Faster mobile devices and all desktop applications should probably use ZXHybridBinarizer instead. + */ +@interface ZXGlobalHistogramBinarizer : ZXBinarizer + +// Applies simple sharpening to the row data to improve performance of the 1D Readers. +- (ZXBitArray *)blackRow:(int)y row:(ZXBitArray *)row error:(NSError **)error; + +// Does not sharpen the data, as this call is intended to only be used by 2D Readers. +- (ZXBinarizer *)createBinarizer:(ZXLuminanceSource *)source; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/ZXGlobalHistogramBinarizer.m b/iDearQRCode/Tools/ZXingObjC/common/ZXGlobalHistogramBinarizer.m new file mode 100755 index 0000000..4dc07f8 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/ZXGlobalHistogramBinarizer.m @@ -0,0 +1,199 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXGlobalHistogramBinarizer.h" +#import "ZXBitArray.h" +#import "ZXBitMatrix.h" +#import "ZXByteArray.h" +#import "ZXErrors.h" +#import "ZXIntArray.h" +#import "ZXLuminanceSource.h" + +const int ZX_LUMINANCE_BITS = 5; +const int ZX_LUMINANCE_SHIFT = 8 - ZX_LUMINANCE_BITS; +const int ZX_LUMINANCE_BUCKETS = 1 << ZX_LUMINANCE_BITS; + +@interface ZXGlobalHistogramBinarizer () + +@property (nonatomic, strong) ZXByteArray *luminances; +@property (nonatomic, strong) ZXIntArray *buckets; + +@end + +@implementation ZXGlobalHistogramBinarizer + +- (id)initWithSource:(ZXLuminanceSource *)source { + if (self = [super initWithSource:source]) { + _luminances = [[ZXByteArray alloc] initWithLength:0]; + _buckets = [[ZXIntArray alloc] initWithLength:ZX_LUMINANCE_BUCKETS]; + } + + return self; +} + +- (ZXBitArray *)blackRow:(int)y row:(ZXBitArray *)row error:(NSError **)error { + ZXLuminanceSource *source = self.luminanceSource; + int width = source.width; + if (row == nil || row.size < width) { + row = [[ZXBitArray alloc] initWithSize:width]; + } else { + [row clear]; + } + + [self initArrays:width]; + ZXByteArray *localLuminances = [source rowAtY:y row:self.luminances]; + ZXIntArray *localBuckets = self.buckets; + for (int x = 0; x < width; x++) { + int pixel = localLuminances.array[x] & 0xff; + localBuckets.array[pixel >> ZX_LUMINANCE_SHIFT]++; + } + int blackPoint = [self estimateBlackPoint:localBuckets]; + if (blackPoint == -1) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + + int left = localLuminances.array[0] & 0xff; + int center = localLuminances.array[1] & 0xff; + for (int x = 1; x < width - 1; x++) { + int right = localLuminances.array[x + 1] & 0xff; + // A simple -1 4 -1 box filter with a weight of 2. + int luminance = ((center * 4) - left - right) >> 1; + if (luminance < blackPoint) { + [row set:x]; + } + left = center; + center = right; + } + + return row; +} + +- (ZXBitMatrix *)blackMatrixWithError:(NSError **)error { + ZXLuminanceSource *source = self.luminanceSource; + int width = source.width; + int height = source.height; + ZXBitMatrix *matrix = [[ZXBitMatrix alloc] initWithWidth:width height:height]; + + // Quickly calculates the histogram by sampling four rows from the image. This proved to be + // more robust on the blackbox tests than sampling a diagonal as we used to do. + [self initArrays:width]; + + // We delay reading the entire image luminance until the black point estimation succeeds. + // Although we end up reading four rows twice, it is consistent with our motto of + // "fail quickly" which is necessary for continuous scanning. + ZXIntArray *localBuckets = self.buckets; + for (int y = 1; y < 5; y++) { + int row = height * y / 5; + ZXByteArray *localLuminances = [source rowAtY:row row:self.luminances]; + int right = (width * 4) / 5; + for (int x = width / 5; x < right; x++) { + int pixel = localLuminances.array[x] & 0xff; + localBuckets.array[pixel >> ZX_LUMINANCE_SHIFT]++; + } + } + int blackPoint = [self estimateBlackPoint:localBuckets]; + if (blackPoint == -1) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + + ZXByteArray *localLuminances = source.matrix; + for (int y = 0; y < height; y++) { + int offset = y * width; + for (int x = 0; x < width; x++) { + int pixel = localLuminances.array[offset + x] & 0xff; + if (pixel < blackPoint) { + [matrix setX:x y:y]; + } + } + } + + return matrix; +} + +- (ZXBinarizer *)createBinarizer:(ZXLuminanceSource *)source { + return [[ZXGlobalHistogramBinarizer alloc] initWithSource:source]; +} + +- (void)initArrays:(int)luminanceSize { + if (self.luminances.length < luminanceSize) { + self.luminances = [[ZXByteArray alloc] initWithLength:luminanceSize]; + } + + for (int x = 0; x < ZX_LUMINANCE_BUCKETS; x++) { + self.buckets.array[x] = 0; + } +} + +- (int)estimateBlackPoint:(ZXIntArray *)buckets { + // Find the tallest peak in the histogram. + int numBuckets = buckets.length; + int maxBucketCount = 0; + int firstPeak = 0; + int firstPeakSize = 0; + for (int x = 0; x < numBuckets; x++) { + if (buckets.array[x] > firstPeakSize) { + firstPeak = x; + firstPeakSize = buckets.array[x]; + } + if (buckets.array[x] > maxBucketCount) { + maxBucketCount = buckets.array[x]; + } + } + + // Find the second-tallest peak which is somewhat far from the tallest peak. + int secondPeak = 0; + int secondPeakScore = 0; + for (int x = 0; x < numBuckets; x++) { + int distanceToBiggest = x - firstPeak; + // Encourage more distant second peaks by multiplying by square of distance. + int score = buckets.array[x] * distanceToBiggest * distanceToBiggest; + if (score > secondPeakScore) { + secondPeak = x; + secondPeakScore = score; + } + } + + // Make sure firstPeak corresponds to the black peak. + if (firstPeak > secondPeak) { + int temp = firstPeak; + firstPeak = secondPeak; + secondPeak = temp; + } + + // If there is too little contrast in the image to pick a meaningful black point, throw rather + // than waste time trying to decode the image, and risk false positives. + if (secondPeak - firstPeak <= numBuckets / 16) { + return -1; + } + + // Find a valley between them that is low and closer to the white peak. + int bestValley = secondPeak - 1; + int bestValleyScore = -1; + for (int x = secondPeak - 1; x > firstPeak; x--) { + int fromFirst = x - firstPeak; + int score = fromFirst * fromFirst * (secondPeak - x) * (maxBucketCount - buckets.array[x]); + if (score > bestValleyScore) { + bestValley = x; + bestValleyScore = score; + } + } + + return bestValley << ZX_LUMINANCE_SHIFT; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/ZXGridSampler.h b/iDearQRCode/Tools/ZXingObjC/common/ZXGridSampler.h new file mode 100755 index 0000000..2ccfd1b --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/ZXGridSampler.h @@ -0,0 +1,93 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXBitMatrix, ZXPerspectiveTransform; + +/** + * Implementations of this class can, given locations of finder patterns for a QR code in an + * image, sample the right points in the image to reconstruct the QR code, accounting for + * perspective distortion. It is abstracted since it is relatively expensive and should be allowed + * to take advantage of platform-specific optimized implementations, like Sun's Java Advanced + * Imaging library, but which may not be available in other environments such as J2ME, and vice + * versa. + * + * The implementation used can be controlled by calling {@link #setGridSampler(GridSampler)} + * with an instance of a class which implements this interface. + */ +@interface ZXGridSampler : NSObject + +/** + * Sets the implementation of GridSampler used by the library. One global + * instance is stored, which may sound problematic. But, the implementation provided + * ought to be appropriate for the entire platform, and all uses of this library + * in the whole lifetime of the JVM. For instance, an Android activity can swap in + * an implementation that takes advantage of native platform libraries. + * + * @param newGridSampler The platform-specific object to install. + */ ++ (void)setGridSampler:(ZXGridSampler *)newGridSampler; + +/** + * @return the current implementation of GridSampler + */ ++ (ZXGridSampler *)instance; + +/** + * Samples an image for a rectangular matrix of bits of the given dimension. + * @param image image to sample + * @param dimensionX width of ZXBitMatrix to sample from image + * @param dimensionY height of ZXBitMatrix to sample from image + * @return ZXBitMatrix representing a grid of points sampled from the image within a region + * defined by the "from" parameters or nil if image can't be sampled, for example, if the transformation defined + * by the given points is invalid or results in sampling outside the image boundaries + */ +- (ZXBitMatrix *)sampleGrid:(ZXBitMatrix *)image + dimensionX:(int)dimensionX + dimensionY:(int)dimensionY + p1ToX:(float)p1ToX p1ToY:(float)p1ToY + p2ToX:(float)p2ToX p2ToY:(float)p2ToY + p3ToX:(float)p3ToX p3ToY:(float)p3ToY + p4ToX:(float)p4ToX p4ToY:(float)p4ToY + p1FromX:(float)p1FromX p1FromY:(float)p1FromY + p2FromX:(float)p2FromX p2FromY:(float)p2FromY + p3FromX:(float)p3FromX p3FromY:(float)p3FromY + p4FromX:(float)p4FromX p4FromY:(float)p4FromY + error:(NSError **)error; + +- (ZXBitMatrix *)sampleGrid:(ZXBitMatrix *)image + dimensionX:(int)dimensionX + dimensionY:(int)dimensionY + transform:(ZXPerspectiveTransform *)transform + error:(NSError **)error; + +/** + *

Checks a set of points that have been transformed to sample points on an image against + * the image's dimensions to see if the point are even within the image.

+ * + *

This method will actually "nudge" the endpoints back onto the image if they are found to be + * barely (less than 1 pixel) off the image. This accounts for imperfect detection of finder + * patterns in an image where the QR Code runs all the way to the image border.

+ * + *

For efficiency, the method will check points from either end of the line until one is found + * to be within the image. Because the set of points are assumed to be linear, this is valid.

+ * + * @param image image into which the points should map + * @param points actual points in x1,y1,...,xn,yn form + * @returns NO if an endpoint is lies outside the image boundaries + */ ++ (BOOL)checkAndNudgePoints:(ZXBitMatrix *)image points:(float *)points pointsLen:(int)pointsLen error:(NSError **)error; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/ZXGridSampler.m b/iDearQRCode/Tools/ZXingObjC/common/ZXGridSampler.m new file mode 100755 index 0000000..cf9add8 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/ZXGridSampler.m @@ -0,0 +1,122 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitMatrix.h" +#import "ZXDefaultGridSampler.h" +#import "ZXErrors.h" +#import "ZXGridSampler.h" +#import "ZXPerspectiveTransform.h" + +static ZXGridSampler *gridSampler = nil; + +@implementation ZXGridSampler + ++ (void)setGridSampler:(ZXGridSampler *)newGridSampler { + gridSampler = newGridSampler; +} + ++ (ZXGridSampler *)instance { + if (!gridSampler) { + gridSampler = [[ZXDefaultGridSampler alloc] init]; + } + + return gridSampler; +} + +- (ZXBitMatrix *)sampleGrid:(ZXBitMatrix *)image + dimensionX:(int)dimensionX + dimensionY:(int)dimensionY + p1ToX:(float)p1ToX p1ToY:(float)p1ToY + p2ToX:(float)p2ToX p2ToY:(float)p2ToY + p3ToX:(float)p3ToX p3ToY:(float)p3ToY + p4ToX:(float)p4ToX p4ToY:(float)p4ToY + p1FromX:(float)p1FromX p1FromY:(float)p1FromY + p2FromX:(float)p2FromX p2FromY:(float)p2FromY + p3FromX:(float)p3FromX p3FromY:(float)p3FromY + p4FromX:(float)p4FromX p4FromY:(float)p4FromY + error:(NSError **)error { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)] + userInfo:nil]; +} + +- (ZXBitMatrix *)sampleGrid:(ZXBitMatrix *)image + dimensionX:(int)dimensionX + dimensionY:(int)dimensionY + transform:(ZXPerspectiveTransform *)transform + error:(NSError **)error { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)] + userInfo:nil]; +} + ++ (BOOL)checkAndNudgePoints:(ZXBitMatrix *)image points:(float *)points pointsLen:(int)pointsLen error:(NSError **)error { + int width = image.width; + int height = image.height; + // Check and nudge points from start until we see some that are OK: + BOOL nudged = YES; + for (int offset = 0; offset < pointsLen && nudged; offset += 2) { + int x = (int) points[offset]; + int y = (int) points[offset + 1]; + if (x < -1 || x > width || y < -1 || y > height) { + if (error) *error = ZXNotFoundErrorInstance(); + return NO; + } + nudged = NO; + if (x == -1) { + points[offset] = 0.0f; + nudged = YES; + } else if (x == width) { + points[offset] = width - 1; + nudged = YES; + } + if (y == -1) { + points[offset + 1] = 0.0f; + nudged = YES; + } else if (y == height) { + points[offset + 1] = height - 1; + nudged = YES; + } + } + // Check and nudge points from end: + nudged = YES; + for (int offset = pointsLen - 2; offset >= 0 && nudged; offset -= 2) { + int x = (int) points[offset]; + int y = (int) points[offset + 1]; + if (x < -1 || x > width || y < -1 || y > height) { + if (error) *error = ZXNotFoundErrorInstance(); + return NO; + } + nudged = NO; + if (x == -1) { + points[offset] = 0.0f; + nudged = YES; + } else if (x == width) { + points[offset] = width - 1; + nudged = YES; + } + if (y == -1) { + points[offset + 1] = 0.0f; + nudged = YES; + } else if (y == height) { + points[offset + 1] = height - 1; + nudged = YES; + } + } + return YES; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/ZXHybridBinarizer.h b/iDearQRCode/Tools/ZXingObjC/common/ZXHybridBinarizer.h new file mode 100755 index 0000000..bb309ef --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/ZXHybridBinarizer.h @@ -0,0 +1,38 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXGlobalHistogramBinarizer.h" + +@class ZXBinarizer, ZXBitMatrix, ZXLuminanceSource; + +/** + * This class implements a local thresholding algorithm, which while slower than the + * ZXGlobalHistogramBinarizer, is fairly efficient for what it does. It is designed for + * high frequency images of barcodes with black data on white backgrounds. For this application, + * it does a much better job than a global blackpoint with severe shadows and gradients. + * However it tends to produce artifacts on lower frequency images and is therefore not + * a good general purpose binarizer for uses outside ZXing. + * + * This class extends ZXGlobalHistogramBinarizer, using the older histogram approach for 1D readers, + * and the newer local approach for 2D readers. 1D decoding using a per-row histogram is already + * inherently local, and only fails for horizontal gradients. We can revisit that problem later, + * but for now it was not a win to use local blocks for 1D. + * + * This Binarizer is the default for the unit tests and the recommended class for library users. + */ +@interface ZXHybridBinarizer : ZXGlobalHistogramBinarizer + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/ZXHybridBinarizer.m b/iDearQRCode/Tools/ZXingObjC/common/ZXHybridBinarizer.m new file mode 100755 index 0000000..5742cb0 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/ZXHybridBinarizer.m @@ -0,0 +1,223 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXByteArray.h" +#import "ZXHybridBinarizer.h" +#import "ZXIntArray.h" + +// This class uses 5x5 blocks to compute local luminance, where each block is 8x8 pixels. +// So this is the smallest dimension in each axis we can accept. +const int ZX_BLOCK_SIZE_POWER = 3; +const int ZX_BLOCK_SIZE = 1 << ZX_BLOCK_SIZE_POWER; // ...0100...00 +const int ZX_BLOCK_SIZE_MASK = ZX_BLOCK_SIZE - 1; // ...0011...11 +const int ZX_MINIMUM_DIMENSION = ZX_BLOCK_SIZE * 5; +const int ZX_MIN_DYNAMIC_RANGE = 24; + +@interface ZXHybridBinarizer () + +@property (nonatomic, strong) ZXBitMatrix *matrix; + +@end + +@implementation ZXHybridBinarizer + +/** + * Calculates the final BitMatrix once for all requests. This could be called once from the + * constructor instead, but there are some advantages to doing it lazily, such as making + * profiling easier, and not doing heavy lifting when callers don't expect it. + */ +- (ZXBitMatrix *)blackMatrixWithError:(NSError **)error { + if (self.matrix != nil) { + return self.matrix; + } + ZXLuminanceSource *source = [self luminanceSource]; + int width = source.width; + int height = source.height; + if (width >= ZX_MINIMUM_DIMENSION && height >= ZX_MINIMUM_DIMENSION) { + ZXByteArray *luminances = source.matrix; + int subWidth = width >> ZX_BLOCK_SIZE_POWER; + if ((width & ZX_BLOCK_SIZE_MASK) != 0) { + subWidth++; + } + int subHeight = height >> ZX_BLOCK_SIZE_POWER; + if ((height & ZX_BLOCK_SIZE_MASK) != 0) { + subHeight++; + } + int **blackPoints = [self calculateBlackPoints:luminances.array subWidth:subWidth subHeight:subHeight width:width height:height]; + + ZXBitMatrix *newMatrix = [[ZXBitMatrix alloc] initWithWidth:width height:height]; + [self calculateThresholdForBlock:luminances.array subWidth:subWidth subHeight:subHeight width:width height:height blackPoints:blackPoints matrix:newMatrix]; + self.matrix = newMatrix; + + for (int i = 0; i < subHeight; i++) { + free(blackPoints[i]); + } + free(blackPoints); + } else { + // If the image is too small, fall back to the global histogram approach. + self.matrix = [super blackMatrixWithError:error]; + } + return self.matrix; +} + +- (ZXBinarizer *)createBinarizer:(ZXLuminanceSource *)source { + return [[ZXHybridBinarizer alloc] initWithSource:source]; +} + +/** + * For each block in the image, calculate the average black point using a 5x5 grid + * of the blocks around it. Also handles the corner cases (fractional blocks are computed based + * on the last pixels in the row/column which are also used in the previous block). + */ +- (void)calculateThresholdForBlock:(int8_t *)luminances + subWidth:(int)subWidth + subHeight:(int)subHeight + width:(int)width + height:(int)height + blackPoints:(int **)blackPoints + matrix:(ZXBitMatrix *)matrix { + for (int y = 0; y < subHeight; y++) { + int yoffset = y << ZX_BLOCK_SIZE_POWER; + int maxYOffset = height - ZX_BLOCK_SIZE; + if (yoffset > maxYOffset) { + yoffset = maxYOffset; + } + for (int x = 0; x < subWidth; x++) { + int xoffset = x << ZX_BLOCK_SIZE_POWER; + int maxXOffset = width - ZX_BLOCK_SIZE; + if (xoffset > maxXOffset) { + xoffset = maxXOffset; + } + int left = [self cap:x min:2 max:subWidth - 3]; + int top = [self cap:y min:2 max:subHeight - 3]; + int sum = 0; + for (int z = -2; z <= 2; z++) { + int *blackRow = blackPoints[top + z]; + sum += blackRow[left - 2] + blackRow[left - 1] + blackRow[left] + blackRow[left + 1] + blackRow[left + 2]; + } + int average = sum / 25; + [self thresholdBlock:luminances xoffset:xoffset yoffset:yoffset threshold:average stride:width matrix:matrix]; + } + } +} + +- (int)cap:(int)value min:(int)min max:(int)max { + return value < min ? min : value > max ? max : value; +} + +/** + * Applies a single threshold to a block of pixels. + */ +- (void)thresholdBlock:(int8_t *)luminances + xoffset:(int)xoffset + yoffset:(int)yoffset + threshold:(int)threshold + stride:(int)stride + matrix:(ZXBitMatrix *)matrix { + for (int y = 0, offset = yoffset * stride + xoffset; y < ZX_BLOCK_SIZE; y++, offset += stride) { + for (int x = 0; x < ZX_BLOCK_SIZE; x++) { + // Comparison needs to be <= so that black == 0 pixels are black even if the threshold is 0 + if ((luminances[offset + x] & 0xFF) <= threshold) { + [matrix setX:xoffset + x y:yoffset + y]; + } + } + } +} + +/** + * Calculates a single black point for each block of pixels and saves it away. + * See the following thread for a discussion of this algorithm: + * http://groups.google.com/group/zxing/browse_thread/thread/d06efa2c35a7ddc0 + */ +- (int **)calculateBlackPoints:(int8_t *)luminances + subWidth:(int)subWidth + subHeight:(int)subHeight + width:(int)width + height:(int)height { + int **blackPoints = (int **)malloc(subHeight * sizeof(int *)); + for (int y = 0; y < subHeight; y++) { + blackPoints[y] = (int *)malloc(subWidth * sizeof(int)); + + int yoffset = y << ZX_BLOCK_SIZE_POWER; + int maxYOffset = height - ZX_BLOCK_SIZE; + if (yoffset > maxYOffset) { + yoffset = maxYOffset; + } + for (int x = 0; x < subWidth; x++) { + int xoffset = x << ZX_BLOCK_SIZE_POWER; + int maxXOffset = width - ZX_BLOCK_SIZE; + if (xoffset > maxXOffset) { + xoffset = maxXOffset; + } + int sum = 0; + int min = 0xFF; + int max = 0; + for (int yy = 0, offset = yoffset * width + xoffset; yy < ZX_BLOCK_SIZE; yy++, offset += width) { + for (int xx = 0; xx < ZX_BLOCK_SIZE; xx++) { + int pixel = luminances[offset + xx] & 0xFF; + sum += pixel; + // still looking for good contrast + if (pixel < min) { + min = pixel; + } + if (pixel > max) { + max = pixel; + } + } + // short-circuit min/max tests once dynamic range is met + if (max - min > ZX_MIN_DYNAMIC_RANGE) { + // finish the rest of the rows quickly + for (yy++, offset += width; yy < ZX_BLOCK_SIZE; yy++, offset += width) { + for (int xx = 0; xx < ZX_BLOCK_SIZE; xx++) { + sum += luminances[offset + xx] & 0xFF; + } + } + } + } + + // The default estimate is the average of the values in the block. + int average = sum >> (ZX_BLOCK_SIZE_POWER * 2); + if (max - min <= ZX_MIN_DYNAMIC_RANGE) { + // If variation within the block is low, assume this is a block with only light or only + // dark pixels. In that case we do not want to use the average, as it would divide this + // low contrast area into black and white pixels, essentially creating data out of noise. + // + // The default assumption is that the block is light/background. Since no estimate for + // the level of dark pixels exists locally, use half the min for the block. + average = min / 2; + + if (y > 0 && x > 0) { + // Correct the "white background" assumption for blocks that have neighbors by comparing + // the pixels in this block to the previously calculated black points. This is based on + // the fact that dark barcode symbology is always surrounded by some amount of light + // background for which reasonable black point estimates were made. The bp estimated at + // the boundaries is used for the interior. + + // The (min < bp) is arbitrary but works better than other heuristics that were tried. + int averageNeighborBlackPoint = + (blackPoints[y - 1][x] + (2 * blackPoints[y][x - 1]) + blackPoints[y - 1][x - 1]) / 4; + if (min < averageNeighborBlackPoint) { + average = averageNeighborBlackPoint; + } + } + } + blackPoints[y][x] = average; + } + } + return blackPoints; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/ZXIntArray.h b/iDearQRCode/Tools/ZXingObjC/common/ZXIntArray.h new file mode 100755 index 0000000..0b45e62 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/ZXIntArray.h @@ -0,0 +1,27 @@ +/* + * Copyright 2014 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@interface ZXIntArray : NSObject + +@property (nonatomic, assign, readonly) int32_t *array; +@property (nonatomic, assign, readonly) unsigned int length; + +- (id)initWithLength:(unsigned int)length; +- (id)initWithInts:(int32_t)int1, ...; +- (void)clear; +- (int)sum; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/ZXIntArray.m b/iDearQRCode/Tools/ZXingObjC/common/ZXIntArray.m new file mode 100755 index 0000000..40221d1 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/ZXIntArray.m @@ -0,0 +1,95 @@ +/* + * Copyright 2014 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXIntArray.h" + +@implementation ZXIntArray + +- (id)initWithLength:(unsigned int)length { + if (self = [super init]) { + if (length > 0) { + _array = (int32_t *)calloc(length, sizeof(int32_t)); + } else { + _array = NULL; + } + _length = length; + } + + return self; +} + +- (id)initWithInts:(int32_t)int1, ... { + va_list args; + va_start(args, int1); + unsigned int length = 0; + for (int32_t i = int1; i != -1; i = va_arg(args, int)) { + length++; + } + va_end(args); + + if ((self = [self initWithLength:length]) && (length > 0)) { + va_list args; + va_start(args, int1); + int i = 0; + for (int32_t c = int1; c != -1; c = va_arg(args, int)) { + _array[i++] = c; + } + va_end(args); + } + + return self; +} + +- (id)copyWithZone:(NSZone *)zone { + ZXIntArray *copy = [[ZXIntArray allocWithZone:zone] initWithLength:self.length]; + memcpy(copy.array, self.array, self.length * sizeof(int32_t)); + return copy; +} + +- (void)dealloc { + if (_array) { + free(_array); + } +} + +- (void)clear { + memset(self.array, 0, self.length * sizeof(int32_t)); +} + +- (int)sum { + int sum = 0; + int32_t *array = self.array; + for (int i = 0; i < self.length; i++) { + sum += array[i]; + } + return sum; +} + +- (NSString *)description { + NSMutableString *s = [NSMutableString stringWithFormat:@"length=%u, array=(", self.length]; + + for (int i = 0; i < self.length; i++) { + [s appendFormat:@"%d", self.array[i]]; + if (i < self.length - 1) { + [s appendString:@", "]; + } + } + + [s appendString:@")"]; + return s; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/ZXPerspectiveTransform.h b/iDearQRCode/Tools/ZXingObjC/common/ZXPerspectiveTransform.h new file mode 100755 index 0000000..ab8cceb --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/ZXPerspectiveTransform.h @@ -0,0 +1,32 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This class implements a perspective transform in two dimensions. Given four source and four + * destination points, it will compute the transformation implied between them. The code is based + * directly upon section 3.4.2 of George Wolberg's "Digital Image Warping"; see pages 54-56. + */ +@interface ZXPerspectiveTransform : NSObject + ++ (ZXPerspectiveTransform *)quadrilateralToQuadrilateral:(float)x0 y0:(float)y0 x1:(float)x1 y1:(float)y1 x2:(float)x2 y2:(float)y2 x3:(float)x3 y3:(float)y3 x0p:(float)x0p y0p:(float)y0p x1p:(float)x1p y1p:(float)y1p x2p:(float)x2p y2p:(float)y2p x3p:(float)x3p y3p:(float)y3p; +- (void)transformPoints:(float *)points pointsLen:(int)pointsLen; +- (void)transformPoints:(float *)xValues yValues:(float *)yValues pointsLen:(int)pointsLen; ++ (ZXPerspectiveTransform *)squareToQuadrilateral:(float)x0 y0:(float)y0 x1:(float)x1 y1:(float)y1 x2:(float)x2 y2:(float)y2 x3:(float)x3 y3:(float)y3; ++ (ZXPerspectiveTransform *)quadrilateralToSquare:(float)x0 y0:(float)y0 x1:(float)x1 y1:(float)y1 x2:(float)x2 y2:(float)y2 x3:(float)x3 y3:(float)y3; +- (ZXPerspectiveTransform *)buildAdjoint; +- (ZXPerspectiveTransform *)times:(ZXPerspectiveTransform *)other; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/ZXPerspectiveTransform.m b/iDearQRCode/Tools/ZXingObjC/common/ZXPerspectiveTransform.m new file mode 100755 index 0000000..442b5c5 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/ZXPerspectiveTransform.m @@ -0,0 +1,128 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXPerspectiveTransform.h" + +@interface ZXPerspectiveTransform () + +@property (nonatomic, assign, readonly) float a11; +@property (nonatomic, assign, readonly) float a12; +@property (nonatomic, assign, readonly) float a13; +@property (nonatomic, assign, readonly) float a21; +@property (nonatomic, assign, readonly) float a22; +@property (nonatomic, assign, readonly) float a23; +@property (nonatomic, assign, readonly) float a31; +@property (nonatomic, assign, readonly) float a32; +@property (nonatomic, assign, readonly) float a33; + +@end + +@implementation ZXPerspectiveTransform + +- (id)initWithA11:(float)a11 a21:(float)a21 a31:(float)a31 a12:(float)a12 a22:(float)a22 a32:(float)a32 a13:(float)a13 a23:(float)a23 a33:(float)a33 { + if (self = [super init]) { + _a11 = a11; + _a12 = a12; + _a13 = a13; + _a21 = a21; + _a22 = a22; + _a23 = a23; + _a31 = a31; + _a32 = a32; + _a33 = a33; + } + + return self; +} + ++ (ZXPerspectiveTransform *)quadrilateralToQuadrilateral:(float)x0 y0:(float)y0 x1:(float)x1 y1:(float)y1 x2:(float)x2 y2:(float)y2 x3:(float)x3 y3:(float)y3 x0p:(float)x0p y0p:(float)y0p x1p:(float)x1p y1p:(float)y1p x2p:(float)x2p y2p:(float)y2p x3p:(float)x3p y3p:(float)y3p { + ZXPerspectiveTransform *qToS = [self quadrilateralToSquare:x0 y0:y0 x1:x1 y1:y1 x2:x2 y2:y2 x3:x3 y3:y3]; + ZXPerspectiveTransform *sToQ = [self squareToQuadrilateral:x0p y0:y0p x1:x1p y1:y1p x2:x2p y2:y2p x3:x3p y3:y3p]; + return [sToQ times:qToS]; +} + +- (void)transformPoints:(float *)points pointsLen:(int)pointsLen { + int max = pointsLen; + for (int i = 0; i < max; i += 2) { + float x = points[i]; + float y = points[i + 1]; + float denominator = self.a13 * x + self.a23 * y + self.a33; + points[i] = (self.a11 * x + self.a21 * y + self.a31) / denominator; + points[i + 1] = (self.a12 * x + self.a22 * y + self.a32) / denominator; + } +} + +/** + * Convenience method, not optimized for performance. + */ +- (void)transformPoints:(float *)xValues yValues:(float *)yValues pointsLen:(int)pointsLen { + int n = pointsLen; + for (int i = 0; i < n; i ++) { + float x = xValues[i]; + float y = yValues[i]; + float denominator = self.a13 * x + self.a23 * y + self.a33; + xValues[i] = (self.a11 * x + self.a21 * y + self.a31) / denominator; + yValues[i] = (self.a12 * x + self.a22 * y + self.a32) / denominator; + } +} + ++ (ZXPerspectiveTransform *)squareToQuadrilateral:(float)x0 y0:(float)y0 x1:(float)x1 y1:(float)y1 x2:(float)x2 y2:(float)y2 x3:(float)x3 y3:(float)y3 { + float dx3 = x0 - x1 + x2 - x3; + float dy3 = y0 - y1 + y2 - y3; + if (dx3 == 0.0f && dy3 == 0.0f) { + // Affine + return [[ZXPerspectiveTransform alloc] initWithA11:x1 - x0 a21:x2 - x1 a31:x0 a12:y1 - y0 a22:y2 - y1 a32:y0 a13:0.0f a23:0.0f a33:1.0f]; + } else { + float dx1 = x1 - x2; + float dx2 = x3 - x2; + float dy1 = y1 - y2; + float dy2 = y3 - y2; + float denominator = dx1 * dy2 - dx2 * dy1; + float a13 = (dx3 * dy2 - dx2 * dy3) / denominator; + float a23 = (dx1 * dy3 - dx3 * dy1) / denominator; + return [[ZXPerspectiveTransform alloc] initWithA11:x1 - x0 + a13 * x1 a21:x3 - x0 + a23 * x3 a31:x0 a12:y1 - y0 + a13 * y1 a22:y3 - y0 + a23 * y3 a32:y0 a13:a13 a23:a23 a33:1.0f]; + } +} + ++ (ZXPerspectiveTransform *)quadrilateralToSquare:(float)x0 y0:(float)y0 x1:(float)x1 y1:(float)y1 x2:(float)x2 y2:(float)y2 x3:(float)x3 y3:(float)y3 { + return [[self squareToQuadrilateral:x0 y0:y0 x1:x1 y1:y1 x2:x2 y2:y2 x3:x3 y3:y3] buildAdjoint]; +} + +- (ZXPerspectiveTransform *)buildAdjoint { + return [[ZXPerspectiveTransform alloc] initWithA11:self.a22 * self.a33 - self.a23 * self.a32 + a21:self.a23 * self.a31 - self.a21 * self.a33 + a31:self.a21 * self.a32 - self.a22 * self.a31 + a12:self.a13 * self.a32 - self.a12 * self.a33 + a22:self.a11 * self.a33 - self.a13 * self.a31 + a32:self.a12 * self.a31 - self.a11 * self.a32 + a13:self.a12 * self.a23 - self.a13 * self.a22 + a23:self.a13 * self.a21 - self.a11 * self.a23 + a33:self.a11 * self.a22 - self.a12 * self.a21]; +} + +- (ZXPerspectiveTransform *)times:(ZXPerspectiveTransform *)other { + return [[ZXPerspectiveTransform alloc] initWithA11:self.a11 * other.a11 + self.a21 * other.a12 + self.a31 * other.a13 + a21:self.a11 * other.a21 + self.a21 * other.a22 + self.a31 * other.a23 + a31:self.a11 * other.a31 + self.a21 * other.a32 + self.a31 * other.a33 + a12:self.a12 * other.a11 + self.a22 * other.a12 + self.a32 * other.a13 + a22:self.a12 * other.a21 + self.a22 * other.a22 + self.a32 * other.a23 + a32:self.a12 * other.a31 + self.a22 * other.a32 + self.a32 * other.a33 + a13:self.a13 * other.a11 + self.a23 * other.a12 + self.a33 * other.a13 + a23:self.a13 * other.a21 + self.a23 * other.a22 + self.a33 * other.a23 + a33:self.a13 * other.a31 + self.a23 * other.a32 + self.a33 * other.a33]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/ZXStringUtils.h b/iDearQRCode/Tools/ZXingObjC/common/ZXStringUtils.h new file mode 100755 index 0000000..074af7e --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/ZXStringUtils.h @@ -0,0 +1,33 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXByteArray, ZXDecodeHints; + +/** + * Common string-related functions. + */ +@interface ZXStringUtils : NSObject + +/** + * @param bytes bytes encoding a string, whose encoding should be guessed + * @param hints decode hints if applicable + * @return name of guessed encoding; at the moment will only guess one of: + * NSShiftJISStringEncoding, NSUTF8StringEncoding, NSISOLatin1StringEncoding, or the platform + * default encoding if none of these can possibly be correct + */ ++ (NSStringEncoding)guessEncoding:(ZXByteArray *)bytes hints:(ZXDecodeHints *)hints; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/ZXStringUtils.m b/iDearQRCode/Tools/ZXingObjC/common/ZXStringUtils.m new file mode 100755 index 0000000..ebd0dff --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/ZXStringUtils.m @@ -0,0 +1,188 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXByteArray.h" +#import "ZXDecodeHints.h" +#import "ZXStringUtils.h" + +@implementation ZXStringUtils + ++ (NSStringEncoding)guessEncoding:(ZXByteArray *)bytes hints:(ZXDecodeHints *)hints { + NSStringEncoding systemEncoding = CFStringConvertEncodingToNSStringEncoding(CFStringGetSystemEncoding()); + BOOL assumeShiftJIS = systemEncoding == NSShiftJISStringEncoding || systemEncoding == NSJapaneseEUCStringEncoding; + + if (hints != nil) { + NSStringEncoding encoding = hints.encoding; + if (encoding > 0) { + return encoding; + } + } + // For now, merely tries to distinguish ISO-8859-1, UTF-8 and Shift_JIS, + // which should be by far the most common encodings. + int length = bytes.length; + BOOL canBeISO88591 = YES; + BOOL canBeShiftJIS = YES; + BOOL canBeUTF8 = YES; + int utf8BytesLeft = 0; + //int utf8LowChars = 0; + int utf2BytesChars = 0; + int utf3BytesChars = 0; + int utf4BytesChars = 0; + int sjisBytesLeft = 0; + //int sjisLowChars = 0; + int sjisKatakanaChars = 0; + //int sjisDoubleBytesChars = 0; + int sjisCurKatakanaWordLength = 0; + int sjisCurDoubleBytesWordLength = 0; + int sjisMaxKatakanaWordLength = 0; + int sjisMaxDoubleBytesWordLength = 0; + //int isoLowChars = 0; + //int isoHighChars = 0; + int isoHighOther = 0; + + BOOL utf8bom = length > 3 && + bytes.array[0] == (int8_t) 0xEF && + bytes.array[1] == (int8_t) 0xBB && + bytes.array[2] == (int8_t) 0xBF; + + for (int i = 0; + i < length && (canBeISO88591 || canBeShiftJIS || canBeUTF8); + i++) { + + int value = bytes.array[i] & 0xFF; + + // UTF-8 stuff + if (canBeUTF8) { + if (utf8BytesLeft > 0) { + if ((value & 0x80) == 0) { + canBeUTF8 = NO; + } else { + utf8BytesLeft--; + } + } else if ((value & 0x80) != 0) { + if ((value & 0x40) == 0) { + canBeUTF8 = NO; + } else { + utf8BytesLeft++; + if ((value & 0x20) == 0) { + utf2BytesChars++; + } else { + utf8BytesLeft++; + if ((value & 0x10) == 0) { + utf3BytesChars++; + } else { + utf8BytesLeft++; + if ((value & 0x08) == 0) { + utf4BytesChars++; + } else { + canBeUTF8 = NO; + } + } + } + } + } //else { + //utf8LowChars++; + //} + } + + // ISO-8859-1 stuff + if (canBeISO88591) { + if (value > 0x7F && value < 0xA0) { + canBeISO88591 = NO; + } else if (value > 0x9F) { + if (value < 0xC0 || value == 0xD7 || value == 0xF7) { + isoHighOther++; + } //else { + //isoHighChars++; + //} + } //else { + //isoLowChars++; + //} + } + + // Shift_JIS stuff + if (canBeShiftJIS) { + if (sjisBytesLeft > 0) { + if (value < 0x40 || value == 0x7F || value > 0xFC) { + canBeShiftJIS = NO; + } else { + sjisBytesLeft--; + } + } else if (value == 0x80 || value == 0xA0 || value > 0xEF) { + canBeShiftJIS = NO; + } else if (value > 0xA0 && value < 0xE0) { + sjisKatakanaChars++; + sjisCurDoubleBytesWordLength = 0; + sjisCurKatakanaWordLength++; + if (sjisCurKatakanaWordLength > sjisMaxKatakanaWordLength) { + sjisMaxKatakanaWordLength = sjisCurKatakanaWordLength; + } + } else if (value > 0x7F) { + sjisBytesLeft++; + //sjisDoubleBytesChars++; + sjisCurKatakanaWordLength = 0; + sjisCurDoubleBytesWordLength++; + if (sjisCurDoubleBytesWordLength > sjisMaxDoubleBytesWordLength) { + sjisMaxDoubleBytesWordLength = sjisCurDoubleBytesWordLength; + } + } else { + //sjisLowChars++; + sjisCurKatakanaWordLength = 0; + sjisCurDoubleBytesWordLength = 0; + } + } + } + + if (canBeUTF8 && utf8BytesLeft > 0) { + canBeUTF8 = NO; + } + if (canBeShiftJIS && sjisBytesLeft > 0) { + canBeShiftJIS = NO; + } + + // Easy -- if there is BOM or at least 1 valid not-single byte character (and no evidence it can't be UTF-8), done + if (canBeUTF8 && (utf8bom || utf2BytesChars + utf3BytesChars + utf4BytesChars > 0)) { + return NSUTF8StringEncoding; + } + // Easy -- if assuming Shift_JIS or at least 3 valid consecutive not-ascii characters (and no evidence it can't be), done + if (canBeShiftJIS && (assumeShiftJIS || sjisMaxKatakanaWordLength >= 3 || sjisMaxDoubleBytesWordLength >= 3)) { + return NSShiftJISStringEncoding; + } + // Distinguishing Shift_JIS and ISO-8859-1 can be a little tough for short words. The crude heuristic is: + // - If we saw + // - only two consecutive katakana chars in the whole text, or + // - at least 10% of bytes that could be "upper" not-alphanumeric Latin1, + // - then we conclude Shift_JIS, else ISO-8859-1 + if (canBeISO88591 && canBeShiftJIS) { + return (sjisMaxKatakanaWordLength == 2 && sjisKatakanaChars == 2) || isoHighOther * 10 >= length + ? NSShiftJISStringEncoding : NSISOLatin1StringEncoding; + } + + // Otherwise, try in order ISO-8859-1, Shift JIS, UTF-8 and fall back to default platform encoding + if (canBeISO88591) { + return NSISOLatin1StringEncoding; + } + if (canBeShiftJIS) { + return NSShiftJISStringEncoding; + } + if (canBeUTF8) { + return NSUTF8StringEncoding; + } + // Otherwise, we take a wild guess with platform encoding + return systemEncoding; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/detector/ZXMathUtils.h b/iDearQRCode/Tools/ZXingObjC/common/detector/ZXMathUtils.h new file mode 100755 index 0000000..cd38da4 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/detector/ZXMathUtils.h @@ -0,0 +1,23 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@interface ZXMathUtils : NSObject + ++ (int)round:(float)d; ++ (float)distance:(float)aX aY:(float)aY bX:(float)bX bY:(float)bY; ++ (float)distanceInt:(int)aX aY:(int)aY bX:(int)bX bY:(int)bY; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/detector/ZXMathUtils.m b/iDearQRCode/Tools/ZXingObjC/common/detector/ZXMathUtils.m new file mode 100755 index 0000000..3c83ce2 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/detector/ZXMathUtils.m @@ -0,0 +1,37 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXMathUtils.h" + +@implementation ZXMathUtils + ++ (int)round:(float)d { + return (int) (d + (d < 0.0f ? -0.5f : 0.5f)); +} + ++ (float)distance:(float)aX aY:(float)aY bX:(float)bX bY:(float)bY { + float xDiff = aX - bX; + float yDiff = aY - bY; + return sqrtf(xDiff * xDiff + yDiff * yDiff); +} + ++ (float)distanceInt:(int)aX aY:(int)aY bX:(int)bX bY:(int)bY { + int xDiff = aX - bX; + int yDiff = aY - bY; + return sqrtf(xDiff * xDiff + yDiff * yDiff); +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/detector/ZXMonochromeRectangleDetector.h b/iDearQRCode/Tools/ZXingObjC/common/detector/ZXMonochromeRectangleDetector.h new file mode 100755 index 0000000..96bd259 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/detector/ZXMonochromeRectangleDetector.h @@ -0,0 +1,40 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXBitMatrix; + +/** + * A somewhat generic detector that looks for a barcode-like rectangular region within an image. + * It looks within a mostly white region of an image for a region of black and white, but mostly + * black. It returns the four corners of the region, as best it can determine. + */ +@interface ZXMonochromeRectangleDetector : NSObject + +- (id)initWithImage:(ZXBitMatrix *)image; + +/** + * Detects a rectangular region of black and white -- mostly black -- with a region of mostly + * white, in an image. + * + * @return ZXResultPoint array describing the corners of the rectangular region. The first and + * last points are opposed on the diagonal, as are the second and third. The first point will be + * the topmost point and the last, the bottommost. The second point will be leftmost and the + * third, the rightmost + * @return nil if no Data Matrix Code can be found + */ +- (NSArray *)detectWithError:(NSError **)error; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/detector/ZXMonochromeRectangleDetector.m b/iDearQRCode/Tools/ZXingObjC/common/detector/ZXMonochromeRectangleDetector.m new file mode 100755 index 0000000..8549d27 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/detector/ZXMonochromeRectangleDetector.m @@ -0,0 +1,209 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitMatrix.h" +#import "ZXErrors.h" +#import "ZXMonochromeRectangleDetector.h" +#import "ZXResultPoint.h" + +const int ZX_MONOCHROME_MAX_MODULES = 32; + +@interface ZXMonochromeRectangleDetector () + +@property (nonatomic, strong, readonly) ZXBitMatrix *image; + +@end + +@implementation ZXMonochromeRectangleDetector + +- (id)initWithImage:(ZXBitMatrix *)image { + if (self = [super init]) { + _image = image; + } + + return self; +} + +- (NSArray *)detectWithError:(NSError **)error { + int height = [self.image height]; + int width = [self.image width]; + int halfHeight = height / 2; + int halfWidth = width / 2; + int deltaY = MAX(1, height / (ZX_MONOCHROME_MAX_MODULES * 8) > 1); + int deltaX = MAX(1, width / (ZX_MONOCHROME_MAX_MODULES * 8) > 1); + + int top = 0; + int bottom = height; + int left = 0; + int right = width; + ZXResultPoint *pointA = [self findCornerFromCenter:halfWidth deltaX:0 left:left right:right + centerY:halfHeight deltaY:-deltaY top:top bottom:bottom maxWhiteRun:halfWidth / 2]; + if (!pointA) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + top = (int)[pointA y] - 1; + ZXResultPoint *pointB = [self findCornerFromCenter:halfWidth deltaX:-deltaX left:left right:right + centerY:halfHeight deltaY:0 top:top bottom:bottom maxWhiteRun:halfHeight / 2]; + if (!pointB) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + left = (int)[pointB x] - 1; + ZXResultPoint *pointC = [self findCornerFromCenter:halfWidth deltaX:deltaX left:left right:right + centerY:halfHeight deltaY:0 top:top bottom:bottom maxWhiteRun:halfHeight / 2]; + if (!pointC) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + right = (int)[pointC x] + 1; + ZXResultPoint *pointD = [self findCornerFromCenter:halfWidth deltaX:0 left:left right:right + centerY:halfHeight deltaY:deltaY top:top bottom:bottom maxWhiteRun:halfWidth / 2]; + if (!pointD) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + bottom = (int)[pointD y] + 1; + + pointA = [self findCornerFromCenter:halfWidth deltaX:0 left:left right:right + centerY:halfHeight deltaY:-deltaY top:top bottom:bottom maxWhiteRun:halfWidth / 4]; + if (!pointA) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + + return @[pointA, pointB, pointC, pointD]; +} + +/** + * Attempts to locate a corner of the barcode by scanning up, down, left or right from a center + * point which should be within the barcode. + * + * @param centerX center's x component (horizontal) + * @param deltaX same as deltaY but change in x per step instead + * @param left minimum value of x + * @param right maximum value of x + * @param centerY center's y component (vertical) + * @param deltaY change in y per step. If scanning up this is negative; down, positive; + * left or right, 0 + * @param top minimum value of y to search through (meaningless when di == 0) + * @param bottom maximum value of y + * @param maxWhiteRun maximum run of white pixels that can still be considered to be within + * the barcode + * @return a {@link com.google.zxing.ResultPoint} encapsulating the corner that was found + * or nil if such a point cannot be found + */ +- (ZXResultPoint *)findCornerFromCenter:(int)centerX deltaX:(int)deltaX left:(int)left right:(int)right centerY:(int)centerY deltaY:(int)deltaY top:(int)top bottom:(int)bottom maxWhiteRun:(int)maxWhiteRun { + NSArray *lastRange = nil; + for (int y = centerY, x = centerX; y < bottom && y >= top && x < right && x >= left; y += deltaY, x += deltaX) { + NSArray *range; + if (deltaX == 0) { + range = [self blackWhiteRange:y maxWhiteRun:maxWhiteRun minDim:left maxDim:right horizontal:YES]; + } else { + range = [self blackWhiteRange:x maxWhiteRun:maxWhiteRun minDim:top maxDim:bottom horizontal:NO]; + } + if (range == nil) { + if (lastRange == nil) { + return nil; + } + if (deltaX == 0) { + int lastY = y - deltaY; + if ([lastRange[0] intValue] < centerX) { + if ([lastRange[0] intValue] > centerX) { + return [[ZXResultPoint alloc] initWithX:deltaY > 0 ? [lastRange[0] intValue] : [lastRange[1] intValue] y:lastY]; + } + return [[ZXResultPoint alloc] initWithX:[lastRange[0] intValue] y:lastY]; + } else { + return [[ZXResultPoint alloc] initWithX:[lastRange[1] intValue] y:lastY]; + } + } else { + int lastX = x - deltaX; + if ([lastRange[0] intValue] < centerY) { + if ([lastRange[1] intValue] > centerY) { + return [[ZXResultPoint alloc] initWithX:lastX y:deltaX < 0 ? [lastRange[0] intValue] : [lastRange[1] intValue]]; + } + return [[ZXResultPoint alloc] initWithX:lastX y:[lastRange[0] intValue]]; + } else { + return [[ZXResultPoint alloc] initWithX:lastX y:[lastRange[1] intValue]]; + } + } + } + lastRange = range; + } + + return nil; +} + +/** + * Computes the start and end of a region of pixels, either horizontally or vertically, that could + * be part of a Data Matrix barcode. + * + * @param fixedDimension if scanning horizontally, this is the row (the fixed vertical location) + * where we are scanning. If scanning vertically it's the column, the fixed horizontal location + * @param maxWhiteRun largest run of white pixels that can still be considered part of the + * barcode region + * @param minDim minimum pixel location, horizontally or vertically, to consider + * @param maxDim maximum pixel location, horizontally or vertically, to consider + * @param horizontal if true, we're scanning left-right, instead of up-down + * @return int[] with start and end of found range, or nil if no such range is found + * (e.g. only white was found) + */ +- (NSArray *)blackWhiteRange:(int)fixedDimension maxWhiteRun:(int)maxWhiteRun minDim:(int)minDim maxDim:(int)maxDim horizontal:(BOOL)horizontal { + int center = (minDim + maxDim) / 2; + + int start = center; + while (start >= minDim) { + if (horizontal ? [self.image getX:start y:fixedDimension] : [self.image getX:fixedDimension y:start]) { + start--; + } else { + int whiteRunStart = start; + + do { + start--; + } while (start >= minDim && !(horizontal ? [self.image getX:start y:fixedDimension] : [self.image getX:fixedDimension y:start])); + int whiteRunSize = whiteRunStart - start; + if (start < minDim || whiteRunSize > maxWhiteRun) { + start = whiteRunStart; + break; + } + } + } + + start++; + int end = center; + + while (end < maxDim) { + if (horizontal ? [self.image getX:end y:fixedDimension] : [self.image getX:fixedDimension y:end]) { + end++; + } else { + int whiteRunStart = end; + + do { + end++; + } while (end < maxDim && !(horizontal ? [self.image getX:end y:fixedDimension] : [self.image getX:fixedDimension y:end])); + int whiteRunSize = end - whiteRunStart; + if (end >= maxDim || whiteRunSize > maxWhiteRun) { + end = whiteRunStart; + break; + } + } + } + + end--; + return end > start ? @[@(start), @(end)] : nil; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/detector/ZXWhiteRectangleDetector.h b/iDearQRCode/Tools/ZXingObjC/common/detector/ZXWhiteRectangleDetector.h new file mode 100755 index 0000000..09dbb46 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/detector/ZXWhiteRectangleDetector.h @@ -0,0 +1,45 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXResultPoint.h" +#import "ZXBitMatrix.h" + +/** + * Detects a candidate barcode-like rectangular region within an image. It + * starts around the center of the image, increases the size of the candidate + * region until it finds a white rectangular region. By keeping track of the + * last black points it encountered, it determines the corners of the barcode. + */ +@interface ZXWhiteRectangleDetector : NSObject + +- (id)initWithImage:(ZXBitMatrix *)image error:(NSError **)error; +- (id)initWithImage:(ZXBitMatrix *)image initSize:(int)initSize x:(int)x y:(int)y error:(NSError **)error; + +/** + * Detects a candidate barcode-like rectangular region within an image. It + * starts around the center of the image, increases the size of the candidate + * region until it finds a white rectangular region. + * + * @return {@link ResultPoint}[] describing the corners of the rectangular + * region. The first and last points are opposed on the diagonal, as + * are the second and third. The first point will be the topmost + * point and the last, the bottommost. The second point will be + * leftmost and the third, the rightmost + * @return nil if no Data Matrix Code can be found + */ +- (NSArray *)detectWithError:(NSError **)error; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/detector/ZXWhiteRectangleDetector.m b/iDearQRCode/Tools/ZXingObjC/common/detector/ZXWhiteRectangleDetector.m new file mode 100755 index 0000000..677c873 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/detector/ZXWhiteRectangleDetector.m @@ -0,0 +1,311 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXErrors.h" +#import "ZXMathUtils.h" +#import "ZXWhiteRectangleDetector.h" + +@interface ZXWhiteRectangleDetector () + +@property (nonatomic, strong, readonly) ZXBitMatrix *image; +@property (nonatomic, assign, readonly) int height; +@property (nonatomic, assign, readonly) int width; +@property (nonatomic, assign, readonly) int leftInit; +@property (nonatomic, assign, readonly) int rightInit; +@property (nonatomic, assign, readonly) int downInit; +@property (nonatomic, assign, readonly) int upInit; + +@end + +const int ZX_INIT_SIZE = 10; +const int ZX_CORR = 1; + +@implementation ZXWhiteRectangleDetector + +- (id)initWithImage:(ZXBitMatrix *)image error:(NSError **)error { + return [self initWithImage:image initSize:ZX_INIT_SIZE x:image.width / 2 y:image.height / 2 error:error]; +} + +- (id)initWithImage:(ZXBitMatrix *)image initSize:(int)initSize x:(int)x y:(int)y error:(NSError **)error { + if (self = [super init]) { + _image = image; + _height = image.height; + _width = image.width; + int halfsize = initSize / 2; + _leftInit = x - halfsize; + _rightInit = x + halfsize; + _upInit = y - halfsize; + _downInit = y + halfsize; + if (_upInit < 0 || _leftInit < 0 || _downInit >= _height || _rightInit >= _width) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + } + + return self; +} + +- (NSArray *)detectWithError:(NSError **)error { + int left = self.leftInit; + int right = self.rightInit; + int up = self.upInit; + int down = self.downInit; + BOOL sizeExceeded = NO; + BOOL aBlackPointFoundOnBorder = YES; + BOOL atLeastOneBlackPointFoundOnBorder = NO; + + BOOL atLeastOneBlackPointFoundOnRight = NO; + BOOL atLeastOneBlackPointFoundOnBottom = NO; + BOOL atLeastOneBlackPointFoundOnLeft = NO; + BOOL atLeastOneBlackPointFoundOnTop = NO; + + while (aBlackPointFoundOnBorder) { + aBlackPointFoundOnBorder = NO; + + // ..... + // . | + // ..... + BOOL rightBorderNotWhite = YES; + while ((rightBorderNotWhite || !atLeastOneBlackPointFoundOnRight) && right < self.width) { + rightBorderNotWhite = [self containsBlackPoint:up b:down fixed:right horizontal:NO]; + if (rightBorderNotWhite) { + right++; + aBlackPointFoundOnBorder = YES; + atLeastOneBlackPointFoundOnRight = YES; + } else if (!atLeastOneBlackPointFoundOnRight) { + right++; + } + } + + if (right >= self.width) { + sizeExceeded = YES; + break; + } + + // ..... + // . . + // .___. + BOOL bottomBorderNotWhite = YES; + while ((bottomBorderNotWhite || !atLeastOneBlackPointFoundOnBottom) && down < self.height) { + bottomBorderNotWhite = [self containsBlackPoint:left b:right fixed:down horizontal:YES]; + if (bottomBorderNotWhite) { + down++; + aBlackPointFoundOnBorder = YES; + atLeastOneBlackPointFoundOnBottom = YES; + } else if (!atLeastOneBlackPointFoundOnBottom) { + down++; + } + } + + if (down >= self.height) { + sizeExceeded = YES; + break; + } + + // ..... + // | . + // ..... + BOOL leftBorderNotWhite = YES; + while ((leftBorderNotWhite || !atLeastOneBlackPointFoundOnLeft) && left >= 0) { + leftBorderNotWhite = [self containsBlackPoint:up b:down fixed:left horizontal:NO]; + if (leftBorderNotWhite) { + left--; + aBlackPointFoundOnBorder = YES; + atLeastOneBlackPointFoundOnLeft = YES; + } else if (!atLeastOneBlackPointFoundOnLeft) { + left--; + } + } + + if (left < 0) { + sizeExceeded = YES; + break; + } + + // .___. + // . . + // ..... + BOOL topBorderNotWhite = YES; + while ((topBorderNotWhite || !atLeastOneBlackPointFoundOnTop) && up >= 0) { + topBorderNotWhite = [self containsBlackPoint:left b:right fixed:up horizontal:YES]; + if (topBorderNotWhite) { + up--; + aBlackPointFoundOnBorder = YES; + atLeastOneBlackPointFoundOnTop = YES; + } else if (!atLeastOneBlackPointFoundOnTop) { + up--; + } + } + + if (up < 0) { + sizeExceeded = YES; + break; + } + + if (aBlackPointFoundOnBorder) { + atLeastOneBlackPointFoundOnBorder = YES; + } + } + + if (!sizeExceeded && atLeastOneBlackPointFoundOnBorder) { + int maxSize = right - left; + + ZXResultPoint *z = nil; + for (int i = 1; i < maxSize; i++) { + z = [self blackPointOnSegment:left aY:down - i bX:left + i bY:down]; + if (z != nil) { + break; + } + } + + if (z == nil) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + + ZXResultPoint *t = nil; + for (int i = 1; i < maxSize; i++) { + t = [self blackPointOnSegment:left aY:up + i bX:left + i bY:up]; + if (t != nil) { + break; + } + } + + if (t == nil) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + + ZXResultPoint *x = nil; + for (int i = 1; i < maxSize; i++) { + x = [self blackPointOnSegment:right aY:up + i bX:right - i bY:up]; + if (x != nil) { + break; + } + } + + if (x == nil) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + + ZXResultPoint *y = nil; + for (int i = 1; i < maxSize; i++) { + y = [self blackPointOnSegment:right aY:down - i bX:right - i bY:down]; + if (y != nil) { + break; + } + } + + if (y == nil) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + return [self centerEdges:y z:z x:x t:t]; + } else { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } +} + + +- (ZXResultPoint *)blackPointOnSegment:(float)aX aY:(float)aY bX:(float)bX bY:(float)bY { + int dist = [ZXMathUtils round:[ZXMathUtils distance:aX aY:aY bX:bX bY:bY]]; + float xStep = (bX - aX) / dist; + float yStep = (bY - aY) / dist; + + for (int i = 0; i < dist; i++) { + int x = [ZXMathUtils round:aX + i * xStep]; + int y = [ZXMathUtils round:aY + i * yStep]; + if ([self.image getX:x y:y]) { + return [[ZXResultPoint alloc] initWithX:x y:y]; + } + } + + return nil; +} + +/** + * recenters the points of a constant distance towards the center + * + * @param y bottom most point + * @param z left most point + * @param x right most point + * @param t top most point + * @return ZXResultPoint array describing the corners of the rectangular + * region. The first and last points are opposed on the diagonal, as + * are the second and third. The first point will be the topmost + * point and the last, the bottommost. The second point will be + * leftmost and the third, the rightmost + */ +- (NSArray *)centerEdges:(ZXResultPoint *)y z:(ZXResultPoint *)z x:(ZXResultPoint *)x t:(ZXResultPoint *)t { + // + // t t + // z x + // x OR z + // y y + // + + float yi = y.x; + float yj = y.y; + float zi = z.x; + float zj = z.y; + float xi = x.x; + float xj = x.y; + float ti = t.x; + float tj = t.y; + + if (yi < self.width / 2.0f) { + return @[[[ZXResultPoint alloc] initWithX:ti - ZX_CORR y:tj + ZX_CORR], + [[ZXResultPoint alloc] initWithX:zi + ZX_CORR y:zj + ZX_CORR], + [[ZXResultPoint alloc] initWithX:xi - ZX_CORR y:xj - ZX_CORR], + [[ZXResultPoint alloc] initWithX:yi + ZX_CORR y:yj - ZX_CORR]]; + } else { + return @[[[ZXResultPoint alloc] initWithX:ti + ZX_CORR y:tj + ZX_CORR], + [[ZXResultPoint alloc] initWithX:zi + ZX_CORR y:zj - ZX_CORR], + [[ZXResultPoint alloc] initWithX:xi - ZX_CORR y:xj + ZX_CORR], + [[ZXResultPoint alloc] initWithX:yi - ZX_CORR y:yj - ZX_CORR]]; + } +} + +/** + * Determines whether a segment contains a black point + * + * @param a min value of the scanned coordinate + * @param b max value of the scanned coordinate + * @param fixed value of fixed coordinate + * @param horizontal set to true if scan must be horizontal, false if vertical + * @return true if a black point has been found, else false. + */ +- (BOOL)containsBlackPoint:(int)a b:(int)b fixed:(int)fixed horizontal:(BOOL)horizontal { + if (horizontal) { + for (int x = a; x <= b; x++) { + if ([self.image getX:x y:fixed]) { + return YES; + } + } + } else { + for (int y = a; y <= b; y++) { + if ([self.image getX:fixed y:y]) { + return YES; + } + } + } + + return NO; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/reedsolomon/ZXGenericGF.h b/iDearQRCode/Tools/ZXingObjC/common/reedsolomon/ZXGenericGF.h new file mode 100755 index 0000000..f5d0b62 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/reedsolomon/ZXGenericGF.h @@ -0,0 +1,87 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXGenericGFPoly; + +/** + * This class contains utility methods for performing mathematical operations over + * the Galois Fields. Operations use a given primitive polynomial in calculations. + * + * Throughout this package, elements of the GF are represented as an int + * for convenience and speed (but at the cost of memory). + */ +@interface ZXGenericGF : NSObject + +@property (nonatomic, strong, readonly) ZXGenericGFPoly *zero; +@property (nonatomic, strong, readonly) ZXGenericGFPoly *one; +@property (nonatomic, assign, readonly) int32_t size; +@property (nonatomic, assign, readonly) int32_t generatorBase; + ++ (ZXGenericGF *)AztecData12; ++ (ZXGenericGF *)AztecData10; ++ (ZXGenericGF *)AztecData6; ++ (ZXGenericGF *)AztecParam; ++ (ZXGenericGF *)QrCodeField256; ++ (ZXGenericGF *)DataMatrixField256; ++ (ZXGenericGF *)AztecData8; ++ (ZXGenericGF *)MaxiCodeField64; + +/** + * Create a representation of GF(size) using the given primitive polynomial. + * + * @param primitive irreducible polynomial whose coefficients are represented by + * the bits of an int, where the least-significant bit represents the constant + * coefficient + * @param size the size of the field + * @param b the factor b in the generator polynomial can be 0- or 1-based + * (g(x) = (x+a^b)(x+a^(b+1))...(x+a^(b+2t-1))). + * In most cases it should be 1, but for QR code it is 0. + */ +- (id)initWithPrimitive:(int)primitive size:(int)size b:(int)b; + +/** + * @return the monomial representing coefficient * x^degree + */ +- (ZXGenericGFPoly *)buildMonomial:(int)degree coefficient:(int)coefficient; + +/** + * Implements both addition and subtraction -- they are the same in GF(size). + * + * @return sum/difference of a and b + */ ++ (int32_t)addOrSubtract:(int32_t)a b:(int32_t)b; + +/** + * @return 2 to the power of a in GF(size) + */ +- (int32_t)exp:(int)a; + +/** + * @return base 2 log of a in GF(size) + */ +- (int32_t)log:(int)a; + +/** + * @return multiplicative inverse of a + */ +- (int32_t)inverse:(int)a; + +/** + * @return product of a and b in GF(size) + */ +- (int32_t)multiply:(int)a b:(int)b; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/reedsolomon/ZXGenericGF.m b/iDearQRCode/Tools/ZXingObjC/common/reedsolomon/ZXGenericGF.m new file mode 100755 index 0000000..be1eb5d --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/reedsolomon/ZXGenericGF.m @@ -0,0 +1,178 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXGenericGF.h" +#import "ZXGenericGFPoly.h" +#import "ZXIntArray.h" + +@interface ZXGenericGF () + +@property (nonatomic, assign, readonly) int32_t *expTable; +@property (nonatomic, assign, readonly) int32_t *logTable; +@property (nonatomic, assign, readonly) int primitive; + +@end + +@implementation ZXGenericGF { + ZXGenericGFPoly *_one; + ZXGenericGFPoly *_zero; +} + +- (id)initWithPrimitive:(int)primitive size:(int)size b:(int)b { + if (self = [super init]) { + _primitive = primitive; + _size = size; + _generatorBase = b; + + _expTable = (int32_t *)calloc(self.size, sizeof(int32_t)); + _logTable = (int32_t *)calloc(self.size, sizeof(int32_t)); + int32_t x = 1; + for (int i = 0; i < self.size; i++) { + _expTable[i] = x; + x <<= 1; // we're assuming the generator alpha is 2 + if (x >= self.size) { + x ^= (int32_t)self.primitive; + x &= (int32_t)self.size - 1; + } + } + + for (int32_t i = 0; i < (int32_t)self.size-1; i++) { + _logTable[_expTable[i]] = i; + } + // logTable[0] == 0 but this should never be used + _zero = [[ZXGenericGFPoly alloc] initWithField:self coefficients:[[ZXIntArray alloc] initWithLength:1]]; + + _one = [[ZXGenericGFPoly alloc] initWithField:self coefficients:[[ZXIntArray alloc] initWithInts:1, -1]]; + } + + return self; +} + ++ (ZXGenericGF *)AztecData12 { + static ZXGenericGF *AztecData12 = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + AztecData12 = [[ZXGenericGF alloc] initWithPrimitive:0x1069 size:4096 b:1]; // x^12 + x^6 + x^5 + x^3 + 1 + }); + return AztecData12; +} + ++ (ZXGenericGF *)AztecData10 { + static ZXGenericGF *AztecData10 = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + AztecData10 = [[ZXGenericGF alloc] initWithPrimitive:0x409 size:1024 b:1]; // x^10 + x^3 + 1 + }); + return AztecData10; +} + ++ (ZXGenericGF *)AztecData6 { + static ZXGenericGF *AztecData6 = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + AztecData6 = [[ZXGenericGF alloc] initWithPrimitive:0x43 size:64 b:1]; // x^6 + x + 1 + }); + return AztecData6; +} + ++ (ZXGenericGF *)AztecParam { + static ZXGenericGF *AztecParam = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + AztecParam = [[ZXGenericGF alloc] initWithPrimitive:0x13 size:16 b:1]; // x^4 + x + 1 + }); + return AztecParam; +} + ++ (ZXGenericGF *)QrCodeField256 { + static ZXGenericGF *QrCodeField256 = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + QrCodeField256 = [[ZXGenericGF alloc] initWithPrimitive:0x011D size:256 b:0]; // x^8 + x^4 + x^3 + x^2 + 1 + }); + return QrCodeField256; +} + ++ (ZXGenericGF *)DataMatrixField256 { + static ZXGenericGF *DataMatrixField256 = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + DataMatrixField256 = [[ZXGenericGF alloc] initWithPrimitive:0x012D size:256 b:1]; // x^8 + x^5 + x^3 + x^2 + 1 + }); + return DataMatrixField256; +} + ++ (ZXGenericGF *)AztecData8 { + return [self DataMatrixField256]; +} + ++ (ZXGenericGF *)MaxiCodeField64 { + return [self AztecData6]; +} + +- (ZXGenericGFPoly *)buildMonomial:(int)degree coefficient:(int32_t)coefficient { + if (degree < 0) { + [NSException raise:NSInvalidArgumentException format:@"Degree must be greater than 0."]; + } + if (coefficient == 0) { + return self.zero; + } + ZXIntArray *coefficients = [[ZXIntArray alloc] initWithLength:degree + 1]; + coefficients.array[0] = coefficient; + return [[ZXGenericGFPoly alloc] initWithField:self coefficients:coefficients]; +} + ++ (int32_t)addOrSubtract:(int32_t)a b:(int32_t)b { + return a ^ b; +} + +- (int32_t)exp:(int)a { + return _expTable[a]; +} + +- (int32_t)log:(int)a { + if (a == 0) { + [NSException raise:NSInvalidArgumentException format:@"Argument must be non-zero."]; + } + + return _logTable[a]; +} + +- (int32_t)inverse:(int)a { + if (a == 0) { + [NSException raise:NSInvalidArgumentException format:@"Argument must be non-zero."]; + } + + return _expTable[_size - _logTable[a] - 1]; +} + +- (int32_t)multiply:(int)a b:(int)b { + if (a == 0 || b == 0) { + return 0; + } + + return _expTable[(_logTable[a] + _logTable[b]) % (_size - 1)]; +} + +- (BOOL)isEqual:(ZXGenericGF *)object { + return self.primitive == object.primitive && self.size == object.size; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"GF(0x%X,%d)", self.primitive, self.size]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/reedsolomon/ZXGenericGFPoly.h b/iDearQRCode/Tools/ZXingObjC/common/reedsolomon/ZXGenericGFPoly.h new file mode 100755 index 0000000..feae94a --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/reedsolomon/ZXGenericGFPoly.h @@ -0,0 +1,64 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXGenericGF, ZXIntArray; + +/** + * Represents a polynomial whose coefficients are elements of a GF. + * Instances of this class are immutable. + * + * Much credit is due to William Rucklidge since portions of this code are an indirect + * port of his C++ Reed-Solomon implementation. + */ +@interface ZXGenericGFPoly : NSObject + +@property (nonatomic, strong, readonly) ZXIntArray *coefficients; + +/** + * @param field the {@link GenericGF} instance representing the field to use + * to perform computations + * @param coefficients coefficients as ints representing elements of GF(size), arranged + * from most significant (highest-power term) coefficient to least significant + */ +- (id)initWithField:(ZXGenericGF *)field coefficients:(ZXIntArray *)coefficients; + +/** + * @return degree of this polynomial + */ +- (int)degree; + +/** + * @return true iff this polynomial is the monomial "0" + */ +- (BOOL)zero; + +/** + * @return coefficient of x^degree term in this polynomial + */ +- (int)coefficient:(int)degree; + +/** + * @return evaluation of this polynomial at a given point + */ +- (int)evaluateAt:(int)a; + +- (ZXGenericGFPoly *)addOrSubtract:(ZXGenericGFPoly *)other; +- (ZXGenericGFPoly *)multiply:(ZXGenericGFPoly *)other; +- (ZXGenericGFPoly *)multiplyScalar:(int)scalar; +- (ZXGenericGFPoly *)multiplyByMonomial:(int)degree coefficient:(int)coefficient; +- (NSArray *)divide:(ZXGenericGFPoly *)other; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/reedsolomon/ZXGenericGFPoly.m b/iDearQRCode/Tools/ZXingObjC/common/reedsolomon/ZXGenericGFPoly.m new file mode 100755 index 0000000..5df43db --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/reedsolomon/ZXGenericGFPoly.m @@ -0,0 +1,246 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXGenericGF.h" +#import "ZXGenericGFPoly.h" +#import "ZXIntArray.h" + +@interface ZXGenericGFPoly () + +@property (nonatomic, strong, readonly) ZXGenericGF *field; + +@end + +@implementation ZXGenericGFPoly + +- (id)initWithField:(ZXGenericGF *)field coefficients:(ZXIntArray *)coefficients { + if (self = [super init]) { + if (coefficients.length == 0) { + @throw [NSException exceptionWithName:@"IllegalArgumentException" + reason:@"coefficients must have at least one element" + userInfo:nil]; + } + _field = field; + int coefficientsLength = coefficients.length; + if (coefficientsLength > 1 && coefficients.array[0] == 0) { + // Leading term must be non-zero for anything except the constant polynomial "0" + int firstNonZero = 1; + while (firstNonZero < coefficientsLength && coefficients.array[firstNonZero] == 0) { + firstNonZero++; + } + if (firstNonZero == coefficientsLength) { + _coefficients = [[ZXIntArray alloc] initWithLength:1]; + } else { + _coefficients = [[ZXIntArray alloc] initWithLength:coefficientsLength - firstNonZero]; + for (int i = 0; i < _coefficients.length; i++) { + _coefficients.array[i] = coefficients.array[firstNonZero + i]; + } + } + } else { + _coefficients = coefficients; + } + } + + return self; +} + +- (int)degree { + return self.coefficients.length - 1; +} + +- (BOOL)zero { + return self.coefficients.array[0] == 0; +} + +- (int)coefficient:(int)degree { + return self.coefficients.array[self.coefficients.length - 1 - degree]; +} + +- (int)evaluateAt:(int)a { + if (a == 0) { + return [self coefficient:0]; + } + int size = self.coefficients.length; + int32_t *coefficients = self.coefficients.array; + ZXGenericGF *field = self.field; + if (a == 1) { + // Just the sum of the coefficients + int result = 0; + for (int i = 0; i < size; i++) { + result = [ZXGenericGF addOrSubtract:result b:coefficients[i]]; + } + return result; + } + int result = coefficients[0]; + for (int i = 1; i < size; i++) { + result = [ZXGenericGF addOrSubtract:[field multiply:a b:result] b:coefficients[i]]; + } + return result; +} + +- (ZXGenericGFPoly *)addOrSubtract:(ZXGenericGFPoly *)other { + if (![self.field isEqual:other.field]) { + [NSException raise:NSInvalidArgumentException format:@"ZXGenericGFPolys do not have same ZXGenericGF field"]; + } + if (self.zero) { + return other; + } + if (other.zero) { + return self; + } + + ZXIntArray *smallerCoefficients = self.coefficients; + ZXIntArray *largerCoefficients = other.coefficients; + if (smallerCoefficients.length > largerCoefficients.length) { + ZXIntArray *temp = smallerCoefficients; + smallerCoefficients = largerCoefficients; + largerCoefficients = temp; + } + ZXIntArray *sumDiff = [[ZXIntArray alloc] initWithLength:largerCoefficients.length]; + int lengthDiff = largerCoefficients.length - smallerCoefficients.length; + // Copy high-order terms only found in higher-degree polynomial's coefficients + memcpy(sumDiff.array, largerCoefficients.array, lengthDiff * sizeof(int32_t)); + + for (int i = lengthDiff; i < largerCoefficients.length; i++) { + sumDiff.array[i] = [ZXGenericGF addOrSubtract:smallerCoefficients.array[i - lengthDiff] b:largerCoefficients.array[i]]; + } + + return [[ZXGenericGFPoly alloc] initWithField:self.field coefficients:sumDiff]; +} + +- (ZXGenericGFPoly *)multiply:(ZXGenericGFPoly *)other { + ZXGenericGF *field = self.field; + if (![self.field isEqual:other.field]) { + [NSException raise:NSInvalidArgumentException format:@"ZXGenericGFPolys do not have same GenericGF field"]; + } + if (self.zero || other.zero) { + return field.zero; + } + ZXIntArray *aCoefficients = self.coefficients; + int aLength = aCoefficients.length; + ZXIntArray *bCoefficients = other.coefficients; + int bLength = bCoefficients.length; + ZXIntArray *product = [[ZXIntArray alloc] initWithLength:aLength + bLength - 1]; + for (int i = 0; i < aLength; i++) { + int aCoeff = aCoefficients.array[i]; + for (int j = 0; j < bLength; j++) { + product.array[i + j] = [ZXGenericGF addOrSubtract:product.array[i + j] + b:[field multiply:aCoeff b:bCoefficients.array[j]]]; + } + } + return [[ZXGenericGFPoly alloc] initWithField:field coefficients:product]; +} + +- (ZXGenericGFPoly *)multiplyScalar:(int)scalar { + if (scalar == 0) { + return self.field.zero; + } + if (scalar == 1) { + return self; + } + int size = self.coefficients.length; + int32_t *coefficients = self.coefficients.array; + ZXIntArray *product = [[ZXIntArray alloc] initWithLength:size]; + for (int i = 0; i < size; i++) { + product.array[i] = [self.field multiply:coefficients[i] b:scalar]; + } + return [[ZXGenericGFPoly alloc] initWithField:self.field coefficients:product]; +} + +- (ZXGenericGFPoly *)multiplyByMonomial:(int)degree coefficient:(int)coefficient { + if (degree < 0) { + [NSException raise:NSInvalidArgumentException format:@"Degree must be greater than 0."]; + } + if (coefficient == 0) { + return self.field.zero; + } + int size = self.coefficients.length; + int32_t *coefficients = self.coefficients.array; + ZXGenericGF *field = self.field; + ZXIntArray *product = [[ZXIntArray alloc] initWithLength:size + degree]; + for (int i = 0; i < size; i++) { + product.array[i] = [field multiply:coefficients[i] b:coefficient]; + } + + return [[ZXGenericGFPoly alloc] initWithField:field coefficients:product]; +} + +- (NSArray *)divide:(ZXGenericGFPoly *)other { + if (![self.field isEqual:other.field]) { + [NSException raise:NSInvalidArgumentException format:@"ZXGenericGFPolys do not have same ZXGenericGF field"]; + } + if (other.zero) { + [NSException raise:NSInvalidArgumentException format:@"Divide by 0"]; + } + + ZXGenericGFPoly *quotient = self.field.zero; + ZXGenericGFPoly *remainder = self; + + int denominatorLeadingTerm = [other coefficient:other.degree]; + int inverseDenominatorLeadingTerm = [self.field inverse:denominatorLeadingTerm]; + + ZXGenericGF *field = self.field; + while ([remainder degree] >= other.degree && !remainder.zero) { + int degreeDifference = remainder.degree - other.degree; + int scale = [field multiply:[remainder coefficient:remainder.degree] b:inverseDenominatorLeadingTerm]; + ZXGenericGFPoly *term = [other multiplyByMonomial:degreeDifference coefficient:scale]; + ZXGenericGFPoly *iterationQuotient = [field buildMonomial:degreeDifference coefficient:scale]; + quotient = [quotient addOrSubtract:iterationQuotient]; + remainder = [remainder addOrSubtract:term]; + } + + return @[quotient, remainder]; +} + +- (NSString *)description { + NSMutableString *result = [NSMutableString stringWithCapacity:8 * [self degree]]; + for (int degree = [self degree]; degree >= 0; degree--) { + int coefficient = [self coefficient:degree]; + if (coefficient != 0) { + if (coefficient < 0) { + [result appendString:@" - "]; + coefficient = -coefficient; + } else { + if ([result length] > 0) { + [result appendString:@" + "]; + } + } + if (degree == 0 || coefficient != 1) { + int alphaPower = [self.field log:coefficient]; + if (alphaPower == 0) { + [result appendString:@"1"]; + } else if (alphaPower == 1) { + [result appendString:@"a"]; + } else { + [result appendString:@"a^"]; + [result appendFormat:@"%d", alphaPower]; + } + } + if (degree != 0) { + if (degree == 1) { + [result appendString:@"x"]; + } else { + [result appendString:@"x^"]; + [result appendFormat:@"%d", degree]; + } + } + } + } + + return result; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/reedsolomon/ZXReedSolomonDecoder.h b/iDearQRCode/Tools/ZXingObjC/common/reedsolomon/ZXReedSolomonDecoder.h new file mode 100755 index 0000000..62863d2 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/reedsolomon/ZXReedSolomonDecoder.h @@ -0,0 +1,51 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXGenericGF, ZXIntArray; + +/** + * Implements Reed-Solomon decoding, as the name implies. + * + * The algorithm will not be explained here, but the following references were helpful + * in creating this implementation: + * + * Bruce Maggs. + * http://www.cs.cmu.edu/afs/cs.cmu.edu/project/pscico-guyb/realworld/www/rs_decode.ps + * "Decoding Reed-Solomon Codes" (see discussion of Forney's Formula) + * + * J.I. Hall. www.mth.msu.edu/~jhall/classes/codenotes/GRS.pdf + * "Chapter 5. Generalized Reed-Solomon Codes" + * (see discussion of Euclidean algorithm) + * + * Much credit is due to William Rucklidge since portions of this code are an indirect + * port of his C++ Reed-Solomon implementation. + */ +@interface ZXReedSolomonDecoder : NSObject + +- (id)initWithField:(ZXGenericGF *)field; + +/** + * Decodes given set of received codewords, which include both data and error-correction + * codewords. Really, this means it uses Reed-Solomon to detect and correct errors, in-place, + * in the input. + * + * @param received data and error-correction codewords + * @param twoS number of error-correction codewords available + * @return NO if decoding fails for any reason + */ +- (BOOL)decode:(ZXIntArray *)received twoS:(int)twoS error:(NSError **)error; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/reedsolomon/ZXReedSolomonDecoder.m b/iDearQRCode/Tools/ZXingObjC/common/reedsolomon/ZXReedSolomonDecoder.m new file mode 100755 index 0000000..3f7b6d8 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/reedsolomon/ZXReedSolomonDecoder.m @@ -0,0 +1,189 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXErrors.h" +#import "ZXGenericGF.h" +#import "ZXGenericGFPoly.h" +#import "ZXIntArray.h" +#import "ZXReedSolomonDecoder.h" + +@interface ZXReedSolomonDecoder () + +@property (nonatomic, strong, readonly) ZXGenericGF *field; + +@end + +@implementation ZXReedSolomonDecoder + +- (id)initWithField:(ZXGenericGF *)field { + if (self = [super init]) { + _field = field; + } + + return self; +} + +- (BOOL)decode:(ZXIntArray *)received twoS:(int)twoS error:(NSError **)error { + ZXGenericGFPoly *poly = [[ZXGenericGFPoly alloc] initWithField:self.field coefficients:received]; + ZXIntArray *syndromeCoefficients = [[ZXIntArray alloc] initWithLength:twoS]; + BOOL noError = YES; + for (int i = 0; i < twoS; i++) { + int eval = [poly evaluateAt:[self.field exp:i + self.field.generatorBase]]; + syndromeCoefficients.array[syndromeCoefficients.length - 1 - i] = eval; + if (eval != 0) { + noError = NO; + } + } + if (noError) { + return YES; + } + ZXGenericGFPoly *syndrome = [[ZXGenericGFPoly alloc] initWithField:self.field coefficients:syndromeCoefficients]; + NSArray *sigmaOmega = [self runEuclideanAlgorithm:[self.field buildMonomial:twoS coefficient:1] b:syndrome R:twoS error:error]; + if (!sigmaOmega) { + return NO; + } + ZXGenericGFPoly *sigma = sigmaOmega[0]; + ZXGenericGFPoly *omega = sigmaOmega[1]; + ZXIntArray *errorLocations = [self findErrorLocations:sigma error:error]; + if (!errorLocations) { + return NO; + } + ZXIntArray *errorMagnitudes = [self findErrorMagnitudes:omega errorLocations:errorLocations]; + for (int i = 0; i < errorLocations.length; i++) { + int position = received.length - 1 - [self.field log:errorLocations.array[i]]; + if (position < 0) { + NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @"Bad error location"}; + + if (error) *error = [[NSError alloc] initWithDomain:ZXErrorDomain code:ZXReedSolomonError userInfo:userInfo]; + return NO; + } + received.array[position] = [ZXGenericGF addOrSubtract:received.array[position] b:errorMagnitudes.array[i]]; + } + return YES; +} + +- (NSArray *)runEuclideanAlgorithm:(ZXGenericGFPoly *)a b:(ZXGenericGFPoly *)b R:(int)R error:(NSError **)error { + if (a.degree < b.degree) { + ZXGenericGFPoly *temp = a; + a = b; + b = temp; + } + + ZXGenericGFPoly *rLast = a; + ZXGenericGFPoly *r = b; + ZXGenericGFPoly *tLast = self.field.zero; + ZXGenericGFPoly *t = self.field.one; + + while ([r degree] >= R / 2) { + ZXGenericGFPoly *rLastLast = rLast; + ZXGenericGFPoly *tLastLast = tLast; + rLast = r; + tLast = t; + + if ([rLast zero]) { + NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @"r_{i-1} was zero"}; + + if (error) *error = [[NSError alloc] initWithDomain:ZXErrorDomain code:ZXReedSolomonError userInfo:userInfo]; + return nil; + } + r = rLastLast; + ZXGenericGFPoly *q = [self.field zero]; + int denominatorLeadingTerm = [rLast coefficient:[rLast degree]]; + int dltInverse = [self.field inverse:denominatorLeadingTerm]; + + while ([r degree] >= [rLast degree] && ![r zero]) { + int degreeDiff = [r degree] - [rLast degree]; + int scale = [self.field multiply:[r coefficient:[r degree]] b:dltInverse]; + q = [q addOrSubtract:[self.field buildMonomial:degreeDiff coefficient:scale]]; + r = [r addOrSubtract:[rLast multiplyByMonomial:degreeDiff coefficient:scale]]; + } + + t = [[q multiply:tLast] addOrSubtract:tLastLast]; + + if (r.degree >= rLast.degree) { + @throw [NSException exceptionWithName:@"IllegalStateException" + reason:@"Division algorithm failed to reduce polynomial?" + userInfo:nil]; + } + } + + int sigmaTildeAtZero = [t coefficient:0]; + if (sigmaTildeAtZero == 0) { + NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @"sigmaTilde(0) was zero"}; + + if (error) *error = [[NSError alloc] initWithDomain:ZXErrorDomain code:ZXReedSolomonError userInfo:userInfo]; + return nil; + } + + int inverse = [self.field inverse:sigmaTildeAtZero]; + ZXGenericGFPoly *sigma = [t multiplyScalar:inverse]; + ZXGenericGFPoly *omega = [r multiplyScalar:inverse]; + return @[sigma, omega]; +} + +- (ZXIntArray *)findErrorLocations:(ZXGenericGFPoly *)errorLocator error:(NSError **)error { + int numErrors = [errorLocator degree]; + if (numErrors == 1) { + ZXIntArray *array = [[ZXIntArray alloc] initWithLength:1]; + array.array[0] = [errorLocator coefficient:1]; + return array; + } + ZXIntArray *result = [[ZXIntArray alloc] initWithLength:numErrors]; + int e = 0; + for (int i = 1; i < [self.field size] && e < numErrors; i++) { + if ([errorLocator evaluateAt:i] == 0) { + result.array[e] = [self.field inverse:i]; + e++; + } + } + + if (e != numErrors) { + NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @"Error locator degree does not match number of roots"}; + + if (error) *error = [[NSError alloc] initWithDomain:ZXErrorDomain code:ZXReedSolomonError userInfo:userInfo]; + return nil; + } + return result; +} + +- (ZXIntArray *)findErrorMagnitudes:(ZXGenericGFPoly *)errorEvaluator errorLocations:(ZXIntArray *)errorLocations { + int s = errorLocations.length; + ZXIntArray *result = [[ZXIntArray alloc] initWithLength:s]; + ZXGenericGF *field = self.field; + for (int i = 0; i < s; i++) { + int xiInverse = [field inverse:errorLocations.array[i]]; + int denominator = 1; + for (int j = 0; j < s; j++) { + if (i != j) { + //denominator = field.multiply(denominator, + // GenericGF.addOrSubtract(1, field.multiply(errorLocations[j], xiInverse))); + // Above should work but fails on some Apple and Linux JDKs due to a Hotspot bug. + // Below is a funny-looking workaround from Steven Parkes + int term = [field multiply:errorLocations.array[j] b:xiInverse]; + int termPlus1 = (term & 0x1) == 0 ? term | 1 : term & ~1; + denominator = [field multiply:denominator b:termPlus1]; + } + } + result.array[i] = [field multiply:[errorEvaluator evaluateAt:xiInverse] b:[field inverse:denominator]]; + if (field.generatorBase != 0) { + result.array[i] = [field multiply:result.array[i] b:xiInverse]; + } + } + + return result; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/reedsolomon/ZXReedSolomonEncoder.h b/iDearQRCode/Tools/ZXingObjC/common/reedsolomon/ZXReedSolomonEncoder.h new file mode 100755 index 0000000..af27289 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/reedsolomon/ZXReedSolomonEncoder.h @@ -0,0 +1,27 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXGenericGF, ZXIntArray; + +/** + * Implements Reed-Solomon enbcoding, as the name implies. + */ +@interface ZXReedSolomonEncoder : NSObject + +- (id)initWithField:(ZXGenericGF *)field; +- (void)encode:(ZXIntArray *)toEncode ecBytes:(int)ecBytes; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/common/reedsolomon/ZXReedSolomonEncoder.m b/iDearQRCode/Tools/ZXingObjC/common/reedsolomon/ZXReedSolomonEncoder.m new file mode 100755 index 0000000..2a6ccc4 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/common/reedsolomon/ZXReedSolomonEncoder.m @@ -0,0 +1,88 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXGenericGF.h" +#import "ZXGenericGFPoly.h" +#import "ZXIntArray.h" +#import "ZXReedSolomonEncoder.h" + +@interface ZXReedSolomonEncoder () + +@property (nonatomic, strong, readonly) NSMutableArray *cachedGenerators; +@property (nonatomic, strong, readonly) ZXGenericGF *field; + +@end + +@implementation ZXReedSolomonEncoder + +- (id)initWithField:(ZXGenericGF *)field { + if (self = [super init]) { + _field = field; + ZXIntArray *one = [[ZXIntArray alloc] initWithLength:1]; + one.array[0] = 1; + _cachedGenerators = [NSMutableArray arrayWithObject:[[ZXGenericGFPoly alloc] initWithField:field coefficients:one]]; + } + + return self; +} + +- (ZXGenericGFPoly *)buildGenerator:(int)degree { + if (degree >= self.cachedGenerators.count) { + ZXGenericGFPoly *lastGenerator = self.cachedGenerators[[self.cachedGenerators count] - 1]; + for (NSUInteger d = [self.cachedGenerators count]; d <= degree; d++) { + ZXIntArray *next = [[ZXIntArray alloc] initWithLength:2]; + next.array[0] = 1; + next.array[1] = [self.field exp:(int)d - 1 + self.field.generatorBase]; + ZXGenericGFPoly *nextGenerator = [lastGenerator multiply:[[ZXGenericGFPoly alloc] initWithField:self.field coefficients:next]]; + [self.cachedGenerators addObject:nextGenerator]; + lastGenerator = nextGenerator; + } + } + + return (ZXGenericGFPoly *)self.cachedGenerators[degree]; +} + +- (void)encode:(ZXIntArray *)toEncode ecBytes:(int)ecBytes { + if (ecBytes == 0) { + @throw [NSException exceptionWithName:NSInvalidArgumentException + reason:@"No error correction bytes" + userInfo:nil]; + } + int dataBytes = toEncode.length - ecBytes; + if (dataBytes <= 0) { + @throw [NSException exceptionWithName:NSInvalidArgumentException + reason:@"No data bytes provided" + userInfo:nil]; + } + ZXGenericGFPoly *generator = [self buildGenerator:ecBytes]; + ZXIntArray *infoCoefficients = [[ZXIntArray alloc] initWithLength:dataBytes]; + for (int i = 0; i < dataBytes; i++) { + infoCoefficients.array[i] = toEncode.array[i]; + } + ZXGenericGFPoly *info = [[ZXGenericGFPoly alloc] initWithField:self.field coefficients:infoCoefficients]; + info = [info multiplyByMonomial:ecBytes coefficient:1]; + ZXGenericGFPoly *remainder = [info divide:generator][1]; + ZXIntArray *coefficients = remainder.coefficients; + int numZeroCoefficients = ecBytes - coefficients.length; + for (int i = 0; i < numZeroCoefficients; i++) { + toEncode.array[dataBytes + i] = 0; + } + for (int i = 0; i < coefficients.length; i++) { + toEncode.array[dataBytes + numZeroCoefficients + i] = coefficients.array[i]; + } +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/core/ZXBarcodeFormat.h b/iDearQRCode/Tools/ZXingObjC/core/ZXBarcodeFormat.h new file mode 100755 index 0000000..4f74599 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/core/ZXBarcodeFormat.h @@ -0,0 +1,71 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Enumerates barcode formats known to this package. Please keep alphabetized. + */ +typedef enum { + /** Aztec 2D barcode format. */ + kBarcodeFormatAztec, + + /** CODABAR 1D format. */ + kBarcodeFormatCodabar, + + /** Code 39 1D format. */ + kBarcodeFormatCode39, + + /** Code 93 1D format. */ + kBarcodeFormatCode93, + + /** Code 128 1D format. */ + kBarcodeFormatCode128, + + /** Data Matrix 2D barcode format. */ + kBarcodeFormatDataMatrix, + + /** EAN-8 1D format. */ + kBarcodeFormatEan8, + + /** EAN-13 1D format. */ + kBarcodeFormatEan13, + + /** ITF (Interleaved Two of Five) 1D format. */ + kBarcodeFormatITF, + + /** MaxiCode 2D barcode format. */ + kBarcodeFormatMaxiCode, + + /** PDF417 format. */ + kBarcodeFormatPDF417, + + /** QR Code 2D barcode format. */ + kBarcodeFormatQRCode, + + /** RSS 14 */ + kBarcodeFormatRSS14, + + /** RSS EXPANDED */ + kBarcodeFormatRSSExpanded, + + /** UPC-A 1D format. */ + kBarcodeFormatUPCA, + + /** UPC-E 1D format. */ + kBarcodeFormatUPCE, + + /** UPC/EAN extension format. Not a stand-alone format. */ + kBarcodeFormatUPCEANExtension +} ZXBarcodeFormat; diff --git a/iDearQRCode/Tools/ZXingObjC/core/ZXBinarizer.h b/iDearQRCode/Tools/ZXingObjC/core/ZXBinarizer.h new file mode 100755 index 0000000..c6fe676 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/core/ZXBinarizer.h @@ -0,0 +1,74 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import +#import "ZXBitArray.h" +#import "ZXBitMatrix.h" +#import "ZXLuminanceSource.h" + +/** + * This class hierarchy provides a set of methods to convert luminance data to 1 bit data. + * It allows the algorithm to vary polymorphically, for example allowing a very expensive + * thresholding technique for servers and a fast one for mobile. It also permits the implementation + * to vary, e.g. a JNI version for Android and a Java fallback version for other platforms. + */ +@interface ZXBinarizer : NSObject + +@property (nonatomic, strong, readonly) ZXLuminanceSource *luminanceSource; +@property (nonatomic, assign, readonly) int width; +@property (nonatomic, assign, readonly) int height; + +- (id)initWithSource:(ZXLuminanceSource *)source; ++ (id)binarizerWithSource:(ZXLuminanceSource *)source; + +/** + * Converts one row of luminance data to 1 bit data. May actually do the conversion, or return + * cached data. Callers should assume this method is expensive and call it as seldom as possible. + * This method is intended for decoding 1D barcodes and may choose to apply sharpening. + * For callers which only examine one row of pixels at a time, the same BitArray should be reused + * and passed in with each call for performance. However it is legal to keep more than one row + * at a time if needed. + * + * @param y The row to fetch, 0 <= y < bitmap height. + * @param row An optional preallocated array. If null or too small, it will be ignored. + * If used, the Binarizer will call ZXBitArray clear. Always use the returned object. + * @return The array of bits for this row (true means black). + */ +- (ZXBitArray *)blackRow:(int)y row:(ZXBitArray *)row error:(NSError **)error; + +/** + * Converts a 2D array of luminance data to 1 bit data. As above, assume this method is expensive + * and do not call it repeatedly. This method is intended for decoding 2D barcodes and may or + * may not apply sharpening. Therefore, a row from this matrix may not be identical to one + * fetched using getBlackRow(), so don't mix and match between them. + * + * @return The 2D array of bits for the image (true means black). + */ +- (ZXBitMatrix *)blackMatrixWithError:(NSError **)error; + +/** + * Creates a new object with the same type as this Binarizer implementation, but with pristine + * state. This is needed because Binarizer implementations may be stateful, e.g. keeping a cache + * of 1 bit data. See Effective Java for why we can't use Java's clone() method. + * + * @param source The LuminanceSource this Binarizer will operate on. + * @return A new concrete Binarizer implementation object. + */ +- (ZXBinarizer *)createBinarizer:(ZXLuminanceSource *)source; + +- (CGImageRef)createImage CF_RETURNS_RETAINED; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/core/ZXBinarizer.m b/iDearQRCode/Tools/ZXingObjC/core/ZXBinarizer.m new file mode 100755 index 0000000..d87e551 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/core/ZXBinarizer.m @@ -0,0 +1,123 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBinarizer.h" + +#if TARGET_OS_EMBEDDED || TARGET_IPHONE_SIMULATOR +#import +#define ZXBlack [[UIColor blackColor] CGColor] +#define ZXWhite [[UIColor whiteColor] CGColor] +#else +#define ZXBlack CGColorGetConstantColor(kCGColorBlack) +#define ZXWhite CGColorGetConstantColor(kCGColorWhite) +#endif + +@implementation ZXBinarizer + +- (id)initWithSource:(ZXLuminanceSource *)source { + if (self = [super init]) { + _luminanceSource = source; + } + + return self; +} + +- (id)initWithLuminanceSource:(ZXLuminanceSource *)source { + return [self initWithSource:source]; +} + ++ (id)binarizerWithSource:(ZXLuminanceSource *)source { + return [[self alloc] initWithLuminanceSource:source]; +} + +- (ZXBitArray *)blackRow:(int)y row:(ZXBitArray *)row error:(NSError **)error { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)] + userInfo:nil]; +} + + +- (ZXBitMatrix *)blackMatrixWithError:(NSError **)error { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)] + userInfo:nil]; +} + +- (ZXBinarizer *)createBinarizer:(ZXLuminanceSource *)source { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)] + userInfo:nil]; +} + +- (CGImageRef)createImage CF_RETURNS_RETAINED { + ZXBitMatrix *matrix = [self blackMatrixWithError:nil]; + if (!matrix) { + return nil; + } + ZXLuminanceSource *source = [self luminanceSource]; + + int width = source.width; + int height = source.height; + + int bytesPerRow = ((width&0xf)>>4)<<4; + + CGColorSpaceRef gray = CGColorSpaceCreateDeviceGray(); + CGContextRef context = CGBitmapContextCreate ( + 0, + width, + height, + 8, // bits per component + bytesPerRow, + gray, + kCGBitmapAlphaInfoMask & kCGImageAlphaNone); + CGColorSpaceRelease(gray); + + CGRect r = CGRectZero; + r.size.width = width; + r.size.height = height; + CGContextSetFillColorWithColor(context, ZXBlack); + CGContextFillRect(context, r); + + r.size.width = 1; + r.size.height = 1; + + CGContextSetFillColorWithColor(context, ZXWhite); + for (int y=0; y + ++ (id)hints; + +/** + * Assume Code 39 codes employ a check digit. + */ +@property (nonatomic, assign) BOOL assumeCode39CheckDigit; + +/** + * Assume the barcode is being processed as a GS1 barcode, and modify behavior as needed. + * For example this affects FNC1 handling for Code 128 (aka GS1-128). + */ +@property (nonatomic, assign) BOOL assumeGS1; + +/** + * Allowed lengths of encoded data -- reject anything else. + */ +@property (nonatomic, strong) NSArray *allowedLengths; + +/** + * Specifies what character encoding to use when decoding, where applicable (type String) + */ +@property (nonatomic, assign) NSStringEncoding encoding; + +/** + * Unspecified, application-specific hint. + */ +@property (nonatomic, strong) id other; + +/** + * Image is a pure monochrome image of a barcode. + */ +@property (nonatomic, assign) BOOL pureBarcode; + +/** + * If true, return the start and end digits in a Codabar barcode instead of stripping them. They + * are alpha, whereas the rest are numeric. By default, they are stripped, but this causes them + * to not be. + */ +@property (nonatomic, assign) BOOL returnCodaBarStartEnd; + +/** + * The caller needs to be notified via callback when a possible ZXResultPoint + * is found. + */ +@property (nonatomic, strong) id resultPointCallback; + +/** + * Spend more time to try to find a barcode; optimize for accuracy, not speed. + */ +@property (nonatomic, assign) BOOL tryHarder; + +/** + * Allowed extension lengths for EAN or UPC barcodes. Other formats will ignore this. + * Maps to an ZXIntArray of the allowed extension lengths, for example [2], [5], or [2, 5]. + * If it is optional to have an extension, do not set this hint. If this is set, + * and a UPC or EAN barcode is found but an extension is not, then no result will be returned + * at all. + */ +@property (nonatomic, strong) ZXIntArray *allowedEANExtensions; + +/** + * Image is known to be of one of a few possible formats. + */ +- (void)addPossibleFormat:(ZXBarcodeFormat)format; +- (BOOL)containsFormat:(ZXBarcodeFormat)format; +- (int)numberOfPossibleFormats; +- (void)removePossibleFormat:(ZXBarcodeFormat)format; + +@end \ No newline at end of file diff --git a/iDearQRCode/Tools/ZXingObjC/core/ZXDecodeHints.m b/iDearQRCode/Tools/ZXingObjC/core/ZXDecodeHints.m new file mode 100755 index 0000000..2c1f5ca --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/core/ZXDecodeHints.m @@ -0,0 +1,77 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXDecodeHints.h" +#import "ZXResultPointCallback.h" + +@interface ZXDecodeHints () + +@property (nonatomic, strong, readonly) NSMutableArray *barcodeFormats; + +@end + +@implementation ZXDecodeHints + +- (id)init { + if (self = [super init]) { + _barcodeFormats = [NSMutableArray array]; + } + + return self; +} + ++ (id)hints { + return [[self alloc] init]; +} + +- (id)copyWithZone:(NSZone *)zone { + ZXDecodeHints *result = [[[self class] allocWithZone:zone] init]; + if (result) { + result.assumeCode39CheckDigit = self.assumeCode39CheckDigit; + result.allowedLengths = [self.allowedLengths copy]; + + for (NSNumber *formatNumber in self.barcodeFormats) { + [result addPossibleFormat:[formatNumber intValue]]; + } + + result.encoding = self.encoding; + result.other = self.other; + result.pureBarcode = self.pureBarcode; + result.returnCodaBarStartEnd = self.returnCodaBarStartEnd; + result.resultPointCallback = self.resultPointCallback; + result.tryHarder = self.tryHarder; + } + + return result; +} + +- (void)addPossibleFormat:(ZXBarcodeFormat)format { + [self.barcodeFormats addObject:[NSNumber numberWithInt:format]]; +} + +- (BOOL)containsFormat:(ZXBarcodeFormat)format { + return [self.barcodeFormats containsObject:[NSNumber numberWithInt:format]]; +} + +- (int)numberOfPossibleFormats { + return (int)self.barcodeFormats.count; +} + +- (void)removePossibleFormat:(ZXBarcodeFormat)format { + [self.barcodeFormats removeObject:[NSNumber numberWithInt:format]]; +} + +@end \ No newline at end of file diff --git a/iDearQRCode/Tools/ZXingObjC/core/ZXDimension.h b/iDearQRCode/Tools/ZXingObjC/core/ZXDimension.h new file mode 100755 index 0000000..8095847 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/core/ZXDimension.h @@ -0,0 +1,27 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Simply encapsulates a width and height. + */ +@interface ZXDimension : NSObject + +@property (nonatomic, assign, readonly) int height; +@property (nonatomic, assign, readonly) int width; + +- (id)initWithWidth:(int)width height:(int)height; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/core/ZXDimension.m b/iDearQRCode/Tools/ZXingObjC/core/ZXDimension.m new file mode 100755 index 0000000..3eed89a --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/core/ZXDimension.m @@ -0,0 +1,50 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXDimension.h" + +@implementation ZXDimension + +- (id)initWithWidth:(int)width height:(int)height { + if (width < 0 || height < 0) { + [NSException raise:NSInvalidArgumentException format:@"Width and height must not be negative"]; + } + + if (self = [super init]) { + _width = width; + _height = height; + } + + return self; +} + +- (BOOL)isEqual:(id)other { + if ([other isKindOfClass:[ZXDimension class]]) { + ZXDimension *d = (ZXDimension *)other; + return self.width == d.width && self.height == d.height; + } + return NO; +} + +- (NSUInteger)hash { + return self.width * 32713 + self.height; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"%dx%d", self.width, self.height]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/core/ZXEncodeHints.h b/iDearQRCode/Tools/ZXingObjC/core/ZXEncodeHints.h new file mode 100755 index 0000000..b3571eb --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/core/ZXEncodeHints.h @@ -0,0 +1,112 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Enumeration for DataMatrix symbol shape hint. It can be used to force square or rectangular + * symbols. + */ +typedef enum { + ZXDataMatrixSymbolShapeHintForceNone, + ZXDataMatrixSymbolShapeHintForceSquare, + ZXDataMatrixSymbolShapeHintForceRectangle +} ZXDataMatrixSymbolShapeHint; + +typedef enum { + ZXPDF417CompactionAuto, + ZXPDF417CompactionText, + ZXPDF417CompactionByte, + ZXPDF417CompactionNumeric +} ZXPDF417Compaction; + +@class ZXDimension, ZXPDF417Dimensions, ZXQRCodeErrorCorrectionLevel; + +/** + * These are a set of hints that you may pass to Writers to specify their behavior. + */ +@interface ZXEncodeHints : NSObject + ++ (id)hints; + +/** + * Specifies what character encoding to use where applicable. + */ +@property (nonatomic, assign) NSStringEncoding encoding; + +/** + * Specifies the matrix shape for Data Matrix. + */ +@property (nonatomic, assign) ZXDataMatrixSymbolShapeHint dataMatrixShape; + +/** + * Specifies a minimum barcode size. Only applicable to Data Matrix now. + * + * @deprecated use width/height params in + * ZXDataMatrixWriter encode:format:width:height:error: + */ +@property (nonatomic, strong) ZXDimension *minSize DEPRECATED_ATTRIBUTE; + +/** + * Specifies a maximum barcode size. Only applicable to Data Matrix now. + * + * @deprecated without replacement + */ +@property (nonatomic, strong) ZXDimension *maxSize DEPRECATED_ATTRIBUTE; + +/** + * Specifies what degree of error correction to use, for example in QR Codes. + * For Aztec it represents the minimal percentage of error correction words. + * Note: an Aztec symbol should have a minimum of 25% EC words. + */ +@property (nonatomic, strong) ZXQRCodeErrorCorrectionLevel *errorCorrectionLevel; + +/** + * Specifies what percent of error correction to use. + * For Aztec it represents the minimal percentage of error correction words. + * Note: an Aztec symbol should have a minimum of 25% EC words. + */ +@property (nonatomic, strong) NSNumber *errorCorrectionPercent; + +/** + * Specifies margin, in pixels, to use when generating the barcode. The meaning can vary + * by format; for example it controls margin before and after the barcode horizontally for + * most 1D formats. + */ +@property (nonatomic, strong) NSNumber *margin; + +/** + * Specifies whether to use compact mode for PDF417. + */ +@property (nonatomic, assign) BOOL pdf417Compact; + +/** + * Specifies what compaction mode to use for PDF417. + */ +@property (nonatomic, assign) ZXPDF417Compaction pdf417Compaction; + +/** + * Specifies the minimum and maximum number of rows and columns for PDF417. + */ +@property (nonatomic, strong) ZXPDF417Dimensions *pdf417Dimensions; + +/** + * Specifies the required number of layers for an Aztec code: + * a negative number (-1, -2, -3, -4) specifies a compact Aztec code + * 0 indicates to use the minimum number of layers (the default) + * a positive number (1, 2, .. 32) specifies a normaol (non-compact) Aztec code + */ +@property (nonatomic, strong) NSNumber *aztecLayers; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/core/ZXEncodeHints.m b/iDearQRCode/Tools/ZXingObjC/core/ZXEncodeHints.m new file mode 100755 index 0000000..539a3ce --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/core/ZXEncodeHints.m @@ -0,0 +1,25 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXEncodeHints.h" + +@implementation ZXEncodeHints + ++ (id)hints { + return [[self alloc] init]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/core/ZXErrors.h b/iDearQRCode/Tools/ZXingObjC/core/ZXErrors.h new file mode 100755 index 0000000..20e6e88 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/core/ZXErrors.h @@ -0,0 +1,61 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define ZXErrorDomain @"ZXErrorDomain" + +enum { + /** + * Thrown when a barcode was successfully detected and decoded, but + * was not returned because its checksum feature failed. + */ + ZXChecksumError = 1000, + + /** + * Thrown when a barcode was successfully detected, but some aspect of + * the content did not conform to the barcode's format rules. This could have + * been due to a mis-detection. + */ + ZXFormatError = 1001, + + /** + * Thrown when a barcode was not found in the image. It might have been + * partially detected but could not be confirmed. + */ + ZXNotFoundError = 1002, + + /** + * Thrown when an exception occurs during Reed-Solomon decoding, such as when + * there are too many errors to correct. + */ + ZXReedSolomonError = 1003, + + /** + * This general error is thrown when something goes wrong during decoding of a barcode. + * This includes, but is not limited to, failing checksums / error correction algorithms, being + * unable to locate finder timing patterns, and so on. + */ + ZXReaderError = 1004, + + /** + * Covers the range of error which may occur when encoding a barcode using the Writer framework. + */ + ZXWriterError = 1005 +}; + +// Helper methods for error instances +NSError *ZXChecksumErrorInstance(void); +NSError *ZXFormatErrorInstance(void); +NSError *ZXNotFoundErrorInstance(void); diff --git a/iDearQRCode/Tools/ZXingObjC/core/ZXErrors.m b/iDearQRCode/Tools/ZXingObjC/core/ZXErrors.m new file mode 100755 index 0000000..08730cf --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/core/ZXErrors.m @@ -0,0 +1,35 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXErrors.h" + +NSError *ZXChecksumErrorInstance() { + NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @"This barcode failed its checksum"}; + + return [[NSError alloc] initWithDomain:ZXErrorDomain code:ZXChecksumError userInfo:userInfo]; +} + +NSError *ZXFormatErrorInstance() { + NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @"This barcode does not confirm to the format's rules"}; + + return [[NSError alloc] initWithDomain:ZXErrorDomain code:ZXFormatError userInfo:userInfo]; +} + +NSError *ZXNotFoundErrorInstance() { + NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @"A barcode was not found in this image"}; + + return [[NSError alloc] initWithDomain:ZXErrorDomain code:ZXNotFoundError userInfo:userInfo]; +} diff --git a/iDearQRCode/Tools/ZXingObjC/core/ZXInvertedLuminanceSource.h b/iDearQRCode/Tools/ZXingObjC/core/ZXInvertedLuminanceSource.h new file mode 100755 index 0000000..7db6f2d --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/core/ZXInvertedLuminanceSource.h @@ -0,0 +1,27 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXLuminanceSource.h" + +/** + * A wrapper implementation of ZXLuminanceSource which inverts the luminances it returns -- black becomes + * white and vice versa, and each value becomes (255-value). + */ +@interface ZXInvertedLuminanceSource : ZXLuminanceSource + +- (id)initWithDelegate:(ZXLuminanceSource *)delegate; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/core/ZXInvertedLuminanceSource.m b/iDearQRCode/Tools/ZXingObjC/core/ZXInvertedLuminanceSource.m new file mode 100755 index 0000000..5265f87 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/core/ZXInvertedLuminanceSource.m @@ -0,0 +1,86 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXByteArray.h" +#import "ZXInvertedLuminanceSource.h" + +@interface ZXInvertedLuminanceSource () + +@property (nonatomic, weak, readonly) ZXLuminanceSource *delegate; + +@end + +@implementation ZXInvertedLuminanceSource + +- (id)initWithDelegate:(ZXLuminanceSource *)delegate { + self = [super initWithWidth:delegate.width height:delegate.height]; + if (self) { + _delegate = delegate; + } + + return self; +} + +- (ZXByteArray *)rowAtY:(int)y row:(ZXByteArray *)row { + row = [self.delegate rowAtY:y row:row]; + int width = self.width; + int8_t *rowArray = row.array; + for (int i = 0; i < width; i++) { + rowArray[i] = (int8_t) (255 - (rowArray[i] & 0xFF)); + } + return row; +} + +- (ZXByteArray *)matrix { + ZXByteArray *matrix = [self.delegate matrix]; + int length = self.width * self.height; + ZXByteArray *invertedMatrix = [[ZXByteArray alloc] initWithLength:length]; + int8_t *invertedMatrixArray = invertedMatrix.array; + int8_t *matrixArray = matrix.array; + for (int i = 0; i < length; i++) { + invertedMatrixArray[i] = (int8_t) (255 - (matrixArray[i] & 0xFF)); + } + return invertedMatrix; +} + +- (BOOL)cropSupported { + return self.delegate.cropSupported; +} + +- (ZXLuminanceSource *)crop:(int)left top:(int)top width:(int)aWidth height:(int)aHeight { + return [[ZXInvertedLuminanceSource alloc] initWithDelegate:[self.delegate crop:left top:top width:aWidth height:aHeight]]; +} + +- (BOOL)rotateSupported { + return self.delegate.rotateSupported; +} + +/** + * @return original delegate ZXLuminanceSource since invert undoes itself + */ +- (ZXLuminanceSource *)invert { + return self.delegate; +} + +- (ZXLuminanceSource *)rotateCounterClockwise { + return [[ZXInvertedLuminanceSource alloc] initWithDelegate:[self.delegate rotateCounterClockwise]]; +} + +- (ZXLuminanceSource *)rotateCounterClockwise45 { + return [[ZXInvertedLuminanceSource alloc] initWithDelegate:[self.delegate rotateCounterClockwise45]]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/core/ZXLuminanceSource.h b/iDearQRCode/Tools/ZXingObjC/core/ZXLuminanceSource.h new file mode 100755 index 0000000..d279afd --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/core/ZXLuminanceSource.h @@ -0,0 +1,108 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXByteArray; + +/** + * The purpose of this class hierarchy is to abstract different bitmap implementations across + * platforms into a standard interface for requesting greyscale luminance values. The interface + * only provides immutable methods; therefore crop and rotation create copies. This is to ensure + * that one Reader does not modify the original luminance source and leave it in an unknown state + * for other Readers in the chain. + */ +@interface ZXLuminanceSource : NSObject + +/** + * @return The width of the bitmap. + */ +@property (nonatomic, assign, readonly) int width; + +/** + * @return The height of the bitmap. + */ +@property (nonatomic, assign, readonly) int height; + +/** + * @return Whether this subclass supports cropping. + */ +@property (nonatomic, assign, readonly) BOOL cropSupported; + +/** + * @return Whether this subclass supports counter-clockwise rotation. + */ +@property (nonatomic, assign, readonly) BOOL rotateSupported; + +- (id)initWithWidth:(int)width height:(int)height; + +/** + * Fetches one row of luminance data from the underlying platform's bitmap. Values range from + * 0 (black) to 255 (white). Because Java does not have an unsigned byte type, callers will have + * to bitwise and with 0xff for each value. It is preferable for implementations of this method + * to only fetch this row rather than the whole image, since no 2D Readers may be installed and + * getMatrix() may never be called. + * + * @param y The row to fetch, 0 <= y < getHeight(). + * @param row An optional preallocated array. If null or too small, it will be ignored. + * Always use the returned object, and ignore the .length of the array. + * @return An array containing the luminance data. + */ +- (ZXByteArray *)rowAtY:(int)y row:(ZXByteArray *)row; + +/** + * Fetches luminance data for the underlying bitmap. Values should be fetched using: + * int luminance = array[y * width + x] & 0xff; + * + * @return A row-major 2D array of luminance values. Do not use result.length as it may be + * larger than width * height bytes on some platforms. Do not modify the contents + * of the result. + */ +- (ZXByteArray *)matrix; + +/** + * Returns a new object with cropped image data. Implementations may keep a reference to the + * original data rather than a copy. Only callable if isCropSupported() is true. + * + * @param left The left coordinate, 0 <= left < getWidth(). + * @param top The top coordinate, 0 <= top <= getHeight(). + * @param width The width of the rectangle to crop. + * @param height The height of the rectangle to crop. + * @return A cropped version of this object. + */ +- (ZXLuminanceSource *)crop:(int)left top:(int)top width:(int)width height:(int)height; + +/** + * @return a wrapper of this ZXLuminanceSource which inverts the luminances it returns -- black becomes + * white and vice versa, and each value becomes (255-value). + */ +- (ZXLuminanceSource *)invert; + +/** + * Returns a new object with rotated image data by 90 degrees counterclockwise. + * Only callable if isRotateSupported is true. + * + * @return A rotated version of this object. + */ +- (ZXLuminanceSource *)rotateCounterClockwise; + +/** + * Returns a new object with rotated image data by 45 degrees counterclockwise. + * Only callable if isRotateSupported is true. + * + * @return A rotated version of this object. + */ +- (ZXLuminanceSource *)rotateCounterClockwise45; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/core/ZXLuminanceSource.m b/iDearQRCode/Tools/ZXingObjC/core/ZXLuminanceSource.m new file mode 100755 index 0000000..6351d18 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/core/ZXLuminanceSource.m @@ -0,0 +1,92 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXByteArray.h" +#import "ZXInvertedLuminanceSource.h" +#import "ZXLuminanceSource.h" + +@implementation ZXLuminanceSource + +- (id)initWithWidth:(int)width height:(int)height { + if (self = [super init]) { + _width = width; + _height = height; + _cropSupported = NO; + _rotateSupported = NO; + } + + return self; +} + +- (ZXByteArray *)rowAtY:(int)y row:(ZXByteArray *)row { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)] + userInfo:nil]; +} + +- (ZXByteArray *)matrix { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)] + userInfo:nil]; +} + +- (ZXLuminanceSource *)crop:(int)left top:(int)top width:(int)width height:(int)height { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:@"This luminance source does not support cropping." + userInfo:nil]; +} + +- (ZXLuminanceSource *)invert { + return [[ZXInvertedLuminanceSource alloc] initWithDelegate:self]; +} + +- (ZXLuminanceSource *)rotateCounterClockwise { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:@"This luminance source does not support rotation by 90 degrees." + userInfo:nil]; +} + +- (ZXLuminanceSource *)rotateCounterClockwise45 { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:@"This luminance source does not support rotation by 45 degrees." + userInfo:nil]; +} + +- (NSString *)description { + ZXByteArray *row = [[ZXByteArray alloc] initWithLength:self.width]; + NSMutableString *result = [NSMutableString stringWithCapacity:self.height * (self.width + 1)]; + for (int y = 0; y < self.height; y++) { + row = [self rowAtY:y row:row]; + for (int x = 0; x < self.width; x++) { + int luminance = row.array[x] & 0xFF; + unichar c; + if (luminance < 0x40) { + c = '#'; + } else if (luminance < 0x80) { + c = '+'; + } else if (luminance < 0xC0) { + c = '.'; + } else { + c = ' '; + } + [result appendFormat:@"%C", c]; + } + [result appendString:@"\n"]; + } + return result; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/core/ZXPlanarYUVLuminanceSource.h b/iDearQRCode/Tools/ZXingObjC/core/ZXPlanarYUVLuminanceSource.h new file mode 100755 index 0000000..e11aa73 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/core/ZXPlanarYUVLuminanceSource.h @@ -0,0 +1,44 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXLuminanceSource.h" + +/** + * This object extends LuminanceSource around an array of YUV data returned from the camera driver, + * with the option to crop to a rectangle within the full data. This can be used to exclude + * superfluous pixels around the perimeter and speed up decoding. + * + * It works for any pixel format where the Y channel is planar and appears first, including + * YCbCr_420_SP and YCbCr_422_SP. + */ +@interface ZXPlanarYUVLuminanceSource : ZXLuminanceSource + +/** + * @return width of image from renderThumbnail + */ +@property (nonatomic, assign, readonly) int thumbnailWidth; + +/** + * @return height of image from renderThumbnail + */ +@property (nonatomic, assign, readonly) int thumbnailHeight; + +- (id)initWithYuvData:(int8_t *)yuvData yuvDataLen:(int)yuvDataLen dataWidth:(int)dataWidth + dataHeight:(int)dataHeight left:(int)left top:(int)top width:(int)width height:(int)height + reverseHorizontal:(BOOL)reverseHorizontal; +- (int32_t *)renderThumbnail; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/core/ZXPlanarYUVLuminanceSource.m b/iDearQRCode/Tools/ZXingObjC/core/ZXPlanarYUVLuminanceSource.m new file mode 100755 index 0000000..8d26033 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/core/ZXPlanarYUVLuminanceSource.m @@ -0,0 +1,147 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXByteArray.h" +#import "ZXPlanarYUVLuminanceSource.h" + +const int THUMBNAIL_SCALE_FACTOR = 2; + +@interface ZXPlanarYUVLuminanceSource () + +@property (nonatomic, strong, readonly) ZXByteArray *yuvData; +@property (nonatomic, assign, readonly) int dataWidth; +@property (nonatomic, assign, readonly) int dataHeight; +@property (nonatomic, assign, readonly) int left; +@property (nonatomic, assign, readonly) int top; + +@end + +@implementation ZXPlanarYUVLuminanceSource + +- (id)initWithYuvData:(int8_t *)yuvData yuvDataLen:(int)yuvDataLen dataWidth:(int)dataWidth + dataHeight:(int)dataHeight left:(int)left top:(int)top width:(int)width height:(int)height + reverseHorizontal:(BOOL)reverseHorizontal { + if (self = [super initWithWidth:width height:height]) { + if (left + width > dataWidth || top + height > dataHeight) { + [NSException raise:NSInvalidArgumentException format:@"Crop rectangle does not fit within image data."]; + } + + _yuvData = [[ZXByteArray alloc] initWithLength:yuvDataLen]; + memcpy(_yuvData.array, yuvData, yuvDataLen * sizeof(int8_t)); + _dataWidth = dataWidth; + _dataHeight = dataHeight; + _left = left; + _top = top; + + if (reverseHorizontal) { + [self reverseHorizontal:width height:height]; + } + } + + return self; +} + +- (ZXByteArray *)rowAtY:(int)y row:(ZXByteArray *)row { + if (y < 0 || y >= self.height) { + [NSException raise:NSInvalidArgumentException + format:@"Requested row is outside the image: %d", y]; + } + int width = self.width; + if (!row || row.length < width) { + row = [[ZXByteArray alloc] initWithLength:width]; + } + int offset = (y + self.top) * self.dataWidth + self.left; + memcpy(row.array, self.yuvData.array + offset, self.width * sizeof(int8_t)); + return row; +} + +- (ZXByteArray *)matrix { + int width = self.width; + int height = self.height; + + // If the caller asks for the entire underlying image, save the copy and give them the + // original data. The docs specifically warn that result.length must be ignored. + if (width == self.dataWidth && height == self.dataHeight) { + return self.yuvData; + } + + int area = self.width * self.height; + ZXByteArray *matrix = [[ZXByteArray alloc] initWithLength:area]; + int inputOffset = self.top * self.dataWidth + self.left; + + // If the width matches the full width of the underlying data, perform a single copy. + if (self.width == self.dataWidth) { + memcpy(matrix.array, self.yuvData.array + inputOffset, (area - inputOffset) * sizeof(int8_t)); + return matrix; + } + + // Otherwise copy one cropped row at a time. + ZXByteArray *yuvData = self.yuvData; + for (int y = 0; y < self.height; y++) { + int outputOffset = y * self.width; + memcpy(matrix.array + outputOffset, yuvData.array + inputOffset, self.width * sizeof(int8_t)); + inputOffset += self.dataWidth; + } + return matrix; +} + +- (BOOL)cropSupported { + return YES; +} + +- (ZXLuminanceSource *)crop:(int)left top:(int)top width:(int)width height:(int)height { + return [[[self class] alloc] initWithYuvData:self.yuvData.array yuvDataLen:self.yuvData.length dataWidth:self.dataWidth + dataHeight:self.dataHeight left:self.left + left top:self.top + top + width:width height:height reverseHorizontal:NO]; +} + +- (int *)renderThumbnail { + int thumbWidth = self.width / THUMBNAIL_SCALE_FACTOR; + int thumbHeight = self.height / THUMBNAIL_SCALE_FACTOR; + int *pixels = (int *)malloc(thumbWidth * thumbHeight * sizeof(int)); + int inputOffset = self.top * self.dataWidth + self.left; + + for (int y = 0; y < self.height; y++) { + int outputOffset = y * self.width; + for (int x = 0; x < self.width; x++) { + int grey = self.yuvData.array[inputOffset + x * THUMBNAIL_SCALE_FACTOR] & 0xff; + pixels[outputOffset + x] = 0xFF000000 | (grey * 0x00010101); + } + inputOffset += self.dataWidth * THUMBNAIL_SCALE_FACTOR; + } + return pixels; +} + +- (int)thumbnailWidth { + return self.width / THUMBNAIL_SCALE_FACTOR; +} + +- (int)thumbnailHeight { + return self.height / THUMBNAIL_SCALE_FACTOR; +} + +- (void)reverseHorizontal:(int)width height:(int)height { + for (int y = 0, rowStart = self.top * self.dataWidth + self.left; y < height; y++, rowStart += self.dataWidth) { + int middle = rowStart + width / 2; + for (int x1 = rowStart, x2 = rowStart + width - 1; x1 < middle; x1++, x2--) { + int8_t temp = self.yuvData.array[x1]; + self.yuvData.array[x1] = self.yuvData.array[x2]; + self.yuvData.array[x2] = temp; + } + } +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/core/ZXRGBLuminanceSource.h b/iDearQRCode/Tools/ZXingObjC/core/ZXRGBLuminanceSource.h new file mode 100755 index 0000000..3944cac --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/core/ZXRGBLuminanceSource.h @@ -0,0 +1,27 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXLuminanceSource.h" + +/** + * This class is used to help decode images from files which arrive as RGB data from + * an ARGB pixel array. It does not support rotation. + */ +@interface ZXRGBLuminanceSource : ZXLuminanceSource + +- (id)initWithWidth:(int)width height:(int)height pixels:(int32_t *)pixels pixelsLen:(int)pixelsLen; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/core/ZXRGBLuminanceSource.m b/iDearQRCode/Tools/ZXingObjC/core/ZXRGBLuminanceSource.m new file mode 100755 index 0000000..91aa197 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/core/ZXRGBLuminanceSource.m @@ -0,0 +1,136 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXByteArray.h" +#import "ZXRGBLuminanceSource.h" + +@interface ZXRGBLuminanceSource () + +@property (nonatomic, strong, readonly) ZXByteArray *luminances; +@property (nonatomic, assign, readonly) int dataWidth; +@property (nonatomic, assign, readonly) int dataHeight; +@property (nonatomic, assign, readonly) int left; +@property (nonatomic, assign, readonly) int top; + +@end + +@implementation ZXRGBLuminanceSource + +- (id)initWithWidth:(int)width height:(int)height pixels:(int *)pixels pixelsLen:(int)pixelsLen { + if (self = [super initWithWidth:width height:height]) { + _dataWidth = width; + _dataHeight = height; + _left = 0; + _top = 0; + + // In order to measure pure decoding speed, we convert the entire image to a greyscale array + // up front, which is the same as the Y channel of the YUVLuminanceSource in the real app. + _luminances = [[ZXByteArray alloc] initWithLength:width * height]; + for (int y = 0; y < height; y++) { + int offset = y * width; + for (int x = 0; x < width; x++) { + int pixel = pixels[offset + x]; + int r = (pixel >> 16) & 0xff; + int g = (pixel >> 8) & 0xff; + int b = pixel & 0xff; + if (r == g && g == b) { + // Image is already greyscale, so pick any channel. + _luminances.array[offset + x] = (int8_t) r; + } else { + // Calculate luminance cheaply, favoring green. + _luminances.array[offset + x] = (int8_t) ((r + g + g + b) / 4); + } + } + } + } + + return self; +} + +- (id)initWithPixels:(ZXByteArray *)pixels dataWidth:(int)dataWidth dataHeight:(int)dataHeight + left:(int)left top:(int)top width:(int)width height:(int)height { + if (self = [super initWithWidth:width height:height]) { + if (left + self.width > dataWidth || top + self.height > dataHeight) { + [NSException raise:NSInvalidArgumentException format:@"Crop rectangle does not fit within image data."]; + } + + _luminances = pixels; + _dataWidth = dataWidth; + _dataHeight = dataHeight; + _left = left; + _top = top; + } + + return self; +} + +- (ZXByteArray *)rowAtY:(int)y row:(ZXByteArray *)row { + if (y < 0 || y >= self.height) { + [NSException raise:NSInvalidArgumentException format:@"Requested row is outside the image: %d", y]; + } + int width = self.width; + if (!row || row.length < width) { + row = [[ZXByteArray alloc] initWithLength:width]; + } + int offset = (y + self.top) * self.dataWidth + self.left; + memcpy(row.array, self.luminances.array + offset, self.width * sizeof(int8_t)); + return row; +} + +- (ZXByteArray *)matrix { + int width = self.width; + int height = self.height; + + // If the caller asks for the entire underlying image, save the copy and give them the + // original data. The docs specifically warn that result.length must be ignored. + if (width == self.dataWidth && height == self.dataHeight) { + return self.luminances; + } + + int area = self.width * self.height; + ZXByteArray *matrix = [[ZXByteArray alloc] initWithLength:area]; + int inputOffset = self.top * self.dataWidth + self.left; + + // If the width matches the full width of the underlying data, perform a single copy. + if (self.width == self.dataWidth) { + memcpy(matrix.array, self.luminances.array + inputOffset, (area - inputOffset) * sizeof(int8_t)); + return matrix; + } + + // Otherwise copy one cropped row at a time. + for (int y = 0; y < self.height; y++) { + int outputOffset = y * self.width; + memcpy(matrix.array + outputOffset, self.luminances.array + inputOffset, self.width * sizeof(int8_t)); + inputOffset += self.dataWidth; + } + return matrix; +} + +- (BOOL)cropSupported { + return YES; +} + +- (ZXLuminanceSource *)crop:(int)left top:(int)top width:(int)width height:(int)height { + return [[[self class] alloc] initWithPixels:self.luminances + dataWidth:self.dataWidth + dataHeight:self.dataHeight + left:self.left + left + top:self.top + top + width:width + height:height]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/core/ZXReader.h b/iDearQRCode/Tools/ZXingObjC/core/ZXReader.h new file mode 100755 index 0000000..d1a5d86 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/core/ZXReader.h @@ -0,0 +1,59 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXBinaryBitmap, ZXDecodeHints, ZXResult; + +/** + * Implementations of this interface can decode an image of a barcode in some format into + * the String it encodes. For example, ZXQRCodeReader can + * decode a QR code. The decoder may optionally receive hints from the caller which may help + * it decode more quickly or accurately. + * + * See ZXMultiFormatReader, which attempts to determine what barcode + * format is present within the image as well, and then decodes it accordingly. + */ +@protocol ZXReader + +/** + * Locates and decodes a barcode in some format within an image. + * + * @param image image of barcode to decode + * @return String which the barcode encodes or nil if + * the barcode cannot be located or decoded for any reason + */ +- (ZXResult *)decode:(ZXBinaryBitmap *)image error:(NSError **)error; + +/** + * Locates and decodes a barcode in some format within an image. This method also accepts + * hints, each possibly associated to some data, which may help the implementation decode. + * + * @param image image of barcode to decode + * @param hints passed as a {@link java.util.Map} from {@link com.google.zxing.DecodeHintType} + * to arbitrary data. The + * meaning of the data depends upon the hint type. The implementation may or may not do + * anything with these hints. + * @return String which the barcode encodes or nil if + * the barcode cannot be located or decoded for any reason + */ +- (ZXResult *)decode:(ZXBinaryBitmap *)image hints:(ZXDecodeHints *)hints error:(NSError **)error; + +/** + * Resets any internal state the implementation has after a decode, to prepare it + * for reuse. + */ +- (void)reset; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/core/ZXResult.h b/iDearQRCode/Tools/ZXingObjC/core/ZXResult.h new file mode 100755 index 0000000..dab3e97 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/core/ZXResult.h @@ -0,0 +1,66 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBarcodeFormat.h" +#import "ZXResultMetadataType.h" + +@class ZXByteArray; + +/** + * Encapsulates the result of decoding a barcode within an image. + */ +@interface ZXResult : NSObject + +/** + * @return raw text encoded by the barcode + */ +@property (nonatomic, copy, readonly) NSString *text; + +/** + * @return raw bytes encoded by the barcode, if applicable, otherwise nil + */ +@property (nonatomic, strong, readonly) ZXByteArray *rawBytes; + +/** + * @return points related to the barcode in the image. These are typically points + * identifying finder patterns or the corners of the barcode. The exact meaning is + * specific to the type of barcode that was decoded. + */ +@property (nonatomic, strong, readonly) NSMutableArray *resultPoints; + +/** + * @return ZXBarcodeFormat representing the format of the barcode that was decoded + */ +@property (nonatomic, assign, readonly) ZXBarcodeFormat barcodeFormat; + +/** + * @return NSDictionary mapping ZXResultMetadataType keys to values. May be + * nil. This contains optional metadata about what was detected about the barcode, + * like orientation. + */ +@property (nonatomic, strong, readonly) NSMutableDictionary *resultMetadata; + +@property (nonatomic, assign, readonly) long timestamp; + +- (id)initWithText:(NSString *)text rawBytes:(ZXByteArray *)rawBytes resultPoints:(NSArray *)resultPoints format:(ZXBarcodeFormat)format; +- (id)initWithText:(NSString *)text rawBytes:(ZXByteArray *)rawBytes resultPoints:(NSArray *)resultPoints format:(ZXBarcodeFormat)format timestamp:(long)timestamp; ++ (id)resultWithText:(NSString *)text rawBytes:(ZXByteArray *)rawBytes resultPoints:(NSArray *)resultPoints format:(ZXBarcodeFormat)format; ++ (id)resultWithText:(NSString *)text rawBytes:(ZXByteArray *)rawBytes resultPoints:(NSArray *)resultPoints format:(ZXBarcodeFormat)format timestamp:(long)timestamp; +- (void)putMetadata:(ZXResultMetadataType)type value:(id)value; +- (void)putAllMetadata:(NSMutableDictionary *)metadata; +- (void)addResultPoints:(NSArray *)newPoints; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/core/ZXResult.m b/iDearQRCode/Tools/ZXingObjC/core/ZXResult.m new file mode 100755 index 0000000..c2ae7cf --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/core/ZXResult.m @@ -0,0 +1,82 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXResult.h" + +@interface ZXResult () + +@property (nonatomic, strong) NSMutableDictionary *resultMetadata; +@property (nonatomic, strong) NSMutableArray *resultPoints; + +@end + +@implementation ZXResult + +- (id)initWithText:(NSString *)text rawBytes:(ZXByteArray *)rawBytes resultPoints:(NSArray *)resultPoints format:(ZXBarcodeFormat)format { + return [self initWithText:text rawBytes:rawBytes resultPoints:resultPoints format:format timestamp:CFAbsoluteTimeGetCurrent()]; +} + +- (id)initWithText:(NSString *)text rawBytes:(ZXByteArray *)rawBytes resultPoints:(NSArray *)resultPoints format:(ZXBarcodeFormat)format timestamp:(long)timestamp { + if (self = [super init]) { + _text = text; + _rawBytes = rawBytes; + _resultPoints = [resultPoints mutableCopy]; + _barcodeFormat = format; + _resultMetadata = nil; + _timestamp = timestamp; + } + + return self; +} + ++ (id)resultWithText:(NSString *)text rawBytes:(ZXByteArray *)rawBytes resultPoints:(NSArray *)resultPoints format:(ZXBarcodeFormat)format { + return [[self alloc] initWithText:text rawBytes:rawBytes resultPoints:resultPoints format:format]; +} + ++ (id)resultWithText:(NSString *)text rawBytes:(ZXByteArray *)rawBytes resultPoints:(NSArray *)resultPoints format:(ZXBarcodeFormat)format timestamp:(long)timestamp { + return [[self alloc] initWithText:text rawBytes:rawBytes resultPoints:resultPoints format:format timestamp:timestamp]; +} + +- (void)putMetadata:(ZXResultMetadataType)type value:(id)value { + if (self.resultMetadata == nil) { + self.resultMetadata = [NSMutableDictionary dictionary]; + } + self.resultMetadata[@(type)] = value; +} + +- (void)putAllMetadata:(NSMutableDictionary *)metadata { + if (metadata != nil) { + if (self.resultMetadata == nil) { + self.resultMetadata = metadata; + } else { + [self.resultMetadata addEntriesFromDictionary:metadata]; + } + } +} + +- (void)addResultPoints:(NSArray *)newPoints { + if (self.resultPoints == nil) { + self.resultPoints = [newPoints mutableCopy]; + } else if (newPoints != nil && [newPoints count] > 0) { + [self.resultPoints addObjectsFromArray:newPoints]; + } +} + +- (NSString *)description { + return self.text; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/core/ZXResultMetadataType.h b/iDearQRCode/Tools/ZXingObjC/core/ZXResultMetadataType.h new file mode 100755 index 0000000..e466f02 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/core/ZXResultMetadataType.h @@ -0,0 +1,91 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Represents some type of metadata about the result of the decoding that the decoder + * wishes to communicate back to the caller. + */ +typedef enum { + /** + * Unspecified, application-specific metadata. Maps to an unspecified NSObject. + */ + kResultMetadataTypeOther, + + /** + * Denotes the likely approximate orientation of the barcode in the image. This value + * is given as degrees rotated clockwise from the normal, upright orientation. + * For example a 1D barcode which was found by reading top-to-bottom would be + * said to have orientation "90". This key maps to an integer whose + * value is in the range [0,360). + */ + kResultMetadataTypeOrientation, + + /** + * 2D barcode formats typically encode text, but allow for a sort of 'byte mode' + * which is sometimes used to encode binary data. While {@link Result} makes available + * the complete raw bytes in the barcode for these formats, it does not offer the bytes + * from the byte segments alone. + * + * This maps to an array of byte arrays corresponding to the + * raw bytes in the byte segments in the barcode, in order. + */ + kResultMetadataTypeByteSegments, + + /** + * Error correction level used, if applicable. The value type depends on the + * format, but is typically a String. + */ + kResultMetadataTypeErrorCorrectionLevel, + + /** + * For some periodicals, indicates the issue number as an integer. + */ + kResultMetadataTypeIssueNumber, + + /** + * For some products, indicates the suggested retail price in the barcode as a + * formatted NSString. + */ + kResultMetadataTypeSuggestedPrice, + + /** + * For some products, the possible country of manufacture as NSString denoting the + * ISO country code. Some map to multiple possible countries, like "US/CA". + */ + kResultMetadataTypePossibleCountry, + + /** + * For some products, the extension text + */ + kResultMetadataTypeUPCEANExtension, + + /** + * PDF417-specific metadata + */ + kResultMetadataTypePDF417ExtraMetadata, + + /** + * If the code format supports structured append and the current scanned code is part of one then the + * sequence number is given with it. + */ + kResultMetadataTypeStructuredAppendSequence, + + /** + * If the code format supports structured append and the current scanned code is part of one then the + * parity is given with it. + */ + kResultMetadataTypeStructuredAppendParity +} ZXResultMetadataType; diff --git a/iDearQRCode/Tools/ZXingObjC/core/ZXResultPoint.h b/iDearQRCode/Tools/ZXingObjC/core/ZXResultPoint.h new file mode 100755 index 0000000..8435c07 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/core/ZXResultPoint.h @@ -0,0 +1,41 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Encapsulates a point of interest in an image containing a barcode. Typically, this + * would be the location of a finder pattern or the corner of the barcode, for example. + */ +@interface ZXResultPoint : NSObject + +@property (nonatomic, assign, readonly) float x; +@property (nonatomic, assign, readonly) float y; + +- (id)initWithX:(float)x y:(float)y; + ++ (id)resultPointWithX:(float)x y:(float)y; + +/** + * Orders an array of three ResultPoints in an order [A,B,C] such that AB < AC and + * BC < AC and the angle between BC and BA is less than 180 degrees. + */ ++ (void)orderBestPatterns:(NSMutableArray *)patterns; + +/** + * @return distance between two points + */ ++ (float)distance:(ZXResultPoint *)pattern1 pattern2:(ZXResultPoint *)pattern2; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/core/ZXResultPoint.m b/iDearQRCode/Tools/ZXingObjC/core/ZXResultPoint.m new file mode 100755 index 0000000..038c41a --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/core/ZXResultPoint.m @@ -0,0 +1,99 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXMathUtils.h" +#import "ZXResultPoint.h" + +@implementation ZXResultPoint + +- (id)initWithX:(float)x y:(float)y { + if (self = [super init]) { + _x = x; + _y = y; + } + + return self; +} + ++ (id)resultPointWithX:(float)x y:(float)y { + return [[self alloc] initWithX:x y:y]; +} + +- (id)copyWithZone:(NSZone *)zone { + return [[ZXResultPoint allocWithZone:zone] initWithX:self.x y:self.y]; +} + +- (BOOL)isEqual:(id)other { + if ([other isKindOfClass:[ZXResultPoint class]]) { + ZXResultPoint *otherPoint = (ZXResultPoint *)other; + return self.x == otherPoint.x && self.y == otherPoint.y; + } + return NO; +} + +- (NSUInteger)hash { + return 31 * *((int *)(&_x)) + *((int *)(&_y)); +} + +- (NSString *)description { + return [NSString stringWithFormat:@"(%f,%f)", self.x, self.y]; +} + ++ (void)orderBestPatterns:(NSMutableArray *)patterns { + float zeroOneDistance = [self distance:patterns[0] pattern2:patterns[1]]; + float oneTwoDistance = [self distance:patterns[1] pattern2:patterns[2]]; + float zeroTwoDistance = [self distance:patterns[0] pattern2:patterns[2]]; + ZXResultPoint *pointA; + ZXResultPoint *pointB; + ZXResultPoint *pointC; + if (oneTwoDistance >= zeroOneDistance && oneTwoDistance >= zeroTwoDistance) { + pointB = patterns[0]; + pointA = patterns[1]; + pointC = patterns[2]; + } else if (zeroTwoDistance >= oneTwoDistance && zeroTwoDistance >= zeroOneDistance) { + pointB = patterns[1]; + pointA = patterns[0]; + pointC = patterns[2]; + } else { + pointB = patterns[2]; + pointA = patterns[0]; + pointC = patterns[1]; + } + + if ([self crossProductZ:pointA pointB:pointB pointC:pointC] < 0.0f) { + ZXResultPoint *temp = pointA; + pointA = pointC; + pointC = temp; + } + patterns[0] = pointA; + patterns[1] = pointB; + patterns[2] = pointC; +} + ++ (float)distance:(ZXResultPoint *)pattern1 pattern2:(ZXResultPoint *)pattern2 { + return [ZXMathUtils distance:pattern1.x aY:pattern1.y bX:pattern2.x bY:pattern2.y]; +} + +/** + * Returns the z component of the cross product between vectors BC and BA. + */ ++ (float)crossProductZ:(ZXResultPoint *)pointA pointB:(ZXResultPoint *)pointB pointC:(ZXResultPoint *)pointC { + float bX = pointB.x; + float bY = pointB.y; + return ((pointC.x - bX) * (pointA.y - bY)) - ((pointC.y - bY) * (pointA.x - bX)); +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/core/ZXResultPointCallback.h b/iDearQRCode/Tools/ZXingObjC/core/ZXResultPointCallback.h new file mode 100755 index 0000000..1755e0e --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/core/ZXResultPointCallback.h @@ -0,0 +1,27 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXResultPoint; + +/** + * Callback which is invoked when a possible result point (significant + * point in the barcode image such as a corner) is found. + */ +@protocol ZXResultPointCallback + +- (void)foundPossibleResultPoint:(ZXResultPoint *)point; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/core/ZXWriter.h b/iDearQRCode/Tools/ZXingObjC/core/ZXWriter.h new file mode 100755 index 0000000..a46850d --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/core/ZXWriter.h @@ -0,0 +1,46 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBarcodeFormat.h" + +@class ZXBitMatrix, ZXEncodeHints; + +/** + * The base class for all objects which encode/generate a barcode image. + */ +@protocol ZXWriter + +/** + * Encode a barcode using the default settings. + * + * @param contents The contents to encode in the barcode + * @param format The barcode format to generate + * @param width The preferred width in pixels + * @param height The preferred height in pixels + */ +- (ZXBitMatrix *)encode:(NSString *)contents format:(ZXBarcodeFormat)format width:(int)width height:(int)height error:(NSError **)error; + +/** + * + * @param contents The contents to encode in the barcode + * @param format The barcode format to generate + * @param width The preferred width in pixels + * @param height The preferred height in pixels + * @param hints Additional parameters to supply to the encoder + */ +- (ZXBitMatrix *)encode:(NSString *)contents format:(ZXBarcodeFormat)format width:(int)width height:(int)height hints:(ZXEncodeHints *)hints error:(NSError **)error; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/core/ZXingObjCCore.h b/iDearQRCode/Tools/ZXingObjC/core/ZXingObjCCore.h new file mode 100755 index 0000000..7253b03 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/core/ZXingObjCCore.h @@ -0,0 +1,77 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _ZXINGOBJC_CORE_ + +#define _ZXINGOBJC_CORE_ + +// Client +#import "ZXCapture.h" +#import "ZXCaptureDelegate.h" +#import "ZXCGImageLuminanceSource.h" +#import "ZXImage.h" + +// Common +#import "ZXBitArray.h" +#import "ZXBitMatrix.h" +#import "ZXBitSource.h" +#import "ZXBoolArray.h" +#import "ZXByteArray.h" +#import "ZXCharacterSetECI.h" +#import "ZXDecoderResult.h" +#import "ZXDefaultGridSampler.h" +#import "ZXDetectorResult.h" +#import "ZXGenericGF.h" +#import "ZXGlobalHistogramBinarizer.h" +#import "ZXGridSampler.h" +#import "ZXHybridBinarizer.h" +#import "ZXIntArray.h" +#import "ZXMathUtils.h" +#import "ZXMonochromeRectangleDetector.h" +#import "ZXPerspectiveTransform.h" +#import "ZXReedSolomonDecoder.h" +#import "ZXReedSolomonEncoder.h" +#import "ZXStringUtils.h" +#import "ZXWhiteRectangleDetector.h" + +// Core +#import "ZXBarcodeFormat.h" +#import "ZXBinarizer.h" +#import "ZXBinaryBitmap.h" +#import "ZXByteMatrix.h" +#import "ZXDecodeHints.h" +#import "ZXDimension.h" +#import "ZXEncodeHints.h" +#import "ZXErrors.h" +#import "ZXInvertedLuminanceSource.h" +#import "ZXLuminanceSource.h" +#import "ZXPlanarYUVLuminanceSource.h" +#import "ZXReader.h" +#import "ZXResult.h" +#import "ZXResultMetadataType.h" +#import "ZXResultPoint.h" +#import "ZXResultPointCallback.h" +#import "ZXRGBLuminanceSource.h" +#import "ZXWriter.h" + +// Multi +#import "ZXByQuadrantReader.h" +#import "ZXGenericMultipleBarcodeReader.h" +#import "ZXMultiDetector.h" +#import "ZXMultipleBarcodeReader.h" +#import "ZXQRCodeMultiReader.h" + +#endif diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/ZXDataMatrixReader.h b/iDearQRCode/Tools/ZXingObjC/datamatrix/ZXDataMatrixReader.h new file mode 100755 index 0000000..7c15883 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/ZXDataMatrixReader.h @@ -0,0 +1,26 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXReader.h" + +@class ZXBinaryBitmap, ZXDecodeHints, ZXResult; + +/** + * This implementation can detect and decode Data Matrix codes in an image. + */ +@interface ZXDataMatrixReader : NSObject + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/ZXDataMatrixReader.m b/iDearQRCode/Tools/ZXingObjC/datamatrix/ZXDataMatrixReader.m new file mode 100755 index 0000000..08f4ddc --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/ZXDataMatrixReader.m @@ -0,0 +1,173 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBinaryBitmap.h" +#import "ZXBitMatrix.h" +#import "ZXDataMatrixDecoder.h" +#import "ZXDataMatrixDetector.h" +#import "ZXDataMatrixReader.h" +#import "ZXDecodeHints.h" +#import "ZXDecoderResult.h" +#import "ZXDetectorResult.h" +#import "ZXErrors.h" +#import "ZXIntArray.h" +#import "ZXResult.h" + +@interface ZXDataMatrixReader () + +@property (nonatomic, strong, readonly) ZXDataMatrixDecoder *decoder; + +@end + +@implementation ZXDataMatrixReader + +- (id)init { + if (self = [super init]) { + _decoder = [[ZXDataMatrixDecoder alloc] init]; + } + + return self; +} + +/** + * Locates and decodes a Data Matrix code in an image. + * + * @return a String representing the content encoded by the Data Matrix code + */ +- (ZXResult *)decode:(ZXBinaryBitmap *)image error:(NSError **)error { + return [self decode:image hints:nil error:error]; +} + +- (ZXResult *)decode:(ZXBinaryBitmap *)image hints:(ZXDecodeHints *)hints error:(NSError **)error { + ZXDecoderResult *decoderResult; + NSArray *points; + if (hints != nil && hints.pureBarcode) { + ZXBitMatrix *matrix = [image blackMatrixWithError:error]; + if (!matrix) { + return nil; + } + ZXBitMatrix *bits = [self extractPureBits:matrix]; + if (!bits) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + decoderResult = [self.decoder decodeMatrix:bits error:error]; + if (!decoderResult) { + return nil; + } + points = @[]; + } else { + ZXBitMatrix *matrix = [image blackMatrixWithError:error]; + if (!matrix) { + return nil; + } + ZXDataMatrixDetector *detector = [[ZXDataMatrixDetector alloc] initWithImage:matrix error:error]; + if (!detector) { + return nil; + } + ZXDetectorResult *detectorResult = [detector detectWithError:error]; + if (!detectorResult) { + return nil; + } + decoderResult = [self.decoder decodeMatrix:detectorResult.bits error:error]; + if (!decoderResult) { + return nil; + } + points = detectorResult.points; + } + ZXResult *result = [ZXResult resultWithText:decoderResult.text + rawBytes:decoderResult.rawBytes + resultPoints:points + format:kBarcodeFormatDataMatrix]; + if (decoderResult.byteSegments != nil) { + [result putMetadata:kResultMetadataTypeByteSegments value:decoderResult.byteSegments]; + } + if (decoderResult.ecLevel != nil) { + [result putMetadata:kResultMetadataTypeErrorCorrectionLevel value:decoderResult.ecLevel]; + } + return result; +} + +- (void)reset { + // do nothing +} + + +/** + * This method detects a code in a "pure" image -- that is, pure monochrome image + * which contains only an unrotated, unskewed, image of a code, with some white border + * around it. This is a specialized method that works exceptionally fast in this special + * case. + */ +- (ZXBitMatrix *)extractPureBits:(ZXBitMatrix *)image { + ZXIntArray *leftTopBlack = image.topLeftOnBit; + ZXIntArray *rightBottomBlack = image.bottomRightOnBit; + if (leftTopBlack == nil || rightBottomBlack == nil) { + return nil; + } + + int moduleSize = [self moduleSize:leftTopBlack image:image]; + if (moduleSize == -1) { + return nil; + } + + int top = leftTopBlack.array[1]; + int bottom = rightBottomBlack.array[1]; + int left = leftTopBlack.array[0]; + int right = rightBottomBlack.array[0]; + + int matrixWidth = (right - left + 1) / moduleSize; + int matrixHeight = (bottom - top + 1) / moduleSize; + if (matrixWidth <= 0 || matrixHeight <= 0) { + return nil; + } + + int nudge = moduleSize / 2; + top += nudge; + left += nudge; + + ZXBitMatrix *bits = [[ZXBitMatrix alloc] initWithWidth:matrixWidth height:matrixHeight]; + for (int y = 0; y < matrixHeight; y++) { + int iOffset = top + y * moduleSize; + for (int x = 0; x < matrixWidth; x++) { + if ([image getX:left + x * moduleSize y:iOffset]) { + [bits setX:x y:y]; + } + } + } + + return bits; +} + +- (int)moduleSize:(ZXIntArray *)leftTopBlack image:(ZXBitMatrix *)image { + int width = image.width; + int x = leftTopBlack.array[0]; + int y = leftTopBlack.array[1]; + while (x < width && [image getX:x y:y]) { + x++; + } + if (x == width) { + return -1; + } + + int moduleSize = x - leftTopBlack.array[0]; + if (moduleSize == 0) { + return -1; + } + return moduleSize; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/ZXDataMatrixWriter.h b/iDearQRCode/Tools/ZXingObjC/datamatrix/ZXDataMatrixWriter.h new file mode 100755 index 0000000..2b7387d --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/ZXDataMatrixWriter.h @@ -0,0 +1,24 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXWriter.h" + +/** + * This object renders a Data Matrix code as a BitMatrix 2D array of greyscale values. + */ +@interface ZXDataMatrixWriter : NSObject + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/ZXDataMatrixWriter.m b/iDearQRCode/Tools/ZXingObjC/datamatrix/ZXDataMatrixWriter.m new file mode 100755 index 0000000..63f9bb4 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/ZXDataMatrixWriter.m @@ -0,0 +1,169 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitMatrix.h" +#import "ZXByteMatrix.h" +#import "ZXDataMatrixDefaultPlacement.h" +#import "ZXDataMatrixErrorCorrection.h" +#import "ZXDataMatrixHighLevelEncoder.h" +#import "ZXDataMatrixSymbolInfo.h" +#import "ZXDataMatrixWriter.h" +#import "ZXDimension.h" +#import "ZXEncodeHints.h" + +@implementation ZXDataMatrixWriter + +- (ZXBitMatrix *)encode:(NSString *)contents format:(ZXBarcodeFormat)format width:(int)width height:(int)height error:(NSError **)error { + return [self encode:contents format:format width:width height:height hints:nil error:error]; +} + +- (ZXBitMatrix *)encode:(NSString *)contents format:(ZXBarcodeFormat)format width:(int)width height:(int)height hints:(ZXEncodeHints *)hints error:(NSError **)error { + if (contents.length == 0) { + [NSException raise:NSInvalidArgumentException format:@"Found empty contents"]; + } + + if (format != kBarcodeFormatDataMatrix) { + [NSException raise:NSInvalidArgumentException format:@"Can only encode kBarcodeFormatDataMatrix"]; + } + + if (width < 0 || height < 0) { + [NSException raise:NSInvalidArgumentException + format:@"Requested dimensions are too small: %dx%d", width, height]; + } + + // Try to get force shape & min / max size + ZXDataMatrixSymbolShapeHint shape = ZXDataMatrixSymbolShapeHintForceNone; + ZXDimension *minSize = [[ZXDimension alloc] initWithWidth:width height:height]; + ZXDimension *maxSize = nil; + if (hints != nil) { + shape = hints.dataMatrixShape; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + ZXDimension *requestedMinSize = hints.minSize; +#pragma GCC diagnostic pop + if (requestedMinSize != nil) { + minSize = requestedMinSize; + } +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" + ZXDimension *requestedMaxSize = hints.maxSize; +#pragma GCC diagnostic pop + if (requestedMaxSize != nil) { + maxSize = requestedMaxSize; + } + } + + //1. step: Data encodation + NSString *encoded = [ZXDataMatrixHighLevelEncoder encodeHighLevel:contents shape:shape minSize:minSize maxSize:maxSize]; + + ZXDataMatrixSymbolInfo *symbolInfo = [ZXDataMatrixSymbolInfo lookup:(int)encoded.length shape:shape minSize:minSize maxSize:maxSize fail:YES]; + + //2. step: ECC generation + NSString *codewords = [ZXDataMatrixErrorCorrection encodeECC200:encoded symbolInfo:symbolInfo]; + + //3. step: Module placement in Matrix + ZXDataMatrixDefaultPlacement *placement = [[ZXDataMatrixDefaultPlacement alloc] initWithCodewords:codewords numcols:symbolInfo.symbolDataWidth numrows:symbolInfo.symbolDataHeight]; + [placement place]; + + //4. step: low-level encoding + return [self encodeLowLevel:placement symbolInfo:symbolInfo width:width height:height]; +} + +/** + * Encode the given symbol info to a bit matrix. + * + * @param placement The DataMatrix placement. + * @param symbolInfo The symbol info to encode. + * @return The bit matrix generated. + */ +- (ZXBitMatrix *)encodeLowLevel:(ZXDataMatrixDefaultPlacement *)placement symbolInfo:(ZXDataMatrixSymbolInfo *)symbolInfo width:(int)width height:(int)height { + int symbolWidth = symbolInfo.symbolDataWidth; + int symbolHeight = symbolInfo.symbolDataHeight; + + ZXByteMatrix *matrix = [[ZXByteMatrix alloc] initWithWidth:symbolInfo.symbolWidth height:symbolInfo.symbolHeight]; + + int matrixY = 0; + + for (int y = 0; y < symbolHeight; y++) { + // Fill the top edge with alternate 0 / 1 + int matrixX; + if ((y % symbolInfo.matrixHeight) == 0) { + matrixX = 0; + for (int x = 0; x < symbolInfo.symbolWidth; x++) { + [matrix setX:matrixX y:matrixY boolValue:(x % 2) == 0]; + matrixX++; + } + matrixY++; + } + matrixX = 0; + for (int x = 0; x < symbolWidth; x++) { + // Fill the right edge with full 1 + if ((x % symbolInfo.matrixWidth) == 0) { + [matrix setX:matrixX y:matrixY boolValue:YES]; + matrixX++; + } + [matrix setX:matrixX y:matrixY boolValue:[placement bitAtCol:x row:y]]; + matrixX++; + // Fill the right edge with alternate 0 / 1 + if ((x % symbolInfo.matrixWidth) == symbolInfo.matrixWidth - 1) { + [matrix setX:matrixX y:matrixY boolValue:(y % 2) == 0]; + matrixX++; + } + } + matrixY++; + // Fill the bottom edge with full 1 + if ((y % symbolInfo.matrixHeight) == symbolInfo.matrixHeight - 1) { + matrixX = 0; + for (int x = 0; x < symbolInfo.symbolWidth; x++) { + [matrix setX:matrixX y:matrixY boolValue:YES]; + matrixX++; + } + matrixY++; + } + } + + return [self convertByteMatrixToBitMatrix:matrix width:width height:height]; +} + +/** + * Convert the ZXByteMatrix to ZXBitMatrix. + * + * @param matrix The input matrix. + * @return The output matrix. + */ +- (ZXBitMatrix *)convertByteMatrixToBitMatrix:(ZXByteMatrix *)input width:(int)width height:(int)height { + int inputWidth = input.width; + int inputHeight = input.height; + int outputWidth = MAX(width, inputWidth); + int outputHeight = MAX(height, inputHeight); + + int multiple = MIN(outputWidth / inputWidth, outputHeight / inputHeight); + int leftPadding = (outputWidth - (inputWidth * multiple)) / 2; + int topPadding = (outputHeight - (inputHeight * multiple)) / 2; + + ZXBitMatrix *output = [[ZXBitMatrix alloc] initWithWidth:outputWidth height:outputHeight]; + + for (int inputY = 0, outputY = topPadding; inputY < inputHeight; inputY++, outputY += multiple) { + for (int inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX += multiple) { + if ([input getX:inputX y:inputY] == 1) { + [output setRegionAtLeft:outputX top:outputY width:multiple height:multiple]; + } + } + } + return output; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/ZXingObjCDataMatrix.h b/iDearQRCode/Tools/ZXingObjC/datamatrix/ZXingObjCDataMatrix.h new file mode 100755 index 0000000..39bbd4b --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/ZXingObjCDataMatrix.h @@ -0,0 +1,31 @@ +/* + * Copyright 2014 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _ZXINGOBJC_DATAMATRIX_ + +#define _ZXINGOBJC_DATAMATRIX_ + +#import "ZXDataMatrixDecoder.h" +#import "ZXDataMatrixDefaultPlacement.h" +#import "ZXDataMatrixDetector.h" +#import "ZXDataMatrixErrorCorrection.h" +#import "ZXDataMatrixHighLevelEncoder.h" +#import "ZXDataMatrixReader.h" +#import "ZXDataMatrixSymbolInfo.h" +#import "ZXDataMatrixVersion.h" +#import "ZXDataMatrixWriter.h" + +#endif diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/decoder/ZXDataMatrixBitMatrixParser.h b/iDearQRCode/Tools/ZXingObjC/datamatrix/decoder/ZXDataMatrixBitMatrixParser.h new file mode 100755 index 0000000..b8f1757 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/decoder/ZXDataMatrixBitMatrixParser.h @@ -0,0 +1,38 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXBitMatrix, ZXByteArray, ZXDataMatrixVersion; + +@interface ZXDataMatrixBitMatrixParser : NSObject + +@property (nonatomic, strong, readonly) ZXDataMatrixVersion *version; + +/** + * @param bitMatrix ZXBitMatrix to parse + * @return nil if dimension is < 8 or > 144 or not 0 mod 2 + */ +- (id)initWithBitMatrix:(ZXBitMatrix *)bitMatrix error:(NSError **)error; + +/** + * Reads the bits in the ZXBitMatrix representing the mapping matrix (No alignment patterns) + * in the correct order in order to reconstitute the codewords bytes contained within the + * Data Matrix Code. + * + * @return bytes encoded within the Data Matrix Code or nil if the exact number of bytes expected is not read + */ +- (ZXByteArray *)readCodewords; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/decoder/ZXDataMatrixBitMatrixParser.m b/iDearQRCode/Tools/ZXingObjC/datamatrix/decoder/ZXDataMatrixBitMatrixParser.m new file mode 100755 index 0000000..af4e921 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/decoder/ZXDataMatrixBitMatrixParser.m @@ -0,0 +1,429 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitMatrix.h" +#import "ZXByteArray.h" +#import "ZXDataMatrixBitMatrixParser.h" +#import "ZXDataMatrixVersion.h" +#import "ZXErrors.h" + +@interface ZXDataMatrixBitMatrixParser () + +@property (nonatomic, strong, readonly) ZXBitMatrix *mappingBitMatrix; +@property (nonatomic, strong, readonly) ZXBitMatrix *readMappingMatrix; + +@end + +@implementation ZXDataMatrixBitMatrixParser + +- (id)initWithBitMatrix:(ZXBitMatrix *)bitMatrix error:(NSError **)error { + if (self = [super init]) { + int dimension = bitMatrix.height; + if (dimension < 8 || dimension > 144 || (dimension & 0x01) != 0) { + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + _version = [self readVersion:bitMatrix]; + if (!_version) { + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + _mappingBitMatrix = [self extractDataRegion:bitMatrix]; + _readMappingMatrix = [[ZXBitMatrix alloc] initWithWidth:_mappingBitMatrix.width + height:_mappingBitMatrix.height]; + } + + return self; +} + +/** + * Creates the version object based on the dimension of the original bit matrix from + * the datamatrix code. + * + * See ISO 16022:2006 Table 7 - ECC 200 symbol attributes< + * + * @param bitMatrix Original ZXBitMatrix including alignment patterns + * @return ZXDatamatrixVersion encapsulating the Data Matrix Code's "version" + * or nil if the dimensions of the mapping matrix are not valid + * Data Matrix dimensions. + */ +- (ZXDataMatrixVersion *)readVersion:(ZXBitMatrix *)bitMatrix { + int numRows = bitMatrix.height; + int numColumns = bitMatrix.width; + return [ZXDataMatrixVersion versionForDimensions:numRows numColumns:numColumns]; +} + +- (ZXByteArray *)readCodewords { + ZXByteArray *result = [[ZXByteArray alloc] initWithLength:self.version.totalCodewords]; + int resultOffset = 0; + + int row = 4; + int column = 0; + + int numRows = self.mappingBitMatrix.height; + int numColumns = self.mappingBitMatrix.width; + + BOOL corner1Read = NO; + BOOL corner2Read = NO; + BOOL corner3Read = NO; + BOOL corner4Read = NO; + + do { + if ((row == numRows) && (column == 0) && !corner1Read) { + result.array[resultOffset++] = (int8_t) [self readCorner1:numRows numColumns:numColumns]; + row -= 2; + column += 2; + corner1Read = YES; + } else if ((row == numRows - 2) && (column == 0) && ((numColumns & 0x03) != 0) && !corner2Read) { + result.array[resultOffset++] = (int8_t) [self readCorner2:numRows numColumns:numColumns]; + row -= 2; + column += 2; + corner2Read = YES; + } else if ((row == numRows + 4) && (column == 2) && ((numColumns & 0x07) == 0) && !corner3Read) { + result.array[resultOffset++] = (int8_t) [self readCorner3:numRows numColumns:numColumns]; + row -= 2; + column += 2; + corner3Read = YES; + } else if ((row == numRows - 2) && (column == 0) && ((numColumns & 0x07) == 4) && !corner4Read) { + result.array[resultOffset++] = (int8_t) [self readCorner4:numRows numColumns:numColumns]; + row -= 2; + column += 2; + corner4Read = YES; + } else { + do { + if ((row < numRows) && (column >= 0) && ![self.readMappingMatrix getX:column y:row]) { + result.array[resultOffset++] = (int8_t) [self readUtah:row column:column numRows:numRows numColumns:numColumns]; + } + row -= 2; + column += 2; + } while ((row >= 0) && (column < numColumns)); + row += 1; + column += 3; + + do { + if ((row >= 0) && (column < numColumns) && ![self.readMappingMatrix getX:column y:row]) { + result.array[resultOffset++] = (int8_t) [self readUtah:row column:column numRows:numRows numColumns:numColumns]; + } + row += 2; + column -= 2; + } while ((row < numRows) && (column >= 0)); + row += 3; + column += 1; + } + } while ((row < numRows) || (column < numColumns)); + + if (resultOffset != self.version.totalCodewords) { + return nil; + } + return result; +} + +/** + * Reads a bit of the mapping matrix accounting for boundary wrapping. + * + * @param row Row to read in the mapping matrix + * @param column Column to read in the mapping matrix + * @param numRows Number of rows in the mapping matrix + * @param numColumns Number of columns in the mapping matrix + * @return value of the given bit in the mapping matrix + */ +- (BOOL)readModule:(int)row column:(int)column numRows:(int)numRows numColumns:(int)numColumns { + if (row < 0) { + row += numRows; + column += 4 - ((numRows + 4) & 0x07); + } + if (column < 0) { + column += numColumns; + row += 4 - ((numColumns + 4) & 0x07); + } + [self.readMappingMatrix setX:column y:row]; + return [self.mappingBitMatrix getX:column y:row]; +} + +/** + * Reads the 8 bits of the standard Utah-shaped pattern. + * + * See ISO 16022:2006, 5.8.1 Figure 6 + * + * @param row Current row in the mapping matrix, anchored at the 8th bit (LSB) of the pattern + * @param column Current column in the mapping matrix, anchored at the 8th bit (LSB) of the pattern + * @param numRows Number of rows in the mapping matrix + * @param numColumns Number of columns in the mapping matrix + * @return byte from the utah shape + */ +- (int)readUtah:(int)row column:(int)column numRows:(int)numRows numColumns:(int)numColumns { + int currentByte = 0; + if ([self readModule:row - 2 column:column - 2 numRows:numRows numColumns:numColumns]) { + currentByte |= 1; + } + currentByte <<= 1; + if ([self readModule:row - 2 column:column - 1 numRows:numRows numColumns:numColumns]) { + currentByte |= 1; + } + currentByte <<= 1; + if ([self readModule:row - 1 column:column - 2 numRows:numRows numColumns:numColumns]) { + currentByte |= 1; + } + currentByte <<= 1; + if ([self readModule:row - 1 column:column - 1 numRows:numRows numColumns:numColumns]) { + currentByte |= 1; + } + currentByte <<= 1; + if ([self readModule:row - 1 column:column numRows:numRows numColumns:numColumns]) { + currentByte |= 1; + } + currentByte <<= 1; + if ([self readModule:row column:column - 2 numRows:numRows numColumns:numColumns]) { + currentByte |= 1; + } + currentByte <<= 1; + if ([self readModule:row column:column - 1 numRows:numRows numColumns:numColumns]) { + currentByte |= 1; + } + currentByte <<= 1; + if ([self readModule:row column:column numRows:numRows numColumns:numColumns]) { + currentByte |= 1; + } + return currentByte; +} + +/** + * Reads the 8 bits of the special corner condition 1. + * + * See ISO 16022:2006, Figure F.3 + * + * @param numRows Number of rows in the mapping matrix + * @param numColumns Number of columns in the mapping matrix + * @return byte from the Corner condition 1 + */ +- (int)readCorner1:(int)numRows numColumns:(int)numColumns { + int currentByte = 0; + if ([self readModule:numRows - 1 column:0 numRows:numRows numColumns:numColumns]) { + currentByte |= 1; + } + currentByte <<= 1; + if ([self readModule:numRows - 1 column:1 numRows:numRows numColumns:numColumns]) { + currentByte |= 1; + } + currentByte <<= 1; + if ([self readModule:numRows - 1 column:2 numRows:numRows numColumns:numColumns]) { + currentByte |= 1; + } + currentByte <<= 1; + if ([self readModule:0 column:numColumns - 2 numRows:numRows numColumns:numColumns]) { + currentByte |= 1; + } + currentByte <<= 1; + if ([self readModule:0 column:numColumns - 1 numRows:numRows numColumns:numColumns]) { + currentByte |= 1; + } + currentByte <<= 1; + if ([self readModule:1 column:numColumns - 1 numRows:numRows numColumns:numColumns]) { + currentByte |= 1; + } + currentByte <<= 1; + if ([self readModule:2 column:numColumns - 1 numRows:numRows numColumns:numColumns]) { + currentByte |= 1; + } + currentByte <<= 1; + if ([self readModule:3 column:numColumns - 1 numRows:numRows numColumns:numColumns]) { + currentByte |= 1; + } + return currentByte; +} + +/** + * Reads the 8 bits of the special corner condition 2. + * + * See ISO 16022:2006, Figure F.4 + * + * @param numRows Number of rows in the mapping matrix + * @param numColumns Number of columns in the mapping matrix + * @return byte from the Corner condition 2 + */ +- (int)readCorner2:(int)numRows numColumns:(int)numColumns { + int currentByte = 0; + if ([self readModule:numRows - 3 column:0 numRows:numRows numColumns:numColumns]) { + currentByte |= 1; + } + currentByte <<= 1; + if ([self readModule:numRows - 2 column:0 numRows:numRows numColumns:numColumns]) { + currentByte |= 1; + } + currentByte <<= 1; + if ([self readModule:numRows - 1 column:0 numRows:numRows numColumns:numColumns]) { + currentByte |= 1; + } + currentByte <<= 1; + if ([self readModule:0 column:numColumns - 4 numRows:numRows numColumns:numColumns]) { + currentByte |= 1; + } + currentByte <<= 1; + if ([self readModule:0 column:numColumns - 3 numRows:numRows numColumns:numColumns]) { + currentByte |= 1; + } + currentByte <<= 1; + if ([self readModule:0 column:numColumns - 2 numRows:numRows numColumns:numColumns]) { + currentByte |= 1; + } + currentByte <<= 1; + if ([self readModule:0 column:numColumns - 1 numRows:numRows numColumns:numColumns]) { + currentByte |= 1; + } + currentByte <<= 1; + if ([self readModule:1 column:numColumns - 1 numRows:numRows numColumns:numColumns]) { + currentByte |= 1; + } + return currentByte; +} + +/** + * Reads the 8 bits of the special corner condition 3. + * + * See ISO 16022:2006, Figure F.5 + * + * @param numRows Number of rows in the mapping matrix + * @param numColumns Number of columns in the mapping matrix + * @return byte from the Corner condition 3 + */ +- (int)readCorner3:(int)numRows numColumns:(int)numColumns { + int currentByte = 0; + if ([self readModule:numRows - 1 column:0 numRows:numRows numColumns:numColumns]) { + currentByte |= 1; + } + currentByte <<= 1; + if ([self readModule:numRows - 1 column:numColumns - 1 numRows:numRows numColumns:numColumns]) { + currentByte |= 1; + } + currentByte <<= 1; + if ([self readModule:0 column:numColumns - 3 numRows:numRows numColumns:numColumns]) { + currentByte |= 1; + } + currentByte <<= 1; + if ([self readModule:0 column:numColumns - 2 numRows:numRows numColumns:numColumns]) { + currentByte |= 1; + } + currentByte <<= 1; + if ([self readModule:0 column:numColumns - 1 numRows:numRows numColumns:numColumns]) { + currentByte |= 1; + } + currentByte <<= 1; + if ([self readModule:1 column:numColumns - 3 numRows:numRows numColumns:numColumns]) { + currentByte |= 1; + } + currentByte <<= 1; + if ([self readModule:1 column:numColumns - 2 numRows:numRows numColumns:numColumns]) { + currentByte |= 1; + } + currentByte <<= 1; + if ([self readModule:1 column:numColumns - 1 numRows:numRows numColumns:numColumns]) { + currentByte |= 1; + } + return currentByte; +} + +/** + * Reads the 8 bits of the special corner condition 4. + * + * See ISO 16022:2006, Figure F.6 + * + * @param numRows Number of rows in the mapping matrix + * @param numColumns Number of columns in the mapping matrix + * @return byte from the Corner condition 4 + */ +- (int)readCorner4:(int)numRows numColumns:(int)numColumns { + int currentByte = 0; + if ([self readModule:numRows - 3 column:0 numRows:numRows numColumns:numColumns]) { + currentByte |= 1; + } + currentByte <<= 1; + if ([self readModule:numRows - 2 column:0 numRows:numRows numColumns:numColumns]) { + currentByte |= 1; + } + currentByte <<= 1; + if ([self readModule:numRows - 1 column:0 numRows:numRows numColumns:numColumns]) { + currentByte |= 1; + } + currentByte <<= 1; + if ([self readModule:0 column:numColumns - 2 numRows:numRows numColumns:numColumns]) { + currentByte |= 1; + } + currentByte <<= 1; + if ([self readModule:0 column:numColumns - 1 numRows:numRows numColumns:numColumns]) { + currentByte |= 1; + } + currentByte <<= 1; + if ([self readModule:1 column:numColumns - 1 numRows:numRows numColumns:numColumns]) { + currentByte |= 1; + } + currentByte <<= 1; + if ([self readModule:2 column:numColumns - 1 numRows:numRows numColumns:numColumns]) { + currentByte |= 1; + } + currentByte <<= 1; + if ([self readModule:3 column:numColumns - 1 numRows:numRows numColumns:numColumns]) { + currentByte |= 1; + } + return currentByte; +} + +/** + * Extracts the data region from a ZXBitMatrix that contains + * alignment patterns. + * + * @param bitMatrix Original ZXBitMatrix with alignment patterns + * @return BitMatrix that has the alignment patterns removed + */ +- (ZXBitMatrix *)extractDataRegion:(ZXBitMatrix *)bitMatrix { + int symbolSizeRows = self.version.symbolSizeRows; + int symbolSizeColumns = self.version.symbolSizeColumns; + + if (bitMatrix.height != symbolSizeRows) { + [NSException raise:NSInvalidArgumentException format:@"Dimension of bitMatrix must match the version size"]; + } + + int dataRegionSizeRows = self.version.dataRegionSizeRows; + int dataRegionSizeColumns = self.version.dataRegionSizeColumns; + + int numDataRegionsRow = symbolSizeRows / dataRegionSizeRows; + int numDataRegionsColumn = symbolSizeColumns / dataRegionSizeColumns; + + int sizeDataRegionRow = numDataRegionsRow * dataRegionSizeRows; + int sizeDataRegionColumn = numDataRegionsColumn * dataRegionSizeColumns; + + ZXBitMatrix *bitMatrixWithoutAlignment = [[ZXBitMatrix alloc] initWithWidth:sizeDataRegionColumn height:sizeDataRegionRow]; + for (int dataRegionRow = 0; dataRegionRow < numDataRegionsRow; ++dataRegionRow) { + int dataRegionRowOffset = dataRegionRow * dataRegionSizeRows; + for (int dataRegionColumn = 0; dataRegionColumn < numDataRegionsColumn; ++dataRegionColumn) { + int dataRegionColumnOffset = dataRegionColumn * dataRegionSizeColumns; + for (int i = 0; i < dataRegionSizeRows; ++i) { + int readRowOffset = dataRegionRow * (dataRegionSizeRows + 2) + 1 + i; + int writeRowOffset = dataRegionRowOffset + i; + for (int j = 0; j < dataRegionSizeColumns; ++j) { + int readColumnOffset = dataRegionColumn * (dataRegionSizeColumns + 2) + 1 + j; + if ([bitMatrix getX:readColumnOffset y:readRowOffset]) { + int writeColumnOffset = dataRegionColumnOffset + j; + [bitMatrixWithoutAlignment setX:writeColumnOffset y:writeRowOffset]; + } + } + } + } + } + + return bitMatrixWithoutAlignment; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/decoder/ZXDataMatrixDataBlock.h b/iDearQRCode/Tools/ZXingObjC/datamatrix/decoder/ZXDataMatrixDataBlock.h new file mode 100755 index 0000000..3894233 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/decoder/ZXDataMatrixDataBlock.h @@ -0,0 +1,41 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXByteArray, ZXDataMatrixVersion; + +/** + * Encapsulates a block of data within a Data Matrix Code. Data Matrix Codes may split their data into + * multiple blocks, each of which is a unit of data and error-correction codewords. Each + * is represented by an instance of this class. + */ +@interface ZXDataMatrixDataBlock : NSObject + +@property (nonatomic, assign, readonly) int numDataCodewords; +@property (nonatomic, strong, readonly) ZXByteArray *codewords; + +/** + * When Data Matrix Codes use multiple data blocks, they actually interleave the bytes of each of them. + * That is, the first byte of data block 1 to n is written, then the second bytes, and so on. This + * method will separate the data into original blocks. + * + * @param rawCodewords bytes as read directly from the Data Matrix Code + * @param version version of the Data Matrix Code + * @return DataBlocks containing original bytes, "de-interleaved" from representation in the + * Data Matrix Code + */ ++ (NSArray *)dataBlocks:(ZXByteArray *)rawCodewords version:(ZXDataMatrixVersion *)version; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/decoder/ZXDataMatrixDataBlock.m b/iDearQRCode/Tools/ZXingObjC/datamatrix/decoder/ZXDataMatrixDataBlock.m new file mode 100755 index 0000000..b26fcf3 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/decoder/ZXDataMatrixDataBlock.m @@ -0,0 +1,92 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXByteArray.h" +#import "ZXDataMatrixDataBlock.h" +#import "ZXDataMatrixVersion.h" + +@implementation ZXDataMatrixDataBlock + +- (id)initWithNumDataCodewords:(int)numDataCodewords codewords:(ZXByteArray *)codewords { + if (self = [super init]) { + _numDataCodewords = numDataCodewords; + _codewords = codewords; + } + + return self; +} + ++ (NSArray *)dataBlocks:(ZXByteArray *)rawCodewords version:(ZXDataMatrixVersion *)version { + // Figure out the number and size of data blocks used by this version + ZXDataMatrixECBlocks *ecBlocks = version.ecBlocks; + + // First count the total number of data blocks + int totalBlocks = 0; + NSArray *ecBlockArray = ecBlocks.ecBlocks; + for (ZXDataMatrixECB *ecBlock in ecBlockArray) { + totalBlocks += ecBlock.count; + } + + // Now establish DataBlocks of the appropriate size and number of data codewords + NSMutableArray *result = [NSMutableArray arrayWithCapacity:totalBlocks]; + for (ZXDataMatrixECB *ecBlock in ecBlockArray) { + for (int i = 0; i < ecBlock.count; i++) { + int numDataCodewords = ecBlock.dataCodewords; + int numBlockCodewords = ecBlocks.ecCodewords + numDataCodewords; + [result addObject:[[ZXDataMatrixDataBlock alloc] initWithNumDataCodewords:numDataCodewords codewords:[[ZXByteArray alloc] initWithLength:numBlockCodewords]]]; + } + } + + // All blocks have the same amount of data, except that the last n + // (where n may be 0) have 1 less byte. Figure out where these start. + // TODO(bbrown): There is only one case where there is a difference for Data Matrix for size 144 + int longerBlocksTotalCodewords = [[(ZXDataMatrixDataBlock *)result[0] codewords] length]; + //int shorterBlocksTotalCodewords = longerBlocksTotalCodewords - 1; + + int longerBlocksNumDataCodewords = longerBlocksTotalCodewords - ecBlocks.ecCodewords; + int shorterBlocksNumDataCodewords = longerBlocksNumDataCodewords - 1; + // The last elements of result may be 1 element shorter for 144 matrix + // first fill out as many elements as all of them have minus 1 + int rawCodewordsOffset = 0; + for (int i = 0; i < shorterBlocksNumDataCodewords; i++) { + for (ZXDataMatrixDataBlock *block in result) { + block.codewords.array[i] = rawCodewords.array[rawCodewordsOffset++]; + } + } + + // Fill out the last data block in the longer ones + BOOL specialVersion = version.versionNumber == 24; + int numLongerBlocks = specialVersion ? 8 : (int)[result count]; + for (int j = 0; j < numLongerBlocks; j++) { + [(ZXDataMatrixDataBlock *)result[j] codewords].array[longerBlocksNumDataCodewords - 1] = rawCodewords.array[rawCodewordsOffset++]; + } + + NSUInteger max = [(ZXDataMatrixDataBlock *)result[0] codewords].length; + for (int i = longerBlocksNumDataCodewords; i < max; i++) { + for (int j = 0; j < [result count]; j++) { + int jOffset = specialVersion ? (j + 8) % [result count] : j; + int iOffset = specialVersion && jOffset > 7 ? i - 1 : i; + [(ZXDataMatrixDataBlock *)result[jOffset] codewords].array[iOffset] = rawCodewords.array[rawCodewordsOffset++]; + } + } + + if (rawCodewordsOffset != rawCodewords.length) { + [NSException raise:NSInvalidArgumentException format:@"Codewords size mismatch"]; + } + return result; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/decoder/ZXDataMatrixDecodedBitStreamParser.h b/iDearQRCode/Tools/ZXingObjC/datamatrix/decoder/ZXDataMatrixDecodedBitStreamParser.h new file mode 100755 index 0000000..115f313 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/decoder/ZXDataMatrixDecodedBitStreamParser.h @@ -0,0 +1,29 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXByteArray, ZXDecoderResult; + +/** + * Data Matrix Codes can encode text as bits in one of several modes, and can use multiple modes + * in one Data Matrix Code. This class decodes the bits back into text. + * + * See ISO 16022:2006, 5.2.1 - 5.2.9.2 + */ +@interface ZXDataMatrixDecodedBitStreamParser : NSObject + ++ (ZXDecoderResult *)decode:(ZXByteArray *)bytes error:(NSError **)error; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/decoder/ZXDataMatrixDecodedBitStreamParser.m b/iDearQRCode/Tools/ZXingObjC/datamatrix/decoder/ZXDataMatrixDecodedBitStreamParser.m new file mode 100755 index 0000000..7c7de50 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/decoder/ZXDataMatrixDecodedBitStreamParser.m @@ -0,0 +1,497 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitSource.h" +#import "ZXByteArray.h" +#import "ZXDataMatrixDecodedBitStreamParser.h" +#import "ZXDecoderResult.h" +#import "ZXErrors.h" + +/** + * See ISO 16022:2006, Annex C Table C.1 + * The C40 Basic Character Set (*'s used for placeholders for the shift values) + */ +const unichar C40_BASIC_SET_CHARS[40] = { + '*', '*', '*', ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', + 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' +}; + +const unichar C40_SHIFT2_SET_CHARS[40] = { + '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', + '/', ':', ';', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_' +}; + +/** + * See ISO 16022:2006, Annex C Table C.2 + * The Text Basic Character Set (*'s used for placeholders for the shift values) + */ +const unichar TEXT_BASIC_SET_CHARS[40] = { + '*', '*', '*', ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' +}; + +// Shift 2 for Text is the same encoding as C40 +static unichar TEXT_SHIFT2_SET_CHARS[40]; + +const unichar TEXT_SHIFT3_SET_CHARS[32] = { + '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', + 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '{', '|', '}', '~', (unichar) 127 +}; + +enum { + PAD_ENCODE = 0, // Not really a mode + ASCII_ENCODE, + C40_ENCODE, + TEXT_ENCODE, + ANSIX12_ENCODE, + EDIFACT_ENCODE, + BASE256_ENCODE +}; + +@implementation ZXDataMatrixDecodedBitStreamParser + ++ (void)initialize { + if ([self class] != [ZXDataMatrixDecodedBitStreamParser class]) return; + + memcpy(TEXT_SHIFT2_SET_CHARS, C40_SHIFT2_SET_CHARS, sizeof(C40_SHIFT2_SET_CHARS)); +} + ++ (ZXDecoderResult *)decode:(ZXByteArray *)bytes error:(NSError **)error { + ZXBitSource *bits = [[ZXBitSource alloc] initWithBytes:bytes]; + NSMutableString *result = [NSMutableString stringWithCapacity:100]; + NSMutableString *resultTrailer = [NSMutableString string]; + NSMutableArray *byteSegments = [NSMutableArray arrayWithCapacity:1]; + int mode = ASCII_ENCODE; + do { + if (mode == ASCII_ENCODE) { + mode = [self decodeAsciiSegment:bits result:result resultTrailer:resultTrailer]; + if (mode == -1) { + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + } else { + switch (mode) { + case C40_ENCODE: + if (![self decodeC40Segment:bits result:result]) { + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + break; + case TEXT_ENCODE: + if (![self decodeTextSegment:bits result:result]) { + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + break; + case ANSIX12_ENCODE: + if (![self decodeAnsiX12Segment:bits result:result]) { + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + break; + case EDIFACT_ENCODE: + [self decodeEdifactSegment:bits result:result]; + break; + case BASE256_ENCODE: + if (![self decodeBase256Segment:bits result:result byteSegments:byteSegments]) { + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + break; + default: + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + mode = ASCII_ENCODE; + } + } while (mode != PAD_ENCODE && bits.available > 0); + if ([resultTrailer length] > 0) { + [result appendString:resultTrailer]; + } + return [[ZXDecoderResult alloc] initWithRawBytes:bytes + text:result + byteSegments:[byteSegments count] == 0 ? nil : byteSegments + ecLevel:nil]; +} + +/** + * See ISO 16022:2006, 5.2.3 and Annex C, Table C.2 + */ ++ (int)decodeAsciiSegment:(ZXBitSource *)bits result:(NSMutableString *)result resultTrailer:(NSMutableString *)resultTrailer { + BOOL upperShift = NO; + do { + int oneByte = [bits readBits:8]; + if (oneByte == 0) { + return -1; + } else if (oneByte <= 128) { // ASCII data (ASCII value + 1) + if (upperShift) { + oneByte += 128; + //upperShift = NO; + } + [result appendFormat:@"%C", (unichar)(oneByte - 1)]; + return ASCII_ENCODE; + } else if (oneByte == 129) { // Pad + return PAD_ENCODE; + } else if (oneByte <= 229) { // 2-digit data 00-99 (Numeric Value + 130) + int value = oneByte - 130; + if (value < 10) { // pad with '0' for single digit values + [result appendString:@"0"]; + } + [result appendFormat:@"%d", value]; + } else if (oneByte == 230) { // Latch to C40 encodation + return C40_ENCODE; + } else if (oneByte == 231) { // Latch to Base 256 encodation + return BASE256_ENCODE; + } else if (oneByte == 232) { + // FNC1 + [result appendFormat:@"%C", (unichar)29]; // translate as ASCII 29 + } else if (oneByte == 233 || oneByte == 234) { + // Structured Append, Reader Programming + // Ignore these symbols for now + //return -1; + } else if (oneByte == 235) { // Upper Shift (shift to Extended ASCII) + upperShift = YES; + } else if (oneByte == 236) { // 05 Macro + [result appendFormat:@"[)>%C%C", (unichar)0x001E05, (unichar)0x001D]; + [resultTrailer insertString:[NSString stringWithFormat:@"%C%C", (unichar)0x001E, (unichar)0x0004] atIndex:0]; + } else if (oneByte == 237) { // 06 Macro + [result appendFormat:@"[)>%C%C", (unichar)0x001E06, (unichar)0x001D]; + [resultTrailer insertString:[NSString stringWithFormat:@"%C%C", (unichar)0x001E, (unichar)0x0004] atIndex:0]; + } else if (oneByte == 238) { // Latch to ANSI X12 encodation + return ANSIX12_ENCODE; + } else if (oneByte == 239) { // Latch to Text encodation + return TEXT_ENCODE; + } else if (oneByte == 240) { // Latch to EDIFACT encodation + return EDIFACT_ENCODE; + } else if (oneByte == 241) { // ECI Character + // TODO(bbrown): I think we need to support ECI + // Ignore this symbol for now + } else if (oneByte >= 242) { // Not to be used in ASCII encodation + // ... but work around encoders that end with 254, latch back to ASCII + if (oneByte != 254 || bits.available != 0) { + return -1; + } + } + } while (bits.available > 0); + return ASCII_ENCODE; +} + +/** + * See ISO 16022:2006, 5.2.5 and Annex C, Table C.1 + */ ++ (BOOL)decodeC40Segment:(ZXBitSource *)bits result:(NSMutableString *)result { + // Three C40 values are encoded in a 16-bit value as + // (1600 * C1) + (40 * C2) + C3 + 1 + // TODO(bbrown): The Upper Shift with C40 doesn't work in the 4 value scenario all the time + BOOL upperShift = NO; + + int cValues[3] = {0}; + int shift = 0; + + do { + // If there is only one byte left then it will be encoded as ASCII + if ([bits available] == 8) { + return YES; + } + int firstByte = [bits readBits:8]; + if (firstByte == 254) { // Unlatch codeword + return YES; + } + + [self parseTwoBytes:firstByte secondByte:[bits readBits:8] result:cValues]; + + for (int i = 0; i < 3; i++) { + int cValue = cValues[i]; + switch (shift) { + case 0: + if (cValue < 3) { + shift = cValue + 1; + } else if (cValue < sizeof(C40_BASIC_SET_CHARS) / sizeof(char)) { + unichar c40char = C40_BASIC_SET_CHARS[cValue]; + if (upperShift) { + [result appendFormat:@"%C", (unichar)(c40char + 128)]; + upperShift = NO; + } else { + [result appendFormat:@"%C", c40char]; + } + } else { + return NO; + } + break; + case 1: + if (upperShift) { + [result appendFormat:@"%C", (unichar)(cValue + 128)]; + upperShift = NO; + } else { + [result appendFormat:@"%C", (unichar)cValue]; + } + shift = 0; + break; + case 2: + if (cValue < sizeof(C40_SHIFT2_SET_CHARS) / sizeof(char)) { + unichar c40char = C40_SHIFT2_SET_CHARS[cValue]; + if (upperShift) { + [result appendFormat:@"%C", (unichar)(c40char + 128)]; + upperShift = NO; + } else { + [result appendFormat:@"%C", c40char]; + } + } else if (cValue == 27) { // FNC1 + [result appendFormat:@"%C", (unichar)29]; // translate as ASCII 29 + } else if (cValue == 30) { // Upper Shift + upperShift = YES; + } else { + return NO; + } + shift = 0; + break; + case 3: + if (upperShift) { + [result appendFormat:@"%C", (unichar)(cValue + 224)]; + upperShift = NO; + } else { + [result appendFormat:@"%C", (unichar)(cValue + 96)]; + } + shift = 0; + break; + default: + return NO; + } + } + } while (bits.available > 0); + + return YES; +} + +/** + * See ISO 16022:2006, 5.2.6 and Annex C, Table C.2 + */ ++ (BOOL)decodeTextSegment:(ZXBitSource *)bits result:(NSMutableString *)result { + // Three Text values are encoded in a 16-bit value as + // (1600 * C1) + (40 * C2) + C3 + 1 + // TODO(bbrown): The Upper Shift with Text doesn't work in the 4 value scenario all the time + BOOL upperShift = NO; + + int cValues[3] = {0}; + + int shift = 0; + do { + // If there is only one byte left then it will be encoded as ASCII + if (bits.available == 8) { + return YES; + } + int firstByte = [bits readBits:8]; + if (firstByte == 254) { // Unlatch codeword + return YES; + } + + [self parseTwoBytes:firstByte secondByte:[bits readBits:8] result:cValues]; + + for (int i = 0; i < 3; i++) { + int cValue = cValues[i]; + switch (shift) { + case 0: + if (cValue < 3) { + shift = cValue + 1; + } else if (cValue < sizeof(TEXT_BASIC_SET_CHARS) / sizeof(char)) { + unichar textChar = TEXT_BASIC_SET_CHARS[cValue]; + if (upperShift) { + [result appendFormat:@"%C", (unichar)(textChar + 128)]; + upperShift = NO; + } else { + [result appendFormat:@"%C", textChar]; + } + } else { + return NO; + } + break; + case 1: + if (upperShift) { + [result appendFormat:@"%C", (unichar)(cValue + 128)]; + upperShift = NO; + } else { + [result appendFormat:@"%C", (unichar)cValue]; + } + shift = 0; + break; + case 2: + // Shift 2 for Text is the same encoding as C40 + if (cValue < sizeof(TEXT_SHIFT2_SET_CHARS) / sizeof(unichar)) { + unichar textChar = TEXT_SHIFT2_SET_CHARS[cValue]; + if (upperShift) { + [result appendFormat:@"%C", (unichar)(textChar + 128)]; + upperShift = NO; + } else { + [result appendFormat:@"%C", textChar]; + } + } else if (cValue == 27) { + [result appendFormat:@"%C", (unichar)29]; // translate as ASCII 29 + } else if (cValue == 30) { // Upper Shift + upperShift = YES; + } else { + return NO; + } + shift = 0; + break; + case 3: + if (cValue < sizeof(TEXT_SHIFT3_SET_CHARS) / sizeof(char)) { + unichar textChar = TEXT_SHIFT3_SET_CHARS[cValue]; + if (upperShift) { + [result appendFormat:@"%C", (unichar)(textChar + 128)]; + upperShift = NO; + } else { + [result appendFormat:@"%C", textChar]; + } + shift = 0; + } else { + return NO; + } + break; + default: + return NO; + } + } + } while (bits.available > 0); + return YES; +} + +/** + * See ISO 16022:2006, 5.2.7 + */ ++ (BOOL)decodeAnsiX12Segment:(ZXBitSource *)bits result:(NSMutableString *)result { + // Three ANSI X12 values are encoded in a 16-bit value as + // (1600 * C1) + (40 * C2) + C3 + 1 + + int cValues[3] = {0}; + do { + // If there is only one byte left then it will be encoded as ASCII + if (bits.available == 8) { + return YES; + } + int firstByte = [bits readBits:8]; + if (firstByte == 254) { // Unlatch codeword + return YES; + } + + [self parseTwoBytes:firstByte secondByte:[bits readBits:8] result:cValues]; + + for (int i = 0; i < 3; i++) { + int cValue = cValues[i]; + if (cValue == 0) { // X12 segment terminator + [result appendString:@"\r"]; + } else if (cValue == 1) { // X12 segment separator * + [result appendString:@"*"]; + } else if (cValue == 2) { // X12 sub-element separator > + [result appendString:@">"]; + } else if (cValue == 3) { // space + [result appendString:@" "]; + } else if (cValue < 14) { // 0 - 9 + [result appendFormat:@"%C", (unichar)(cValue + 44)]; + } else if (cValue < 40) { // A - Z + [result appendFormat:@"%C", (unichar)(cValue + 51)]; + } else { + return NO; + } + } + } while (bits.available > 0); + return YES; +} + ++ (void)parseTwoBytes:(int)firstByte secondByte:(int)secondByte result:(int[])result { + int fullBitValue = (firstByte << 8) + secondByte - 1; + int temp = fullBitValue / 1600; + result[0] = temp; + fullBitValue -= temp * 1600; + temp = fullBitValue / 40; + result[1] = temp; + result[2] = fullBitValue - temp * 40; +} + +/** + * See ISO 16022:2006, 5.2.8 and Annex C Table C.3 + */ ++ (void)decodeEdifactSegment:(ZXBitSource *)bits result:(NSMutableString *)result { + do { + // If there is only two or less bytes left then it will be encoded as ASCII + if (bits.available <= 16) { + return; + } + + for (int i = 0; i < 4; i++) { + int edifactValue = [bits readBits:6]; + + // Check for the unlatch character + if (edifactValue == 0x1F) { // 011111 + // Read rest of byte, which should be 0, and stop + int bitsLeft = 8 - bits.bitOffset; + if (bitsLeft != 8) { + [bits readBits:bitsLeft]; + } + return; + } + + if ((edifactValue & 0x20) == 0) { // no 1 in the leading (6th) bit + edifactValue |= 0x40; // Add a leading 01 to the 6 bit binary value + } + [result appendFormat:@"%c", (char)edifactValue]; + } + } while (bits.available > 0); +} + +/** + * See ISO 16022:2006, 5.2.9 and Annex B, B.2 + */ ++ (BOOL)decodeBase256Segment:(ZXBitSource *)bits result:(NSMutableString *)result byteSegments:(NSMutableArray *)byteSegments { + int codewordPosition = 1 + bits.byteOffset; // position is 1-indexed + int d1 = [self unrandomize255State:[bits readBits:8] base256CodewordPosition:codewordPosition++]; + int count; + if (d1 == 0) { + count = [bits available] / 8; + } else if (d1 < 250) { + count = d1; + } else { + count = 250 * (d1 - 249) + [self unrandomize255State:[bits readBits:8] base256CodewordPosition:codewordPosition++]; + } + + if (count < 0) { + return NO; + } + + ZXByteArray *bytes = [[ZXByteArray alloc] initWithLength:count]; + for (int i = 0; i < count; i++) { + if ([bits available] < 8) { + return NO; + } + bytes.array[i] = (int8_t)[self unrandomize255State:[bits readBits:8] base256CodewordPosition:codewordPosition++]; + } + [byteSegments addObject:bytes]; + + [result appendString:[[NSString alloc] initWithBytes:bytes.array length:bytes.length encoding:NSISOLatin1StringEncoding]]; + return YES; +} + +/** + * See ISO 16022:2006, Annex B, B.2 + */ ++ (int)unrandomize255State:(int)randomizedBase256Codeword base256CodewordPosition:(int)base256CodewordPosition { + int pseudoRandomNumber = ((149 * base256CodewordPosition) % 255) + 1; + int tempVariable = randomizedBase256Codeword - pseudoRandomNumber; + return tempVariable >= 0 ? tempVariable : tempVariable + 256; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/decoder/ZXDataMatrixDecoder.h b/iDearQRCode/Tools/ZXingObjC/datamatrix/decoder/ZXDataMatrixDecoder.h new file mode 100755 index 0000000..cf7660a --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/decoder/ZXDataMatrixDecoder.h @@ -0,0 +1,47 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXBitMatrix, ZXDecoderResult, ZXReedSolomonDecoder; + +/** + * The main class which implements Data Matrix Code decoding -- as opposed to locating and extracting + * the Data Matrix Code from an image. + */ +@interface ZXDataMatrixDecoder : NSObject + +/** + * Convenience method that can decode a Data Matrix Code represented as a 2D array of booleans. + * "true" is taken to mean a black module. + * + * @param image booleans representing white/black Data Matrix Code modules + * @return text and bytes encoded within the Data Matrix Code + * @return nil if the Data Matrix Code cannot be decoded + * @return nil if error correction fails + */ +- (ZXDecoderResult *)decode:(NSArray *)image error:(NSError **)error; + +/** + * Decodes a Data Matrix Code represented as a {@link BitMatrix}. A 1 or "true" is taken + * to mean a black module. + * + * @param bits booleans representing white/black Data Matrix Code modules + * @return text and bytes encoded within the Data Matrix Code + * @return nil if the Data Matrix Code cannot be decoded + * @return nil if error correction fails + */ +- (ZXDecoderResult *)decodeMatrix:(ZXBitMatrix *)bits error:(NSError **)error; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/decoder/ZXDataMatrixDecoder.m b/iDearQRCode/Tools/ZXingObjC/datamatrix/decoder/ZXDataMatrixDecoder.m new file mode 100755 index 0000000..d2b33fa --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/decoder/ZXDataMatrixDecoder.m @@ -0,0 +1,135 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitMatrix.h" +#import "ZXBoolArray.h" +#import "ZXByteArray.h" +#import "ZXDataMatrixBitMatrixParser.h" +#import "ZXDataMatrixDataBlock.h" +#import "ZXDataMatrixDecodedBitStreamParser.h" +#import "ZXDataMatrixDecoder.h" +#import "ZXDataMatrixVersion.h" +#import "ZXDecoderResult.h" +#import "ZXErrors.h" +#import "ZXGenericGF.h" +#import "ZXIntArray.h" +#import "ZXReedSolomonDecoder.h" + +@interface ZXDataMatrixDecoder () + +@property (nonatomic, strong, readonly) ZXReedSolomonDecoder *rsDecoder; + +@end + +@implementation ZXDataMatrixDecoder + +- (id)init { + if (self = [super init]) { + _rsDecoder = [[ZXReedSolomonDecoder alloc] initWithField:[ZXGenericGF DataMatrixField256]]; + } + + return self; +} + +- (ZXDecoderResult *)decode:(NSArray *)image error:(NSError **)error { + int dimension = (int)[image count]; + ZXBitMatrix *bits = [[ZXBitMatrix alloc] initWithDimension:dimension]; + for (int i = 0; i < dimension; i++) { + ZXBoolArray *b = image[i]; + for (int j = 0; j < dimension; j++) { + if (b.array[j]) { + [bits setX:j y:i]; + } + } + } + + return [self decodeMatrix:bits error:error]; +} + +- (ZXDecoderResult *)decodeMatrix:(ZXBitMatrix *)bits error:(NSError **)error { + ZXDataMatrixBitMatrixParser *parser = [[ZXDataMatrixBitMatrixParser alloc] initWithBitMatrix:bits error:error]; + if (!parser) { + return nil; + } + ZXDataMatrixVersion *version = [parser version]; + + ZXByteArray *codewords = [parser readCodewords]; + NSArray *dataBlocks = [ZXDataMatrixDataBlock dataBlocks:codewords version:version]; + + NSUInteger dataBlocksCount = [dataBlocks count]; + + int totalBytes = 0; + for (int i = 0; i < dataBlocksCount; i++) { + totalBytes += [dataBlocks[i] numDataCodewords]; + } + + if (totalBytes == 0) { + return nil; + } + + ZXByteArray *resultBytes = [[ZXByteArray alloc] initWithLength:totalBytes]; + + for (int j = 0; j < dataBlocksCount; j++) { + ZXDataMatrixDataBlock *dataBlock = dataBlocks[j]; + ZXByteArray *codewordBytes = dataBlock.codewords; + int numDataCodewords = [dataBlock numDataCodewords]; + if (![self correctErrors:codewordBytes numDataCodewords:numDataCodewords error:error]) { + return nil; + } + for (int i = 0; i < numDataCodewords; i++) { + // De-interlace data blocks. + resultBytes.array[i * dataBlocksCount + j] = codewordBytes.array[i]; + } + } + + return [ZXDataMatrixDecodedBitStreamParser decode:resultBytes error:error]; +} + +/** + * Given data and error-correction codewords received, possibly corrupted by errors, attempts to + * correct the errors in-place using Reed-Solomon error correction. + * + * @param codewordBytes data and error correction codewords + * @param numDataCodewords number of codewords that are data bytes + * @return NO if error correction fails + */ +- (BOOL)correctErrors:(ZXByteArray *)codewordBytes numDataCodewords:(int)numDataCodewords error:(NSError **)error { + int numCodewords = codewordBytes.length; + // First read into an array of ints + ZXIntArray *codewordsInts = [[ZXIntArray alloc] initWithLength:numCodewords]; + for (int i = 0; i < numCodewords; i++) { + codewordsInts.array[i] = codewordBytes.array[i] & 0xFF; + } + int numECCodewords = codewordBytes.length - numDataCodewords; + + NSError *decodeError = nil; + if (![self.rsDecoder decode:codewordsInts twoS:numECCodewords error:&decodeError]) { + if (decodeError.code == ZXReedSolomonError) { + if (error) *error = ZXChecksumErrorInstance(); + return NO; + } else { + if (error) *error = decodeError; + return NO; + } + } + + for (int i = 0; i < numDataCodewords; i++) { + codewordBytes.array[i] = (int8_t) codewordsInts.array[i]; + } + return YES; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/decoder/ZXDataMatrixVersion.h b/iDearQRCode/Tools/ZXingObjC/datamatrix/decoder/ZXDataMatrixVersion.h new file mode 100755 index 0000000..82e01a9 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/decoder/ZXDataMatrixVersion.h @@ -0,0 +1,66 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Encapsulates a set of error-correction blocks in one symbol version. Most versions will + * use blocks of differing sizes within one version, so, this encapsulates the parameters for + * each set of blocks. It also holds the number of error-correction codewords per block since it + * will be the same across all blocks within one version. + */ +@interface ZXDataMatrixECBlocks : NSObject + +@property (nonatomic, strong, readonly) NSArray *ecBlocks; +@property (nonatomic, assign, readonly) int ecCodewords; + +@end + +/** + * Encapsualtes the parameters for one error-correction block in one symbol version. + * This includes the number of data codewords, and the number of times a block with these + * parameters is used consecutively in the Data Matrix code version's format. + */ +@interface ZXDataMatrixECB : NSObject + +@property (nonatomic, assign, readonly) int count; +@property (nonatomic, assign, readonly) int dataCodewords; + +@end + +/** + * The Version object encapsulates attributes about a particular + * size Data Matrix Code. + */ +@interface ZXDataMatrixVersion : NSObject + +@property (nonatomic, strong, readonly) ZXDataMatrixECBlocks *ecBlocks; +@property (nonatomic, assign, readonly) int dataRegionSizeColumns; +@property (nonatomic, assign, readonly) int dataRegionSizeRows; +@property (nonatomic, assign, readonly) int symbolSizeColumns; +@property (nonatomic, assign, readonly) int symbolSizeRows; +@property (nonatomic, assign, readonly) int totalCodewords; +@property (nonatomic, assign, readonly) int versionNumber; + +/** + *

Deduces version information from Data Matrix dimensions.

+ * + * @param numRows Number of rows in modules + * @param numColumns Number of columns in modules + * @return Version for a Data Matrix Code of those dimensions or nil + * if dimensions do correspond to a valid Data Matrix size + */ ++ (ZXDataMatrixVersion *)versionForDimensions:(int)numRows numColumns:(int)numColumns; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/decoder/ZXDataMatrixVersion.m b/iDearQRCode/Tools/ZXingObjC/datamatrix/decoder/ZXDataMatrixVersion.m new file mode 100755 index 0000000..6a3aa82 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/decoder/ZXDataMatrixVersion.m @@ -0,0 +1,348 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXDataMatrixVersion.h" + +@implementation ZXDataMatrixECBlocks + +- (id)initWithCodewords:(int)ecCodewords ecBlocks:(ZXDataMatrixECB *)ecBlocks { + if (self = [super init]) { + _ecCodewords = ecCodewords; + _ecBlocks = @[ecBlocks]; + } + + return self; +} + +- (id)initWithCodewords:(int)ecCodewords ecBlocks1:(ZXDataMatrixECB *)ecBlocks1 ecBlocks2:(ZXDataMatrixECB *)ecBlocks2 { + if (self = [super init]) { + _ecCodewords = ecCodewords; + _ecBlocks = @[ecBlocks1, ecBlocks2]; + } + + return self; +} + +@end + + +@implementation ZXDataMatrixECB + +- (id)initWithCount:(int)count dataCodewords:(int)dataCodewords { + if (self = [super init]) { + _count = count; + _dataCodewords = dataCodewords; + } + + return self; +} + +@end + + +static NSArray *VERSIONS = nil; + +@implementation ZXDataMatrixVersion + +- (id)initWithVersionNumber:(int)versionNumber symbolSizeRows:(int)symbolSizeRows symbolSizeColumns:(int)symbolSizeColumns + dataRegionSizeRows:(int)dataRegionSizeRows dataRegionSizeColumns:(int)dataRegionSizeColumns ecBlocks:(ZXDataMatrixECBlocks *)ecBlocks { + if (self = [super init]) { + _versionNumber = versionNumber; + _symbolSizeRows = symbolSizeRows; + _symbolSizeColumns = symbolSizeColumns; + _dataRegionSizeRows = dataRegionSizeRows; + _dataRegionSizeColumns = dataRegionSizeColumns; + _ecBlocks = ecBlocks; + + int total = 0; + int ecCodewords = ecBlocks.ecCodewords; + NSArray *ecbArray = ecBlocks.ecBlocks; + for (ZXDataMatrixECB *ecBlock in ecbArray) { + total += ecBlock.count * (ecBlock.dataCodewords + ecCodewords); + } + _totalCodewords = total; + } + + return self; +} + ++ (ZXDataMatrixVersion *)versionForDimensions:(int)numRows numColumns:(int)numColumns { + if ((numRows & 0x01) != 0 || (numColumns & 0x01) != 0) { + return nil; + } + + for (ZXDataMatrixVersion *version in VERSIONS) { + if (version.symbolSizeRows == numRows && version.symbolSizeColumns == numColumns) { + return version; + } + } + + return nil; +} + +- (NSString *)description { + return [@(self.versionNumber) stringValue]; +} + +/** + * See ISO 16022:2006 5.5.1 Table 7 + */ ++ (void)initialize { + if ([self class] != [ZXDataMatrixVersion class]) return; + + VERSIONS = @[[[ZXDataMatrixVersion alloc] initWithVersionNumber:1 + symbolSizeRows:10 + symbolSizeColumns:10 + dataRegionSizeRows:8 + dataRegionSizeColumns:8 + ecBlocks:[[ZXDataMatrixECBlocks alloc] initWithCodewords:5 + ecBlocks:[[ZXDataMatrixECB alloc] initWithCount:1 dataCodewords:3]]], + + [[ZXDataMatrixVersion alloc] initWithVersionNumber:2 + symbolSizeRows:12 + symbolSizeColumns:12 + dataRegionSizeRows:10 + dataRegionSizeColumns:10 + ecBlocks:[[ZXDataMatrixECBlocks alloc] initWithCodewords:7 + ecBlocks:[[ZXDataMatrixECB alloc] initWithCount:1 dataCodewords:5]]], + + [[ZXDataMatrixVersion alloc] initWithVersionNumber:3 + symbolSizeRows:14 + symbolSizeColumns:14 + dataRegionSizeRows:12 + dataRegionSizeColumns:12 + ecBlocks:[[ZXDataMatrixECBlocks alloc] initWithCodewords:10 + ecBlocks:[[ZXDataMatrixECB alloc] initWithCount:1 dataCodewords:8]]], + + [[ZXDataMatrixVersion alloc] initWithVersionNumber:4 + symbolSizeRows:16 + symbolSizeColumns:16 + dataRegionSizeRows:14 + dataRegionSizeColumns:14 + ecBlocks:[[ZXDataMatrixECBlocks alloc] initWithCodewords:12 + ecBlocks:[[ZXDataMatrixECB alloc] initWithCount:1 dataCodewords:12]]], + + [[ZXDataMatrixVersion alloc] initWithVersionNumber:5 + symbolSizeRows:18 + symbolSizeColumns:18 + dataRegionSizeRows:16 + dataRegionSizeColumns:16 + ecBlocks:[[ZXDataMatrixECBlocks alloc] initWithCodewords:14 + ecBlocks:[[ZXDataMatrixECB alloc] initWithCount:1 dataCodewords:18]]], + + [[ZXDataMatrixVersion alloc] initWithVersionNumber:6 + symbolSizeRows:20 + symbolSizeColumns:20 + dataRegionSizeRows:18 + dataRegionSizeColumns:18 + ecBlocks:[[ZXDataMatrixECBlocks alloc] initWithCodewords:18 + ecBlocks:[[ZXDataMatrixECB alloc] initWithCount:1 dataCodewords:22]]], + + [[ZXDataMatrixVersion alloc] initWithVersionNumber:7 + symbolSizeRows:22 + symbolSizeColumns:22 + dataRegionSizeRows:20 + dataRegionSizeColumns:20 + ecBlocks:[[ZXDataMatrixECBlocks alloc] initWithCodewords:20 + ecBlocks:[[ZXDataMatrixECB alloc] initWithCount:1 dataCodewords:30]]], + + [[ZXDataMatrixVersion alloc] initWithVersionNumber:8 + symbolSizeRows:24 + symbolSizeColumns:24 + dataRegionSizeRows:22 + dataRegionSizeColumns:22 + ecBlocks:[[ZXDataMatrixECBlocks alloc] initWithCodewords:24 + ecBlocks:[[ZXDataMatrixECB alloc] initWithCount:1 dataCodewords:36]]], + + [[ZXDataMatrixVersion alloc] initWithVersionNumber:9 + symbolSizeRows:26 + symbolSizeColumns:26 + dataRegionSizeRows:24 + dataRegionSizeColumns:24 + ecBlocks:[[ZXDataMatrixECBlocks alloc] initWithCodewords:28 + ecBlocks:[[ZXDataMatrixECB alloc] initWithCount:1 dataCodewords:44]]], + + [[ZXDataMatrixVersion alloc] initWithVersionNumber:10 + symbolSizeRows:32 + symbolSizeColumns:32 + dataRegionSizeRows:14 + dataRegionSizeColumns:14 + ecBlocks:[[ZXDataMatrixECBlocks alloc] initWithCodewords:36 + ecBlocks:[[ZXDataMatrixECB alloc] initWithCount:1 dataCodewords:62]]], + + [[ZXDataMatrixVersion alloc] initWithVersionNumber:11 + symbolSizeRows:36 + symbolSizeColumns:36 + dataRegionSizeRows:16 + dataRegionSizeColumns:16 + ecBlocks:[[ZXDataMatrixECBlocks alloc] initWithCodewords:42 + ecBlocks:[[ZXDataMatrixECB alloc] initWithCount:1 dataCodewords:86]]], + + [[ZXDataMatrixVersion alloc] initWithVersionNumber:12 + symbolSizeRows:40 + symbolSizeColumns:40 + dataRegionSizeRows:18 + dataRegionSizeColumns:18 + ecBlocks:[[ZXDataMatrixECBlocks alloc] initWithCodewords:48 + ecBlocks:[[ZXDataMatrixECB alloc] initWithCount:1 dataCodewords:114]]], + + [[ZXDataMatrixVersion alloc] initWithVersionNumber:13 + symbolSizeRows:44 + symbolSizeColumns:44 + dataRegionSizeRows:20 + dataRegionSizeColumns:20 + ecBlocks:[[ZXDataMatrixECBlocks alloc] initWithCodewords:56 + ecBlocks:[[ZXDataMatrixECB alloc] initWithCount:1 dataCodewords:144]]], + + [[ZXDataMatrixVersion alloc] initWithVersionNumber:14 + symbolSizeRows:48 + symbolSizeColumns:48 + dataRegionSizeRows:22 + dataRegionSizeColumns:22 + ecBlocks:[[ZXDataMatrixECBlocks alloc] initWithCodewords:68 + ecBlocks:[[ZXDataMatrixECB alloc] initWithCount:1 dataCodewords:174]]], + + [[ZXDataMatrixVersion alloc] initWithVersionNumber:15 + symbolSizeRows:52 + symbolSizeColumns:52 + dataRegionSizeRows:24 + dataRegionSizeColumns:24 + ecBlocks:[[ZXDataMatrixECBlocks alloc] initWithCodewords:42 + ecBlocks:[[ZXDataMatrixECB alloc] initWithCount:2 dataCodewords:102]]], + + [[ZXDataMatrixVersion alloc] initWithVersionNumber:16 + symbolSizeRows:64 + symbolSizeColumns:64 + dataRegionSizeRows:14 + dataRegionSizeColumns:14 + ecBlocks:[[ZXDataMatrixECBlocks alloc] initWithCodewords:56 + ecBlocks:[[ZXDataMatrixECB alloc] initWithCount:2 dataCodewords:140]]], + + [[ZXDataMatrixVersion alloc] initWithVersionNumber:17 + symbolSizeRows:72 + symbolSizeColumns:72 + dataRegionSizeRows:16 + dataRegionSizeColumns:16 + ecBlocks:[[ZXDataMatrixECBlocks alloc] initWithCodewords:36 + ecBlocks:[[ZXDataMatrixECB alloc] initWithCount:4 dataCodewords:92]]], + + [[ZXDataMatrixVersion alloc] initWithVersionNumber:18 + symbolSizeRows:80 + symbolSizeColumns:80 + dataRegionSizeRows:18 + dataRegionSizeColumns:18 + ecBlocks:[[ZXDataMatrixECBlocks alloc] initWithCodewords:48 + ecBlocks:[[ZXDataMatrixECB alloc] initWithCount:4 dataCodewords:114]]], + + [[ZXDataMatrixVersion alloc] initWithVersionNumber:19 + symbolSizeRows:88 + symbolSizeColumns:88 + dataRegionSizeRows:20 + dataRegionSizeColumns:20 + ecBlocks:[[ZXDataMatrixECBlocks alloc] initWithCodewords:56 + ecBlocks:[[ZXDataMatrixECB alloc] initWithCount:4 dataCodewords:144]]], + + [[ZXDataMatrixVersion alloc] initWithVersionNumber:20 + symbolSizeRows:96 + symbolSizeColumns:96 + dataRegionSizeRows:22 + dataRegionSizeColumns:22 + ecBlocks:[[ZXDataMatrixECBlocks alloc] initWithCodewords:68 + ecBlocks:[[ZXDataMatrixECB alloc] initWithCount:4 dataCodewords:174]]], + + [[ZXDataMatrixVersion alloc] initWithVersionNumber:21 + symbolSizeRows:104 + symbolSizeColumns:104 + dataRegionSizeRows:24 + dataRegionSizeColumns:24 + ecBlocks:[[ZXDataMatrixECBlocks alloc] initWithCodewords:56 + ecBlocks:[[ZXDataMatrixECB alloc] initWithCount:6 dataCodewords:136]]], + + [[ZXDataMatrixVersion alloc] initWithVersionNumber:22 + symbolSizeRows:120 + symbolSizeColumns:120 + dataRegionSizeRows:18 + dataRegionSizeColumns:18 + ecBlocks:[[ZXDataMatrixECBlocks alloc] initWithCodewords:68 + ecBlocks:[[ZXDataMatrixECB alloc] initWithCount:6 dataCodewords:175]]], + + [[ZXDataMatrixVersion alloc] initWithVersionNumber:23 + symbolSizeRows:132 + symbolSizeColumns:132 + dataRegionSizeRows:20 + dataRegionSizeColumns:20 + ecBlocks:[[ZXDataMatrixECBlocks alloc] initWithCodewords:62 + ecBlocks:[[ZXDataMatrixECB alloc] initWithCount:8 dataCodewords:163]]], + + [[ZXDataMatrixVersion alloc] initWithVersionNumber:24 + symbolSizeRows:144 + symbolSizeColumns:144 + dataRegionSizeRows:22 + dataRegionSizeColumns:22 + ecBlocks:[[ZXDataMatrixECBlocks alloc] initWithCodewords:62 + ecBlocks1:[[ZXDataMatrixECB alloc] initWithCount:8 dataCodewords:156] + ecBlocks2:[[ZXDataMatrixECB alloc] initWithCount:2 dataCodewords:155]]], + + [[ZXDataMatrixVersion alloc] initWithVersionNumber:25 + symbolSizeRows:8 + symbolSizeColumns:18 + dataRegionSizeRows:6 + dataRegionSizeColumns:16 + ecBlocks:[[ZXDataMatrixECBlocks alloc] initWithCodewords:7 + ecBlocks:[[ZXDataMatrixECB alloc] initWithCount:1 dataCodewords:5]]], + + [[ZXDataMatrixVersion alloc] initWithVersionNumber:26 + symbolSizeRows:8 + symbolSizeColumns:32 + dataRegionSizeRows:6 + dataRegionSizeColumns:14 + ecBlocks:[[ZXDataMatrixECBlocks alloc] initWithCodewords:11 + ecBlocks:[[ZXDataMatrixECB alloc] initWithCount:1 dataCodewords:10]]], + + [[ZXDataMatrixVersion alloc] initWithVersionNumber:27 + symbolSizeRows:12 + symbolSizeColumns:26 + dataRegionSizeRows:10 + dataRegionSizeColumns:24 + ecBlocks:[[ZXDataMatrixECBlocks alloc] initWithCodewords:14 + ecBlocks:[[ZXDataMatrixECB alloc] initWithCount:1 dataCodewords:16]]], + + [[ZXDataMatrixVersion alloc] initWithVersionNumber:28 + symbolSizeRows:12 + symbolSizeColumns:36 + dataRegionSizeRows:10 + dataRegionSizeColumns:16 + ecBlocks:[[ZXDataMatrixECBlocks alloc] initWithCodewords:18 + ecBlocks:[[ZXDataMatrixECB alloc] initWithCount:1 dataCodewords:22]]], + + [[ZXDataMatrixVersion alloc] initWithVersionNumber:29 + symbolSizeRows:16 + symbolSizeColumns:36 + dataRegionSizeRows:14 + dataRegionSizeColumns:16 + ecBlocks:[[ZXDataMatrixECBlocks alloc] initWithCodewords:24 + ecBlocks:[[ZXDataMatrixECB alloc] initWithCount:1 dataCodewords:32]]], + + [[ZXDataMatrixVersion alloc] initWithVersionNumber:30 + symbolSizeRows:16 + symbolSizeColumns:48 + dataRegionSizeRows:14 + dataRegionSizeColumns:22 + ecBlocks:[[ZXDataMatrixECBlocks alloc] initWithCodewords:28 + ecBlocks:[[ZXDataMatrixECB alloc] initWithCount:1 dataCodewords:49]]]]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/detector/ZXDataMatrixDetector.h b/iDearQRCode/Tools/ZXingObjC/datamatrix/detector/ZXDataMatrixDetector.h new file mode 100755 index 0000000..babf9e1 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/detector/ZXDataMatrixDetector.h @@ -0,0 +1,35 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXBitMatrix, ZXDetectorResult, ZXWhiteRectangleDetector; + +/** + * Encapsulates logic that can detect a Data Matrix Code in an image, even if the Data Matrix Code + * is rotated or skewed, or partially obscured. + */ +@interface ZXDataMatrixDetector : NSObject + +- (id)initWithImage:(ZXBitMatrix *)image error:(NSError **)error; + +/** + * Detects a Data Matrix Code in an image. + * + * @return ZXDetectorResult encapsulating results of detecting a Data Matrix Code or nil + * if no Data Matrix Code can be found + */ +- (ZXDetectorResult *)detectWithError:(NSError **)error; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/detector/ZXDataMatrixDetector.m b/iDearQRCode/Tools/ZXingObjC/datamatrix/detector/ZXDataMatrixDetector.m new file mode 100755 index 0000000..ada6c2f --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/detector/ZXDataMatrixDetector.m @@ -0,0 +1,359 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXDataMatrixDetector.h" +#import "ZXDetectorResult.h" +#import "ZXErrors.h" +#import "ZXGridSampler.h" +#import "ZXMathUtils.h" +#import "ZXResultPoint.h" +#import "ZXWhiteRectangleDetector.h" + +/** + * Simply encapsulates two points and a number of transitions between them. + */ +@interface ZXResultPointsAndTransitions : NSObject + +@property (nonatomic, strong, readonly) ZXResultPoint *from; +@property (nonatomic, strong, readonly) ZXResultPoint *to; +@property (nonatomic, assign, readonly) int transitions; + +@end + +@implementation ZXResultPointsAndTransitions + +- (id)initWithFrom:(ZXResultPoint *)from to:(ZXResultPoint *)to transitions:(int)transitions { + if (self = [super init]) { + _from = from; + _to = to; + _transitions = transitions; + } + + return self; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"%@/%@/%d", self.from, self.to, self.transitions]; +} + +- (NSComparisonResult)compare:(ZXResultPointsAndTransitions *)otherObject { + return [@(self.transitions) compare:@(otherObject.transitions)]; +} + +@end + + +@interface ZXDataMatrixDetector () + +@property (nonatomic, strong, readonly) ZXBitMatrix *image; +@property (nonatomic, strong, readonly) ZXWhiteRectangleDetector *rectangleDetector; + +@end + +@implementation ZXDataMatrixDetector + +- (id)initWithImage:(ZXBitMatrix *)image error:(NSError **)error { + if (self = [super init]) { + _image = image; + _rectangleDetector = [[ZXWhiteRectangleDetector alloc] initWithImage:_image error:error]; + if (!_rectangleDetector) { + return nil; + } + } + + return self; +} + +- (ZXDetectorResult *)detectWithError:(NSError **)error { + NSArray *cornerPoints = [self.rectangleDetector detectWithError:error]; + if (!cornerPoints) { + return nil; + } + ZXResultPoint *pointA = cornerPoints[0]; + ZXResultPoint *pointB = cornerPoints[1]; + ZXResultPoint *pointC = cornerPoints[2]; + ZXResultPoint *pointD = cornerPoints[3]; + + NSMutableArray *transitions = [NSMutableArray arrayWithCapacity:4]; + [transitions addObject:[self transitionsBetween:pointA to:pointB]]; + [transitions addObject:[self transitionsBetween:pointA to:pointC]]; + [transitions addObject:[self transitionsBetween:pointB to:pointD]]; + [transitions addObject:[self transitionsBetween:pointC to:pointD]]; + [transitions sortUsingSelector:@selector(compare:)]; + + ZXResultPointsAndTransitions *lSideOne = (ZXResultPointsAndTransitions *)transitions[0]; + ZXResultPointsAndTransitions *lSideTwo = (ZXResultPointsAndTransitions *)transitions[1]; + + NSMutableDictionary *pointCount = [NSMutableDictionary dictionary]; + [self increment:pointCount key:[lSideOne from]]; + [self increment:pointCount key:[lSideOne to]]; + [self increment:pointCount key:[lSideTwo from]]; + [self increment:pointCount key:[lSideTwo to]]; + + ZXResultPoint *maybeTopLeft = nil; + ZXResultPoint *bottomLeft = nil; + ZXResultPoint *maybeBottomRight = nil; + for (ZXResultPoint *point in [pointCount allKeys]) { + NSNumber *value = pointCount[point]; + if ([value intValue] == 2) { + bottomLeft = point; + } else { + if (maybeTopLeft == nil) { + maybeTopLeft = point; + } else { + maybeBottomRight = point; + } + } + } + + if (maybeTopLeft == nil || bottomLeft == nil || maybeBottomRight == nil) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + + NSMutableArray *corners = [NSMutableArray arrayWithObjects:maybeTopLeft, bottomLeft, maybeBottomRight, nil]; + [ZXResultPoint orderBestPatterns:corners]; + + ZXResultPoint *bottomRight = corners[0]; + bottomLeft = corners[1]; + ZXResultPoint *topLeft = corners[2]; + + ZXResultPoint *topRight; + if (!pointCount[pointA]) { + topRight = pointA; + } else if (!pointCount[pointB]) { + topRight = pointB; + } else if (!pointCount[pointC]) { + topRight = pointC; + } else { + topRight = pointD; + } + + int dimensionTop = [[self transitionsBetween:topLeft to:topRight] transitions]; + int dimensionRight = [[self transitionsBetween:bottomRight to:topRight] transitions]; + + if ((dimensionTop & 0x01) == 1) { + dimensionTop++; + } + dimensionTop += 2; + + if ((dimensionRight & 0x01) == 1) { + dimensionRight++; + } + dimensionRight += 2; + + ZXBitMatrix *bits; + ZXResultPoint *correctedTopRight; + + if (4 * dimensionTop >= 7 * dimensionRight || 4 * dimensionRight >= 7 * dimensionTop) { + correctedTopRight = [self correctTopRightRectangular:bottomLeft bottomRight:bottomRight topLeft:topLeft topRight:topRight dimensionTop:dimensionTop dimensionRight:dimensionRight]; + if (correctedTopRight == nil) { + correctedTopRight = topRight; + } + + dimensionTop = [[self transitionsBetween:topLeft to:correctedTopRight] transitions]; + dimensionRight = [[self transitionsBetween:bottomRight to:correctedTopRight] transitions]; + + if ((dimensionTop & 0x01) == 1) { + dimensionTop++; + } + + if ((dimensionRight & 0x01) == 1) { + dimensionRight++; + } + + bits = [self sampleGrid:self.image topLeft:topLeft bottomLeft:bottomLeft bottomRight:bottomRight topRight:correctedTopRight dimensionX:dimensionTop dimensionY:dimensionRight error:error]; + if (!bits) { + return nil; + } + } else { + int dimension = MIN(dimensionRight, dimensionTop); + correctedTopRight = [self correctTopRight:bottomLeft bottomRight:bottomRight topLeft:topLeft topRight:topRight dimension:dimension]; + if (correctedTopRight == nil) { + correctedTopRight = topRight; + } + + int dimensionCorrected = MAX([[self transitionsBetween:topLeft to:correctedTopRight] transitions], [[self transitionsBetween:bottomRight to:correctedTopRight] transitions]); + dimensionCorrected++; + if ((dimensionCorrected & 0x01) == 1) { + dimensionCorrected++; + } + + bits = [self sampleGrid:self.image topLeft:topLeft bottomLeft:bottomLeft bottomRight:bottomRight topRight:correctedTopRight dimensionX:dimensionCorrected dimensionY:dimensionCorrected error:error]; + if (!bits) { + return nil; + } + } + return [[ZXDetectorResult alloc] initWithBits:bits points:@[topLeft, bottomLeft, bottomRight, correctedTopRight]]; +} + +/** + * Calculates the position of the white top right module using the output of the rectangle detector + * for a rectangular matrix + */ +- (ZXResultPoint *)correctTopRightRectangular:(ZXResultPoint *)bottomLeft bottomRight:(ZXResultPoint *)bottomRight + topLeft:(ZXResultPoint *)topLeft topRight:(ZXResultPoint *)topRight + dimensionTop:(int)dimensionTop dimensionRight:(int)dimensionRight { + float corr = [self distance:bottomLeft b:bottomRight] / (float)dimensionTop; + int norm = [self distance:topLeft b:topRight]; + float cos = ([topRight x] - [topLeft x]) / norm; + float sin = ([topRight y] - [topLeft y]) / norm; + + ZXResultPoint *c1 = [[ZXResultPoint alloc] initWithX:[topRight x] + corr * cos y:[topRight y] + corr * sin]; + + corr = [self distance:bottomLeft b:topLeft] / (float)dimensionRight; + norm = [self distance:bottomRight b:topRight]; + cos = ([topRight x] - [bottomRight x]) / norm; + sin = ([topRight y] - [bottomRight y]) / norm; + + ZXResultPoint *c2 = [[ZXResultPoint alloc] initWithX:[topRight x] + corr * cos y:[topRight y] + corr * sin]; + + if (![self isValid:c1]) { + if ([self isValid:c2]) { + return c2; + } + return nil; + } else if (![self isValid:c2]) { + return c1; + } + + int l1 = abs(dimensionTop - [[self transitionsBetween:topLeft to:c1] transitions]) + abs(dimensionRight - [[self transitionsBetween:bottomRight to:c1] transitions]); + int l2 = abs(dimensionTop - [[self transitionsBetween:topLeft to:c2] transitions]) + abs(dimensionRight - [[self transitionsBetween:bottomRight to:c2] transitions]); + + if (l1 <= l2) { + return c1; + } + + return c2; +} + +/** + * Calculates the position of the white top right module using the output of the rectangle detector + * for a square matrix + */ +- (ZXResultPoint *)correctTopRight:(ZXResultPoint *)bottomLeft bottomRight:(ZXResultPoint *)bottomRight + topLeft:(ZXResultPoint *)topLeft topRight:(ZXResultPoint *)topRight dimension:(int)dimension { + float corr = [self distance:bottomLeft b:bottomRight] / (float)dimension; + int norm = [self distance:topLeft b:topRight]; + float cos = ([topRight x] - [topLeft x]) / norm; + float sin = ([topRight y] - [topLeft y]) / norm; + + ZXResultPoint *c1 = [[ZXResultPoint alloc] initWithX:[topRight x] + corr * cos y:[topRight y] + corr * sin]; + + corr = [self distance:bottomLeft b:topLeft] / (float)dimension; + norm = [self distance:bottomRight b:topRight]; + cos = ([topRight x] - [bottomRight x]) / norm; + sin = ([topRight y] - [bottomRight y]) / norm; + + ZXResultPoint *c2 = [[ZXResultPoint alloc] initWithX:[topRight x] + corr * cos y:[topRight y] + corr * sin]; + + if (![self isValid:c1]) { + if ([self isValid:c2]) { + return c2; + } + return nil; + } else if (![self isValid:c2]) { + return c1; + } + + int l1 = abs([[self transitionsBetween:topLeft to:c1] transitions] - [[self transitionsBetween:bottomRight to:c1] transitions]); + int l2 = abs([[self transitionsBetween:topLeft to:c2] transitions] - [[self transitionsBetween:bottomRight to:c2] transitions]); + + return l1 <= l2 ? c1 : c2; +} + +- (BOOL) isValid:(ZXResultPoint *)p { + return [p x] >= 0 && [p x] < self.image.width && [p y] > 0 && [p y] < self.image.height; +} + +- (int)distance:(ZXResultPoint *)a b:(ZXResultPoint *)b { + return [ZXMathUtils round:[ZXResultPoint distance:a pattern2:b]]; +} + +/** + * Increments the Integer associated with a key by one. + */ +- (void)increment:(NSMutableDictionary *)table key:(ZXResultPoint *)key { + NSNumber *value = table[key]; + table[key] = value == nil ? @1 : @([value intValue] + 1); +} + +- (ZXBitMatrix *)sampleGrid:(ZXBitMatrix *)image + topLeft:(ZXResultPoint *)topLeft + bottomLeft:(ZXResultPoint *)bottomLeft + bottomRight:(ZXResultPoint *)bottomRight + topRight:(ZXResultPoint *)topRight + dimensionX:(int)dimensionX + dimensionY:(int)dimensionY + error:(NSError **)error { + ZXGridSampler *sampler = [ZXGridSampler instance]; + return [sampler sampleGrid:image + dimensionX:dimensionX dimensionY:dimensionY + p1ToX:0.5f p1ToY:0.5f + p2ToX:dimensionX - 0.5f p2ToY:0.5f + p3ToX:dimensionX - 0.5f p3ToY:dimensionY - 0.5f + p4ToX:0.5f p4ToY:dimensionY - 0.5f + p1FromX:[topLeft x] p1FromY:[topLeft y] + p2FromX:[topRight x] p2FromY:[topRight y] + p3FromX:[bottomRight x] p3FromY:[bottomRight y] + p4FromX:[bottomLeft x] p4FromY:[bottomLeft y] + error:error]; +} + +/** + * Counts the number of black/white transitions between two points, using something like Bresenham's algorithm. + */ +- (ZXResultPointsAndTransitions *)transitionsBetween:(ZXResultPoint *)from to:(ZXResultPoint *)to { + int fromX = (int)[from x]; + int fromY = (int)[from y]; + int toX = (int)[to x]; + int toY = (int)[to y]; + BOOL steep = abs(toY - fromY) > abs(toX - fromX); + if (steep) { + int temp = fromX; + fromX = fromY; + fromY = temp; + temp = toX; + toX = toY; + toY = temp; + } + + int dx = abs(toX - fromX); + int dy = abs(toY - fromY); + int error = -dx / 2; + int ystep = fromY < toY ? 1 : -1; + int xstep = fromX < toX ? 1 : -1; + int transitions = 0; + BOOL inBlack = [self.image getX:steep ? fromY : fromX y:steep ? fromX : fromY]; + for (int x = fromX, y = fromY; x != toX; x += xstep) { + BOOL isBlack = [self.image getX:steep ? y : x y:steep ? x : y]; + if (isBlack != inBlack) { + transitions++; + inBlack = isBlack; + } + error += dy; + if (error > 0) { + if (y == toY) { + break; + } + y += ystep; + error -= dx; + } + } + return [[ZXResultPointsAndTransitions alloc] initWithFrom:from to:to transitions:transitions]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixASCIIEncoder.h b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixASCIIEncoder.h new file mode 100755 index 0000000..86ab58b --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixASCIIEncoder.h @@ -0,0 +1,21 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXDataMatrixEncoder.h" + +@interface ZXDataMatrixASCIIEncoder : NSObject + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixASCIIEncoder.m b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixASCIIEncoder.m new file mode 100755 index 0000000..9673c3f --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixASCIIEncoder.m @@ -0,0 +1,79 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXDataMatrixASCIIEncoder.h" +#import "ZXDataMatrixEncoderContext.h" +#import "ZXDataMatrixHighLevelEncoder.h" + +@implementation ZXDataMatrixASCIIEncoder + +- (int)encodingMode { + return [ZXDataMatrixHighLevelEncoder asciiEncodation]; +} + +- (void)encode:(ZXDataMatrixEncoderContext *)context { + //step B + int n = [ZXDataMatrixHighLevelEncoder determineConsecutiveDigitCount:context.message startpos:context.pos]; + if (n >= 2) { + [context writeCodeword:[self encodeASCIIDigits:[context.message characterAtIndex:context.pos] + digit2:[context.message characterAtIndex:context.pos + 1]]]; + context.pos += 2; + } else { + unichar c = [context currentChar]; + int newMode = [ZXDataMatrixHighLevelEncoder lookAheadTest:context.message startpos:context.pos currentMode:[self encodingMode]]; + if (newMode != [self encodingMode]) { + if (newMode == [ZXDataMatrixHighLevelEncoder base256Encodation]) { + [context writeCodeword:[ZXDataMatrixHighLevelEncoder latchToBase256]]; + [context signalEncoderChange:[ZXDataMatrixHighLevelEncoder base256Encodation]]; + return; + } else if (newMode == [ZXDataMatrixHighLevelEncoder c40Encodation]) { + [context writeCodeword:[ZXDataMatrixHighLevelEncoder latchToC40]]; + [context signalEncoderChange:[ZXDataMatrixHighLevelEncoder c40Encodation]]; + return; + } else if (newMode == [ZXDataMatrixHighLevelEncoder x12Encodation]) { + [context writeCodeword:[ZXDataMatrixHighLevelEncoder latchToAnsiX12]]; + [context signalEncoderChange:[ZXDataMatrixHighLevelEncoder x12Encodation]]; + } else if (newMode == [ZXDataMatrixHighLevelEncoder textEncodation]) { + [context writeCodeword:[ZXDataMatrixHighLevelEncoder latchToText]]; + [context signalEncoderChange:[ZXDataMatrixHighLevelEncoder textEncodation]]; + } else if (newMode == [ZXDataMatrixHighLevelEncoder edifactEncodation]) { + [context writeCodeword:[ZXDataMatrixHighLevelEncoder latchToEdifact]]; + [context signalEncoderChange:[ZXDataMatrixHighLevelEncoder edifactEncodation]]; + } else { + @throw [NSException exceptionWithName:@"IllegalStateException" reason:@"Illegal mode" userInfo:nil]; + } + } else if ([ZXDataMatrixHighLevelEncoder isExtendedASCII:c]) { + [context writeCodeword:[ZXDataMatrixHighLevelEncoder upperShift]]; + [context writeCodeword:(unichar)(c - 128 + 1)]; + context.pos++; + } else { + [context writeCodeword:(unichar)(c + 1)]; + context.pos++; + } + } +} + +- (unichar)encodeASCIIDigits:(unichar)digit1 digit2:(unichar)digit2 { + if ([ZXDataMatrixHighLevelEncoder isDigit:digit1] && [ZXDataMatrixHighLevelEncoder isDigit:digit2]) { + int num = (digit1 - 48) * 10 + (digit2 - 48); + return (unichar) (num + 130); + } + @throw [NSException exceptionWithName:NSInvalidArgumentException + reason:[NSString stringWithFormat:@"not digits: %C %C", digit1, digit2] + userInfo:nil]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixBase256Encoder.h b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixBase256Encoder.h new file mode 100755 index 0000000..b5f73b3 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixBase256Encoder.h @@ -0,0 +1,21 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXDataMatrixEncoder.h" + +@interface ZXDataMatrixBase256Encoder : NSObject + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixBase256Encoder.m b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixBase256Encoder.m new file mode 100755 index 0000000..ede8fa9 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixBase256Encoder.m @@ -0,0 +1,78 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXDataMatrixBase256Encoder.h" +#import "ZXDataMatrixEncoderContext.h" +#import "ZXDataMatrixHighLevelEncoder.h" +#import "ZXDataMatrixSymbolInfo.h" + +@implementation ZXDataMatrixBase256Encoder + +- (int)encodingMode { + return [ZXDataMatrixHighLevelEncoder base256Encodation]; +} + +- (void)encode:(ZXDataMatrixEncoderContext *)context { + NSMutableString *buffer = [NSMutableString string]; + [buffer appendString:@"\0"]; //Initialize length field + while ([context hasMoreCharacters]) { + unichar c = [context currentChar]; + [buffer appendFormat:@"%C", c]; + + context.pos++; + + int newMode = [ZXDataMatrixHighLevelEncoder lookAheadTest:context.message startpos:context.pos currentMode:[self encodingMode]]; + if (newMode != [self encodingMode]) { + [context signalEncoderChange:newMode]; + break; + } + } + int dataCount = (int)buffer.length - 1; + int lengthFieldSize = 1; + int currentSize = [context codewordCount] + dataCount + lengthFieldSize; + [context updateSymbolInfoWithLength:currentSize]; + BOOL mustPad = (context.symbolInfo.dataCapacity - currentSize) > 0; + if ([context hasMoreCharacters] || mustPad) { + if (dataCount <= 249) { + [buffer replaceCharactersInRange:NSMakeRange(0, 1) + withString:[NSString stringWithFormat:@"%C", (unichar) dataCount]]; + } else if (dataCount > 249 && dataCount <= 1555) { + [buffer replaceCharactersInRange:NSMakeRange(0, 1) + withString:[NSString stringWithFormat:@"%C", (unichar) ((dataCount / 250) + 249)]]; + [buffer insertString:[NSString stringWithFormat:@"%C", (unichar) (dataCount % 250)] + atIndex:1]; + } else { + @throw [NSException exceptionWithName:@"IllegalStateException" + reason:[NSString stringWithFormat:@"Message length not in valid ranges: %d", dataCount] + userInfo:nil]; + } + } + for (int i = 0, c = (int)buffer.length; i < c; i++) { + [context writeCodeword:[self randomize255State:[buffer characterAtIndex:i] codewordPosition:context.codewordCount + 1]]; + } +} + +- (unichar)randomize255State:(unichar)ch codewordPosition:(int)codewordPosition { + int pseudoRandom = ((149 * codewordPosition) % 255) + 1; + int tempVariable = ch + pseudoRandom; + if (tempVariable <= 255) { + return (unichar) tempVariable; + } else { + return (unichar) (tempVariable - 256); + } +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixC40Encoder.h b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixC40Encoder.h new file mode 100755 index 0000000..edc98ae --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixC40Encoder.h @@ -0,0 +1,25 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXDataMatrixEncoder.h" + +@interface ZXDataMatrixC40Encoder : NSObject + +- (int)encodeChar:(unichar)c buffer:(NSMutableString *)sb; +- (void)writeNextTriplet:(ZXDataMatrixEncoderContext *)context buffer:(NSMutableString *)buffer; +- (void)handleEOD:(ZXDataMatrixEncoderContext *)context buffer:(NSMutableString *)buffer; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixC40Encoder.m b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixC40Encoder.m new file mode 100755 index 0000000..4a72603 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixC40Encoder.m @@ -0,0 +1,181 @@ +/* + * Copyright 2013 9 authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXDataMatrixC40Encoder.h" +#import "ZXDataMatrixEncoderContext.h" +#import "ZXDataMatrixHighLevelEncoder.h" +#import "ZXDataMatrixSymbolInfo.h" + +@implementation ZXDataMatrixC40Encoder + +- (int)encodingMode { + return [ZXDataMatrixHighLevelEncoder c40Encodation]; +} + +- (void)encode:(ZXDataMatrixEncoderContext *)context { + //step C + NSMutableString *buffer = [NSMutableString string]; + while ([context hasMoreCharacters]) { + unichar c = [context currentChar]; + context.pos++; + + int lastCharSize = [self encodeChar:c buffer:buffer]; + + int unwritten = ((int)buffer.length / 3) * 2; + + int curCodewordCount = context.codewordCount + unwritten; + [context updateSymbolInfoWithLength:curCodewordCount]; + int available = context.symbolInfo.dataCapacity - curCodewordCount; + + if (![context hasMoreCharacters]) { + //Avoid having a single C40 value in the last triplet + NSMutableString *removed = [NSMutableString string]; + if ((buffer.length % 3) == 2) { + if (available < 2 || available > 2) { + lastCharSize = [self backtrackOneCharacter:context buffer:buffer removed:removed lastCharSize:lastCharSize]; + } + } + while ((buffer.length % 3) == 1 + && ((lastCharSize <= 3 && available != 1) || lastCharSize > 3)) { + lastCharSize = [self backtrackOneCharacter:context buffer:buffer removed:removed lastCharSize:lastCharSize]; + } + break; + } + + NSUInteger count = buffer.length; + if ((count % 3) == 0) { + int newMode = [ZXDataMatrixHighLevelEncoder lookAheadTest:context.message startpos:context.pos currentMode:[self encodingMode]]; + if (newMode != [self encodingMode]) { + [context signalEncoderChange:newMode]; + break; + } + } + } + [self handleEOD:context buffer:buffer]; +} + +- (int)backtrackOneCharacter:(ZXDataMatrixEncoderContext *)context buffer:(NSMutableString *)buffer + removed:(NSMutableString *)removed lastCharSize:(int)lastCharSize { + NSUInteger count = buffer.length; + [buffer deleteCharactersInRange:NSMakeRange(count - lastCharSize, lastCharSize)]; + context.pos--; + unichar c = context.currentChar; + lastCharSize = [self encodeChar:c buffer:removed]; + [context resetSymbolInfo]; //Deal with possible reduction in symbol size + return lastCharSize; +} + +- (void)writeNextTriplet:(ZXDataMatrixEncoderContext *)context buffer:(NSMutableString *)buffer { + [context writeCodewords:[self encodeToCodewords:buffer startpos:0]]; + [buffer deleteCharactersInRange:NSMakeRange(0, 3)]; +} + +/** + * Handle "end of data" situations + */ +- (void)handleEOD:(ZXDataMatrixEncoderContext *)context buffer:(NSMutableString *)buffer { + int unwritten = ((int)buffer.length / 3) * 2; + int rest = buffer.length % 3; + + int curCodewordCount = context.codewordCount + unwritten; + [context updateSymbolInfoWithLength:curCodewordCount]; + int available = context.symbolInfo.dataCapacity - curCodewordCount; + + if (rest == 2) { + [buffer appendString:@"\0"]; //Shift 1 + while (buffer.length >= 3) { + [self writeNextTriplet:context buffer:buffer]; + } + if ([context hasMoreCharacters]) { + [context writeCodeword:[ZXDataMatrixHighLevelEncoder c40Unlatch]]; + } + } else if (available == 1 && rest == 1) { + while (buffer.length >= 3) { + [self writeNextTriplet:context buffer:buffer]; + } + if ([context hasMoreCharacters]) { + [context writeCodeword:[ZXDataMatrixHighLevelEncoder c40Unlatch]]; + } + // else no latch + context.pos--; + } else if (rest == 0) { + while (buffer.length >= 3) { + [self writeNextTriplet:context buffer:buffer]; + } + if (available > 0 || [context hasMoreCharacters]) { + [context writeCodeword:[ZXDataMatrixHighLevelEncoder c40Unlatch]]; + } + } else { + @throw [NSException exceptionWithName:@"IllegalStateException" + reason:@"Unexpected case. Please report!" + userInfo:nil]; + } + [context signalEncoderChange:[ZXDataMatrixHighLevelEncoder asciiEncodation]]; +} + +- (int)encodeChar:(unichar)c buffer:(NSMutableString *)sb { + if (c == ' ') { + [sb appendString:@"\3"]; + return 1; + } else if (c >= '0' && c <= '9') { + [sb appendFormat:@"%C", (unichar) (c - 48 + 4)]; + return 1; + } else if (c >= 'A' && c <= 'Z') { + [sb appendFormat:@"%C", (unichar) (c - 65 + 14)]; + return 1; + } else if (c >= '\0' && c <= (unichar)0x001f) { + [sb appendString:@"\0"]; //Shift 1 Set + [sb appendFormat:@"%C", c]; + return 2; + } else if (c >= '!' && c <= '/') { + [sb appendString:@"\1"]; //Shift 2 Set + [sb appendFormat:@"%C", (unichar) (c - 33)]; + return 2; + } else if (c >= ':' && c <= '@') { + [sb appendString:@"\1"]; //Shift 2 Set + [sb appendFormat:@"%C", (unichar) (c - 58 + 15)]; + return 2; + } else if (c >= '[' && c <= '_') { + [sb appendString:@"\1"]; //Shift 2 Set + [sb appendFormat:@"%C", (unichar) (c - 91 + 22)]; + return 2; + } else if (c >= '\u0060' && c <= (unichar)0x007f) { + [sb appendString:@"\2"]; //Shift 3 Set + [sb appendFormat:@"%C", (unichar) (c - 96)]; + return 2; + } else if (c >= (unichar)0x0080) { + [sb appendFormat:@"\1%C", (unichar)0x001e]; //Shift 2, Upper Shift + int len = 2; + len += [self encodeChar:(unichar) (c - 128) buffer:sb]; + return len; + } else { + @throw [NSException exceptionWithName:@"IllegalStateException" + reason:[NSString stringWithFormat:@"Illegal character: %C", c] + userInfo:nil]; + } +} + +- (NSString *)encodeToCodewords:(NSString *)sb startpos:(int)startPos { + unichar c1 = [sb characterAtIndex:startPos]; + unichar c2 = [sb characterAtIndex:startPos + 1]; + unichar c3 = [sb characterAtIndex:startPos + 2]; + int v = (1600 * c1) + (40 * c2) + c3 + 1; + unichar cw1 = (unichar) (v / 256); + unichar cw2 = (unichar) (v % 256); + return [NSString stringWithFormat:@"%C%C", cw1, cw2]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixDefaultPlacement.h b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixDefaultPlacement.h new file mode 100755 index 0000000..a7e0fc7 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixDefaultPlacement.h @@ -0,0 +1,41 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Symbol Character Placement Program. Adapted from Annex M.1 in ISO/IEC 16022:2000(E). + */ +@interface ZXDataMatrixDefaultPlacement : NSObject + +@property (nonatomic, copy, readonly) NSString *codewords; +@property (nonatomic, assign, readonly) int numrows; +@property (nonatomic, assign, readonly) int numcols; +@property (nonatomic, assign, readonly) int8_t *bits; +@property (nonatomic, assign, readonly) int bitsLen; + +/** + * Main constructor + * + * @param codewords the codewords to place + * @param numcols the number of columns + * @param numrows the number of rows + */ +- (id)initWithCodewords:(NSString *)codewords numcols:(int)numcols numrows:(int)numrows; +- (BOOL)bitAtCol:(int)col row:(int)row; +- (void)setBitAtCol:(int)col row:(int)row bit:(BOOL)bit; +- (BOOL)hasBitAtCol:(int)col row:(int)row; +- (void)place; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixDefaultPlacement.m b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixDefaultPlacement.m new file mode 100755 index 0000000..5e1be92 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixDefaultPlacement.m @@ -0,0 +1,181 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXDataMatrixDefaultPlacement.h" + +@implementation ZXDataMatrixDefaultPlacement + +- (id)initWithCodewords:(NSString *)codewords numcols:(int)numcols numrows:(int)numrows { + if (self = [super init]) { + _codewords = [codewords copy]; + _numcols = numcols; + _numrows = numrows; + _bitsLen = numcols * numrows; + _bits = (int8_t *)malloc(_bitsLen * sizeof(int8_t)); + memset(_bits, -1, _bitsLen); //Initialize with "not set" value + } + + return self; +} + +- (void)dealloc { + if (_bits != NULL) { + free(_bits); + _bits = NULL; + } +} + +- (BOOL)bitAtCol:(int)col row:(int)row { + return self.bits[row * self.numcols + col] == 1; +} + +- (void)setBitAtCol:(int)col row:(int)row bit:(BOOL)bit { + self.bits[row * self.numcols + col] = bit ? (int8_t) 1 : (int8_t) 0; +} + +- (BOOL)hasBitAtCol:(int)col row:(int)row { + return self.bits[row * self.numcols + col] >= 0; +} + +- (void)place { + int pos = 0; + int row = 4; + int col = 0; + + do { + /* repeatedly first check for one of the special corner cases, then... */ + if ((row == self.numrows) && (col == 0)) { + [self corner1:pos++]; + } + if ((row == self.numrows - 2) && (col == 0) && ((self.numcols % 4) != 0)) { + [self corner2:pos++]; + } + if ((row == self.numrows - 2) && (col == 0) && (self.numcols % 8 == 4)) { + [self corner3:pos++]; + } + if ((row == self.numrows + 4) && (col == 2) && ((self.numcols % 8) == 0)) { + [self corner4:pos++]; + } + /* sweep upward diagonally, inserting successive characters... */ + do { + if ((row < self.numrows) && (col >= 0) && ![self hasBitAtCol:col row:row]) { + [self utahAtRow:row col:col pos:pos++]; + } + row -= 2; + col += 2; + } while (row >= 0 && (col < self.numcols)); + row++; + col += 3; + + /* and then sweep downward diagonally, inserting successive characters, ... */ + do { + if ((row >= 0) && (col < self.numcols) && ![self hasBitAtCol:col row:row]) { + [self utahAtRow:row col:col pos:pos++]; + } + row += 2; + col -= 2; + } while ((row < self.numrows) && (col >= 0)); + row += 3; + col++; + + /* ...until the entire array is scanned */ + } while ((row < self.numrows) || (col < self.numcols)); + + /* Lastly, if the lower righthand corner is untouched, fill in fixed pattern */ + if (![self hasBitAtCol:self.numcols - 1 row:self.numrows - 1]) { + [self setBitAtCol:self.numcols - 1 row:self.numrows - 1 bit:YES]; + [self setBitAtCol:self.numcols - 2 row:self.numrows - 2 bit:YES]; + } +} + +- (void)moduleAtRow:(int)row col:(int)col pos:(int)pos bit:(int)bit { + if (row < 0) { + row += self.numrows; + col += 4 - ((self.numrows + 4) % 8); + } + if (col < 0) { + col += self.numcols; + row += 4 - ((self.numcols + 4) % 8); + } + // Note the conversion: + int v = [self.codewords characterAtIndex:pos]; + v &= 1 << (8 - bit); + [self setBitAtCol:col row:row bit:v != 0]; +} + +/** + * Places the 8 bits of a utah-shaped symbol character in ECC200. + * + * @param row the row + * @param col the column + * @param pos character position + */ +- (void)utahAtRow:(int)row col:(int)col pos:(int)pos { + [self moduleAtRow:row - 2 col:col - 2 pos:pos bit:1]; + [self moduleAtRow:row - 2 col:col - 1 pos:pos bit:2]; + [self moduleAtRow:row - 1 col:col - 2 pos:pos bit:3]; + [self moduleAtRow:row - 1 col:col - 1 pos:pos bit:4]; + [self moduleAtRow:row - 1 col:col pos:pos bit:5]; + [self moduleAtRow:row col:col - 2 pos:pos bit:6]; + [self moduleAtRow:row col:col - 1 pos:pos bit:7]; + [self moduleAtRow:row col:col pos:pos bit:8]; +} + +- (void)corner1:(int)pos { + [self moduleAtRow:self.numrows - 1 col:0 pos:pos bit:1]; + [self moduleAtRow:self.numrows - 1 col:1 pos:pos bit:2]; + [self moduleAtRow:self.numrows - 1 col:2 pos:pos bit:3]; + [self moduleAtRow:0 col:self.numcols - 2 pos:pos bit:4]; + [self moduleAtRow:0 col:self.numcols - 1 pos:pos bit:5]; + [self moduleAtRow:1 col:self.numcols - 1 pos:pos bit:6]; + [self moduleAtRow:2 col:self.numcols - 1 pos:pos bit:7]; + [self moduleAtRow:3 col:self.numcols - 1 pos:pos bit:8]; +} + +- (void)corner2:(int)pos { + [self moduleAtRow:self.numrows - 3 col:0 pos:pos bit:1]; + [self moduleAtRow:self.numrows - 2 col:0 pos:pos bit:2]; + [self moduleAtRow:self.numrows - 1 col:0 pos:pos bit:3]; + [self moduleAtRow:0 col:self.numcols - 4 pos:pos bit:4]; + [self moduleAtRow:0 col:self.numcols - 3 pos:pos bit:5]; + [self moduleAtRow:0 col:self.numcols - 2 pos:pos bit:6]; + [self moduleAtRow:0 col:self.numcols - 1 pos:pos bit:7]; + [self moduleAtRow:1 col:self.numcols - 1 pos:pos bit:8]; +} + +- (void)corner3:(int)pos { + [self moduleAtRow:self.numrows - 3 col:0 pos:pos bit:1]; + [self moduleAtRow:self.numrows - 2 col:0 pos:pos bit:2]; + [self moduleAtRow:self.numrows - 1 col:0 pos:pos bit:3]; + [self moduleAtRow:0 col:self.numcols - 2 pos:pos bit:4]; + [self moduleAtRow:0 col:self.numcols - 1 pos:pos bit:5]; + [self moduleAtRow:1 col:self.numcols - 1 pos:pos bit:6]; + [self moduleAtRow:2 col:self.numcols - 1 pos:pos bit:7]; + [self moduleAtRow:3 col:self.numcols - 1 pos:pos bit:8]; +} + +- (void)corner4:(int)pos { + [self moduleAtRow:self.numrows - 1 col:0 pos:pos bit:1]; + [self moduleAtRow:self.numrows - 1 col:self.numcols - 1 pos:pos bit:2]; + [self moduleAtRow:0 col:self.numcols - 3 pos:pos bit:3]; + [self moduleAtRow:0 col:self.numcols - 2 pos:pos bit:4]; + [self moduleAtRow:0 col:self.numcols - 1 pos:pos bit:5]; + [self moduleAtRow:1 col:self.numcols - 3 pos:pos bit:6]; + [self moduleAtRow:1 col:self.numcols - 2 pos:pos bit:7]; + [self moduleAtRow:1 col:self.numcols - 1 pos:pos bit:8]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixEdifactEncoder.h b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixEdifactEncoder.h new file mode 100755 index 0000000..20eea46 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixEdifactEncoder.h @@ -0,0 +1,21 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXDataMatrixEncoder.h" + +@interface ZXDataMatrixEdifactEncoder : NSObject + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixEdifactEncoder.m b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixEdifactEncoder.m new file mode 100755 index 0000000..81c5009 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixEdifactEncoder.m @@ -0,0 +1,142 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXDataMatrixEdifactEncoder.h" +#import "ZXDataMatrixEncoderContext.h" +#import "ZXDataMatrixHighLevelEncoder.h" +#import "ZXDataMatrixSymbolInfo.h" + +@implementation ZXDataMatrixEdifactEncoder + +- (int)encodingMode { + return [ZXDataMatrixHighLevelEncoder edifactEncodation]; +} + +- (void)encode:(ZXDataMatrixEncoderContext *)context { + //step F + NSMutableString *buffer = [NSMutableString string]; + while ([context hasMoreCharacters]) { + unichar c = [context currentChar]; + [self encodeChar:c buffer:buffer]; + context.pos++; + + NSUInteger count = buffer.length; + if (count >= 4) { + [context writeCodewords:[self encodeToCodewords:buffer startpos:0]]; + [buffer deleteCharactersInRange:NSMakeRange(0, 4)]; + + int newMode = [ZXDataMatrixHighLevelEncoder lookAheadTest:context.message startpos:context.pos currentMode:[self encodingMode]]; + if (newMode != [self encodingMode]) { + [context signalEncoderChange:[ZXDataMatrixHighLevelEncoder asciiEncodation]]; + break; + } + } + } + [buffer appendFormat:@"%C", (unichar) 31]; //Unlatch + [self handleEOD:context buffer:buffer]; +} + +/** + * Handle "end of data" situations + * + * @param context the encoder context + * @param buffer the buffer with the remaining encoded characters + */ +- (void)handleEOD:(ZXDataMatrixEncoderContext *)context buffer:(NSMutableString *)buffer { + @try { + NSUInteger count = buffer.length; + if (count == 0) { + return; //Already finished + } + if (count == 1) { + //Only an unlatch at the end + [context updateSymbolInfo]; + int available = context.symbolInfo.dataCapacity - context.codewordCount; + int remaining = [context remainingCharacters]; + if (remaining == 0 && available <= 2) { + return; //No unlatch + } + } + + if (count > 4) { + @throw [NSException exceptionWithName:@"IllegalStateException" + reason:@"Count must not exceed 4" + userInfo:nil]; + } + int restChars = (int)count - 1; + NSString *encoded = [self encodeToCodewords:buffer startpos:0]; + BOOL endOfSymbolReached = ![context hasMoreCharacters]; + BOOL restInAscii = endOfSymbolReached && restChars <= 2; + + if (restChars <= 2) { + [context updateSymbolInfoWithLength:context.codewordCount + restChars]; + int available = context.symbolInfo.dataCapacity - context.codewordCount; + if (available >= 3) { + restInAscii = NO; + [context updateSymbolInfoWithLength:context.codewordCount + (int)encoded.length]; + //available = context.symbolInfo.dataCapacity - context.codewordCount; + } + } + + if (restInAscii) { + [context resetSymbolInfo]; + context.pos -= restChars; + } else { + [context writeCodewords:encoded]; + } + } @finally { + [context signalEncoderChange:[ZXDataMatrixHighLevelEncoder asciiEncodation]]; + } +} + +- (void)encodeChar:(unichar)c buffer:(NSMutableString *)sb { + if (c >= ' ' && c <= '?') { + [sb appendFormat:@"%C", c]; + } else if (c >= '@' && c <= '^') { + [sb appendFormat:@"%C", (unichar) (c - 64)]; + } else { + [ZXDataMatrixHighLevelEncoder illegalCharacter:c]; + } +} + +- (NSString *)encodeToCodewords:(NSMutableString *)sb startpos:(int)startPos { + int len = (int)sb.length - startPos; + if (len == 0) { + @throw [NSException exceptionWithName:@"IllegalStateException" + reason:@"Buffer must not be empty" + userInfo:nil]; + } + unichar c1 = [sb characterAtIndex:startPos]; + unichar c2 = len >= 2 ? [sb characterAtIndex:startPos + 1] : 0; + unichar c3 = len >= 3 ? [sb characterAtIndex:startPos + 2] : 0; + unichar c4 = len >= 4 ? [sb characterAtIndex:startPos + 3] : 0; + + int v = (c1 << 18) + (c2 << 12) + (c3 << 6) + c4; + unichar cw1 = (unichar) ((v >> 16) & 255); + unichar cw2 = (unichar) ((v >> 8) & 255); + unichar cw3 = (unichar) (v & 255); + NSMutableString *res = [NSMutableString stringWithCapacity:3]; + [res appendFormat:@"%C", cw1]; + if (len >= 2) { + [res appendFormat:@"%C", cw2]; + } + if (len >= 3) { + [res appendFormat:@"%C", cw3]; + } + return [NSString stringWithString:res]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixEncoder.h b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixEncoder.h new file mode 100755 index 0000000..4d3c63d --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixEncoder.h @@ -0,0 +1,24 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXDataMatrixEncoderContext; + +@protocol ZXDataMatrixEncoder + +- (int)encodingMode; +- (void)encode:(ZXDataMatrixEncoderContext *)context; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixEncoderContext.h b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixEncoderContext.h new file mode 100755 index 0000000..719a97d --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixEncoderContext.h @@ -0,0 +1,48 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXEncodeHints.h" + +@class ZXDataMatrixSymbolInfo, ZXDimension; + +@interface ZXDataMatrixEncoderContext : NSObject + +@property (nonatomic, copy, readonly) NSMutableString *codewords; +@property (nonatomic, copy, readonly) NSString *message; +@property (nonatomic, assign) int newEncoding; +@property (nonatomic, assign) int pos; +@property (nonatomic, assign) int skipAtEnd; +@property (nonatomic, assign) ZXDataMatrixSymbolShapeHint symbolShape; +@property (nonatomic, strong) ZXDataMatrixSymbolInfo *symbolInfo; + +- (id)initWithMessage:(NSString *)msg; +- (void)setSizeConstraints:(ZXDimension *)minSize maxSize:(ZXDimension *)maxSize; +- (void)setSkipAtEnd:(int)count; +- (unichar)currentChar; +- (unichar)current; +- (void)writeCodewords:(NSString *)codewords; +- (void)writeCodeword:(unichar)codeword; +- (int)codewordCount; +- (void)signalEncoderChange:(int)encoding; +- (void)resetEncoderSignal; +- (BOOL)hasMoreCharacters; +- (int)totalMessageCharCount; +- (int)remainingCharacters; +- (void)updateSymbolInfo; +- (void)updateSymbolInfoWithLength:(int)len; +- (void)resetSymbolInfo; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixEncoderContext.m b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixEncoderContext.m new file mode 100755 index 0000000..5e699af --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixEncoderContext.m @@ -0,0 +1,111 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXDataMatrixEncoderContext.h" +#import "ZXDataMatrixSymbolInfo.h" + +@interface ZXDataMatrixEncoderContext () + +@property (nonatomic, strong) ZXDimension *maxSize; +@property (nonatomic, strong) ZXDimension *minSize; + +@end + +@implementation ZXDataMatrixEncoderContext + +- (id)initWithMessage:(NSString *)msg { + if (self = [super init]) { + //From this point on Strings are not Unicode anymore! + NSData *msgData = [msg dataUsingEncoding:NSISOLatin1StringEncoding]; + if (!msgData) { + [NSException raise:NSInvalidArgumentException format:@"Message contains characters outside ISO-8859-1 encoding."]; + } + const char *msgBinary = [msgData bytes]; + NSMutableString *sb = [NSMutableString string]; + for (int i = 0, c = (int)msg.length; i < c; i++) { + unichar ch = (unichar) (msgBinary[i] & 0xff); + [sb appendFormat:@"%C", ch]; + } + + _message = [[NSString alloc] initWithString:sb]; + _symbolShape = ZXDataMatrixSymbolShapeHintForceNone; + _codewords = [[NSMutableString alloc] initWithCapacity:msg.length]; + _newEncoding = -1; + } + + return self; +} + +- (void)setSizeConstraints:(ZXDimension *)minSize maxSize:(ZXDimension *)maxSize { + self.minSize = minSize; + self.maxSize = maxSize; +} + +- (unichar)currentChar { + return [self.message characterAtIndex:self.pos]; +} + +- (unichar)current { + return [self.message characterAtIndex:self.pos]; +} + +- (void)writeCodewords:(NSString *)codewords { + [self.codewords appendString:codewords]; +} + +- (void)writeCodeword:(unichar)codeword { + [self.codewords appendFormat:@"%C", codeword]; +} + +- (int)codewordCount { + return (int)self.codewords.length; +} + +- (void)signalEncoderChange:(int)encoding { + self.newEncoding = encoding; +} + +- (void)resetEncoderSignal { + self.newEncoding = -1; +} + +- (BOOL)hasMoreCharacters { + return self.pos < [self totalMessageCharCount]; +} + +- (int)totalMessageCharCount { + return (int)self.message.length - self.skipAtEnd; +} + +- (int)remainingCharacters { + return [self totalMessageCharCount] - self.pos; +} + +- (void)updateSymbolInfo { + [self updateSymbolInfoWithLength:[self codewordCount]]; +} + +- (void)updateSymbolInfoWithLength:(int)len { + if (self.symbolInfo == nil || len > self.symbolInfo.dataCapacity) { + self.symbolInfo = [ZXDataMatrixSymbolInfo lookup:len shape:self.symbolShape minSize:self.minSize maxSize:self.maxSize fail:YES]; + } +} + +- (void)resetSymbolInfo { + self.symbolInfo = nil; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixErrorCorrection.h b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixErrorCorrection.h new file mode 100755 index 0000000..d93d3fd --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixErrorCorrection.h @@ -0,0 +1,33 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXDataMatrixSymbolInfo; + +/** + * Error Correction Code for ECC200. + */ +@interface ZXDataMatrixErrorCorrection : NSObject + +/** + * Creates the ECC200 error correction for an encoded message. + * + * @param codewords the codewords + * @param symbolInfo information about the symbol to be encoded + * @return the codewords with interleaved error correction. + */ ++ (NSString *)encodeECC200:(NSString *)codewords symbolInfo:(ZXDataMatrixSymbolInfo *)symbolInfo; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixErrorCorrection.m b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixErrorCorrection.m new file mode 100755 index 0000000..6c9f658 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixErrorCorrection.m @@ -0,0 +1,171 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXDataMatrixErrorCorrection.h" +#import "ZXDataMatrixSymbolInfo.h" + +/** + * Lookup table which factors to use for which number of error correction codewords. + * See FACTORS. + */ +const int ZX_FACTOR_SETS[] = {5, 7, 10, 11, 12, 14, 18, 20, 24, 28, 36, 42, 48, 56, 62, 68}; + +/** + * Precomputed polynomial factors for ECC 200. + */ +const int ZX_FACTORS[16][68] = { + {228, 48, 15, 111, 62}, + {23, 68, 144, 134, 240, 92, 254}, + {28, 24, 185, 166, 223, 248, 116, 255, 110, 61}, + {175, 138, 205, 12, 194, 168, 39, 245, 60, 97, 120}, + {41, 153, 158, 91, 61, 42, 142, 213, 97, 178, 100, 242}, + {156, 97, 192, 252, 95, 9, 157, 119, 138, 45, 18, 186, 83, 185}, + {83, 195, 100, 39, 188, 75, 66, 61, 241, 213, 109, 129, 94, 254, 225, 48, 90, 188}, + {15, 195, 244, 9, 233, 71, 168, 2, 188, 160, 153, 145, 253, 79, 108, 82, 27, 174, 186, 172}, + {52, 190, 88, 205, 109, 39, 176, 21, 155, 197, 251, 223, 155, 21, 5, 172, + 254, 124, 12, 181, 184, 96, 50, 193}, + {211, 231, 43, 97, 71, 96, 103, 174, 37, 151, 170, 53, 75, 34, 249, 121, + 17, 138, 110, 213, 141, 136, 120, 151, 233, 168, 93, 255}, + {245, 127, 242, 218, 130, 250, 162, 181, 102, 120, 84, 179, 220, 251, 80, 182, + 229, 18, 2, 4, 68, 33, 101, 137, 95, 119, 115, 44, 175, 184, 59, 25, + 225, 98, 81, 112}, + {77, 193, 137, 31, 19, 38, 22, 153, 247, 105, 122, 2, 245, 133, 242, 8, + 175, 95, 100, 9, 167, 105, 214, 111, 57, 121, 21, 1, 253, 57, 54, 101, + 248, 202, 69, 50, 150, 177, 226, 5, 9, 5}, + {245, 132, 172, 223, 96, 32, 117, 22, 238, 133, 238, 231, 205, 188, 237, 87, + 191, 106, 16, 147, 118, 23, 37, 90, 170, 205, 131, 88, 120, 100, 66, 138, + 186, 240, 82, 44, 176, 87, 187, 147, 160, 175, 69, 213, 92, 253, 225, 19}, + {175, 9, 223, 238, 12, 17, 220, 208, 100, 29, 175, 170, 230, 192, 215, 235, + 150, 159, 36, 223, 38, 200, 132, 54, 228, 146, 218, 234, 117, 203, 29, 232, + 144, 238, 22, 150, 201, 117, 62, 207, 164, 13, 137, 245, 127, 67, 247, 28, + 155, 43, 203, 107, 233, 53, 143, 46}, + {242, 93, 169, 50, 144, 210, 39, 118, 202, 188, 201, 189, 143, 108, 196, 37, + 185, 112, 134, 230, 245, 63, 197, 190, 250, 106, 185, 221, 175, 64, 114, 71, + 161, 44, 147, 6, 27, 218, 51, 63, 87, 10, 40, 130, 188, 17, 163, 31, + 176, 170, 4, 107, 232, 7, 94, 166, 224, 124, 86, 47, 11, 204}, + {220, 228, 173, 89, 251, 149, 159, 56, 89, 33, 147, 244, 154, 36, 73, 127, + 213, 136, 248, 180, 234, 197, 158, 177, 68, 122, 93, 213, 15, 160, 227, 236, + 66, 139, 153, 185, 202, 167, 179, 25, 220, 232, 96, 210, 231, 136, 223, 239, + 181, 241, 59, 52, 172, 25, 49, 232, 211, 189, 64, 54, 108, 153, 132, 63, + 96, 103, 82, 186}}; + +const int ZX_MODULO_VALUE = 0x12D; + +static int ZX_LOG[256], ZX_ALOG[256]; + +@implementation ZXDataMatrixErrorCorrection + ++ (void)initialize { + if ([self class] != [ZXDataMatrixErrorCorrection class]) return; + + //Create log and antilog table + int p = 1; + for (int i = 0; i < 255; i++) { + ZX_ALOG[i] = p; + ZX_LOG[p] = i; + p *= 2; + if (p >= 256) { + p ^= ZX_MODULO_VALUE; + } + } +} + ++ (NSString *)encodeECC200:(NSString *)codewords symbolInfo:(ZXDataMatrixSymbolInfo *)symbolInfo { + if (codewords.length != symbolInfo.dataCapacity) { + [NSException raise:NSInvalidArgumentException format:@"The number of codewords does not match the selected symbol"]; + } + NSUInteger capacity = symbolInfo.dataCapacity + symbolInfo.errorCodewords; + NSMutableString *sb = [NSMutableString stringWithCapacity:capacity]; + [sb appendString:codewords]; + int blockCount = symbolInfo.interleavedBlockCount; + if (blockCount == 1) { + NSString *ecc = [self createECCBlock:codewords numECWords:symbolInfo.errorCodewords]; + [sb appendString:ecc]; + } else { + if (sb.length > capacity) { + [sb deleteCharactersInRange:NSMakeRange(capacity, sb.length - capacity)]; + } + while (sb.length < capacity) { + [sb appendFormat:@"%C", (unichar)0]; + } + int dataSizes[blockCount]; + int errorSizes[blockCount]; + int startPos[blockCount]; + for (int i = 0; i < blockCount; i++) { + dataSizes[i] = [symbolInfo dataLengthForInterleavedBlock:i + 1]; + errorSizes[i] = [symbolInfo errorLengthForInterleavedBlock:i + 1]; + startPos[i] = 0; + if (i > 0) { + startPos[i] = startPos[i - 1] + dataSizes[i]; + } + } + for (int block = 0; block < blockCount; block++) { + NSMutableString *temp = [NSMutableString stringWithCapacity:dataSizes[block]]; + for (int d = block; d < symbolInfo.dataCapacity; d += blockCount) { + [temp appendFormat:@"%c", [codewords characterAtIndex:d]]; + } + NSString *ecc = [self createECCBlock:temp numECWords:errorSizes[block]]; + int pos = 0; + for (int e = block; e < errorSizes[block] * blockCount; e += blockCount) { + [sb replaceCharactersInRange:NSMakeRange(symbolInfo.dataCapacity + e, 1) + withString:[ecc substringWithRange:NSMakeRange(pos++, 1)]]; + } + } + } + return [NSString stringWithString:sb]; +} + ++ (NSString *)createECCBlock:(NSString *)codewords numECWords:(int)numECWords { + return [self createECCBlock:codewords start:0 len:(int)codewords.length numECWords:numECWords]; +} + ++ (NSString *)createECCBlock:(NSString *)codewords start:(int)start len:(int)len numECWords:(int)numECWords { + int table = -1; + for (int i = 0; i < sizeof(ZX_FACTOR_SETS) / sizeof(int); i++) { + if (ZX_FACTOR_SETS[i] == numECWords) { + table = i; + break; + } + } + if (table < 0) { + [NSException raise:NSInvalidArgumentException format:@"Illegal number of error correction codewords specified: %d", numECWords]; + } + int *poly = (int *)ZX_FACTORS[table]; + unichar ecc[numECWords]; + memset(ecc, 0, numECWords * sizeof(unichar)); + for (int i = start; i < start + len; i++) { + int m = ecc[numECWords - 1] ^ [codewords characterAtIndex:i]; + for (int k = numECWords - 1; k > 0; k--) { + if (m != 0 && poly[k] != 0) { + ecc[k] = (unichar) (ecc[k - 1] ^ ZX_ALOG[(ZX_LOG[m] + ZX_LOG[poly[k]]) % 255]); + } else { + ecc[k] = ecc[k - 1]; + } + } + if (m != 0 && poly[0] != 0) { + ecc[0] = (unichar) ZX_ALOG[(ZX_LOG[m] + ZX_LOG[poly[0]]) % 255]; + } else { + ecc[0] = 0; + } + } + unichar eccReversed[numECWords]; + for (int i = 0; i < numECWords; i++) { + eccReversed[i] = ecc[numECWords - i - 1]; + } + return [NSString stringWithCharacters:eccReversed length:numECWords]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixHighLevelEncoder.h b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixHighLevelEncoder.h new file mode 100755 index 0000000..1273030 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixHighLevelEncoder.h @@ -0,0 +1,135 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXEncodeHints.h" + +@class ZXDimension; + +/** + * DataMatrix ECC 200 data encoder following the algorithm described in ISO/IEC 16022:200(E) in + * annex S. + */ +@interface ZXDataMatrixHighLevelEncoder : NSObject + +/** + * mode latch to C40 encodation mode + */ ++ (unichar)latchToC40; + +/** + * mode latch to Base 256 encodation mode + */ ++ (unichar)latchToBase256; + +/** + * Upper Shift + */ ++ (unichar)upperShift; + +/** + * 05 Macro + */ ++ (unichar)macro05; + +/** + * 06 Macro + */ ++ (unichar)macro06; + +/** + * mode latch to ANSI X.12 encodation mode + */ ++ (unichar)latchToAnsiX12; + +/** + * mode latch to Text encodation mode + */ + ++ (unichar)latchToText; + +/** + * mode latch to EDIFACT encodation mode + */ ++ (unichar)latchToEdifact; + +/** + * Unlatch from C40 encodation + */ ++ (unichar)c40Unlatch; + +/** + * Unlatch from X12 encodation + */ ++ (unichar)x12Unlatch; + ++ (int)asciiEncodation; ++ (int)c40Encodation; ++ (int)textEncodation; ++ (int)x12Encodation; ++ (int)edifactEncodation; ++ (int)base256Encodation; + +/* + * Converts the message to a byte array using the default encoding (cp437) as defined by the + * specification + * + * @param msg the message + * @return the byte array of the message + */ + +/* ++ (int8_t *)bytesForMessage:(NSString *)msg; +*/ + +/** + * Performs message encoding of a DataMatrix message using the algorithm described in annex P + * of ISO/IEC 16022:2000(E). + * + * @param msg the message + * @return the encoded message (the char values range from 0 to 255) + */ ++ (NSString *)encodeHighLevel:(NSString *)msg; + +/** + * Performs message encoding of a DataMatrix message using the algorithm described in annex P + * of ISO/IEC 16022:2000(E). + * + * @param msg the message + * @param shape requested shape. May be {@code SymbolShapeHint.FORCE_NONE}, + * {@code SymbolShapeHint.FORCE_SQUARE} or {@code SymbolShapeHint.FORCE_RECTANGLE}. + * @param minSize the minimum symbol size constraint or null for no constraint + * @param maxSize the maximum symbol size constraint or null for no constraint + * @return the encoded message (the char values range from 0 to 255) + */ ++ (NSString *)encodeHighLevel:(NSString *)msg shape:(ZXDataMatrixSymbolShapeHint)shape + minSize:(ZXDimension *)minSize maxSize:(ZXDimension *)maxSize; + ++ (int)lookAheadTest:(NSString *)msg startpos:(int)startpos currentMode:(int)currentMode; + +/** + * Determines the number of consecutive characters that are encodable using numeric compaction. + * + * @param msg the message + * @param startpos the start position within the message + * @return the requested character count + */ ++ (int)determineConsecutiveDigitCount:(NSString *)msg startpos:(int)startpos; + ++ (BOOL)isDigit:(unichar)ch; ++ (BOOL)isExtendedASCII:(unichar)ch; ++ (void)illegalCharacter:(unichar)c; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixHighLevelEncoder.m b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixHighLevelEncoder.m new file mode 100755 index 0000000..b323d23 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixHighLevelEncoder.m @@ -0,0 +1,431 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXDataMatrixASCIIEncoder.h" +#import "ZXDataMatrixBase256Encoder.h" +#import "ZXDataMatrixC40Encoder.h" +#import "ZXDataMatrixEdifactEncoder.h" +#import "ZXDataMatrixEncoderContext.h" +#import "ZXDataMatrixHighLevelEncoder.h" +#import "ZXDataMatrixSymbolInfo.h" +#import "ZXDataMatrixTextEncoder.h" +#import "ZXDataMatrixX12Encoder.h" + +/** + * Padding character + */ +const unichar PAD_CHAR = 129; + +/** + * 05 Macro header + */ +static NSString *MACRO_05_HEADER = nil; + +/** + * 06 Macro header + */ +static NSString *MACRO_06_HEADER = nil; + +/** + * Macro trailer + */ +static NSString *MACRO_TRAILER = nil; + +@implementation ZXDataMatrixHighLevelEncoder + ++ (void)initialize { + if ([self class] != [ZXDataMatrixHighLevelEncoder class]) return; + + MACRO_05_HEADER = [[NSString alloc] initWithFormat:@"[)>%C05%C", (unichar)0x001E, (unichar)0x001D]; + MACRO_06_HEADER = [[NSString alloc] initWithFormat:@"[)>%C06%C", (unichar)0x001E, (unichar)0x001D]; + MACRO_TRAILER = [[NSString alloc] initWithFormat:@"%C%C", (unichar)0x001E, (unichar)0x0004]; +} + ++ (unichar)latchToC40 { + return 230; +} + ++ (unichar)latchToBase256 { + return 231; +} + ++ (unichar)upperShift { + return 235; +} + ++ (unichar)macro05 { + return 236; +} + ++ (unichar)macro06 { + return 237; +} + ++ (unichar)latchToAnsiX12 { + return 238; +} + ++ (unichar)latchToText { + return 239; +} + ++ (unichar)latchToEdifact { + return 240; +} + ++ (unichar)c40Unlatch { + return 254; +} + ++ (unichar)x12Unlatch { + return 254; +} + ++ (int)asciiEncodation { + return 0; +} + ++ (int)c40Encodation { + return 1; +} + ++ (int)textEncodation { + return 2; +} + ++ (int)x12Encodation { + return 3; +} + ++ (int)edifactEncodation { + return 4; +} + ++ (int)base256Encodation { + return 5; +} + +/* ++ (int8_t *)bytesForMessage:(NSString *)msg { + return (int8_t *)[[msg dataUsingEncoding:(NSStringEncoding) 0x80000400] bytes]; //See 4.4.3 and annex B of ISO/IEC 15438:2001(E) +} +*/ + ++ (unichar)randomize253State:(unichar)ch codewordPosition:(int)codewordPosition { + int pseudoRandom = ((149 * codewordPosition) % 253) + 1; + int tempVariable = ch + pseudoRandom; + return tempVariable <= 254 ? (unichar) tempVariable : (unichar) (tempVariable - 254); +} + ++ (NSString *)encodeHighLevel:(NSString *)msg { + return [self encodeHighLevel:msg shape:ZXDataMatrixSymbolShapeHintForceNone minSize:nil maxSize:nil]; +} + ++ (NSString *)encodeHighLevel:(NSString *)msg shape:(ZXDataMatrixSymbolShapeHint)shape + minSize:(ZXDimension *)minSize maxSize:(ZXDimension *)maxSize { + //the codewords 0..255 are encoded as Unicode characters + NSArray *encoders = @[[[ZXDataMatrixASCIIEncoder alloc] init], + [[ZXDataMatrixC40Encoder alloc] init], + [[ZXDataMatrixTextEncoder alloc] init], + [[ZXDataMatrixX12Encoder alloc] init], + [[ZXDataMatrixEdifactEncoder alloc] init], + [[ZXDataMatrixBase256Encoder alloc] init]]; + + ZXDataMatrixEncoderContext *context = [[ZXDataMatrixEncoderContext alloc] initWithMessage:msg]; + context.symbolShape = shape; + [context setSizeConstraints:minSize maxSize:maxSize]; + + if ([msg hasPrefix:MACRO_05_HEADER] && [msg hasSuffix:MACRO_TRAILER]) { + [context writeCodeword:[self macro05]]; + [context setSkipAtEnd:2]; + context.pos += (int)MACRO_05_HEADER.length; + } else if ([msg hasPrefix:MACRO_06_HEADER] && [msg hasSuffix:MACRO_TRAILER]) { + [context writeCodeword:[self macro06]]; + [context setSkipAtEnd:2]; + context.pos += (int)MACRO_06_HEADER.length; + } + + int encodingMode = [self asciiEncodation]; //Default mode + while ([context hasMoreCharacters]) { + [encoders[encodingMode] encode:context]; + if (context.newEncoding >= 0) { + encodingMode = context.newEncoding; + [context resetEncoderSignal]; + } + } + NSUInteger len = context.codewords.length; + [context updateSymbolInfo]; + int capacity = context.symbolInfo.dataCapacity; + if (len < capacity) { + if (encodingMode != [self asciiEncodation] && encodingMode != [self base256Encodation]) { + [context writeCodeword:(unichar)0x00fe]; //Unlatch (254) + } + } + //Padding + NSMutableString *codewords = context.codewords; + if (codewords.length < capacity) { + [codewords appendFormat:@"%C", PAD_CHAR]; + } + while (codewords.length < capacity) { + [codewords appendFormat:@"%C", [self randomize253State:PAD_CHAR codewordPosition:(int)codewords.length + 1]]; + } + + return [NSString stringWithString:context.codewords]; +} + ++ (int)lookAheadTest:(NSString *)msg startpos:(int)startpos currentMode:(int)currentMode { + if (startpos >= msg.length) { + return currentMode; + } + float charCounts[6]; + //step J + if (currentMode == [self asciiEncodation]) { + charCounts[0] = 0; + charCounts[1] = 1; + charCounts[2] = 1; + charCounts[3] = 1; + charCounts[4] = 1; + charCounts[5] = 1.25f; + } else { + charCounts[0] = 1; + charCounts[1] = 2; + charCounts[2] = 2; + charCounts[3] = 2; + charCounts[4] = 2; + charCounts[5] = 2.25f; + charCounts[currentMode] = 0; + } + + int charsProcessed = 0; + while (YES) { + //step K + if ((startpos + charsProcessed) == msg.length) { + int min = INT_MAX; + int8_t mins[6]; + int intCharCounts[6]; + min = [self findMinimums:charCounts intCharCounts:intCharCounts min:min mins:mins]; + int minCount = [self minimumCount:mins]; + + if (intCharCounts[[self asciiEncodation]] == min) { + return [self asciiEncodation]; + } + if (minCount == 1 && mins[[self base256Encodation]] > 0) { + return [self base256Encodation]; + } + if (minCount == 1 && mins[[self edifactEncodation]] > 0) { + return [self edifactEncodation]; + } + if (minCount == 1 && mins[[self textEncodation]] > 0) { + return [self textEncodation]; + } + if (minCount == 1 && mins[[self x12Encodation]] > 0) { + return [self x12Encodation]; + } + return [self c40Encodation]; + } + + unichar c = [msg characterAtIndex:startpos + charsProcessed]; + charsProcessed++; + + //step L + if ([self isDigit:c]) { + charCounts[[self asciiEncodation]] += 0.5; + } else if ([self isExtendedASCII:c]) { + charCounts[[self asciiEncodation]] = (int) ceil(charCounts[[self asciiEncodation]]); + charCounts[[self asciiEncodation]] += 2; + } else { + charCounts[[self asciiEncodation]] = (int) ceil(charCounts[[self asciiEncodation]]); + charCounts[[self asciiEncodation]]++; + } + + //step M + if ([self isNativeC40:c]) { + charCounts[[self c40Encodation]] += 2.0f / 3.0f; + } else if ([self isExtendedASCII:c]) { + charCounts[[self c40Encodation]] += 8.0f / 3.0f; + } else { + charCounts[[self c40Encodation]] += 4.0f / 3.0f; + } + + //step N + if ([self isNativeText:c]) { + charCounts[[self textEncodation]] += 2.0f / 3.0f; + } else if ([self isExtendedASCII:c]) { + charCounts[[self textEncodation]] += 8.0f / 3.0f; + } else { + charCounts[[self textEncodation]] += 4.0f / 3.0f; + } + + //step O + if ([self isNativeX12:c]) { + charCounts[[self x12Encodation]] += 2.0f / 3.0f; + } else if ([self isExtendedASCII:c]) { + charCounts[[self x12Encodation]] += 13.0f / 3.0f; + } else { + charCounts[[self x12Encodation]] += 10.0f / 3.0f; + } + + //step P + if ([self isNativeEDIFACT:c]) { + charCounts[[self edifactEncodation]] += 3.0f / 4.0f; + } else if ([self isExtendedASCII:c]) { + charCounts[[self edifactEncodation]] += 17.0f / 4.0f; + } else { + charCounts[[self edifactEncodation]] += 13.0f / 4.0f; + } + + // step Q + if ([self isSpecialB256:c]) { + charCounts[[self base256Encodation]] += 4; + } else { + charCounts[[self base256Encodation]]++; + } + + //step R + if (charsProcessed >= 4) { + int intCharCounts[6]; + int8_t mins[6]; + [self findMinimums:charCounts intCharCounts:intCharCounts min:INT_MAX mins:mins]; + int minCount = [self minimumCount:mins]; + + if (intCharCounts[[self asciiEncodation]] < intCharCounts[[self base256Encodation]] + && intCharCounts[[self asciiEncodation]] < intCharCounts[[self c40Encodation]] + && intCharCounts[[self asciiEncodation]] < intCharCounts[[self textEncodation]] + && intCharCounts[[self asciiEncodation]] < intCharCounts[[self x12Encodation]] + && intCharCounts[[self asciiEncodation]] < intCharCounts[[self edifactEncodation]]) { + return [self asciiEncodation]; + } + if (intCharCounts[[self base256Encodation]] < intCharCounts[[self asciiEncodation]] + || (mins[[self c40Encodation]] + mins[[self textEncodation]] + mins[[self x12Encodation]] + mins[[self edifactEncodation]]) == 0) { + return [self base256Encodation]; + } + if (minCount == 1 && mins[[self edifactEncodation]] > 0) { + return [self edifactEncodation]; + } + if (minCount == 1 && mins[[self textEncodation]] > 0) { + return [self textEncodation]; + } + if (minCount == 1 && mins[[self x12Encodation]] > 0) { + return [self x12Encodation]; + } + if (intCharCounts[[self c40Encodation]] + 1 < intCharCounts[[self asciiEncodation]] + && intCharCounts[[self c40Encodation]] + 1 < intCharCounts[[self base256Encodation]] + && intCharCounts[[self c40Encodation]] + 1 < intCharCounts[[self edifactEncodation]] + && intCharCounts[[self c40Encodation]] + 1 < intCharCounts[[self textEncodation]]) { + if (intCharCounts[[self c40Encodation]] < intCharCounts[[self x12Encodation]]) { + return [self c40Encodation]; + } + if (intCharCounts[[self c40Encodation]] == intCharCounts[[self x12Encodation]]) { + int p = startpos + charsProcessed + 1; + while (p < msg.length) { + char tc = [msg characterAtIndex:p]; + if ([self isX12TermSep:tc]) { + return [self x12Encodation]; + } + if (![self isNativeX12:tc]) { + break; + } + p++; + } + return [self c40Encodation]; + } + } + } + } +} + ++ (int)findMinimums:(float *)charCounts intCharCounts:(int *)intCharCounts min:(int)min mins:(int8_t *)mins { + memset(mins, 0, 6); + for (int i = 0; i < 6; i++) { + intCharCounts[i] = (int) ceil(charCounts[i]); + int current = intCharCounts[i]; + if (min > current) { + min = current; + memset(mins, 0, 6); + } + if (min == current) { + mins[i]++; + } + } + return min; +} + ++ (int)minimumCount:(int8_t *)mins { + int minCount = 0; + for (int i = 0; i < 6; i++) { + minCount += mins[i]; + } + return minCount; +} + ++ (BOOL)isDigit:(unichar)ch { + return ch >= '0' && ch <= '9'; +} + ++ (BOOL)isExtendedASCII:(unichar)ch { + return ch >= 128 && ch <= 255; +} + ++ (BOOL)isNativeC40:(unichar)ch { + return (ch == ' ') || (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z'); +} + ++ (BOOL)isNativeText:(unichar)ch { + return (ch == ' ') || (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'z'); +} + ++ (BOOL)isNativeX12:(unichar)ch { + return [self isX12TermSep:ch] || (ch == ' ') || (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z'); +} + ++ (BOOL)isX12TermSep:(unichar)ch { + return (ch == '\r') //CR + || (ch == '*') + || (ch == '>'); +} + ++ (BOOL)isNativeEDIFACT:(unichar)ch { + return ch >= ' ' && ch <= '^'; +} + ++ (BOOL)isSpecialB256:(unichar)ch { + return NO; //TODO NOT IMPLEMENTED YET!!! +} + ++ (int)determineConsecutiveDigitCount:(NSString *)msg startpos:(int)startpos { + int count = 0; + NSUInteger len = msg.length; + int idx = startpos; + if (idx < len) { + unichar ch = [msg characterAtIndex:idx]; + while ([self isDigit:ch] && idx < len) { + count++; + idx++; + if (idx < len) { + ch = [msg characterAtIndex:idx]; + } + } + } + return count; +} + ++ (void)illegalCharacter:(unichar)c { + NSString *hex = [NSString stringWithFormat:@"%x", c]; + hex = [[@"0000" substringWithRange:NSMakeRange(0, hex.length)] stringByAppendingString:hex]; + [NSException raise:NSInvalidArgumentException format:@"Illegal character: %C (0x%@)", c, hex]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixSymbolInfo.h b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixSymbolInfo.h new file mode 100755 index 0000000..aa85076 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixSymbolInfo.h @@ -0,0 +1,63 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXEncodeHints.h" + +@class ZXDimension; + +/** + * Symbol info table for DataMatrix. + */ +@interface ZXDataMatrixSymbolInfo : NSObject + +@property (nonatomic, assign, readonly) BOOL rectangular; +@property (nonatomic, assign, readonly) int errorCodewords; +@property (nonatomic, assign, readonly) int dataCapacity; +@property (nonatomic, assign, readonly) int dataRegions; +@property (nonatomic, assign, readonly) int matrixWidth; +@property (nonatomic, assign, readonly) int matrixHeight; +@property (nonatomic, assign, readonly) int rsBlockData; +@property (nonatomic, assign, readonly) int rsBlockError; + +/** + * Overrides the symbol info set used by this class. Used for testing purposes. + * + * @param override the symbol info set to use + */ ++ (void)overrideSymbolSet:(NSArray *)override; ++ (NSArray *)prodSymbols; +- (id)initWithRectangular:(BOOL)rectangular dataCapacity:(int)dataCapacity errorCodewords:(int)errorCodewords + matrixWidth:(int)matrixWidth matrixHeight:(int)matrixHeight dataRegions:(int)dataRegions; +- (id)initWithRectangular:(BOOL)rectangular dataCapacity:(int)dataCapacity errorCodewords:(int)errorCodewords + matrixWidth:(int)matrixWidth matrixHeight:(int)matrixHeight dataRegions:(int)dataRegions + rsBlockData:(int)rsBlockData rsBlockError:(int)rsBlockError; ++ (ZXDataMatrixSymbolInfo *)lookup:(int)dataCodewords; ++ (ZXDataMatrixSymbolInfo *)lookup:(int)dataCodewords shape:(ZXDataMatrixSymbolShapeHint)shape; ++ (ZXDataMatrixSymbolInfo *)lookup:(int)dataCodewords allowRectangular:(BOOL)allowRectangular fail:(BOOL)fail; ++ (ZXDataMatrixSymbolInfo *)lookup:(int)dataCodewords shape:(ZXDataMatrixSymbolShapeHint)shape fail:(BOOL)fail; ++ (ZXDataMatrixSymbolInfo *)lookup:(int)dataCodewords shape:(ZXDataMatrixSymbolShapeHint)shape minSize:(ZXDimension *)minSize maxSize:(ZXDimension *)maxSize fail:(BOOL)fail; +- (int)horizontalDataRegions; +- (int)verticalDataRegions; +- (int)symbolDataWidth; +- (int)symbolDataHeight; +- (int)symbolWidth; +- (int)symbolHeight; +- (int)codewordCount; +- (int)interleavedBlockCount; +- (int)dataLengthForInterleavedBlock:(int)index; +- (int)errorLengthForInterleavedBlock:(int)index; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixSymbolInfo.m b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixSymbolInfo.m new file mode 100755 index 0000000..45d3c50 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixSymbolInfo.m @@ -0,0 +1,220 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXDataMatrixSymbolInfo.h" +#import "ZXDataMatrixSymbolInfo144.h" +#import "ZXDimension.h" + +static NSArray *PROD_SYMBOLS = nil; +static NSArray *symbols = nil; + +@implementation ZXDataMatrixSymbolInfo + ++ (void)initialize { + if ([self class] != [ZXDataMatrixSymbolInfo class]) return; + + PROD_SYMBOLS = @[[[ZXDataMatrixSymbolInfo alloc] initWithRectangular:NO dataCapacity:3 errorCodewords:5 matrixWidth:8 matrixHeight:8 dataRegions:1], + [[ZXDataMatrixSymbolInfo alloc] initWithRectangular:NO dataCapacity:5 errorCodewords:7 matrixWidth:10 matrixHeight:10 dataRegions:1], + /*rect*/[[ZXDataMatrixSymbolInfo alloc] initWithRectangular:YES dataCapacity:5 errorCodewords:7 matrixWidth:16 matrixHeight:6 dataRegions:1], + [[ZXDataMatrixSymbolInfo alloc] initWithRectangular:NO dataCapacity:8 errorCodewords:10 matrixWidth:12 matrixHeight:12 dataRegions:1], + /*rect*/[[ZXDataMatrixSymbolInfo alloc] initWithRectangular:YES dataCapacity:10 errorCodewords:11 matrixWidth:14 matrixHeight:6 dataRegions:2], + [[ZXDataMatrixSymbolInfo alloc] initWithRectangular:NO dataCapacity:12 errorCodewords:12 matrixWidth:14 matrixHeight:14 dataRegions:1], + /*rect*/[[ZXDataMatrixSymbolInfo alloc] initWithRectangular:YES dataCapacity:16 errorCodewords:14 matrixWidth:24 matrixHeight:10 dataRegions:1], + + [[ZXDataMatrixSymbolInfo alloc] initWithRectangular:NO dataCapacity:18 errorCodewords:14 matrixWidth:16 matrixHeight:16 dataRegions:1], + [[ZXDataMatrixSymbolInfo alloc] initWithRectangular:NO dataCapacity:22 errorCodewords:18 matrixWidth:18 matrixHeight:18 dataRegions:1], + /*rect*/[[ZXDataMatrixSymbolInfo alloc] initWithRectangular:YES dataCapacity:22 errorCodewords:18 matrixWidth:16 matrixHeight:10 dataRegions:2], + [[ZXDataMatrixSymbolInfo alloc] initWithRectangular:NO dataCapacity:30 errorCodewords:20 matrixWidth:20 matrixHeight:20 dataRegions:1], + /*rect*/[[ZXDataMatrixSymbolInfo alloc] initWithRectangular:YES dataCapacity:32 errorCodewords:24 matrixWidth:16 matrixHeight:14 dataRegions:2], + [[ZXDataMatrixSymbolInfo alloc] initWithRectangular:NO dataCapacity:36 errorCodewords:24 matrixWidth:22 matrixHeight:22 dataRegions:1], + [[ZXDataMatrixSymbolInfo alloc] initWithRectangular:NO dataCapacity:44 errorCodewords:28 matrixWidth:24 matrixHeight:24 dataRegions:1], + /*rect*/[[ZXDataMatrixSymbolInfo alloc] initWithRectangular:YES dataCapacity:49 errorCodewords:28 matrixWidth:22 matrixHeight:14 dataRegions:2], + + [[ZXDataMatrixSymbolInfo alloc] initWithRectangular:NO dataCapacity:62 errorCodewords:36 matrixWidth:14 matrixHeight:14 dataRegions:4], + [[ZXDataMatrixSymbolInfo alloc] initWithRectangular:NO dataCapacity:86 errorCodewords:42 matrixWidth:16 matrixHeight:16 dataRegions:4], + [[ZXDataMatrixSymbolInfo alloc] initWithRectangular:NO dataCapacity:114 errorCodewords:48 matrixWidth:18 matrixHeight:18 dataRegions:4], + [[ZXDataMatrixSymbolInfo alloc] initWithRectangular:NO dataCapacity:144 errorCodewords:56 matrixWidth:20 matrixHeight:20 dataRegions:4], + [[ZXDataMatrixSymbolInfo alloc] initWithRectangular:NO dataCapacity:174 errorCodewords:68 matrixWidth:22 matrixHeight:22 dataRegions:4], + + [[ZXDataMatrixSymbolInfo alloc] initWithRectangular:NO dataCapacity:204 errorCodewords:84 matrixWidth:24 matrixHeight:24 dataRegions:4 rsBlockData:102 rsBlockError:42], + [[ZXDataMatrixSymbolInfo alloc] initWithRectangular:NO dataCapacity:280 errorCodewords:112 matrixWidth:14 matrixHeight:14 dataRegions:16 rsBlockData:140 rsBlockError:56], + [[ZXDataMatrixSymbolInfo alloc] initWithRectangular:NO dataCapacity:368 errorCodewords:144 matrixWidth:16 matrixHeight:16 dataRegions:16 rsBlockData:92 rsBlockError:36], + [[ZXDataMatrixSymbolInfo alloc] initWithRectangular:NO dataCapacity:456 errorCodewords:192 matrixWidth:18 matrixHeight:18 dataRegions:16 rsBlockData:114 rsBlockError:48], + [[ZXDataMatrixSymbolInfo alloc] initWithRectangular:NO dataCapacity:576 errorCodewords:224 matrixWidth:20 matrixHeight:20 dataRegions:16 rsBlockData:144 rsBlockError:56], + [[ZXDataMatrixSymbolInfo alloc] initWithRectangular:NO dataCapacity:696 errorCodewords:272 matrixWidth:22 matrixHeight:22 dataRegions:16 rsBlockData:174 rsBlockError:68], + [[ZXDataMatrixSymbolInfo alloc] initWithRectangular:NO dataCapacity:816 errorCodewords:336 matrixWidth:24 matrixHeight:24 dataRegions:16 rsBlockData:136 rsBlockError:56], + [[ZXDataMatrixSymbolInfo alloc] initWithRectangular:NO dataCapacity:1050 errorCodewords:408 matrixWidth:18 matrixHeight:18 dataRegions:36 rsBlockData:175 rsBlockError:68], + [[ZXDataMatrixSymbolInfo alloc] initWithRectangular:NO dataCapacity:1304 errorCodewords:496 matrixWidth:20 matrixHeight:20 dataRegions:36 rsBlockData:163 rsBlockError:62], + [[ZXDataMatrixSymbolInfo144 alloc] init]]; + symbols = PROD_SYMBOLS; +} + ++ (NSArray *)prodSymbols { + return PROD_SYMBOLS; +} + ++ (void)overrideSymbolSet:(NSArray *)override { + symbols = override; +} + +- (id)initWithRectangular:(BOOL)rectangular dataCapacity:(int)dataCapacity errorCodewords:(int)errorCodewords + matrixWidth:(int)matrixWidth matrixHeight:(int)matrixHeight dataRegions:(int)dataRegions { + return [self initWithRectangular:rectangular dataCapacity:dataCapacity errorCodewords:errorCodewords + matrixWidth:matrixWidth matrixHeight:matrixHeight dataRegions:dataRegions + rsBlockData:dataCapacity rsBlockError:errorCodewords]; +} + +- (id)initWithRectangular:(BOOL)rectangular dataCapacity:(int)dataCapacity errorCodewords:(int)errorCodewords + matrixWidth:(int)matrixWidth matrixHeight:(int)matrixHeight dataRegions:(int)dataRegions + rsBlockData:(int)rsBlockData rsBlockError:(int)rsBlockError { + if (self = [super init]) { + _rectangular = rectangular; + _dataCapacity = dataCapacity; + _errorCodewords = errorCodewords; + _matrixWidth = matrixWidth; + _matrixHeight = matrixHeight; + _dataRegions = dataRegions; + _rsBlockData = rsBlockData; + _rsBlockError = rsBlockError; + } + + return self; +} + ++ (ZXDataMatrixSymbolInfo *)lookup:(int)dataCodewords { + return [self lookup:dataCodewords shape:ZXDataMatrixSymbolShapeHintForceNone fail:YES]; +} + ++ (ZXDataMatrixSymbolInfo *)lookup:(int)dataCodewords shape:(ZXDataMatrixSymbolShapeHint)shape { + return [self lookup:dataCodewords shape:shape fail:YES]; +} + ++ (ZXDataMatrixSymbolInfo *)lookup:(int)dataCodewords allowRectangular:(BOOL)allowRectangular fail:(BOOL)fail { + ZXDataMatrixSymbolShapeHint shape = allowRectangular + ? ZXDataMatrixSymbolShapeHintForceNone : ZXDataMatrixSymbolShapeHintForceSquare; + return [self lookup:dataCodewords shape:shape fail:fail]; +} + ++ (ZXDataMatrixSymbolInfo *)lookup:(int)dataCodewords shape:(ZXDataMatrixSymbolShapeHint)shape fail:(BOOL)fail { + return [self lookup:dataCodewords shape:shape minSize:nil maxSize:nil fail:fail]; +} + ++ (ZXDataMatrixSymbolInfo *)lookup:(int)dataCodewords shape:(ZXDataMatrixSymbolShapeHint)shape minSize:(ZXDimension *)minSize + maxSize:(ZXDimension *)maxSize fail:(BOOL)fail { + for (ZXDataMatrixSymbolInfo *symbol in symbols) { + if (shape == ZXDataMatrixSymbolShapeHintForceSquare && symbol.rectangular) { + continue; + } + if (shape == ZXDataMatrixSymbolShapeHintForceRectangle && !symbol.rectangular) { + continue; + } + if (minSize != nil + && ([symbol symbolWidth] < minSize.width + || [symbol symbolHeight] < minSize.height)) { + continue; + } + if (maxSize != nil + && ([symbol symbolWidth] > maxSize.width + || [symbol symbolHeight] > maxSize.height)) { + continue; + } + if (dataCodewords <= symbol.dataCapacity) { + return symbol; + } + } + if (fail) { + [NSException raise:NSInvalidArgumentException format:@"Can't find a symbol arrangement that matches the message. Data codewords: %d", dataCodewords]; + } + return nil; +} + +- (int)horizontalDataRegions { + switch (_dataRegions) { + case 1: + return 1; + case 2: + return 2; + case 4: + return 2; + case 16: + return 4; + case 36: + return 6; + default: + @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Cannot handle this number of data regions" userInfo:nil]; + } +} + +- (int)verticalDataRegions { + switch (_dataRegions) { + case 1: + return 1; + case 2: + return 1; + case 4: + return 2; + case 16: + return 4; + case 36: + return 6; + default: + @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Cannot handle this number of data regions" userInfo:nil]; + } +} + +- (int)symbolDataWidth { + return [self horizontalDataRegions] * _matrixWidth; +} + +- (int)symbolDataHeight { + return [self verticalDataRegions] * _matrixHeight; +} + +- (int)symbolWidth { + return [self symbolDataWidth] + ([self horizontalDataRegions] * 2); +} + +- (int)symbolHeight { + return [self symbolDataHeight] + ([self verticalDataRegions] * 2); +} + +- (int)codewordCount { + return _dataCapacity + _errorCodewords; +} + +- (int)interleavedBlockCount { + return _dataCapacity / _rsBlockData; +} + +- (int)dataLengthForInterleavedBlock:(int)index { + return _rsBlockData; +} + +- (int)errorLengthForInterleavedBlock:(int)index { + return _rsBlockError; +} + +- (NSString *)description { + NSMutableString *sb = [NSMutableString string]; + [sb appendString:_rectangular ? @"Rectangular Symbol:" : @"Square Symbol:"]; + [sb appendFormat:@" data region %dx%d", _matrixWidth, _matrixHeight]; + [sb appendFormat:@", symbol size %dx%d", [self symbolWidth], [self symbolHeight]]; + [sb appendFormat:@", symbol data size %dx%d", [self symbolDataWidth], [self symbolDataHeight]]; + [sb appendFormat:@", codewords %d+%d", _dataCapacity, _errorCodewords]; + return [NSString stringWithString:sb]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixSymbolInfo144.h b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixSymbolInfo144.h new file mode 100755 index 0000000..e9f82b5 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixSymbolInfo144.h @@ -0,0 +1,21 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXDataMatrixSymbolInfo.h" + +@interface ZXDataMatrixSymbolInfo144 : ZXDataMatrixSymbolInfo + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixSymbolInfo144.m b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixSymbolInfo144.m new file mode 100755 index 0000000..fa5af67 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixSymbolInfo144.m @@ -0,0 +1,33 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXDataMatrixSymbolInfo144.h" + +@implementation ZXDataMatrixSymbolInfo144 + +- (id)init { + return [super initWithRectangular:NO dataCapacity:1558 errorCodewords:620 matrixWidth:22 matrixHeight:22 dataRegions:36 rsBlockData:-1 rsBlockError:62]; +} + +- (int)interleavedBlockCount { + return 10; +} + +- (int)dataLengthForInterleavedBlock:(int)index { + return (index <= 8) ? 156 : 155; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixTextEncoder.h b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixTextEncoder.h new file mode 100755 index 0000000..4f82605 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixTextEncoder.h @@ -0,0 +1,21 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXDataMatrixC40Encoder.h" + +@interface ZXDataMatrixTextEncoder : ZXDataMatrixC40Encoder + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixTextEncoder.m b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixTextEncoder.m new file mode 100755 index 0000000..d766c5d --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixTextEncoder.m @@ -0,0 +1,84 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXDataMatrixHighLevelEncoder.h" +#import "ZXDataMatrixTextEncoder.h" + +@implementation ZXDataMatrixTextEncoder + +- (int)encodingMode { + return [ZXDataMatrixHighLevelEncoder textEncodation]; +} + +- (int)encodeChar:(unichar)c buffer:(NSMutableString *)sb { + if (c == ' ') { + [sb appendString:@"\3"]; + return 1; + } + if (c >= '0' && c <= '9') { + [sb appendFormat:@"%C", (unichar) (c - 48 + 4)]; + return 1; + } + if (c >= 'a' && c <= 'z') { + [sb appendFormat:@"%C", (unichar) (c - 97 + 14)]; + return 1; + } + if (c >= '\0' && c <= (unichar)0x001f) { + [sb appendString:@"\0"]; //Shift 1 Set + [sb appendFormat:@"%C", c]; + return 2; + } + if (c >= '!' && c <= '/') { + [sb appendString:@"\1"]; //Shift 2 Set + [sb appendFormat:@"%C", (unichar) (c - 33)]; + return 2; + } + if (c >= ':' && c <= '@') { + [sb appendString:@"\1"]; //Shift 2 Set + [sb appendFormat:@"%C", (unichar) (c - 58 + 15)]; + return 2; + } + if (c >= '[' && c <= '_') { + [sb appendString:@"\1"]; //Shift 2 Set + [sb appendFormat:@"%C", (unichar) (c - 91 + 22)]; + return 2; + } + if (c == '\u0060') { + [sb appendString:@"\2"]; //Shift 3 Set + [sb appendFormat:@"%C", (unichar) (c - 96)]; + return 2; + } + if (c >= 'A' && c <= 'Z') { + [sb appendString:@"\2"]; //Shift 3 Set + [sb appendFormat:@"%C", (unichar) (c - 65 + 1)]; + return 2; + } + if (c >= '{' && c <= (unichar)0x007f) { + [sb appendString:@"\2"]; //Shift 3 Set + [sb appendFormat:@"%C", (unichar) (c - 123 + 27)]; + return 2; + } + if (c >= (unichar)0x0080) { + [sb appendFormat:@"\1%C", (unichar)0x001e]; //Shift 2, Upper Shift + int len = 2; + len += [self encodeChar:(unichar) (c - 128) buffer:sb]; + return len; + } + [ZXDataMatrixHighLevelEncoder illegalCharacter:c]; + return -1; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixX12Encoder.h b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixX12Encoder.h new file mode 100755 index 0000000..2c5dfea --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixX12Encoder.h @@ -0,0 +1,21 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXDataMatrixC40Encoder.h" + +@interface ZXDataMatrixX12Encoder : ZXDataMatrixC40Encoder + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixX12Encoder.m b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixX12Encoder.m new file mode 100755 index 0000000..b377531 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/datamatrix/encoder/ZXDataMatrixX12Encoder.m @@ -0,0 +1,84 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXDataMatrixEncoderContext.h" +#import "ZXDataMatrixHighLevelEncoder.h" +#import "ZXDataMatrixSymbolInfo.h" +#import "ZXDataMatrixX12Encoder.h" + +@implementation ZXDataMatrixX12Encoder + +- (int)encodingMode { + return [ZXDataMatrixHighLevelEncoder x12Encodation]; +} + +- (void)encode:(ZXDataMatrixEncoderContext *)context { + //step C + NSMutableString *buffer = [NSMutableString string]; + while ([context hasMoreCharacters]) { + unichar c = [context currentChar]; + context.pos++; + + [self encodeChar:c buffer:buffer]; + + NSUInteger count = buffer.length; + if ((count % 3) == 0) { + [self writeNextTriplet:context buffer:buffer]; + + int newMode = [ZXDataMatrixHighLevelEncoder lookAheadTest:context.message startpos:context.pos currentMode:[self encodingMode]]; + if (newMode != [self encodingMode]) { + [context signalEncoderChange:newMode]; + break; + } + } + } + [self handleEOD:context buffer:buffer]; +} + +- (int)encodeChar:(unichar)c buffer:(NSMutableString *)sb { + if (c == '\r') { + [sb appendString:@"\0"]; + } else if (c == '*') { + [sb appendString:@"\1"]; + } else if (c == '>') { + [sb appendString:@"\2"]; + } else if (c == ' ') { + [sb appendString:@"\3"]; + } else if (c >= '0' && c <= '9') { + [sb appendFormat:@"%C", (unichar) (c - 48 + 4)]; + } else if (c >= 'A' && c <= 'Z') { + [sb appendFormat:@"%C", (unichar) (c - 65 + 14)]; + } else { + [ZXDataMatrixHighLevelEncoder illegalCharacter:c]; + } + return 1; +} + +- (void)handleEOD:(ZXDataMatrixEncoderContext *)context buffer:(NSMutableString *)buffer { + [context updateSymbolInfo]; + int available = context.symbolInfo.dataCapacity - [context codewordCount]; + int count = (int)buffer.length; + context.pos -= count; + if (context.remainingCharacters > 1 || available > 1 || + context.remainingCharacters != available) { + [context writeCodeword:[ZXDataMatrixHighLevelEncoder x12Unlatch]]; + } + if (context.newEncoding < 0) { + [context signalEncoderChange:[ZXDataMatrixHighLevelEncoder asciiEncodation]]; + } +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/maxicode/ZXMaxiCodeReader.h b/iDearQRCode/Tools/ZXingObjC/maxicode/ZXMaxiCodeReader.h new file mode 100755 index 0000000..27f42b0 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/maxicode/ZXMaxiCodeReader.h @@ -0,0 +1,26 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXReader.h" + +@class ZXBinaryBitmap, ZXDecodeHints, ZXResult; + +/** + * This implementation can detect and decode a MaxiCode in an image. + */ +@interface ZXMaxiCodeReader : NSObject + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/maxicode/ZXMaxiCodeReader.m b/iDearQRCode/Tools/ZXingObjC/maxicode/ZXMaxiCodeReader.m new file mode 100755 index 0000000..9bf2546 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/maxicode/ZXMaxiCodeReader.m @@ -0,0 +1,128 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBinaryBitmap.h" +#import "ZXBitMatrix.h" +#import "ZXDecodeHints.h" +#import "ZXDecoderResult.h" +#import "ZXErrors.h" +#import "ZXIntArray.h" +#import "ZXMaxiCodeDecoder.h" +#import "ZXMaxiCodeReader.h" +#import "ZXResult.h" + +const int ZX_MATRIX_WIDTH = 30; +const int ZX_MATRIX_HEIGHT = 33; + +@interface ZXMaxiCodeReader () + +@property (nonatomic, strong, readonly) ZXMaxiCodeDecoder *decoder; + +@end + +@implementation ZXMaxiCodeReader + +- (id)init { + if (self = [super init]) { + _decoder = [[ZXMaxiCodeDecoder alloc] init]; + } + + return self; +} + +/** + * Locates and decodes a MaxiCode in an image. + * + * @return a String representing the content encoded by the MaxiCode + * @return nil if a MaxiCode cannot be found + * @return nil if a MaxiCode cannot be decoded + * @return nil if error correction fails + */ +- (ZXResult *)decode:(ZXBinaryBitmap *)image error:(NSError **)error { + return [self decode:image hints:nil error:error]; +} + +- (ZXResult *)decode:(ZXBinaryBitmap *)image hints:(ZXDecodeHints *)hints error:(NSError **)error { + ZXDecoderResult *decoderResult; + if (hints != nil && hints.pureBarcode) { + ZXBitMatrix *matrix = [image blackMatrixWithError:error]; + if (!matrix) { + return nil; + } + ZXBitMatrix *bits = [self extractPureBits:matrix]; + if (!bits) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + decoderResult = [self.decoder decode:bits hints:hints error:error]; + if (!decoderResult) { + return nil; + } + } else { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + + NSArray *points = @[]; + ZXResult *result = [ZXResult resultWithText:decoderResult.text + rawBytes:decoderResult.rawBytes + resultPoints:points + format:kBarcodeFormatMaxiCode]; + + NSString *ecLevel = decoderResult.ecLevel; + if (ecLevel != nil) { + [result putMetadata:kResultMetadataTypeErrorCorrectionLevel value:ecLevel]; + } + return result; +} + +- (void)reset { + // do nothing +} + +/** + * This method detects a code in a "pure" image -- that is, pure monochrome image + * which contains only an unrotated, unskewed, image of a code, with some white border + * around it. This is a specialized method that works exceptionally fast in this special + * case. + */ +- (ZXBitMatrix *)extractPureBits:(ZXBitMatrix *)image { + ZXIntArray *enclosingRectangle = image.enclosingRectangle; + if (enclosingRectangle == nil) { + return nil; + } + + int left = enclosingRectangle.array[0]; + int top = enclosingRectangle.array[1]; + int width = enclosingRectangle.array[2]; + int height = enclosingRectangle.array[3]; + + // Now just read off the bits + ZXBitMatrix *bits = [[ZXBitMatrix alloc] initWithWidth:ZX_MATRIX_WIDTH height:ZX_MATRIX_HEIGHT]; + for (int y = 0; y < ZX_MATRIX_HEIGHT; y++) { + int iy = top + (y * height + height / 2) / ZX_MATRIX_HEIGHT; + for (int x = 0; x < ZX_MATRIX_WIDTH; x++) { + int ix = left + (x * width + width / 2 + (y & 0x01) * width / 2) / ZX_MATRIX_WIDTH; + if ([image getX:ix y:iy]) { + [bits setX:x y:y]; + } + } + } + + return bits; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/maxicode/ZXingObjCMaxiCode.h b/iDearQRCode/Tools/ZXingObjC/maxicode/ZXingObjCMaxiCode.h new file mode 100755 index 0000000..34b12ce --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/maxicode/ZXingObjCMaxiCode.h @@ -0,0 +1,24 @@ +/* + * Copyright 2014 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _ZXINGOBJC_MAXICODE_ + +#define _ZXINGOBJC_MAXICODE_ + +#import "ZXMaxiCodeDecoder.h" +#import "ZXMaxiCodeReader.h" + +#endif diff --git a/iDearQRCode/Tools/ZXingObjC/maxicode/decoder/ZXMaxiCodeBitMatrixParser.h b/iDearQRCode/Tools/ZXingObjC/maxicode/decoder/ZXMaxiCodeBitMatrixParser.h new file mode 100755 index 0000000..da287f9 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/maxicode/decoder/ZXMaxiCodeBitMatrixParser.h @@ -0,0 +1,24 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXBitMatrix, ZXByteArray; + +@interface ZXMaxiCodeBitMatrixParser : NSObject + +- (id)initWithBitMatrix:(ZXBitMatrix *)bitMatrix error:(NSError **)error; +- (ZXByteArray *)readCodewords; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/maxicode/decoder/ZXMaxiCodeBitMatrixParser.m b/iDearQRCode/Tools/ZXingObjC/maxicode/decoder/ZXMaxiCodeBitMatrixParser.m new file mode 100755 index 0000000..0ec8de9 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/maxicode/decoder/ZXMaxiCodeBitMatrixParser.m @@ -0,0 +1,90 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitMatrix.h" +#import "ZXByteArray.h" +#import "ZXErrors.h" +#import "ZXMaxiCodeBitMatrixParser.h" + +const int ZX_BITNR[33][30] = { + {121,120,127,126,133,132,139,138,145,144,151,150,157,156,163,162,169,168,175,174,181,180,187,186,193,192,199,198, -2, -2}, + {123,122,129,128,135,134,141,140,147,146,153,152,159,158,165,164,171,170,177,176,183,182,189,188,195,194,201,200,816, -3}, + {125,124,131,130,137,136,143,142,149,148,155,154,161,160,167,166,173,172,179,178,185,184,191,190,197,196,203,202,818,817}, + {283,282,277,276,271,270,265,264,259,258,253,252,247,246,241,240,235,234,229,228,223,222,217,216,211,210,205,204,819, -3}, + {285,284,279,278,273,272,267,266,261,260,255,254,249,248,243,242,237,236,231,230,225,224,219,218,213,212,207,206,821,820}, + {287,286,281,280,275,274,269,268,263,262,257,256,251,250,245,244,239,238,233,232,227,226,221,220,215,214,209,208,822, -3}, + {289,288,295,294,301,300,307,306,313,312,319,318,325,324,331,330,337,336,343,342,349,348,355,354,361,360,367,366,824,823}, + {291,290,297,296,303,302,309,308,315,314,321,320,327,326,333,332,339,338,345,344,351,350,357,356,363,362,369,368,825, -3}, + {293,292,299,298,305,304,311,310,317,316,323,322,329,328,335,334,341,340,347,346,353,352,359,358,365,364,371,370,827,826}, + {409,408,403,402,397,396,391,390, 79, 78, -2, -2, 13, 12, 37, 36, 2, -1, 44, 43,109,108,385,384,379,378,373,372,828, -3}, + {411,410,405,404,399,398,393,392, 81, 80, 40, -2, 15, 14, 39, 38, 3, -1, -1, 45,111,110,387,386,381,380,375,374,830,829}, + {413,412,407,406,401,400,395,394, 83, 82, 41, -3, -3, -3, -3, -3, 5, 4, 47, 46,113,112,389,388,383,382,377,376,831, -3}, + {415,414,421,420,427,426,103,102, 55, 54, 16, -3, -3, -3, -3, -3, -3, -3, 20, 19, 85, 84,433,432,439,438,445,444,833,832}, + {417,416,423,422,429,428,105,104, 57, 56, -3, -3, -3, -3, -3, -3, -3, -3, 22, 21, 87, 86,435,434,441,440,447,446,834, -3}, + {419,418,425,424,431,430,107,106, 59, 58, -3, -3, -3, -3, -3, -3, -3, -3, -3, 23, 89, 88,437,436,443,442,449,448,836,835}, + {481,480,475,474,469,468, 48, -2, 30, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, 0, 53, 52,463,462,457,456,451,450,837, -3}, + {483,482,477,476,471,470, 49, -1, -2, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, -2, -1,465,464,459,458,453,452,839,838}, + {485,484,479,478,473,472, 51, 50, 31, -3, -3, -3, -3, -3, -3, -3, -3, -3, -3, 1, -2, 42,467,466,461,460,455,454,840, -3}, + {487,486,493,492,499,498, 97, 96, 61, 60, -3, -3, -3, -3, -3, -3, -3, -3, -3, 26, 91, 90,505,504,511,510,517,516,842,841}, + {489,488,495,494,501,500, 99, 98, 63, 62, -3, -3, -3, -3, -3, -3, -3, -3, 28, 27, 93, 92,507,506,513,512,519,518,843, -3}, + {491,490,497,496,503,502,101,100, 65, 64, 17, -3, -3, -3, -3, -3, -3, -3, 18, 29, 95, 94,509,508,515,514,521,520,845,844}, + {559,558,553,552,547,546,541,540, 73, 72, 32, -3, -3, -3, -3, -3, -3, 10, 67, 66,115,114,535,534,529,528,523,522,846, -3}, + {561,560,555,554,549,548,543,542, 75, 74, -2, -1, 7, 6, 35, 34, 11, -2, 69, 68,117,116,537,536,531,530,525,524,848,847}, + {563,562,557,556,551,550,545,544, 77, 76, -2, 33, 9, 8, 25, 24, -1, -2, 71, 70,119,118,539,538,533,532,527,526,849, -3}, + {565,564,571,570,577,576,583,582,589,588,595,594,601,600,607,606,613,612,619,618,625,624,631,630,637,636,643,642,851,850}, + {567,566,573,572,579,578,585,584,591,590,597,596,603,602,609,608,615,614,621,620,627,626,633,632,639,638,645,644,852, -3}, + {569,568,575,574,581,580,587,586,593,592,599,598,605,604,611,610,617,616,623,622,629,628,635,634,641,640,647,646,854,853}, + {727,726,721,720,715,714,709,708,703,702,697,696,691,690,685,684,679,678,673,672,667,666,661,660,655,654,649,648,855, -3}, + {729,728,723,722,717,716,711,710,705,704,699,698,693,692,687,686,681,680,675,674,669,668,663,662,657,656,651,650,857,856}, + {731,730,725,724,719,718,713,712,707,706,701,700,695,694,689,688,683,682,677,676,671,670,665,664,659,658,653,652,858, -3}, + {733,732,739,738,745,744,751,750,757,756,763,762,769,768,775,774,781,780,787,786,793,792,799,798,805,804,811,810,860,859}, + {735,734,741,740,747,746,753,752,759,758,765,764,771,770,777,776,783,782,789,788,795,794,801,800,807,806,813,812,861, -3}, + {737,736,743,742,749,748,755,754,761,760,767,766,773,772,779,778,785,784,791,790,797,796,803,802,809,808,815,814,863,862} +}; + +@interface ZXMaxiCodeBitMatrixParser () + +@property (nonatomic, strong, readonly) ZXBitMatrix *bitMatrix; + +@end + +@implementation ZXMaxiCodeBitMatrixParser + +- (id)initWithBitMatrix:(ZXBitMatrix *)bitMatrix error:(NSError **)error { + if (self = [super init]) { + _bitMatrix = bitMatrix; + } + + return self; +} + +- (ZXByteArray *)readCodewords { + ZXByteArray *result = [[ZXByteArray alloc] initWithLength:144]; + int height = self.bitMatrix.height; + int width = self.bitMatrix.width; + for (int y = 0; y < height; y++) { + int *bitnrRow = (int *)ZX_BITNR[y]; + for (int x = 0; x < width; x++) { + int bit = bitnrRow[x]; + if (bit >= 0 && [self.bitMatrix getX:x y:y]) { + result.array[bit / 6] |= (int8_t) (1 << (5 - (bit % 6))); + } + } + } + return result; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/maxicode/decoder/ZXMaxiCodeDecodedBitStreamParser.h b/iDearQRCode/Tools/ZXingObjC/maxicode/decoder/ZXMaxiCodeDecodedBitStreamParser.h new file mode 100755 index 0000000..6e824b9 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/maxicode/decoder/ZXMaxiCodeDecodedBitStreamParser.h @@ -0,0 +1,27 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXByteArray, ZXDecoderResult; + +/** + * MaxiCodes can encode text or structured information as bits in one of several modes, + * with multiple character sets in one code. This class decodes the bits back into text. + */ +@interface ZXMaxiCodeDecodedBitStreamParser : NSObject + ++ (ZXDecoderResult *)decode:(ZXByteArray *)bytes mode:(int)mode; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/maxicode/decoder/ZXMaxiCodeDecodedBitStreamParser.m b/iDearQRCode/Tools/ZXingObjC/maxicode/decoder/ZXMaxiCodeDecodedBitStreamParser.m new file mode 100755 index 0000000..d2d95b6 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/maxicode/decoder/ZXMaxiCodeDecodedBitStreamParser.m @@ -0,0 +1,203 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXByteArray.h" +#import "ZXDecoderResult.h" +#import "ZXErrors.h" +#import "ZXMaxiCodeDecodedBitStreamParser.h" + +const unichar SHIFTA = 0xFFF0; +const unichar SHIFTB = 0xFFF1; +const unichar SHIFTC = 0xFFF2; +const unichar SHIFTD = 0xFFF3; +const unichar SHIFTE = 0xFFF4; +const unichar TWOSHIFTA = 0xFFF5; +const unichar THREESHIFTA = 0xFFF6; +const unichar LATCHA = 0xFFF7; +const unichar LATCHB = 0xFFF8; +const unichar LOCK = 0xFFF9; +const unichar ECI = 0xFFFA; +const unichar NS = 0xFFFB; +const unichar PAD = 0xFFFC; +const unichar FS = 0x001C; +const unichar GS = 0x001D; +const unichar RS = 0x001E; + +const unichar SETS[1][383] = { + '\n', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', ECI, FS, GS, RS, NS, ' ', PAD, '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', '0', + '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', SHIFTB, SHIFTC, SHIFTD, SHIFTE, LATCHB, + '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p' , 'q', 'r', 's', 't', 'u', 'v', 'w', + 'x', 'y', 'z', ECI, FS, GS, RS, NS, '{', PAD, '}', '~', 0x007F, ';', '<', '=', '>', '?', '[', '\\', ']', '^', '_', ' ', + ',', '.', '/', ':', '@', '!', '|', PAD, TWOSHIFTA, THREESHIFTA, PAD, SHIFTA, SHIFTC, SHIFTD, SHIFTE, LATCHA, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, + 0x00CF, 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, 0x00D8, 0x00D9, 0x00DA, ECI, FS, GS, RS, 0x00DB, + 0x00DC, 0x00DD, 0x00DE, 0x00DF, 0x00AA, 0x00AC, 0x00B1, 0x00B2, 0x00B3, 0x00B5, 0x00B9, 0x00BA, 0x00BC, 0x00BD, 0x00BE, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, LATCHA, ' ', LOCK, SHIFTD, SHIFTE, LATCHB, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, + 0x00EF, 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, ECI, FS, GS, RS, NS, + 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF, 0x00A1, 0x00A8, 0x00AB, 0x00AF, 0x00B0, 0x00B4, 0x00B7, 0x00B8, 0x00BB, 0x00BF, + 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, LATCHA, ' ', SHIFTC, LOCK, SHIFTE, + LATCHB, 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, '\n', 0x000B, 0x000C, '\r', + 0x000E, 0x000F, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001A, ECI, PAD, PAD, + 0x001B, NS, FS, GS, RS, 0x001F, 0x009F, 0x00A0, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A9, 0x00AD, 0x00AE, + 0x00B6, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, LATCHA, ' ', SHIFTC, SHIFTD, LOCK, + LATCHB, 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, '\n', 0x000B, 0x000C, '\r', + 0x000E, 0x000F, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, + 0x001D, 0x001E, 0x001F, 0x0020, 0x0021, '"', 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002A, 0x002B, + 0x002C, 0x002D, 0x002E, 0x002F, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003A, + 0x003B, 0x003C, 0x003D, 0x003E, 0x003F +}; + +@implementation ZXMaxiCodeDecodedBitStreamParser + ++ (ZXDecoderResult *)decode:(ZXByteArray *)bytes mode:(int)mode { + NSMutableString *result = [NSMutableString stringWithCapacity:144]; + switch (mode) { + case 2: + case 3: { + NSString *postcode; + if (mode == 2) { + int pc = [self postCode2:bytes]; + postcode = [NSString stringWithFormat:@"%9d", pc]; + } else { + postcode = [self postCode3:bytes]; + } + NSString *country = [NSString stringWithFormat:@"%3d", [self country:bytes]]; + NSString *service = [NSString stringWithFormat:@"%3d", [self serviceClass:bytes]]; + [result appendString:[self message:bytes start:10 len:84]]; + if ([result hasPrefix:[NSString stringWithFormat:@"[)>%C01%C", RS, GS]]) { + [result insertString:[NSString stringWithFormat:@"%@%C%@%C%@%C", postcode, GS, country, GS, service, GS] atIndex:9]; + } else { + [result insertString:[NSString stringWithFormat:@"%@%C%@%C%@%C", postcode, GS, country, GS, service, GS] atIndex:0]; + } + break; + } + case 4: + [result appendString:[self message:bytes start:1 len:93]]; + break; + case 5: + [result appendString:[self message:bytes start:1 len:77]]; + break; + } + return [[ZXDecoderResult alloc] initWithRawBytes:bytes + text:result + byteSegments:nil + ecLevel:[NSString stringWithFormat:@"%d", mode]]; +} + ++ (int)bit:(int)bit bytes:(ZXByteArray *)bytes { + bit--; + return (bytes.array[bit / 6] & (1 << (5 - (bit % 6)))) == 0 ? 0 : 1; +} + ++ (int)integer:(ZXByteArray *)bytes x:(ZXByteArray *)x { + int val = 0; + for (int i = 0; i < x.length; i++) { + val += [self bit:x.array[i] bytes:bytes] << (x.length - i - 1); + } + return val; +} + ++ (int)country:(ZXByteArray *)bytes { + return [self integer:bytes x:[[ZXByteArray alloc] initWithBytes:53, 54, 43, 44, 45, 46, 47, 48, 37, 38, -1]]; +} + ++ (int)serviceClass:(ZXByteArray *)bytes { + return [self integer:bytes x:[[ZXByteArray alloc] initWithBytes:55, 56, 57, 58, 59, 60, 49, 50, 51, 52, -1]]; +} + ++ (int)postCode2Length:(ZXByteArray *)bytes { + return [self integer:bytes x:[[ZXByteArray alloc] initWithBytes:39, 40, 41, 42, 31, 32, -1]]; +} + ++ (int)postCode2:(ZXByteArray *)bytes { + return [self integer:bytes x:[[ZXByteArray alloc] initWithBytes:33, 34, 35, 36, 25, 26, 27, 28, 29, 30, 19, + 20, 21, 22, 23, 24, 13, 14, 15, 16, 17, 18, 7, 8, 9, 10, 11, 12, 1, 2, -1]]; +} + ++ (NSString *)postCode3:(ZXByteArray *)bytes { + return [NSString stringWithFormat:@"%C%C%C%C%C%C", + SETS[0][[self integer:bytes x:[[ZXByteArray alloc] initWithBytes:39, 40, 41, 42, 31, 32, -1]]], + SETS[0][[self integer:bytes x:[[ZXByteArray alloc] initWithBytes:33, 34, 35, 36, 25, 26, -1]]], + SETS[0][[self integer:bytes x:[[ZXByteArray alloc] initWithBytes:27, 28, 29, 30, 19, 20, -1]]], + SETS[0][[self integer:bytes x:[[ZXByteArray alloc] initWithBytes:21, 22, 23, 24, 13, 14, -1]]], + SETS[0][[self integer:bytes x:[[ZXByteArray alloc] initWithBytes:15, 16, 17, 18, 7, 8, -1]]], + SETS[0][[self integer:bytes x:[[ZXByteArray alloc] initWithBytes: 9, 10, 11, 12, 1, 2, -1]]]]; +} + ++ (NSString *)message:(ZXByteArray *)bytes start:(int)start len:(int)len { + NSMutableString *sb = [NSMutableString string]; + int shift = -1; + int set = 0; + int lastset = 0; + for (int i = start; i < start + len; i++) { + unichar c = SETS[set][bytes.array[i]]; + switch (c) { + case LATCHA: + set = 0; + shift = -1; + break; + case LATCHB: + set = 1; + shift = -1; + break; + case SHIFTA: + case SHIFTB: + case SHIFTC: + case SHIFTD: + case SHIFTE: + lastset = set; + set = c - SHIFTA; + shift = 1; + break; + case TWOSHIFTA: + lastset = set; + set = 0; + shift = 2; + break; + case THREESHIFTA: + lastset = set; + set = 0; + shift = 3; + break; + case NS: { + int nsval1 = bytes.array[++i] << 24; + int nsval2 = bytes.array[++i] << 18; + int nsval3 = bytes.array[++i] << 12; + int nsval4 = bytes.array[++i] << 6; + int nsval5 = bytes.array[++i]; + int nsval = nsval1 + nsval2 + nsval3 + nsval4 + nsval5; + [sb appendFormat:@"%9d", nsval]; + break; + } + case LOCK: + shift = -1; + break; + default: + [sb appendFormat:@"%C", c]; + } + if (shift-- == 0) { + set = lastset; + } + } + while (sb.length > 0 && [sb characterAtIndex:sb.length - 1] == PAD) { + [sb deleteCharactersInRange:NSMakeRange(sb.length - 1, 1)]; + } + return sb; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/maxicode/decoder/ZXMaxiCodeDecoder.h b/iDearQRCode/Tools/ZXingObjC/maxicode/decoder/ZXMaxiCodeDecoder.h new file mode 100755 index 0000000..53f1e13 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/maxicode/decoder/ZXMaxiCodeDecoder.h @@ -0,0 +1,28 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXBitMatrix, ZXDecodeHints, ZXDecoderResult; + +/** + * The main class which implements MaxiCode decoding -- as opposed to locating and extracting + * the MaxiCode from an image. + */ +@interface ZXMaxiCodeDecoder : NSObject + +- (ZXDecoderResult *)decode:(ZXBitMatrix *)bits error:(NSError **)error; +- (ZXDecoderResult *)decode:(ZXBitMatrix *)bits hints:(ZXDecodeHints *)hints error:(NSError **)error; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/maxicode/decoder/ZXMaxiCodeDecoder.m b/iDearQRCode/Tools/ZXingObjC/maxicode/decoder/ZXMaxiCodeDecoder.m new file mode 100755 index 0000000..a74de8c --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/maxicode/decoder/ZXMaxiCodeDecoder.m @@ -0,0 +1,134 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitMatrix.h" +#import "ZXByteArray.h" +#import "ZXDecodeHints.h" +#import "ZXDecoderResult.h" +#import "ZXErrors.h" +#import "ZXGenericGF.h" +#import "ZXIntArray.h" +#import "ZXMaxiCodeBitMatrixParser.h" +#import "ZXMaxiCodeDecodedBitStreamParser.h" +#import "ZXMaxiCodeDecoder.h" +#import "ZXReedSolomonDecoder.h" + +const int ZX_MAXI_CODE_ALL = 0; +const int ZX_MAXI_CODE_EVEN = 1; +const int ZX_MAXI_CODE_ODD = 2; + +@interface ZXMaxiCodeDecoder () + +@property (nonatomic, strong, readonly) ZXReedSolomonDecoder *rsDecoder; + +@end + +@implementation ZXMaxiCodeDecoder + +- (id)init { + if (self = [super init]) { + _rsDecoder = [[ZXReedSolomonDecoder alloc] initWithField:[ZXGenericGF MaxiCodeField64]]; + } + + return self; +} + +- (ZXDecoderResult *)decode:(ZXBitMatrix *)bits error:(NSError **)error { + return [self decode:bits hints:nil error:error]; +} + +- (ZXDecoderResult *)decode:(ZXBitMatrix *)bits hints:(ZXDecodeHints *)hints error:(NSError **)error { + ZXMaxiCodeBitMatrixParser *parser = [[ZXMaxiCodeBitMatrixParser alloc] initWithBitMatrix:bits error:error]; + if (!parser) { + return nil; + } + ZXByteArray *codewords = [parser readCodewords]; + + if (![self correctErrors:codewords start:0 dataCodewords:10 ecCodewords:10 mode:ZX_MAXI_CODE_ALL error:error]) { + return nil; + } + int mode = codewords.array[0] & 0x0F; + ZXByteArray *datawords; + switch (mode) { + case 2: + case 3: + case 4: + if (![self correctErrors:codewords start:20 dataCodewords:84 ecCodewords:40 mode:ZX_MAXI_CODE_EVEN error:error]) { + return nil; + } + if (![self correctErrors:codewords start:20 dataCodewords:84 ecCodewords:40 mode:ZX_MAXI_CODE_ODD error:error]) { + return nil; + } + datawords = [[ZXByteArray alloc] initWithLength:94]; + break; + case 5: + if (![self correctErrors:codewords start:20 dataCodewords:68 ecCodewords:56 mode:ZX_MAXI_CODE_EVEN error:error]) { + return nil; + } + if (![self correctErrors:codewords start:20 dataCodewords:68 ecCodewords:56 mode:ZX_MAXI_CODE_ODD error:error]) { + return nil; + } + datawords = [[ZXByteArray alloc] initWithLength:78]; + break; + default: + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + + for (int i = 0; i < 10; i++) { + datawords.array[i] = codewords.array[i]; + } + for (int i = 20; i < datawords.length + 10; i++) { + datawords.array[i - 10] = codewords.array[i]; + } + + return [ZXMaxiCodeDecodedBitStreamParser decode:datawords mode:mode]; +} + +- (BOOL)correctErrors:(ZXByteArray *)codewordBytes start:(int)start dataCodewords:(int)dataCodewords + ecCodewords:(int)ecCodewords mode:(int)mode error:(NSError **)error { + int codewords = dataCodewords + ecCodewords; + + // in EVEN or ODD mode only half the codewords + int divisor = mode == ZX_MAXI_CODE_ALL ? 1 : 2; + + // First read into an array of ints + ZXIntArray *codewordsInts = [[ZXIntArray alloc] initWithLength:codewords / divisor]; + for (int i = 0; i < codewords; i++) { + if ((mode == ZX_MAXI_CODE_ALL) || (i % 2 == (mode - 1))) { + codewordsInts.array[i / divisor] = codewordBytes.array[i + start] & 0xFF; + } + } + + NSError *decodeError = nil; + if (![self.rsDecoder decode:codewordsInts twoS:ecCodewords / divisor error:&decodeError]) { + if (decodeError.code == ZXReedSolomonError && error) { + *error = ZXChecksumErrorInstance(); + } + return NO; + } + // Copy back into array of bytes -- only need to worry about the bytes that were data + // We don't care about errors in the error-correction codewords + for (int i = 0; i < dataCodewords; i++) { + if ((mode == ZX_MAXI_CODE_ALL) || (i % 2 == (mode - 1))) { + codewordBytes.array[i + start] = (int8_t) codewordsInts.array[i / divisor]; + } + } + + return YES; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/multi/ZXByQuadrantReader.h b/iDearQRCode/Tools/ZXingObjC/multi/ZXByQuadrantReader.h new file mode 100755 index 0000000..8de8442 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/multi/ZXByQuadrantReader.h @@ -0,0 +1,30 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXReader.h" + +/** + * This class attempts to decode a barcode from an image, not by scanning the whole image, + * but by scanning subsets of the image. This is important when there may be multiple barcodes in + * an image, and detecting a barcode may find parts of multiple barcode and fail to decode + * (e.g. QR Codes). Instead this scans the four quadrants of the image -- and also the center + * 'quadrant' to cover the case where a barcode is found in the center. + */ +@interface ZXByQuadrantReader : NSObject + +- (id)initWithDelegate:(id)delegate; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/multi/ZXByQuadrantReader.m b/iDearQRCode/Tools/ZXingObjC/multi/ZXByQuadrantReader.m new file mode 100755 index 0000000..22f009f --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/multi/ZXByQuadrantReader.m @@ -0,0 +1,121 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBinaryBitmap.h" +#import "ZXByQuadrantReader.h" +#import "ZXDecodeHints.h" +#import "ZXErrors.h" +#import "ZXResult.h" +#import "ZXResultPoint.h" + +@interface ZXByQuadrantReader () + +@property (nonatomic, weak, readonly) id delegate; + +@end + +@implementation ZXByQuadrantReader + +- (id)initWithDelegate:(id)delegate { + if (self = [super init]) { + _delegate = delegate; + } + + return self; +} + +- (ZXResult *)decode:(ZXBinaryBitmap *)image error:(NSError **)error { + return [self decode:image hints:nil error:error]; +} + +- (ZXResult *)decode:(ZXBinaryBitmap *)image hints:(ZXDecodeHints *)hints error:(NSError **)error { + int width = image.width; + int height = image.height; + int halfWidth = width / 2; + int halfHeight = height / 2; + + // No need to call makeAbsolute as results will be relative to original top left here + NSError *decodeError = nil; + ZXResult *result = [self.delegate decode:[image crop:0 top:0 width:halfWidth height:halfHeight] + hints:hints + error:&decodeError]; + if (result) { + return result; + } else if (decodeError.code != ZXNotFoundError) { + if (error) *error = decodeError; + return nil; + } + + decodeError = nil; + result = [self.delegate decode:[image crop:halfWidth top:0 width:halfWidth height:halfHeight] + hints:hints + error:&decodeError]; + if (result) { + [self makeAbsolute:result.resultPoints leftOffset:halfWidth topOffset:0]; + return result; + } else if (decodeError.code != ZXNotFoundError) { + if (error) *error = decodeError; + return nil; + } + + decodeError = nil; + result = [self.delegate decode:[image crop:0 top:halfHeight width:halfWidth height:halfHeight] + hints:hints + error:&decodeError]; + if (result) { + [self makeAbsolute:result.resultPoints leftOffset:0 topOffset:halfHeight]; + return result; + } else if (decodeError.code != ZXNotFoundError) { + if (error) *error = decodeError; + return nil; + } + + decodeError = nil; + result = [self.delegate decode:[image crop:halfWidth top:halfHeight width:halfWidth height:halfHeight] + hints:hints + error:&decodeError]; + if (result) { + [self makeAbsolute:result.resultPoints leftOffset:halfWidth topOffset:halfHeight]; + return result; + } else if (decodeError.code != ZXNotFoundError) { + if (error) *error = decodeError; + return nil; + } + + int quarterWidth = halfWidth / 2; + int quarterHeight = halfHeight / 2; + ZXBinaryBitmap *center = [image crop:quarterWidth top:quarterHeight width:halfWidth height:halfHeight]; + result = [self.delegate decode:center hints:hints error:error]; + if (result) { + [self makeAbsolute:result.resultPoints leftOffset:quarterWidth topOffset:quarterHeight]; + } + return result; +} + +- (void)reset { + [self.delegate reset]; +} + +- (void)makeAbsolute:(NSMutableArray *)points leftOffset:(int)leftOffset topOffset:(int)topOffset { + if (points) { + for (int i = 0; i < points.count; i++) { + ZXResultPoint *relative = points[i]; + points[i] = [[ZXResultPoint alloc] initWithX:relative.x + leftOffset y:relative.y + topOffset]; + } + } +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/multi/ZXGenericMultipleBarcodeReader.h b/iDearQRCode/Tools/ZXingObjC/multi/ZXGenericMultipleBarcodeReader.h new file mode 100755 index 0000000..68ed611 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/multi/ZXGenericMultipleBarcodeReader.h @@ -0,0 +1,37 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXMultipleBarcodeReader.h" + +@protocol ZXReader; + +/** + * Attempts to locate multiple barcodes in an image by repeatedly decoding portion of the image. + * After one barcode is found, the areas left, above, right and below the barcode's + * ZXResultPoints are scanned, recursively. + * + * A caller may want to also employ ZXByQuadrantReader when attempting to find multiple + * 2D barcodes, like QR Codes, in an image, where the presence of multiple barcodes might prevent + * detecting any one of them. + * + * That is, instead of passing an ZXReader a caller might pass + * [[ZXByQuadrantReader alloc] initWithDelegate:reader]. + */ +@interface ZXGenericMultipleBarcodeReader : NSObject + +- (id)initWithDelegate:(id)delegate; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/multi/ZXGenericMultipleBarcodeReader.m b/iDearQRCode/Tools/ZXingObjC/multi/ZXGenericMultipleBarcodeReader.m new file mode 100755 index 0000000..3c2680c --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/multi/ZXGenericMultipleBarcodeReader.m @@ -0,0 +1,140 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXErrors.h" +#import "ZXGenericMultipleBarcodeReader.h" +#import "ZXReader.h" +#import "ZXResultPoint.h" + +const int ZX_MIN_DIMENSION_TO_RECUR = 100; +const int ZX_MAX_DEPTH = 4; + +@interface ZXGenericMultipleBarcodeReader () + +@property (nonatomic, weak, readonly) id delegate; + +@end + +@implementation ZXGenericMultipleBarcodeReader + +- (id)initWithDelegate:(id)delegate { + if (self = [super init]) { + _delegate = delegate; + } + + return self; +} + +- (NSArray *)decodeMultiple:(ZXBinaryBitmap *)image error:(NSError **)error { + return [self decodeMultiple:image hints:nil error:error]; +} + +- (NSArray *)decodeMultiple:(ZXBinaryBitmap *)image hints:(ZXDecodeHints *)hints error:(NSError **)error { + NSMutableArray *results = [NSMutableArray array]; + if (![self doDecodeMultiple:image hints:hints results:results xOffset:0 yOffset:0 currentDepth:0 error:error]) { + return nil; + } else if (results.count == 0) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + return results; +} + +- (BOOL)doDecodeMultiple:(ZXBinaryBitmap *)image hints:(ZXDecodeHints *)hints results:(NSMutableArray *)results + xOffset:(int)xOffset yOffset:(int)yOffset currentDepth:(int)currentDepth error:(NSError **)error { + if (currentDepth > ZX_MAX_DEPTH) { + return YES; + } + + ZXResult *result = [self.delegate decode:image hints:hints error:error]; + if (!result) { + return NO; + } + + BOOL alreadyFound = NO; + for (ZXResult *existingResult in results) { + if ([[existingResult text] isEqualToString:[result text]]) { + alreadyFound = YES; + break; + } + } + if (!alreadyFound) { + [results addObject:[self translateResultPoints:result xOffset:xOffset yOffset:yOffset]]; + } + NSMutableArray *resultPoints = [result resultPoints]; + if (resultPoints == nil || [resultPoints count] == 0) { + return YES; + } + int width = [image width]; + int height = [image height]; + float minX = width; + float minY = height; + float maxX = 0.0f; + float maxY = 0.0f; + for (ZXResultPoint *point in resultPoints) { + if ((id)point == [NSNull null]) { + continue; + } + float x = [point x]; + float y = [point y]; + if (x < minX) { + minX = x; + } + if (y < minY) { + minY = y; + } + if (x > maxX) { + maxX = x; + } + if (y > maxY) { + maxY = y; + } + } + + if (minX > ZX_MIN_DIMENSION_TO_RECUR) { + return [self doDecodeMultiple:[image crop:0 top:0 width:(int)minX height:height] hints:hints results:results xOffset:xOffset yOffset:yOffset currentDepth:currentDepth + 1 error:error]; + } + if (minY > ZX_MIN_DIMENSION_TO_RECUR) { + return [self doDecodeMultiple:[image crop:0 top:0 width:width height:(int)minY] hints:hints results:results xOffset:xOffset yOffset:yOffset currentDepth:currentDepth + 1 error:error]; + } + if (maxX < width - ZX_MIN_DIMENSION_TO_RECUR) { + return [self doDecodeMultiple:[image crop:(int)maxX top:0 width:width - (int)maxX height:height] hints:hints results:results xOffset:xOffset + (int)maxX yOffset:yOffset currentDepth:currentDepth + 1 error:error]; + } + if (maxY < height - ZX_MIN_DIMENSION_TO_RECUR) { + return [self doDecodeMultiple:[image crop:0 top:(int)maxY width:width height:height - (int)maxY] hints:hints results:results xOffset:xOffset yOffset:yOffset + (int)maxY currentDepth:currentDepth + 1 error:error]; + } + + return YES; +} + +- (ZXResult *)translateResultPoints:(ZXResult *)result xOffset:(int)xOffset yOffset:(int)yOffset { + NSArray *oldResultPoints = [result resultPoints]; + if (oldResultPoints == nil) { + return result; + } + NSMutableArray *newResultPoints = [NSMutableArray arrayWithCapacity:[oldResultPoints count]]; + for (ZXResultPoint *oldPoint in oldResultPoints) { + if ((id)oldPoint != [NSNull null]) { + [newResultPoints addObject:[[ZXResultPoint alloc] initWithX:[oldPoint x] + xOffset y:[oldPoint y] + yOffset]]; + } + } + + ZXResult *newResult = [ZXResult resultWithText:result.text rawBytes:result.rawBytes resultPoints:newResultPoints format:result.barcodeFormat]; + [newResult putAllMetadata:result.resultMetadata]; + return newResult; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/multi/ZXMultipleBarcodeReader.h b/iDearQRCode/Tools/ZXingObjC/multi/ZXMultipleBarcodeReader.h new file mode 100755 index 0000000..b7766f3 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/multi/ZXMultipleBarcodeReader.h @@ -0,0 +1,30 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBinaryBitmap.h" +#import "ZXResult.h" + +@class ZXDecodeHints; + +/** + * Implementation of this interface attempt to read several barcodes from one image. + */ +@protocol ZXMultipleBarcodeReader + +- (NSArray *)decodeMultiple:(ZXBinaryBitmap *)image error:(NSError **)error; +- (NSArray *)decodeMultiple:(ZXBinaryBitmap *)image hints:(ZXDecodeHints *)hints error:(NSError **)error; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXCodaBarReader.h b/iDearQRCode/Tools/ZXingObjC/oned/ZXCodaBarReader.h new file mode 100755 index 0000000..cda00d1 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXCodaBarReader.h @@ -0,0 +1,32 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXOneDReader.h" + +extern const int ZX_CODA_ALPHABET_LEN; +extern const unichar ZX_CODA_ALPHABET[]; +extern const int ZX_CODA_CHARACTER_ENCODINGS[]; + +@class ZXBitArray, ZXDecodeHints, ZXResult; + +/** + * Decodes Codabar barcodes. + */ +@interface ZXCodaBarReader : ZXOneDReader + ++ (BOOL)arrayContains:(const unichar *)array length:(unsigned int)length key:(unichar)key; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXCodaBarReader.m b/iDearQRCode/Tools/ZXingObjC/oned/ZXCodaBarReader.m new file mode 100755 index 0000000..0c3b001 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXCodaBarReader.m @@ -0,0 +1,367 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitArray.h" +#import "ZXCodaBarReader.h" +#import "ZXDecodeHints.h" +#import "ZXErrors.h" +#import "ZXIntArray.h" +#import "ZXResult.h" +#import "ZXResultPoint.h" + +// These values are critical for determining how permissive the decoding +// will be. All stripe sizes must be within the window these define, as +// compared to the average stripe size. +static float ZX_CODA_MAX_ACCEPTABLE = 2.0f; +static float ZX_CODA_PADDING = 1.5f; + +const unichar ZX_CODA_ALPHABET[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + '-', '$', ':', '/', '.', '+', 'A', 'B', 'C', 'D', 'T', 'N'}; +const int ZX_CODA_ALPHABET_LEN = sizeof(ZX_CODA_ALPHABET) / sizeof(unichar); + +/** + * These represent the encodings of characters, as patterns of wide and narrow bars. The 7 least-significant bits of + * each int correspond to the pattern of wide and narrow, with 1s representing "wide" and 0s representing narrow. + */ +const int ZX_CODA_CHARACTER_ENCODINGS[] = { + 0x003, 0x006, 0x009, 0x060, 0x012, 0x042, 0x021, 0x024, 0x030, 0x048, // 0-9 + 0x00c, 0x018, 0x045, 0x051, 0x054, 0x015, 0x01A, 0x029, 0x00B, 0x00E, // -$:/.+ABCD +}; + +// minimal number of characters that should be present (inclusing start and stop characters) +// under normal circumstances this should be set to 3, but can be set higher +// as a last-ditch attempt to reduce false positives. +const int ZX_CODA_MIN_CHARACTER_LENGTH = 3; + +// official start and end patterns +const unichar ZX_CODA_STARTEND_ENCODING[] = {'A', 'B', 'C', 'D'}; + +// some codabar generator allow the codabar string to be closed by every +// character. This will cause lots of false positives! + +// some industries use a checksum standard but this is not part of the original codabar standard +// for more information see : http://www.mecsw.com/specs/codabar.html + +@interface ZXCodaBarReader () + +@property (nonatomic, strong) NSMutableString *decodeRowResult; +@property (nonatomic, strong) ZXIntArray *counters; +@property (nonatomic, assign) int counterLength; + +@end + +@implementation ZXCodaBarReader + +- (id)init { + if (self = [super init]) { + _decodeRowResult = [NSMutableString stringWithCapacity:20]; + _counters = [[ZXIntArray alloc] initWithLength:80]; + _counterLength = 0; + } + + return self; +} + +- (ZXResult *)decodeRow:(int)rowNumber row:(ZXBitArray *)row hints:(ZXDecodeHints *)hints error:(NSError **)error { + [self.counters clear]; + + if (![self setCountersWithRow:row]) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + + int startOffset = [self findStartPattern]; + if (startOffset == -1) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + + int nextStart = startOffset; + + self.decodeRowResult = [NSMutableString string]; + do { + int charOffset = [self toNarrowWidePattern:nextStart]; + if (charOffset == -1) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + // Hack: We store the position in the alphabet table into a + // NSMutableString, so that we can access the decoded patterns in + // validatePattern. We'll translate to the actual characters later. + [self.decodeRowResult appendFormat:@"%C", (unichar)charOffset]; + nextStart += 8; + // Stop as soon as we see the end character. + if (self.decodeRowResult.length > 1 && + [ZXCodaBarReader arrayContains:ZX_CODA_STARTEND_ENCODING + length:sizeof(ZX_CODA_STARTEND_ENCODING) / sizeof(unichar) + key:ZX_CODA_ALPHABET[charOffset]]) { + break; + } + } while (nextStart < self.counterLength); // no fixed end pattern so keep on reading while data is available + + // Look for whitespace after pattern: + int trailingWhitespace = self.counters.array[nextStart - 1]; + int lastPatternSize = 0; + for (int i = -8; i < -1; i++) { + lastPatternSize += self.counters.array[nextStart + i]; + } + + // We need to see whitespace equal to 50% of the last pattern size, + // otherwise this is probably a false positive. The exception is if we are + // at the end of the row. (I.e. the barcode barely fits.) + if (nextStart < self.counterLength && trailingWhitespace < lastPatternSize / 2) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + + if (![self validatePattern:startOffset]) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + + // Translate character table offsets to actual characters. + for (int i = 0; i < self.decodeRowResult.length; i++) { + [self.decodeRowResult replaceCharactersInRange:NSMakeRange(i, 1) withString:[NSString stringWithFormat:@"%c", ZX_CODA_ALPHABET[[self.decodeRowResult characterAtIndex:i]]]]; + } + // Ensure a valid start and end character + unichar startchar = [self.decodeRowResult characterAtIndex:0]; + if (![ZXCodaBarReader arrayContains:ZX_CODA_STARTEND_ENCODING + length:sizeof(ZX_CODA_STARTEND_ENCODING) / sizeof(unichar) + key:startchar]) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + unichar endchar = [self.decodeRowResult characterAtIndex:self.decodeRowResult.length - 1]; + if (![ZXCodaBarReader arrayContains:ZX_CODA_STARTEND_ENCODING + length:sizeof(ZX_CODA_STARTEND_ENCODING) / sizeof(unichar) + key:endchar]) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + + // remove stop/start characters character and check if a long enough string is contained + if (self.decodeRowResult.length <= ZX_CODA_MIN_CHARACTER_LENGTH) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + + if (!hints.returnCodaBarStartEnd) { + [self.decodeRowResult deleteCharactersInRange:NSMakeRange(self.decodeRowResult.length - 1, 1)]; + [self.decodeRowResult deleteCharactersInRange:NSMakeRange(0, 1)]; + } + + int runningCount = 0; + for (int i = 0; i < startOffset; i++) { + runningCount += self.counters.array[i]; + } + float left = (float) runningCount; + for (int i = startOffset; i < nextStart - 1; i++) { + runningCount += self.counters.array[i]; + } + float right = (float) runningCount; + return [ZXResult resultWithText:self.decodeRowResult + rawBytes:nil + resultPoints:@[[[ZXResultPoint alloc] initWithX:left y:(float)rowNumber], + [[ZXResultPoint alloc] initWithX:right y:(float)rowNumber]] + format:kBarcodeFormatCodabar]; +} + +- (BOOL)validatePattern:(int)start { + // First, sum up the total size of our four categories of stripe sizes; + int sizes[4] = {0, 0, 0, 0}; + int counts[4] = {0, 0, 0, 0}; + int end = (int)self.decodeRowResult.length - 1; + + // We break out of this loop in the middle, in order to handle + // inter-character spaces properly. + int pos = start; + for (int i = 0; true; i++) { + int pattern = ZX_CODA_CHARACTER_ENCODINGS[[self.decodeRowResult characterAtIndex:i]]; + for (int j = 6; j >= 0; j--) { + // Even j = bars, while odd j = spaces. Categories 2 and 3 are for + // long stripes, while 0 and 1 are for short stripes. + int category = (j & 1) + (pattern & 1) * 2; + sizes[category] += self.counters.array[pos + j]; + counts[category]++; + pattern >>= 1; + } + if (i >= end) { + break; + } + // We ignore the inter-character space - it could be of any size. + pos += 8; + } + + // Calculate our allowable size thresholds using fixed-point math. + float maxes[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + float mins[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + // Define the threshold of acceptability to be the midpoint between the + // average small stripe and the average large stripe. No stripe lengths + // should be on the "wrong" side of that line. + for (int i = 0; i < 2; i++) { + mins[i] = 0.0f; // Accept arbitrarily small "short" stripes. + mins[i + 2] = ((float) sizes[i] / counts[i] + (float) sizes[i + 2] / counts[i + 2]) / 2.0f; + maxes[i] = mins[i + 2]; + maxes[i + 2] = (sizes[i + 2] * ZX_CODA_MAX_ACCEPTABLE + ZX_CODA_PADDING) / counts[i + 2]; + } + + // Now verify that all of the stripes are within the thresholds. + pos = start; + for (int i = 0; true; i++) { + int pattern = ZX_CODA_CHARACTER_ENCODINGS[[self.decodeRowResult characterAtIndex:i]]; + for (int j = 6; j >= 0; j--) { + // Even j = bars, while odd j = spaces. Categories 2 and 3 are for + // long stripes, while 0 and 1 are for short stripes. + int category = (j & 1) + (pattern & 1) * 2; + int size = self.counters.array[pos + j]; + if (size < mins[category] || size > maxes[category]) { + return NO; + } + pattern >>= 1; + } + if (i >= end) { + break; + } + pos += 8; + } + + return YES; +} + +/** + * Records the size of all runs of white and black pixels, starting with white. + * This is just like recordPattern, except it records all the counters, and + * uses our builtin "counters" member for storage. + */ +- (BOOL)setCountersWithRow:(ZXBitArray *)row { + self.counterLength = 0; + // Start from the first white bit. + int i = [row nextUnset:0]; + int end = row.size; + if (i >= end) { + return NO; + } + BOOL isWhite = YES; + int count = 0; + while (i < end) { + if ([row get:i] ^ isWhite) { // that is, exactly one is true + count++; + } else { + [self counterAppend:count]; + count = 1; + isWhite = !isWhite; + } + i++; + } + [self counterAppend:count]; + return YES; +} + +- (void)counterAppend:(int)e { + self.counters.array[self.counterLength] = e; + self.counterLength++; + if (self.counterLength >= self.counters.length) { + ZXIntArray *temp = [[ZXIntArray alloc] initWithLength:self.counterLength * 2]; + memcpy(temp.array, self.counters.array, self.counters.length * sizeof(int32_t)); + self.counters = temp; + } +} + +- (int)findStartPattern { + for (int i = 1; i < self.counterLength; i += 2) { + int charOffset = [self toNarrowWidePattern:i]; + if (charOffset != -1 && [[self class] arrayContains:ZX_CODA_STARTEND_ENCODING + length:sizeof(ZX_CODA_STARTEND_ENCODING) / sizeof(unichar) + key:ZX_CODA_ALPHABET[charOffset]]) { + // Look for whitespace before start pattern, >= 50% of width of start pattern + // We make an exception if the whitespace is the first element. + int patternSize = 0; + for (int j = i; j < i + 7; j++) { + patternSize += self.counters.array[j]; + } + if (i == 1 || self.counters.array[i-1] >= patternSize / 2) { + return i; + } + } + } + + return -1; +} + ++ (BOOL)arrayContains:(const unichar *)array length:(unsigned int)length key:(unichar)key { + if (array != nil) { + for (int i = 0; i < length; i++) { + if (array[i] == key) { + return YES; + } + } + } + return NO; +} + +// Assumes that counters[position] is a bar. +- (int)toNarrowWidePattern:(int)position { + int32_t *array = self.counters.array; + int end = position + 7; + if (end >= self.counterLength) { + return -1; + } + + int maxBar = 0; + int minBar = INT_MAX; + for (int j = position; j < end; j += 2) { + int currentCounter = array[j]; + if (currentCounter < minBar) { + minBar = currentCounter; + } + if (currentCounter > maxBar) { + maxBar = currentCounter; + } + } + int thresholdBar = (minBar + maxBar) / 2; + + int maxSpace = 0; + int minSpace = INT_MAX; + for (int j = position + 1; j < end; j += 2) { + int currentCounter = array[j]; + if (currentCounter < minSpace) { + minSpace = currentCounter; + } + if (currentCounter > maxSpace) { + maxSpace = currentCounter; + } + } + int thresholdSpace = (minSpace + maxSpace) / 2; + + int bitmask = 1 << 7; + int pattern = 0; + for (int i = 0; i < 7; i++) { + int threshold = (i & 1) == 0 ? thresholdBar : thresholdSpace; + bitmask >>= 1; + if (array[position + i] > threshold) { + pattern |= bitmask; + } + } + + for (int i = 0; i < sizeof(ZX_CODA_CHARACTER_ENCODINGS) / sizeof(int); i++) { + if (ZX_CODA_CHARACTER_ENCODINGS[i] == pattern) { + return i; + } + } + return -1; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXCodaBarWriter.h b/iDearQRCode/Tools/ZXingObjC/oned/ZXCodaBarWriter.h new file mode 100755 index 0000000..c28a007 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXCodaBarWriter.h @@ -0,0 +1,24 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXOneDimensionalCodeWriter.h" + +/** + * This class renders CodaBar as ZXBoolArray. + */ +@interface ZXCodaBarWriter : ZXOneDimensionalCodeWriter + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXCodaBarWriter.m b/iDearQRCode/Tools/ZXingObjC/oned/ZXCodaBarWriter.m new file mode 100755 index 0000000..20f5d9b --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXCodaBarWriter.m @@ -0,0 +1,140 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBoolArray.h" +#import "ZXCodaBarReader.h" +#import "ZXCodaBarWriter.h" + +const unichar ZX_CODA_START_END_CHARS[] = {'A', 'B', 'C', 'D'}; +const unichar ZX_CODA_ALT_START_END_CHARS[] = {'T', 'N', '*', 'E'}; +const unichar ZX_CHARS_WHICH_ARE_TEN_LENGTH_EACH_AFTER_DECODED[] = {'/', ':', '+', '.'}; +static unichar ZX_CODA_DEFAULT_GUARD; + +@implementation ZXCodaBarWriter + ++ (void)initialize { + if ([self class] != [ZXCodaBarWriter class]) return; + + ZX_CODA_DEFAULT_GUARD = ZX_CODA_START_END_CHARS[0]; +} + +- (ZXBoolArray *)encode:(NSString *)contents { + if ([contents length] < 2) { + // Can't have a start/end guard, so tentatively add default guards + contents = [NSString stringWithFormat:@"%C%@%C", ZX_CODA_DEFAULT_GUARD, contents, ZX_CODA_DEFAULT_GUARD]; + } else { + // Verify input and calculate decoded length. + unichar firstChar = [[contents uppercaseString] characterAtIndex:0]; + unichar lastChar = [[contents uppercaseString] characterAtIndex:contents.length - 1]; + BOOL startsNormal = [ZXCodaBarReader arrayContains:ZX_CODA_START_END_CHARS length:sizeof(ZX_CODA_START_END_CHARS) / sizeof(unichar) key:firstChar]; + BOOL endsNormal = [ZXCodaBarReader arrayContains:ZX_CODA_START_END_CHARS length:sizeof(ZX_CODA_START_END_CHARS) / sizeof(unichar) key:lastChar]; + BOOL startsAlt = [ZXCodaBarReader arrayContains:ZX_CODA_ALT_START_END_CHARS length:sizeof(ZX_CODA_ALT_START_END_CHARS) / sizeof(unichar) key:firstChar]; + BOOL endsAlt = [ZXCodaBarReader arrayContains:ZX_CODA_ALT_START_END_CHARS length:sizeof(ZX_CODA_ALT_START_END_CHARS) / sizeof(unichar) key:lastChar]; + if (startsNormal) { + if (!endsNormal) { + @throw [NSException exceptionWithName:NSInvalidArgumentException + reason:[NSString stringWithFormat:@"Invalid start/end guards: %@", contents] + userInfo:nil]; + } + // else already has valid start/end + } else if (startsAlt) { + if (!endsAlt) { + @throw [NSException exceptionWithName:NSInvalidArgumentException + reason:[NSString stringWithFormat:@"Invalid start/end guards: %@", contents] + userInfo:nil]; + } + // else already has valid start/end + } else { + // Doesn't start with a guard + if (endsNormal || endsAlt) { + @throw [NSException exceptionWithName:NSInvalidArgumentException + reason:[NSString stringWithFormat:@"Invalid start/end guards: %@", contents] + userInfo:nil]; + } + // else doesn't end with guard either, so add a default + contents = [NSString stringWithFormat:@"%C%@%C", ZX_CODA_DEFAULT_GUARD, contents, ZX_CODA_DEFAULT_GUARD]; + } + } + + // The start character and the end character are decoded to 10 length each. + int resultLength = 20; + for (int i = 1; i < contents.length - 1; i++) { + if (([contents characterAtIndex:i] >= '0' && [contents characterAtIndex:i] <= '9') || + [contents characterAtIndex:i] == '-' || [contents characterAtIndex:i] == '$') { + resultLength += 9; + } else if ([ZXCodaBarReader arrayContains:ZX_CHARS_WHICH_ARE_TEN_LENGTH_EACH_AFTER_DECODED length:4 key:[contents characterAtIndex:i]]) { + resultLength += 10; + } else { + @throw [NSException exceptionWithName:NSInvalidArgumentException + reason:[NSString stringWithFormat:@"Cannot encode : '%C'", [contents characterAtIndex:i]] + userInfo:nil]; + } + } + // A blank is placed between each character. + resultLength += contents.length - 1; + + ZXBoolArray *result = [[ZXBoolArray alloc] initWithLength:resultLength]; + int position = 0; + for (int index = 0; index < contents.length; index++) { + unichar c = [[contents uppercaseString] characterAtIndex:index]; + if (index == 0 || index == contents.length - 1) { + // The start/end chars are not in the CodaBarReader.ALPHABET. + switch (c) { + case 'T': + c = 'A'; + break; + case 'N': + c = 'B'; + break; + case '*': + c = 'C'; + break; + case 'E': + c = 'D'; + break; + } + } + int code = 0; + for (int i = 0; i < ZX_CODA_ALPHABET_LEN; i++) { + // Found any, because I checked above. + if (c == ZX_CODA_ALPHABET[i]) { + code = ZX_CODA_CHARACTER_ENCODINGS[i]; + break; + } + } + BOOL color = YES; + int counter = 0; + int bit = 0; + while (bit < 7) { // A character consists of 7 digit. + result.array[position] = color; + position++; + if (((code >> (6 - bit)) & 1) == 0 || counter == 1) { + color = !color; // Flip the color. + bit++; + counter = 0; + } else { + counter++; + } + } + if (index < contents.length - 1) { + result.array[position] = NO; + position++; + } + } + return result; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXCode128Reader.h b/iDearQRCode/Tools/ZXingObjC/oned/ZXCode128Reader.h new file mode 100755 index 0000000..ff0a0c8 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXCode128Reader.h @@ -0,0 +1,40 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXOneDReader.h" + +extern const int ZX_CODE128_CODE_PATTERNS[][7]; + +extern const int ZX_CODE128_CODE_START_B; +extern const int ZX_CODE128_CODE_START_C; +extern const int ZX_CODE128_CODE_CODE_B; +extern const int ZX_CODE128_CODE_CODE_C; +extern const int ZX_CODE128_CODE_STOP; + +extern const int ZX_CODE128_CODE_FNC_1; +extern const int ZX_CODE128_CODE_FNC_2; +extern const int ZX_CODE128_CODE_FNC_3; +extern const int ZX_CODE128_CODE_FNC_4_A; +extern const int ZX_CODE128_CODE_FNC_4_B; + +@class ZXDecodeHints, ZXResult; + +/** + * Decodes Code 128 barcodes. + */ +@interface ZXCode128Reader : ZXOneDReader + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXCode128Reader.m b/iDearQRCode/Tools/ZXingObjC/oned/ZXCode128Reader.m new file mode 100755 index 0000000..90d2574 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXCode128Reader.m @@ -0,0 +1,534 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitArray.h" +#import "ZXByteArray.h" +#import "ZXCode128Reader.h" +#import "ZXDecodeHints.h" +#import "ZXErrors.h" +#import "ZXIntArray.h" +#import "ZXOneDReader.h" +#import "ZXResult.h" +#import "ZXResultPoint.h" + +const int ZX_CODE128_CODE_PATTERNS_LEN = 107; +const int ZX_CODE128_CODE_PATTERNS[ZX_CODE128_CODE_PATTERNS_LEN][7] = { + {2, 1, 2, 2, 2, 2}, // 0 + {2, 2, 2, 1, 2, 2}, + {2, 2, 2, 2, 2, 1}, + {1, 2, 1, 2, 2, 3}, + {1, 2, 1, 3, 2, 2}, + {1, 3, 1, 2, 2, 2}, // 5 + {1, 2, 2, 2, 1, 3}, + {1, 2, 2, 3, 1, 2}, + {1, 3, 2, 2, 1, 2}, + {2, 2, 1, 2, 1, 3}, + {2, 2, 1, 3, 1, 2}, // 10 + {2, 3, 1, 2, 1, 2}, + {1, 1, 2, 2, 3, 2}, + {1, 2, 2, 1, 3, 2}, + {1, 2, 2, 2, 3, 1}, + {1, 1, 3, 2, 2, 2}, // 15 + {1, 2, 3, 1, 2, 2}, + {1, 2, 3, 2, 2, 1}, + {2, 2, 3, 2, 1, 1}, + {2, 2, 1, 1, 3, 2}, + {2, 2, 1, 2, 3, 1}, // 20 + {2, 1, 3, 2, 1, 2}, + {2, 2, 3, 1, 1, 2}, + {3, 1, 2, 1, 3, 1}, + {3, 1, 1, 2, 2, 2}, + {3, 2, 1, 1, 2, 2}, // 25 + {3, 2, 1, 2, 2, 1}, + {3, 1, 2, 2, 1, 2}, + {3, 2, 2, 1, 1, 2}, + {3, 2, 2, 2, 1, 1}, + {2, 1, 2, 1, 2, 3}, // 30 + {2, 1, 2, 3, 2, 1}, + {2, 3, 2, 1, 2, 1}, + {1, 1, 1, 3, 2, 3}, + {1, 3, 1, 1, 2, 3}, + {1, 3, 1, 3, 2, 1}, // 35 + {1, 1, 2, 3, 1, 3}, + {1, 3, 2, 1, 1, 3}, + {1, 3, 2, 3, 1, 1}, + {2, 1, 1, 3, 1, 3}, + {2, 3, 1, 1, 1, 3}, // 40 + {2, 3, 1, 3, 1, 1}, + {1, 1, 2, 1, 3, 3}, + {1, 1, 2, 3, 3, 1}, + {1, 3, 2, 1, 3, 1}, + {1, 1, 3, 1, 2, 3}, // 45 + {1, 1, 3, 3, 2, 1}, + {1, 3, 3, 1, 2, 1}, + {3, 1, 3, 1, 2, 1}, + {2, 1, 1, 3, 3, 1}, + {2, 3, 1, 1, 3, 1}, // 50 + {2, 1, 3, 1, 1, 3}, + {2, 1, 3, 3, 1, 1}, + {2, 1, 3, 1, 3, 1}, + {3, 1, 1, 1, 2, 3}, + {3, 1, 1, 3, 2, 1}, // 55 + {3, 3, 1, 1, 2, 1}, + {3, 1, 2, 1, 1, 3}, + {3, 1, 2, 3, 1, 1}, + {3, 3, 2, 1, 1, 1}, + {3, 1, 4, 1, 1, 1}, // 60 + {2, 2, 1, 4, 1, 1}, + {4, 3, 1, 1, 1, 1}, + {1, 1, 1, 2, 2, 4}, + {1, 1, 1, 4, 2, 2}, + {1, 2, 1, 1, 2, 4}, // 65 + {1, 2, 1, 4, 2, 1}, + {1, 4, 1, 1, 2, 2}, + {1, 4, 1, 2, 2, 1}, + {1, 1, 2, 2, 1, 4}, + {1, 1, 2, 4, 1, 2}, // 70 + {1, 2, 2, 1, 1, 4}, + {1, 2, 2, 4, 1, 1}, + {1, 4, 2, 1, 1, 2}, + {1, 4, 2, 2, 1, 1}, + {2, 4, 1, 2, 1, 1}, // 75 + {2, 2, 1, 1, 1, 4}, + {4, 1, 3, 1, 1, 1}, + {2, 4, 1, 1, 1, 2}, + {1, 3, 4, 1, 1, 1}, + {1, 1, 1, 2, 4, 2}, // 80 + {1, 2, 1, 1, 4, 2}, + {1, 2, 1, 2, 4, 1}, + {1, 1, 4, 2, 1, 2}, + {1, 2, 4, 1, 1, 2}, + {1, 2, 4, 2, 1, 1}, // 85 + {4, 1, 1, 2, 1, 2}, + {4, 2, 1, 1, 1, 2}, + {4, 2, 1, 2, 1, 1}, + {2, 1, 2, 1, 4, 1}, + {2, 1, 4, 1, 2, 1}, // 90 + {4, 1, 2, 1, 2, 1}, + {1, 1, 1, 1, 4, 3}, + {1, 1, 1, 3, 4, 1}, + {1, 3, 1, 1, 4, 1}, + {1, 1, 4, 1, 1, 3}, // 95 + {1, 1, 4, 3, 1, 1}, + {4, 1, 1, 1, 1, 3}, + {4, 1, 1, 3, 1, 1}, + {1, 1, 3, 1, 4, 1}, + {1, 1, 4, 1, 3, 1}, // 100 + {3, 1, 1, 1, 4, 1}, + {4, 1, 1, 1, 3, 1}, + {2, 1, 1, 4, 1, 2}, + {2, 1, 1, 2, 1, 4}, + {2, 1, 1, 2, 3, 2}, // 105 + {2, 3, 3, 1, 1, 1, 2} +}; + +static float ZX_CODE128_MAX_AVG_VARIANCE = 0.25f; +static float ZX_CODE128_MAX_INDIVIDUAL_VARIANCE = 0.7f; + +const int ZX_CODE128_CODE_SHIFT = 98; +const int ZX_CODE128_CODE_CODE_C = 99; +const int ZX_CODE128_CODE_CODE_B = 100; +const int ZX_CODE128_CODE_CODE_A = 101; +const int ZX_CODE128_CODE_FNC_1 = 102; +const int ZX_CODE128_CODE_FNC_2 = 97; +const int ZX_CODE128_CODE_FNC_3 = 96; +const int ZX_CODE128_CODE_FNC_4_A = 101; +const int ZX_CODE128_CODE_FNC_4_B = 100; +const int ZX_CODE128_CODE_START_A = 103; +const int ZX_CODE128_CODE_START_B = 104; +const int ZX_CODE128_CODE_START_C = 105; +const int ZX_CODE128_CODE_STOP = 106; + +@implementation ZXCode128Reader + +- (ZXIntArray *)findStartPattern:(ZXBitArray *)row { + int width = row.size; + int rowOffset = [row nextSet:0]; + + int counterPosition = 0; + ZXIntArray *counters = [[ZXIntArray alloc] initWithLength:6]; + int32_t *array = counters.array; + int patternStart = rowOffset; + BOOL isWhite = NO; + int patternLength = (int)counters.length; + + for (int i = rowOffset; i < width; i++) { + if ([row get:i] ^ isWhite) { + array[counterPosition]++; + } else { + if (counterPosition == patternLength - 1) { + float bestVariance = ZX_CODE128_MAX_AVG_VARIANCE; + int bestMatch = -1; + for (int startCode = ZX_CODE128_CODE_START_A; startCode <= ZX_CODE128_CODE_START_C; startCode++) { + float variance = [ZXOneDReader patternMatchVariance:counters pattern:ZX_CODE128_CODE_PATTERNS[startCode] maxIndividualVariance:ZX_CODE128_MAX_INDIVIDUAL_VARIANCE]; + if (variance < bestVariance) { + bestVariance = variance; + bestMatch = startCode; + } + } + // Look for whitespace before start pattern, >= 50% of width of start pattern + if (bestMatch >= 0 && + [row isRange:MAX(0, patternStart - (i - patternStart) / 2) end:patternStart value:NO]) { + return [[ZXIntArray alloc] initWithInts:patternStart, i, bestMatch, -1]; + } + patternStart += array[0] + array[1]; + for (int y = 2; y < patternLength; y++) { + array[y - 2] = array[y]; + } + array[patternLength - 2] = 0; + array[patternLength - 1] = 0; + counterPosition--; + } else { + counterPosition++; + } + array[counterPosition] = 1; + isWhite = !isWhite; + } + } + + return nil; +} + +- (int)decodeCode:(ZXBitArray *)row counters:(ZXIntArray *)counters rowOffset:(int)rowOffset { + if (![ZXOneDReader recordPattern:row start:rowOffset counters:counters]) { + return -1; + } + float bestVariance = ZX_CODE128_MAX_AVG_VARIANCE; + int bestMatch = -1; + + for (int d = 0; d < ZX_CODE128_CODE_PATTERNS_LEN; d++) { + float variance = [ZXOneDReader patternMatchVariance:counters pattern:ZX_CODE128_CODE_PATTERNS[d] maxIndividualVariance:ZX_CODE128_MAX_INDIVIDUAL_VARIANCE]; + if (variance < bestVariance) { + bestVariance = variance; + bestMatch = d; + } + } + + if (bestMatch >= 0) { + return bestMatch; + } else { + return -1; + } +} + +- (ZXResult *)decodeRow:(int)rowNumber row:(ZXBitArray *)row hints:(ZXDecodeHints *)hints error:(NSError **)error { + BOOL convertFNC1 = hints && hints.assumeGS1; + + ZXIntArray *startPatternInfo = [self findStartPattern:row]; + if (!startPatternInfo) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + + int startCode = startPatternInfo.array[2]; + int codeSet; + + NSMutableArray *rawCodes = [NSMutableArray arrayWithObject:@(startCode)]; + + switch (startCode) { + case ZX_CODE128_CODE_START_A: + codeSet = ZX_CODE128_CODE_CODE_A; + break; + case ZX_CODE128_CODE_START_B: + codeSet = ZX_CODE128_CODE_CODE_B; + break; + case ZX_CODE128_CODE_START_C: + codeSet = ZX_CODE128_CODE_CODE_C; + break; + default: + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + + BOOL done = NO; + BOOL isNextShifted = NO; + + NSMutableString *result = [NSMutableString stringWithCapacity:20]; + + int lastStart = startPatternInfo.array[0]; + int nextStart = startPatternInfo.array[1]; + ZXIntArray *counters = [[ZXIntArray alloc] initWithLength:6]; + + int lastCode = 0; + int code = 0; + int checksumTotal = startCode; + int multiplier = 0; + BOOL lastCharacterWasPrintable = YES; + BOOL upperMode = NO; + BOOL shiftUpperMode = NO; + + while (!done) { + BOOL unshift = isNextShifted; + isNextShifted = NO; + + // Save off last code + lastCode = code; + + // Decode another code from image + code = [self decodeCode:row counters:counters rowOffset:nextStart]; + if (code == -1) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + + [rawCodes addObject:@(code)]; + + // Remember whether the last code was printable or not (excluding ZX_CODE128_CODE_STOP) + if (code != ZX_CODE128_CODE_STOP) { + lastCharacterWasPrintable = YES; + } + + // Add to checksum computation (if not ZX_CODE128_CODE_STOP of course) + if (code != ZX_CODE128_CODE_STOP) { + multiplier++; + checksumTotal += multiplier * code; + } + + // Advance to where the next code will to start + lastStart = nextStart; + nextStart += [counters sum]; + + // Take care of illegal start codes + switch (code) { + case ZX_CODE128_CODE_START_A: + case ZX_CODE128_CODE_START_B: + case ZX_CODE128_CODE_START_C: + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + + switch (codeSet) { + case ZX_CODE128_CODE_CODE_A: + if (code < 64) { + if (shiftUpperMode == upperMode) { + [result appendFormat:@"%C", (unichar)(' ' + code)]; + } else { + [result appendFormat:@"%C", (unichar)(' ' + code + 128)]; + } + shiftUpperMode = NO; + } else if (code < 96) { + if (shiftUpperMode == upperMode) { + [result appendFormat:@"%C", (unichar)(code - 64)]; + } else { + [result appendFormat:@"%C", (unichar)(code + 64)]; + } + shiftUpperMode = NO; + } else { + // Don't let CODE_STOP, which always appears, affect whether whether we think the last + // code was printable or not. + if (code != ZX_CODE128_CODE_STOP) { + lastCharacterWasPrintable = NO; + } + + switch (code) { + case ZX_CODE128_CODE_FNC_1: + if (convertFNC1) { + if (result.length == 0) { + // GS1 specification 5.4.3.7. and 5.4.6.4. If the first char after the start code + // is FNC1 then this is GS1-128. We add the symbology identifier. + [result appendString:@"]C1"]; + } else { + // GS1 specification 5.4.7.5. Every subsequent FNC1 is returned as ASCII 29 (GS) + [result appendFormat:@"%C", (unichar) 29]; + } + } + break; + case ZX_CODE128_CODE_FNC_2: + case ZX_CODE128_CODE_FNC_3: + // do nothing? + break; + case ZX_CODE128_CODE_FNC_4_A: + if (!upperMode && shiftUpperMode) { + upperMode = YES; + shiftUpperMode = NO; + } else if (upperMode && shiftUpperMode) { + upperMode = NO; + shiftUpperMode = NO; + } else { + shiftUpperMode = YES; + } + break; + case ZX_CODE128_CODE_SHIFT: + isNextShifted = YES; + codeSet = ZX_CODE128_CODE_CODE_B; + break; + case ZX_CODE128_CODE_CODE_B: + codeSet = ZX_CODE128_CODE_CODE_B; + break; + case ZX_CODE128_CODE_CODE_C: + codeSet = ZX_CODE128_CODE_CODE_C; + break; + case ZX_CODE128_CODE_STOP: + done = YES; + break; + } + } + break; + case ZX_CODE128_CODE_CODE_B: + if (code < 96) { + if (shiftUpperMode == upperMode) { + [result appendFormat:@"%C", (unichar)(' ' + code)]; + } else { + [result appendFormat:@"%C", (unichar)(' ' + code + 128)]; + } + shiftUpperMode = NO; + } else { + if (code != ZX_CODE128_CODE_STOP) { + lastCharacterWasPrintable = NO; + } + + switch (code) { + case ZX_CODE128_CODE_FNC_1: + if (convertFNC1) { + if (result.length == 0) { + // GS1 specification 5.4.3.7. and 5.4.6.4. If the first char after the start code + // is FNC1 then this is GS1-128. We add the symbology identifier. + [result appendString:@"]C1"]; + } else { + // GS1 specification 5.4.7.5. Every subsequent FNC1 is returned as ASCII 29 (GS) + [result appendFormat:@"%C", (unichar) 29]; + } + } + break; + case ZX_CODE128_CODE_FNC_2: + case ZX_CODE128_CODE_FNC_3: + // do nothing? + break; + case ZX_CODE128_CODE_FNC_4_B: + if (!upperMode && shiftUpperMode) { + upperMode = YES; + shiftUpperMode = NO; + } else if (upperMode && shiftUpperMode) { + upperMode = NO; + shiftUpperMode = NO; + } else { + shiftUpperMode = YES; + } + break; + case ZX_CODE128_CODE_SHIFT: + isNextShifted = YES; + codeSet = ZX_CODE128_CODE_CODE_A; + break; + case ZX_CODE128_CODE_CODE_A: + codeSet = ZX_CODE128_CODE_CODE_A; + break; + case ZX_CODE128_CODE_CODE_C: + codeSet = ZX_CODE128_CODE_CODE_C; + break; + case ZX_CODE128_CODE_STOP: + done = YES; + break; + } + } + break; + case ZX_CODE128_CODE_CODE_C: + if (code < 100) { + if (code < 10) { + [result appendString:@"0"]; + } + [result appendFormat:@"%d", code]; + } else { + if (code != ZX_CODE128_CODE_STOP) { + lastCharacterWasPrintable = NO; + } + + switch (code) { + case ZX_CODE128_CODE_FNC_1: + if (convertFNC1) { + if (result.length == 0) { + // GS1 specification 5.4.3.7. and 5.4.6.4. If the first char after the start code + // is FNC1 then this is GS1-128. We add the symbology identifier. + [result appendString:@"]C1"]; + } else { + // GS1 specification 5.4.7.5. Every subsequent FNC1 is returned as ASCII 29 (GS) + [result appendFormat:@"%C", (unichar) 29]; + } + } + break; + case ZX_CODE128_CODE_CODE_A: + codeSet = ZX_CODE128_CODE_CODE_A; + break; + case ZX_CODE128_CODE_CODE_B: + codeSet = ZX_CODE128_CODE_CODE_B; + break; + case ZX_CODE128_CODE_STOP: + done = YES; + break; + } + } + break; + } + + // Unshift back to another code set if we were shifted + if (unshift) { + codeSet = codeSet == ZX_CODE128_CODE_CODE_A ? ZX_CODE128_CODE_CODE_B : ZX_CODE128_CODE_CODE_A; + } + } + + int lastPatternSize = nextStart - lastStart; + + // Check for ample whitespace following pattern, but, to do this we first need to remember that + // we fudged decoding CODE_STOP since it actually has 7 bars, not 6. There is a black bar left + // to read off. Would be slightly better to properly read. Here we just skip it: + nextStart = [row nextUnset:nextStart]; + if (![row isRange:nextStart end:MIN(row.size, nextStart + (nextStart - lastStart) / 2) value:NO]) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + + // Pull out from sum the value of the penultimate check code + checksumTotal -= multiplier * lastCode; + // lastCode is the checksum then: + if (checksumTotal % 103 != lastCode) { + if (error) *error = ZXChecksumErrorInstance(); + return nil; + } + + // Need to pull out the check digits from string + NSUInteger resultLength = [result length]; + if (resultLength == 0) { + // false positive + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + + // Only bother if the result had at least one character, and if the checksum digit happened to + // be a printable character. If it was just interpreted as a control code, nothing to remove. + if (resultLength > 0 && lastCharacterWasPrintable) { + if (codeSet == ZX_CODE128_CODE_CODE_C) { + [result deleteCharactersInRange:NSMakeRange(resultLength - 2, 2)]; + } else { + [result deleteCharactersInRange:NSMakeRange(resultLength - 1, 1)]; + } + } + + float left = (float)(startPatternInfo.array[1] + startPatternInfo.array[0]) / 2.0f; + float right = lastStart + lastPatternSize / 2.0f; + + NSUInteger rawCodesSize = [rawCodes count]; + ZXByteArray *rawBytes = [[ZXByteArray alloc] initWithLength:(unsigned int)rawCodesSize]; + for (int i = 0; i < rawCodesSize; i++) { + rawBytes.array[i] = (int8_t)[rawCodes[i] intValue]; + } + + return [ZXResult resultWithText:result + rawBytes:rawBytes + resultPoints:@[[[ZXResultPoint alloc] initWithX:left y:(float)rowNumber], + [[ZXResultPoint alloc] initWithX:right y:(float)rowNumber]] + format:kBarcodeFormatCode128]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXCode128Writer.h b/iDearQRCode/Tools/ZXingObjC/oned/ZXCode128Writer.h new file mode 100755 index 0000000..61a3949 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXCode128Writer.h @@ -0,0 +1,24 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXOneDimensionalCodeWriter.h" + +/** + * This object renders a CODE128 code as a ZXBitMatrix. + */ +@interface ZXCode128Writer : ZXOneDimensionalCodeWriter + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXCode128Writer.m b/iDearQRCode/Tools/ZXingObjC/oned/ZXCode128Writer.m new file mode 100755 index 0000000..77656c7 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXCode128Writer.m @@ -0,0 +1,188 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBoolArray.h" +#import "ZXCode128Reader.h" +#import "ZXCode128Writer.h" + +// Dummy characters used to specify control characters in input +const unichar ZX_CODE128_ESCAPE_FNC_1 = L'\u00f1'; +const unichar ZX_CODE128_ESCAPE_FNC_2 = L'\u00f2'; +const unichar ZX_CODE128_ESCAPE_FNC_3 = L'\u00f3'; +const unichar ZX_CODE128_ESCAPE_FNC_4 = L'\u00f4'; + +@implementation ZXCode128Writer + +- (ZXBitMatrix *)encode:(NSString *)contents format:(ZXBarcodeFormat)format width:(int)width height:(int)height hints:(ZXEncodeHints *)hints error:(NSError **)error { + if (format != kBarcodeFormatCode128) { + [NSException raise:NSInvalidArgumentException format:@"Can only encode CODE_128"]; + } + return [super encode:contents format:format width:width height:height hints:hints error:error]; +} + +- (ZXBoolArray *)encode:(NSString *)contents { + int length = (int)[contents length]; + // Check length + if (length < 1 || length > 80) { + [NSException raise:NSInvalidArgumentException format:@"Contents length should be between 1 and 80 characters, but got %d", length]; + } + // Check content + for (int i = 0; i < length; i++) { + unichar c = [contents characterAtIndex:i]; + if (c < ' ' || c > '~') { + switch (c) { + case ZX_CODE128_ESCAPE_FNC_1: + case ZX_CODE128_ESCAPE_FNC_2: + case ZX_CODE128_ESCAPE_FNC_3: + case ZX_CODE128_ESCAPE_FNC_4: + break; + default: + [NSException raise:NSInvalidArgumentException format:@"Bad character in input: %C", c]; + } + } + } + + NSMutableArray *patterns = [NSMutableArray array]; // temporary storage for patterns + int checkSum = 0; + int checkWeight = 1; + int codeSet = 0; // selected code (CODE_CODE_B or CODE_CODE_C) + int position = 0; // position in contents + + while (position < length) { + //Select code to use + int requiredDigitCount = codeSet == ZX_CODE128_CODE_CODE_C ? 2 : 4; + int newCodeSet; + if ([self isDigits:contents start:position length:requiredDigitCount]) { + newCodeSet = ZX_CODE128_CODE_CODE_C; + } else { + newCodeSet = ZX_CODE128_CODE_CODE_B; + } + + //Get the pattern index + int patternIndex; + if (newCodeSet == codeSet) { + // Encode the current character + // First handle escapes + switch ([contents characterAtIndex:position]) { + case ZX_CODE128_ESCAPE_FNC_1: + patternIndex = ZX_CODE128_CODE_FNC_1; + break; + case ZX_CODE128_ESCAPE_FNC_2: + patternIndex = ZX_CODE128_CODE_FNC_2; + break; + case ZX_CODE128_ESCAPE_FNC_3: + patternIndex = ZX_CODE128_CODE_FNC_3; + break; + case ZX_CODE128_ESCAPE_FNC_4: + patternIndex = ZX_CODE128_CODE_FNC_4_B; // FIXME if this ever outputs Code A + break; + default: + // Then handle normal characters otherwise + if (codeSet == ZX_CODE128_CODE_CODE_B) { + patternIndex = [contents characterAtIndex:position] - ' '; + } else { // CODE_CODE_C + patternIndex = [[contents substringWithRange:NSMakeRange(position, 2)] intValue]; + position++; // Also incremented below + } + } + position++; + } else { + // Should we change the current code? + // Do we have a code set? + if (codeSet == 0) { + // No, we don't have a code set + if (newCodeSet == ZX_CODE128_CODE_CODE_B) { + patternIndex = ZX_CODE128_CODE_START_B; + } else { + // CODE_CODE_C + patternIndex = ZX_CODE128_CODE_START_C; + } + } else { + // Yes, we have a code set + patternIndex = newCodeSet; + } + codeSet = newCodeSet; + } + + // Get the pattern + NSMutableArray *pattern = [NSMutableArray array]; + for (int i = 0; i < sizeof(ZX_CODE128_CODE_PATTERNS[patternIndex]) / sizeof(int); i++) { + [pattern addObject:@(ZX_CODE128_CODE_PATTERNS[patternIndex][i])]; + } + [patterns addObject:pattern]; + + // Compute checksum + checkSum += patternIndex * checkWeight; + if (position != 0) { + checkWeight++; + } + } + + // Compute and append checksum + checkSum %= 103; + NSMutableArray *pattern = [NSMutableArray array]; + for (int i = 0; i < sizeof(ZX_CODE128_CODE_PATTERNS[checkSum]) / sizeof(int); i++) { + [pattern addObject:@(ZX_CODE128_CODE_PATTERNS[checkSum][i])]; + } + [patterns addObject:pattern]; + + // Append stop code + pattern = [NSMutableArray array]; + for (int i = 0; i < sizeof(ZX_CODE128_CODE_PATTERNS[ZX_CODE128_CODE_STOP]) / sizeof(int); i++) { + [pattern addObject:@(ZX_CODE128_CODE_PATTERNS[ZX_CODE128_CODE_STOP][i])]; + } + [patterns addObject:pattern]; + + // Compute code width + int codeWidth = 0; + for (pattern in patterns) { + for (int i = 0; i < pattern.count; i++) { + codeWidth += [pattern[i] intValue]; + } + } + + // Compute result + ZXBoolArray *result = [[ZXBoolArray alloc] initWithLength:codeWidth]; + int pos = 0; + for (NSArray *patternArray in patterns) { + int patternLen = (int)[patternArray count]; + int pattern[patternLen]; + for (int i = 0; i < patternLen; i++) { + pattern[i] = [patternArray[i] intValue]; + } + + pos += [self appendPattern:result pos:pos pattern:pattern patternLen:patternLen startColor:YES]; + } + + return result; +} + +- (BOOL)isDigits:(NSString *)value start:(int)start length:(unsigned int)length { + int end = start + length; + int last = (int)[value length]; + for (int i = start; i < end && i < last; i++) { + unichar c = [value characterAtIndex:i]; + if (c < '0' || c > '9') { + if (c != ZX_CODE128_ESCAPE_FNC_1) { + return NO; + } + end++; // ignore FNC_1 + } + } + return end <= last; // end > last if we've run out of string +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXCode39Reader.h b/iDearQRCode/Tools/ZXingObjC/oned/ZXCode39Reader.h new file mode 100755 index 0000000..d621148 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXCode39Reader.h @@ -0,0 +1,57 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXOneDReader.h" + +extern unichar ZX_CODE39_ALPHABET[]; +extern NSString *ZX_CODE39_ALPHABET_STRING; +extern const int ZX_CODE39_CHARACTER_ENCODINGS[]; + +@class ZXDecodeHints, ZXResult; + +/** + * Decodes Code 39 barcodes. This does not support "Full ASCII Code 39" yet. + */ +@interface ZXCode39Reader : ZXOneDReader + +/** + * Creates a reader that assumes all encoded data is data, and does not treat the final + * character as a check digit. It will not decoded "extended Code 39" sequences. + */ +- (id)init; + +/** + * Creates a reader that can be configured to check the last character as a check digit. + * It will not decoded "extended Code 39" sequences. + * + * @param usingCheckDigit if true, treat the last data character as a check digit, not + * data, and verify that the checksum passes. + */ +- (id)initUsingCheckDigit:(BOOL)usingCheckDigit; + +/** + * Creates a reader that can be configured to check the last character as a check digit, + * or optionally attempt to decode "extended Code 39" sequences that are used to encode + * the full ASCII character set. + * + * @param usingCheckDigit if true, treat the last data character as a check digit, not + * data, and verify that the checksum passes. + * @param extendedMode if true, will attempt to decode extended Code 39 sequences in the + * text. + */ +- (id)initUsingCheckDigit:(BOOL)usingCheckDigit extendedMode:(BOOL)extendedMode; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXCode39Reader.m b/iDearQRCode/Tools/ZXingObjC/oned/ZXCode39Reader.m new file mode 100755 index 0000000..944a390 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXCode39Reader.m @@ -0,0 +1,310 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitArray.h" +#import "ZXCode39Reader.h" +#import "ZXErrors.h" +#import "ZXIntArray.h" +#import "ZXResult.h" +#import "ZXResultPoint.h" + +unichar ZX_CODE39_ALPHABET[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', + 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', '-', '.', ' ', '*', '$', '/', '+', '%'}; +NSString *ZX_CODE39_ALPHABET_STRING = nil; + + +/** + * These represent the encodings of characters, as patterns of wide and narrow bars. + * The 9 least-significant bits of each int correspond to the pattern of wide and narrow, + * with 1s representing "wide" and 0s representing narrow. + */ +const int ZX_CODE39_CHARACTER_ENCODINGS[] = { + 0x034, 0x121, 0x061, 0x160, 0x031, 0x130, 0x070, 0x025, 0x124, 0x064, // 0-9 + 0x109, 0x049, 0x148, 0x019, 0x118, 0x058, 0x00D, 0x10C, 0x04C, 0x01C, // A-J + 0x103, 0x043, 0x142, 0x013, 0x112, 0x052, 0x007, 0x106, 0x046, 0x016, // K-T + 0x181, 0x0C1, 0x1C0, 0x091, 0x190, 0x0D0, 0x085, 0x184, 0x0C4, 0x094, // U-* + 0x0A8, 0x0A2, 0x08A, 0x02A // $-% +}; + +const int ZX_CODE39_ASTERISK_ENCODING = 0x094; + +@interface ZXCode39Reader () + +@property (nonatomic, assign, readonly) BOOL extendedMode; +@property (nonatomic, assign, readonly) BOOL usingCheckDigit; +@property (nonatomic, strong, readonly) ZXIntArray *counters; + +@end + +@implementation ZXCode39Reader + ++ (void)load { + ZX_CODE39_ALPHABET_STRING = [[NSString alloc] initWithCharacters:ZX_CODE39_ALPHABET + length:sizeof(ZX_CODE39_ALPHABET) / sizeof(unichar)]; +} + +- (id)init { + return [self initUsingCheckDigit:NO extendedMode:NO]; +} + +- (id)initUsingCheckDigit:(BOOL)isUsingCheckDigit { + return [self initUsingCheckDigit:isUsingCheckDigit extendedMode:NO]; +} + +- (id)initUsingCheckDigit:(BOOL)usingCheckDigit extendedMode:(BOOL)extendedMode { + if (self = [super init]) { + _usingCheckDigit = usingCheckDigit; + _extendedMode = extendedMode; + _counters = [[ZXIntArray alloc] initWithLength:9]; + } + + return self; +} + +- (ZXResult *)decodeRow:(int)rowNumber row:(ZXBitArray *)row hints:(ZXDecodeHints *)hints error:(NSError **)error { + ZXIntArray *theCounters = self.counters; + [theCounters clear]; + NSMutableString *result = [NSMutableString stringWithCapacity:20]; + + ZXIntArray *start = [self findAsteriskPattern:row counters:theCounters]; + if (!start) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + // Read off white space + int nextStart = [row nextSet:start.array[1]]; + int end = [row size]; + + unichar decodedChar; + int lastStart; + do { + if (![ZXOneDReader recordPattern:row start:nextStart counters:theCounters]) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + int pattern = [self toNarrowWidePattern:theCounters]; + if (pattern < 0) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + decodedChar = [self patternToChar:pattern]; + if (decodedChar == 0) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + [result appendFormat:@"%C", decodedChar]; + lastStart = nextStart; + for (int i = 0; i < theCounters.length; i++) { + nextStart += theCounters.array[i]; + } + // Read off white space + nextStart = [row nextSet:nextStart]; + } while (decodedChar != '*'); + [result deleteCharactersInRange:NSMakeRange([result length] - 1, 1)]; + + int lastPatternSize = 0; + for (int i = 0; i < theCounters.length; i++) { + lastPatternSize += theCounters.array[i]; + } + int whiteSpaceAfterEnd = nextStart - lastStart - lastPatternSize; + if (nextStart != end && (whiteSpaceAfterEnd * 2) < lastPatternSize) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + + if (self.usingCheckDigit) { + int max = (int)[result length] - 1; + int total = 0; + for (int i = 0; i < max; i++) { + total += [ZX_CODE39_ALPHABET_STRING rangeOfString:[result substringWithRange:NSMakeRange(i, 1)]].location; + } + if ([result characterAtIndex:max] != ZX_CODE39_ALPHABET[total % 43]) { + if (error) *error = ZXChecksumErrorInstance(); + return nil; + } + [result deleteCharactersInRange:NSMakeRange(max, 1)]; + } + + if ([result length] == 0) { + // false positive + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + + NSString *resultString; + if (self.extendedMode) { + resultString = [self decodeExtended:result]; + if (!resultString) { + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + } else { + resultString = result; + } + + float left = (float) (start.array[1] + start.array[0]) / 2.0f; + float right = (lastStart + lastPatternSize) / 2.0f; + + return [ZXResult resultWithText:resultString + rawBytes:nil + resultPoints:@[[[ZXResultPoint alloc] initWithX:left y:(float)rowNumber], + [[ZXResultPoint alloc] initWithX:right y:(float)rowNumber]] + format:kBarcodeFormatCode39]; +} + +- (ZXIntArray *)findAsteriskPattern:(ZXBitArray *)row counters:(ZXIntArray *)counters { + int width = row.size; + int rowOffset = [row nextSet:0]; + + int counterPosition = 0; + int patternStart = rowOffset; + BOOL isWhite = NO; + int patternLength = counters.length; + int32_t *array = counters.array; + + for (int i = rowOffset; i < width; i++) { + if ([row get:i] ^ isWhite) { + array[counterPosition]++; + } else { + if (counterPosition == patternLength - 1) { + if ([self toNarrowWidePattern:counters] == ZX_CODE39_ASTERISK_ENCODING && + [row isRange:MAX(0, patternStart - ((i - patternStart) / 2)) end:patternStart value:NO]) { + return [[ZXIntArray alloc] initWithInts:patternLength, i, -1]; + } + patternStart += array[0] + array[1]; + for (int y = 2; y < counters.length; y++) { + array[y - 2] = array[y]; + } + array[patternLength - 2] = 0; + array[patternLength - 1] = 0; + counterPosition--; + } else { + counterPosition++; + } + array[counterPosition] = 1; + isWhite = !isWhite; + } + } + + return nil; +} + +- (int)toNarrowWidePattern:(ZXIntArray *)counters { + int numCounters = counters.length; + int maxNarrowCounter = 0; + int wideCounters; + do { + int minCounter = INT_MAX; + int32_t *array = counters.array; + for (int i = 0; i < numCounters; i++) { + int counter = array[i]; + if (counter < minCounter && counter > maxNarrowCounter) { + minCounter = counter; + } + } + maxNarrowCounter = minCounter; + wideCounters = 0; + int totalWideCountersWidth = 0; + int pattern = 0; + for (int i = 0; i < numCounters; i++) { + int counter = array[i]; + if (array[i] > maxNarrowCounter) { + pattern |= 1 << (numCounters - 1 - i); + wideCounters++; + totalWideCountersWidth += counter; + } + } + if (wideCounters == 3) { + for (int i = 0; i < numCounters && wideCounters > 0; i++) { + int counter = array[i]; + if (array[i] > maxNarrowCounter) { + wideCounters--; + if ((counter * 2) >= totalWideCountersWidth) { + return -1; + } + } + } + return pattern; + } + } while (wideCounters > 3); + return -1; +} + +- (unichar)patternToChar:(int)pattern { + for (int i = 0; i < sizeof(ZX_CODE39_CHARACTER_ENCODINGS) / sizeof(int); i++) { + if (ZX_CODE39_CHARACTER_ENCODINGS[i] == pattern) { + return ZX_CODE39_ALPHABET[i]; + } + } + return 0; +} + +- (NSString *)decodeExtended:(NSMutableString *)encoded { + NSUInteger length = [encoded length]; + NSMutableString *decoded = [NSMutableString stringWithCapacity:length]; + + for (int i = 0; i < length; i++) { + unichar c = [encoded characterAtIndex:i]; + if (c == '+' || c == '$' || c == '%' || c == '/') { + unichar next = [encoded characterAtIndex:i + 1]; + unichar decodedChar = '\0'; + + switch (c) { + case '+': + if (next >= 'A' && next <= 'Z') { + decodedChar = (unichar)(next + 32); + } else { + return nil; + } + break; + case '$': + if (next >= 'A' && next <= 'Z') { + decodedChar = (unichar)(next - 64); + } else { + return nil; + } + break; + case '%': + if (next >= 'A' && next <= 'E') { + decodedChar = (unichar)(next - 38); + } else if (next >= 'F' && next <= 'W') { + decodedChar = (unichar)(next - 11); + } else { + return nil; + } + break; + case '/': + if (next >= 'A' && next <= 'O') { + decodedChar = (unichar)(next - 32); + } else if (next == 'Z') { + decodedChar = ':'; + } else { + return nil; + } + break; + } + [decoded appendFormat:@"%C", decodedChar]; + i++; + } else { + [decoded appendFormat:@"%C", c]; + } + } + + return decoded; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXCode39Writer.h b/iDearQRCode/Tools/ZXingObjC/oned/ZXCode39Writer.h new file mode 100755 index 0000000..c7b30d7 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXCode39Writer.h @@ -0,0 +1,24 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXOneDimensionalCodeWriter.h" + +/** + * This object renders a CODE39 code as a ZXBitMatrix. + */ +@interface ZXCode39Writer : ZXOneDimensionalCodeWriter + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXCode39Writer.m b/iDearQRCode/Tools/ZXingObjC/oned/ZXCode39Writer.m new file mode 100755 index 0000000..6a15037 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXCode39Writer.m @@ -0,0 +1,74 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitMatrix.h" +#import "ZXBoolArray.h" +#import "ZXCode39Reader.h" +#import "ZXCode39Writer.h" +#import "ZXIntArray.h" + +@implementation ZXCode39Writer + +- (ZXBitMatrix *)encode:(NSString *)contents format:(ZXBarcodeFormat)format width:(int)width height:(int)height hints:(ZXEncodeHints *)hints error:(NSError **)error { + if (format != kBarcodeFormatCode39) { + [NSException raise:NSInvalidArgumentException format:@"Can only encode CODE_39."]; + } + return [super encode:contents format:format width:width height:height hints:hints error:error]; +} + +- (ZXBoolArray *)encode:(NSString *)contents { + int length = (int)[contents length]; + if (length > 80) { + [NSException raise:NSInvalidArgumentException + format:@"Requested contents should be less than 80 digits long, but got %d", length]; + } + + ZXIntArray *widths = [[ZXIntArray alloc] initWithLength:9]; + int codeWidth = 24 + 1 + length; + for (int i = 0; i < length; i++) { + NSUInteger indexInString = [ZX_CODE39_ALPHABET_STRING rangeOfString:[contents substringWithRange:NSMakeRange(i, 1)]].location; + if (indexInString == NSNotFound) { + [NSException raise:NSInvalidArgumentException format:@"Bad contents: %@", contents]; + } + [self toIntArray:ZX_CODE39_CHARACTER_ENCODINGS[indexInString] toReturn:widths]; + codeWidth += [widths sum]; + } + ZXBoolArray *result = [[ZXBoolArray alloc] initWithLength:codeWidth]; + [self toIntArray:ZX_CODE39_CHARACTER_ENCODINGS[39] toReturn:widths]; + int pos = [self appendPattern:result pos:0 pattern:widths.array patternLen:widths.length startColor:YES]; + ZXIntArray *narrowWhite = [[ZXIntArray alloc] initWithInts:1, -1]; + pos += [self appendPattern:result pos:pos pattern:narrowWhite.array patternLen:narrowWhite.length startColor:NO]; + //append next character to byte matrix + for (int i = 0; i < length; i++) { + NSUInteger indexInString = [ZX_CODE39_ALPHABET_STRING rangeOfString:[contents substringWithRange:NSMakeRange(i, 1)]].location; + [self toIntArray:ZX_CODE39_CHARACTER_ENCODINGS[indexInString] toReturn:widths]; + pos += [self appendPattern:result pos:pos pattern:widths.array patternLen:widths.length startColor:YES]; + pos += [self appendPattern:result pos:pos pattern:narrowWhite.array patternLen:narrowWhite.length startColor:NO]; + } + + [self toIntArray:ZX_CODE39_CHARACTER_ENCODINGS[39] toReturn:widths]; + [self appendPattern:result pos:pos pattern:widths.array patternLen:widths.length startColor:YES]; + return result; +} + +- (void)toIntArray:(int)a toReturn:(ZXIntArray *)toReturn { + for (int i = 0; i < 9; i++) { + int temp = a & (1 << (8 - i)); + toReturn.array[i] = temp == 0 ? 1 : 2; + } +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXCode93Reader.h b/iDearQRCode/Tools/ZXingObjC/oned/ZXCode93Reader.h new file mode 100755 index 0000000..e3368f4 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXCode93Reader.h @@ -0,0 +1,24 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXOneDReader.h" + +/** + * Decodes Code 93 barcodes. + */ +@interface ZXCode93Reader : ZXOneDReader + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXCode93Reader.m b/iDearQRCode/Tools/ZXingObjC/oned/ZXCode93Reader.m new file mode 100755 index 0000000..7d8be27 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXCode93Reader.m @@ -0,0 +1,291 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitArray.h" +#import "ZXCode93Reader.h" +#import "ZXErrors.h" +#import "ZXIntArray.h" +#import "ZXResult.h" +#import "ZXResultPoint.h" + +NSString *ZX_CODE93_ALPHABET_STRING = nil; +const unichar ZX_CODE93_ALPHABET[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', + 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', '-', '.', ' ', '$', '/', '+', '%', 'a', 'b', 'c', 'd', '*'}; + +/** + * These represent the encodings of characters, as patterns of wide and narrow bars. + * The 9 least-significant bits of each int correspond to the pattern of wide and narrow. + */ +const int ZX_CODE93_CHARACTER_ENCODINGS[] = { + 0x114, 0x148, 0x144, 0x142, 0x128, 0x124, 0x122, 0x150, 0x112, 0x10A, // 0-9 + 0x1A8, 0x1A4, 0x1A2, 0x194, 0x192, 0x18A, 0x168, 0x164, 0x162, 0x134, // A-J + 0x11A, 0x158, 0x14C, 0x146, 0x12C, 0x116, 0x1B4, 0x1B2, 0x1AC, 0x1A6, // K-T + 0x196, 0x19A, 0x16C, 0x166, 0x136, 0x13A, // U-Z + 0x12E, 0x1D4, 0x1D2, 0x1CA, 0x16E, 0x176, 0x1AE, // - - % + 0x126, 0x1DA, 0x1D6, 0x132, 0x15E, // Control chars? $-* +}; + +const int ZX_CODE93_ASTERISK_ENCODING = 0x15E; + +@interface ZXCode93Reader () + +@property (nonatomic, strong, readonly) ZXIntArray *counters; + +@end + +@implementation ZXCode93Reader + ++ (void)initialize { + if ([self class] != [ZXCode93Reader class]) return; + + ZX_CODE93_ALPHABET_STRING = [[NSString alloc] initWithCharacters:ZX_CODE93_ALPHABET + length:sizeof(ZX_CODE93_ALPHABET) / sizeof(unichar)]; +} + +- (id)init { + if (self = [super init]) { + _counters = [[ZXIntArray alloc] initWithLength:6]; + } + + return self; +} + +- (ZXResult *)decodeRow:(int)rowNumber row:(ZXBitArray *)row hints:(ZXDecodeHints *)hints error:(NSError **)error { + ZXIntArray *start = [self findAsteriskPattern:row]; + if (!start) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + // Read off white space + int nextStart = [row nextSet:start.array[1]]; + int end = row.size; + + ZXIntArray *theCounters = self.counters; + memset(theCounters.array, 0, theCounters.length * sizeof(int32_t)); + NSMutableString *result = [NSMutableString string]; + + unichar decodedChar; + int lastStart; + do { + if (![ZXOneDReader recordPattern:row start:nextStart counters:theCounters]) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + int pattern = [self toPattern:theCounters]; + if (pattern < 0) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + decodedChar = [self patternToChar:pattern]; + if (decodedChar == 0) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + [result appendFormat:@"%C", decodedChar]; + lastStart = nextStart; + for (int i = 0; i < theCounters.length; i++) { + nextStart += theCounters.array[i]; + } + // Read off white space + nextStart = [row nextSet:nextStart]; + } while (decodedChar != '*'); + [result deleteCharactersInRange:NSMakeRange([result length] - 1, 1)]; // remove asterisk + + int lastPatternSize = [theCounters sum]; + + // Should be at least one more black module + if (nextStart == end || ![row get:nextStart]) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + + if ([result length] < 2) { + // false positive -- need at least 2 checksum digits + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + + if (![self checkChecksums:result error:error]) { + return nil; + } + [result deleteCharactersInRange:NSMakeRange([result length] - 2, 2)]; + + NSString *resultString = [self decodeExtended:result]; + if (!resultString) { + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + + float left = (float) (start.array[1] + start.array[0]) / 2.0f; + float right = lastStart + lastPatternSize / 2.0f; + return [ZXResult resultWithText:resultString + rawBytes:nil + resultPoints:@[[[ZXResultPoint alloc] initWithX:left y:(float)rowNumber], + [[ZXResultPoint alloc] initWithX:right y:(float)rowNumber]] + format:kBarcodeFormatCode93]; +} + +- (ZXIntArray *)findAsteriskPattern:(ZXBitArray *)row { + int width = row.size; + int rowOffset = [row nextSet:0]; + + [self.counters clear]; + ZXIntArray *theCounters = self.counters; + int patternStart = rowOffset; + BOOL isWhite = NO; + int patternLength = theCounters.length; + + int counterPosition = 0; + for (int i = rowOffset; i < width; i++) { + if ([row get:i] ^ isWhite) { + theCounters.array[counterPosition]++; + } else { + if (counterPosition == patternLength - 1) { + if ([self toPattern:theCounters] == ZX_CODE93_ASTERISK_ENCODING) { + return [[ZXIntArray alloc] initWithInts:patternStart, i, -1]; + } + patternStart += theCounters.array[0] + theCounters.array[1]; + for (int y = 2; y < patternLength; y++) { + theCounters.array[y - 2] = theCounters.array[y]; + } + theCounters.array[patternLength - 2] = 0; + theCounters.array[patternLength - 1] = 0; + counterPosition--; + } else { + counterPosition++; + } + theCounters.array[counterPosition] = 1; + isWhite = !isWhite; + } + } + + return nil; +} + +- (int)toPattern:(ZXIntArray *)counters { + int max = counters.length; + int sum = [counters sum]; + int32_t *array = counters.array; + int pattern = 0; + for (int i = 0; i < max; i++) { + int scaled = round(array[i] * 9.0f / sum); + if (scaled < 1 || scaled > 4) { + return -1; + } + if ((i & 0x01) == 0) { + for (int j = 0; j < scaled; j++) { + pattern = (pattern << 1) | 0x01; + } + } else { + pattern <<= scaled; + } + } + return pattern; +} + +- (unichar)patternToChar:(int)pattern { + for (int i = 0; i < sizeof(ZX_CODE93_CHARACTER_ENCODINGS) / sizeof(int); i++) { + if (ZX_CODE93_CHARACTER_ENCODINGS[i] == pattern) { + return ZX_CODE93_ALPHABET[i]; + } + } + + return -1; +} + +- (NSString *)decodeExtended:(NSMutableString *)encoded { + NSUInteger length = [encoded length]; + NSMutableString *decoded = [NSMutableString stringWithCapacity:length]; + for (int i = 0; i < length; i++) { + unichar c = [encoded characterAtIndex:i]; + if (c >= 'a' && c <= 'd') { + if (i >= length - 1) { + return nil; + } + unichar next = [encoded characterAtIndex:i + 1]; + unichar decodedChar = '\0'; + switch (c) { + case 'd': + if (next >= 'A' && next <= 'Z') { + decodedChar = (unichar)(next + 32); + } else { + return nil; + } + break; + case 'a': + if (next >= 'A' && next <= 'Z') { + decodedChar = (unichar)(next - 64); + } else { + return nil; + } + break; + case 'b': + if (next >= 'A' && next <= 'E') { + decodedChar = (unichar)(next - 38); + } else if (next >= 'F' && next <= 'W') { + decodedChar = (unichar)(next - 11); + } else { + return nil; + } + break; + case 'c': + if (next >= 'A' && next <= 'O') { + decodedChar = (unichar)(next - 32); + } else if (next == 'Z') { + decodedChar = ':'; + } else { + return nil; + } + break; + } + [decoded appendFormat:@"%C", decodedChar]; + i++; + } else { + [decoded appendFormat:@"%C", c]; + } + } + + return decoded; +} + +- (BOOL)checkChecksums:(NSMutableString *)result error:(NSError **)error { + NSUInteger length = [result length]; + if (![self checkOneChecksum:result checkPosition:(int)length - 2 weightMax:20 error:error]) { + return NO; + } + return [self checkOneChecksum:result checkPosition:(int)length - 1 weightMax:15 error:error]; +} + +- (BOOL)checkOneChecksum:(NSMutableString *)result checkPosition:(int)checkPosition weightMax:(int)weightMax error:(NSError **)error { + int weight = 1; + int total = 0; + + for (int i = checkPosition - 1; i >= 0; i--) { + total += weight * [ZX_CODE93_ALPHABET_STRING rangeOfString:[NSString stringWithFormat:@"%C", [result characterAtIndex:i]]].location; + if (++weight > weightMax) { + weight = 1; + } + } + + if ([result characterAtIndex:checkPosition] != ZX_CODE93_ALPHABET[total % 47]) { + if (error) *error = ZXChecksumErrorInstance(); + return NO; + } + return YES; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXEAN13Reader.h b/iDearQRCode/Tools/ZXingObjC/oned/ZXEAN13Reader.h new file mode 100755 index 0000000..f94ecd5 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXEAN13Reader.h @@ -0,0 +1,26 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXUPCEANReader.h" + +extern const int ZX_EAN13_FIRST_DIGIT_ENCODINGS[]; + +/** + * Implements decoding of the EAN-13 format. + */ +@interface ZXEAN13Reader : ZXUPCEANReader + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXEAN13Reader.m b/iDearQRCode/Tools/ZXingObjC/oned/ZXEAN13Reader.m new file mode 100755 index 0000000..fed8b7c --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXEAN13Reader.m @@ -0,0 +1,146 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitArray.h" +#import "ZXEAN13Reader.h" +#import "ZXErrors.h" +#import "ZXIntArray.h" + +// For an EAN-13 barcode, the first digit is represented by the parities used +// to encode the next six digits, according to the table below. For example, +// if the barcode is 5 123456 789012 then the value of the first digit is +// signified by using odd for '1', even for '2', even for '3', odd for '4', +// odd for '5', and even for '6'. See http://en.wikipedia.org/wiki/EAN-13 +// +// Parity of next 6 digits +// Digit 0 1 2 3 4 5 +// 0 Odd Odd Odd Odd Odd Odd +// 1 Odd Odd Even Odd Even Even +// 2 Odd Odd Even Even Odd Even +// 3 Odd Odd Even Even Even Odd +// 4 Odd Even Odd Odd Even Even +// 5 Odd Even Even Odd Odd Even +// 6 Odd Even Even Even Odd Odd +// 7 Odd Even Odd Even Odd Even +// 8 Odd Even Odd Even Even Odd +// 9 Odd Even Even Odd Even Odd +// +// Note that the encoding for '0' uses the same parity as a UPC barcode. Hence +// a UPC barcode can be converted to an EAN-13 barcode by prepending a 0. +// +// The encoding is represented by the following array, which is a bit pattern +// using Odd = 0 and Even = 1. For example, 5 is represented by: +// +// Odd Even Even Odd Odd Even +// in binary: +// 0 1 1 0 0 1 == 0x19 +// +const int ZX_EAN13_FIRST_DIGIT_ENCODINGS[] = { + 0x00, 0x0B, 0x0D, 0xE, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A +}; + +@interface ZXEAN13Reader () + +@property (nonatomic, strong, readonly) ZXIntArray *decodeMiddleCounters; + +@end + +@implementation ZXEAN13Reader + +- (id)init { + if (self = [super init]) { + _decodeMiddleCounters = [[ZXIntArray alloc] initWithLength:4]; + } + return self; +} + +- (int)decodeMiddle:(ZXBitArray *)row startRange:(NSRange)startRange result:(NSMutableString *)result error:(NSError **)error { + ZXIntArray *counters = self.decodeMiddleCounters; + [counters clear]; + int end = row.size; + int rowOffset = (int)NSMaxRange(startRange); + + int lgPatternFound = 0; + + for (int x = 0; x < 6 && rowOffset < end; x++) { + int bestMatch = [ZXUPCEANReader decodeDigit:row counters:counters rowOffset:rowOffset patternType:ZX_UPC_EAN_PATTERNS_L_AND_G_PATTERNS error:error]; + if (bestMatch == -1) { + return -1; + } + [result appendFormat:@"%C", (unichar)('0' + bestMatch % 10)]; + rowOffset += [counters sum]; + if (bestMatch >= 10) { + lgPatternFound |= 1 << (5 - x); + } + } + + if (![self determineFirstDigit:result lgPatternFound:lgPatternFound]) { + if (error) *error = ZXNotFoundErrorInstance(); + return -1; + } + + NSRange middleRange = [[self class] findGuardPattern:row + rowOffset:rowOffset + whiteFirst:YES + pattern:ZX_UPC_EAN_MIDDLE_PATTERN + patternLen:ZX_UPC_EAN_MIDDLE_PATTERN_LEN + error:error]; + if (middleRange.location == NSNotFound) { + return -1; + } + rowOffset = (int)NSMaxRange(middleRange); + + for (int x = 0; x < 6 && rowOffset < end; x++) { + int bestMatch = [ZXUPCEANReader decodeDigit:row + counters:counters + rowOffset:rowOffset + patternType:ZX_UPC_EAN_PATTERNS_L_PATTERNS + error:error]; + if (bestMatch == -1) { + return -1; + } + [result appendFormat:@"%C", (unichar)('0' + bestMatch)]; + rowOffset += [counters sum]; + } + + return rowOffset; +} + +- (ZXBarcodeFormat)barcodeFormat { + return kBarcodeFormatEan13; +} + +/** + * Based on pattern of odd-even ('L' and 'G') patterns used to encoded the explicitly-encoded + * digits in a barcode, determines the implicitly encoded first digit and adds it to the + * result string. + * + * @param resultString string to insert decoded first digit into + * @param lgPatternFound int whose bits indicates the pattern of odd/even L/G patterns used to + * encode digits + * @return NO if first digit cannot be determined + */ +- (BOOL)determineFirstDigit:(NSMutableString *)resultString lgPatternFound:(int)lgPatternFound { + for (int d = 0; d < 10; d++) { + if (lgPatternFound == ZX_EAN13_FIRST_DIGIT_ENCODINGS[d]) { + [resultString insertString:[NSString stringWithFormat:@"%C", (unichar)('0' + d)] atIndex:0]; + return YES; + } + } + return NO; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXEAN13Writer.h b/iDearQRCode/Tools/ZXingObjC/oned/ZXEAN13Writer.h new file mode 100755 index 0000000..6dc59d8 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXEAN13Writer.h @@ -0,0 +1,24 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXUPCEANWriter.h" + +/** + * This object renders an EAN13 code as a ZXBitMatrix. + */ +@interface ZXEAN13Writer : ZXUPCEANWriter + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXEAN13Writer.m b/iDearQRCode/Tools/ZXingObjC/oned/ZXEAN13Writer.m new file mode 100755 index 0000000..b9ad4bd --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXEAN13Writer.m @@ -0,0 +1,78 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBarcodeFormat.h" +#import "ZXBoolArray.h" +#import "ZXEAN13Reader.h" +#import "ZXEAN13Writer.h" +#import "ZXUPCEANReader.h" + +const int ZX_EAN13_CODE_WIDTH = 3 + // start guard + (7 * 6) + // left bars + 5 + // middle guard + (7 * 6) + // right bars + 3; // end guard + +@implementation ZXEAN13Writer + +- (ZXBitMatrix *)encode:(NSString *)contents format:(ZXBarcodeFormat)format width:(int)width height:(int)height hints:(ZXEncodeHints *)hints error:(NSError **)error { + if (format != kBarcodeFormatEan13) { + @throw [NSException exceptionWithName:NSInvalidArgumentException + reason:[NSString stringWithFormat:@"Can only encode EAN_13, but got %d", format] + userInfo:nil]; + } + + return [super encode:contents format:format width:width height:height hints:hints error:error]; +} + +- (ZXBoolArray *)encode:(NSString *)contents { + if ([contents length] != 13) { + [NSException raise:NSInvalidArgumentException + format:@"Requested contents should be 13 digits long, but got %d", (int)[contents length]]; + } + + if (![ZXUPCEANReader checkStandardUPCEANChecksum:contents]) { + [NSException raise:NSInvalidArgumentException + format:@"Contents do not pass checksum"]; + } + + int firstDigit = [[contents substringToIndex:1] intValue]; + int parities = ZX_EAN13_FIRST_DIGIT_ENCODINGS[firstDigit]; + ZXBoolArray *result = [[ZXBoolArray alloc] initWithLength:ZX_EAN13_CODE_WIDTH]; + int pos = 0; + + pos += [self appendPattern:result pos:pos pattern:ZX_UPC_EAN_START_END_PATTERN patternLen:ZX_UPC_EAN_START_END_PATTERN_LEN startColor:YES]; + + for (int i = 1; i <= 6; i++) { + int digit = [[contents substringWithRange:NSMakeRange(i, 1)] intValue]; + if ((parities >> (6 - i) & 1) == 1) { + digit += 10; + } + pos += [self appendPattern:result pos:pos pattern:ZX_UPC_EAN_L_AND_G_PATTERNS[digit] patternLen:ZX_UPC_EAN_L_PATTERNS_SUB_LEN startColor:FALSE]; + } + + pos += [self appendPattern:result pos:pos pattern:ZX_UPC_EAN_MIDDLE_PATTERN patternLen:ZX_UPC_EAN_MIDDLE_PATTERN_LEN startColor:FALSE]; + + for (int i = 7; i <= 12; i++) { + int digit = [[contents substringWithRange:NSMakeRange(i, 1)] intValue]; + pos += [self appendPattern:result pos:pos pattern:ZX_UPC_EAN_L_PATTERNS[digit] patternLen:ZX_UPC_EAN_L_PATTERNS_SUB_LEN startColor:YES]; + } + [self appendPattern:result pos:pos pattern:ZX_UPC_EAN_START_END_PATTERN patternLen:ZX_UPC_EAN_START_END_PATTERN_LEN startColor:YES]; + + return result; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXEAN8Reader.h b/iDearQRCode/Tools/ZXingObjC/oned/ZXEAN8Reader.h new file mode 100755 index 0000000..886ce3b --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXEAN8Reader.h @@ -0,0 +1,24 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXUPCEANReader.h" + +/** + * Implements decoding of the EAN-8 format. + */ +@interface ZXEAN8Reader : ZXUPCEANReader + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXEAN8Reader.m b/iDearQRCode/Tools/ZXingObjC/oned/ZXEAN8Reader.m new file mode 100755 index 0000000..eb1538a --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXEAN8Reader.m @@ -0,0 +1,74 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitArray.h" +#import "ZXEAN8Reader.h" +#import "ZXIntArray.h" + +@interface ZXEAN8Reader () + +@property (nonatomic, strong, readonly) ZXIntArray *decodeMiddleCounters; + +@end + +@implementation ZXEAN8Reader + +- (id)init { + if (self = [super init]) { + _decodeMiddleCounters = [[ZXIntArray alloc] initWithLength:4]; + } + + return self; +} + +- (int)decodeMiddle:(ZXBitArray *)row startRange:(NSRange)startRange result:(NSMutableString *)result error:(NSError **)error { + ZXIntArray *counters = self.decodeMiddleCounters; + [counters clear]; + int end = row.size; + int rowOffset = (int)NSMaxRange(startRange); + + for (int x = 0; x < 4 && rowOffset < end; x++) { + int bestMatch = [ZXUPCEANReader decodeDigit:row counters:counters rowOffset:rowOffset patternType:ZX_UPC_EAN_PATTERNS_L_PATTERNS error:error]; + if (bestMatch == -1) { + return -1; + } + [result appendFormat:@"%C", (unichar)('0' + bestMatch)]; + rowOffset += [counters sum]; + } + + NSRange middleRange = [[self class] findGuardPattern:row rowOffset:rowOffset whiteFirst:YES pattern:ZX_UPC_EAN_MIDDLE_PATTERN patternLen:ZX_UPC_EAN_MIDDLE_PATTERN_LEN error:error]; + if (middleRange.location == NSNotFound) { + return -1; + } + rowOffset = (int)NSMaxRange(middleRange); + + for (int x = 0; x < 4 && rowOffset < end; x++) { + int bestMatch = [ZXUPCEANReader decodeDigit:row counters:counters rowOffset:rowOffset patternType:ZX_UPC_EAN_PATTERNS_L_PATTERNS error:error]; + if (bestMatch == -1) { + return -1; + } + [result appendFormat:@"%C", (unichar)('0' + bestMatch)]; + rowOffset += [counters sum]; + } + + return rowOffset; +} + +- (ZXBarcodeFormat)barcodeFormat { + return kBarcodeFormatEan8; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXEAN8Writer.h b/iDearQRCode/Tools/ZXingObjC/oned/ZXEAN8Writer.h new file mode 100755 index 0000000..5171806 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXEAN8Writer.h @@ -0,0 +1,24 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXUPCEANWriter.h" + +/** + * This object renders an EAN8 code as a ZXBitMatrix. + */ +@interface ZXEAN8Writer : ZXUPCEANWriter + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXEAN8Writer.m b/iDearQRCode/Tools/ZXingObjC/oned/ZXEAN8Writer.m new file mode 100755 index 0000000..7307bd1 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXEAN8Writer.m @@ -0,0 +1,63 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBarcodeFormat.h" +#import "ZXBoolArray.h" +#import "ZXEAN8Writer.h" +#import "ZXUPCEANReader.h" + +const int ZX_EAN8_CODE_WIDTH = 3 + (7 * 4) + 5 + (7 * 4) + 3; + +@implementation ZXEAN8Writer + +- (ZXBitMatrix *)encode:(NSString *)contents format:(ZXBarcodeFormat)format width:(int)width height:(int)height hints:(ZXEncodeHints *)hints error:(NSError **)error { + if (format != kBarcodeFormatEan8) { + [NSException raise:NSInvalidArgumentException format:@"Can only encode EAN_8"]; + } + return [super encode:contents format:format width:width height:height hints:hints error:error]; +} + +/** + * Returns a byte array of horizontal pixels (FALSE = white, TRUE = black) + */ +- (ZXBoolArray *)encode:(NSString *)contents { + if ([contents length] != 8) { + [NSException raise:NSInvalidArgumentException format:@"Requested contents should be 8 digits long, but got %d", (int)[contents length]]; + } + + ZXBoolArray *result = [[ZXBoolArray alloc] initWithLength:ZX_EAN8_CODE_WIDTH]; + int pos = 0; + + pos += [self appendPattern:result pos:pos pattern:ZX_UPC_EAN_START_END_PATTERN patternLen:ZX_UPC_EAN_START_END_PATTERN_LEN startColor:YES]; + + for (int i = 0; i <= 3; i++) { + int digit = [[contents substringWithRange:NSMakeRange(i, 1)] intValue]; + pos += [self appendPattern:result pos:pos pattern:ZX_UPC_EAN_L_PATTERNS[digit] patternLen:ZX_UPC_EAN_L_PATTERNS_SUB_LEN startColor:FALSE]; + } + + pos += [self appendPattern:result pos:pos pattern:ZX_UPC_EAN_MIDDLE_PATTERN patternLen:ZX_UPC_EAN_MIDDLE_PATTERN_LEN startColor:FALSE]; + + for (int i = 4; i <= 7; i++) { + int digit = [[contents substringWithRange:NSMakeRange(i, 1)] intValue]; + pos += [super appendPattern:result pos:pos pattern:ZX_UPC_EAN_L_PATTERNS[digit] patternLen:ZX_UPC_EAN_L_PATTERNS_SUB_LEN startColor:YES]; + } + + [self appendPattern:result pos:pos pattern:ZX_UPC_EAN_START_END_PATTERN patternLen:ZX_UPC_EAN_START_END_PATTERN_LEN startColor:YES]; + + return result; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXEANManufacturerOrgSupport.h b/iDearQRCode/Tools/ZXingObjC/oned/ZXEANManufacturerOrgSupport.h new file mode 100755 index 0000000..60b385a --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXEANManufacturerOrgSupport.h @@ -0,0 +1,27 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Records EAN prefix to GS1 Member Organization, where the member organization + * correlates strongly with a country. This is an imperfect means of identifying + * a country of origin by EAN-13 barcode value. See + * http://en.wikipedia.org/wiki/List_of_GS1_country_codes + */ +@interface ZXEANManufacturerOrgSupport : NSObject + +- (NSString *)lookupCountryIdentifier:(NSString *)productCode; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXEANManufacturerOrgSupport.m b/iDearQRCode/Tools/ZXingObjC/oned/ZXEANManufacturerOrgSupport.m new file mode 100755 index 0000000..3bdac20 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXEANManufacturerOrgSupport.m @@ -0,0 +1,178 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXEANManufacturerOrgSupport.h" + +@interface ZXEANManufacturerOrgSupport () + +@property (nonatomic, strong, readonly) NSMutableArray *countryIdentifiers; +@property (nonatomic, strong, readonly) NSMutableArray *ranges; + +@end + +@implementation ZXEANManufacturerOrgSupport + +- (id)init { + if (self = [super init]) { + _ranges = [NSMutableArray array]; + _countryIdentifiers = [NSMutableArray array]; + } + + return self; +} + +- (NSString *)lookupCountryIdentifier:(NSString *)productCode { + [self initIfNeeded]; + + int prefix = [[productCode substringToIndex:3] intValue]; + NSUInteger max = self.ranges.count; + + for (int i = 0; i < max; i++) { + NSArray *range = self.ranges[i]; + int start = [range[0] intValue]; + if (prefix < start) { + return nil; + } + int end = [range count] == 1 ? start : [range[1] intValue]; + if (prefix <= end) { + return self.countryIdentifiers[i]; + } + } + + return nil; +} + +- (void)add:(NSArray *)range identifier:(NSString *)identifier { + [self.ranges addObject:range]; + [self.countryIdentifiers addObject:identifier]; +} + +- (void)initIfNeeded { + @synchronized (self.ranges) { + if ([self.ranges count] > 0) { + return; + } + + [self add:@[@0, @19] identifier:@"US/CA"]; + [self add:@[@30, @39] identifier:@"US"]; + [self add:@[@60, @139] identifier:@"US/CA"]; + [self add:@[@300, @379] identifier:@"FR"]; + [self add:@[@380] identifier:@"BG"]; + [self add:@[@383] identifier:@"SI"]; + [self add:@[@385] identifier:@"HR"]; + [self add:@[@387] identifier:@"BA"]; + [self add:@[@400, @440] identifier:@"DE"]; + [self add:@[@450, @459] identifier:@"JP"]; + [self add:@[@460, @469] identifier:@"RU"]; + [self add:@[@471] identifier:@"TW"]; + [self add:@[@474] identifier:@"EE"]; + [self add:@[@475] identifier:@"LV"]; + [self add:@[@476] identifier:@"AZ"]; + [self add:@[@477] identifier:@"LT"]; + [self add:@[@478] identifier:@"UZ"]; + [self add:@[@479] identifier:@"LK"]; + [self add:@[@480] identifier:@"PH"]; + [self add:@[@481] identifier:@"BY"]; + [self add:@[@482] identifier:@"UA"]; + [self add:@[@484] identifier:@"MD"]; + [self add:@[@485] identifier:@"AM"]; + [self add:@[@486] identifier:@"GE"]; + [self add:@[@487] identifier:@"KZ"]; + [self add:@[@489] identifier:@"HK"]; + [self add:@[@490, @499] identifier:@"JP"]; + [self add:@[@500, @509] identifier:@"GB"]; + [self add:@[@520] identifier:@"GR"]; + [self add:@[@528] identifier:@"LB"]; + [self add:@[@529] identifier:@"CY"]; + [self add:@[@531] identifier:@"MK"]; + [self add:@[@535] identifier:@"MT"]; + [self add:@[@539] identifier:@"IE"]; + [self add:@[@540, @549] identifier:@"BE/LU"]; + [self add:@[@560] identifier:@"PT"]; + [self add:@[@569] identifier:@"IS"]; + [self add:@[@570, @579] identifier:@"DK"]; + [self add:@[@590] identifier:@"PL"]; + [self add:@[@594] identifier:@"RO"]; + [self add:@[@599] identifier:@"HU"]; + [self add:@[@600, @601] identifier:@"ZA"]; + [self add:@[@603] identifier:@"GH"]; + [self add:@[@608] identifier:@"BH"]; + [self add:@[@609] identifier:@"MU"]; + [self add:@[@611] identifier:@"MA"]; + [self add:@[@613] identifier:@"DZ"]; + [self add:@[@616] identifier:@"KE"]; + [self add:@[@618] identifier:@"CI"]; + [self add:@[@619] identifier:@"TN"]; + [self add:@[@621] identifier:@"SY"]; + [self add:@[@622] identifier:@"EG"]; + [self add:@[@624] identifier:@"LY"]; + [self add:@[@625] identifier:@"JO"]; + [self add:@[@626] identifier:@"IR"]; + [self add:@[@627] identifier:@"KW"]; + [self add:@[@628] identifier:@"SA"]; + [self add:@[@629] identifier:@"AE"]; + [self add:@[@640, @649] identifier:@"FI"]; + [self add:@[@690, @695] identifier:@"CN"]; + [self add:@[@700, @709] identifier:@"NO"]; + [self add:@[@729] identifier:@"IL"]; + [self add:@[@730, @739] identifier:@"SE"]; + [self add:@[@740] identifier:@"GT"]; + [self add:@[@741] identifier:@"SV"]; + [self add:@[@742] identifier:@"HN"]; + [self add:@[@743] identifier:@"NI"]; + [self add:@[@744] identifier:@"CR"]; + [self add:@[@745] identifier:@"PA"]; + [self add:@[@746] identifier:@"DO"]; + [self add:@[@750] identifier:@"MX"]; + [self add:@[@754, @755] identifier:@"CA"]; + [self add:@[@759] identifier:@"VE"]; + [self add:@[@760, @769] identifier:@"CH"]; + [self add:@[@770] identifier:@"CO"]; + [self add:@[@773] identifier:@"UY"]; + [self add:@[@775] identifier:@"PE"]; + [self add:@[@777] identifier:@"BO"]; + [self add:@[@779] identifier:@"AR"]; + [self add:@[@780] identifier:@"CL"]; + [self add:@[@784] identifier:@"PY"]; + [self add:@[@785] identifier:@"PE"]; + [self add:@[@786] identifier:@"EC"]; + [self add:@[@789, @790] identifier:@"BR"]; + [self add:@[@800, @839] identifier:@"IT"]; + [self add:@[@840, @849] identifier:@"ES"]; + [self add:@[@850] identifier:@"CU"]; + [self add:@[@858] identifier:@"SK"]; + [self add:@[@859] identifier:@"CZ"]; + [self add:@[@860] identifier:@"YU"]; + [self add:@[@865] identifier:@"MN"]; + [self add:@[@867] identifier:@"KP"]; + [self add:@[@868, @869] identifier:@"TR"]; + [self add:@[@870, @879] identifier:@"NL"]; + [self add:@[@880] identifier:@"KR"]; + [self add:@[@885] identifier:@"TH"]; + [self add:@[@888] identifier:@"SG"]; + [self add:@[@890] identifier:@"IN"]; + [self add:@[@893] identifier:@"VN"]; + [self add:@[@896] identifier:@"PK"]; + [self add:@[@899] identifier:@"ID"]; + [self add:@[@900, @919] identifier:@"AT"]; + [self add:@[@930, @939] identifier:@"AU"]; + [self add:@[@940, @949] identifier:@"AZ"]; + [self add:@[@955] identifier:@"MY"]; + [self add:@[@958] identifier:@"MO"]; + } +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXITFReader.h b/iDearQRCode/Tools/ZXingObjC/oned/ZXITFReader.h new file mode 100755 index 0000000..bc145f4 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXITFReader.h @@ -0,0 +1,39 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXOneDReader.h" + +extern const int ZX_ITF_PATTERNS[][5]; + +/** + * Implements decoding of the ITF format, or Interleaved Two of Five. + * + * This Reader will scan ITF barcodes of certain lengths only. + * At the moment it reads length 6, 8, 10, 12, 14, 16, 18, 20, 24, and 44 as these have appeared "in the wild". Not all + * lengths are scanned, especially shorter ones, to avoid false positives. This in turn is due to a lack of + * required checksum function. + * + * The checksum is optional and is not applied by this Reader. The consumer of the decoded + * value will have to apply a checksum if required. + * + * http://en.wikipedia.org/wiki/Interleaved_2_of_5 is a great reference for Interleaved 2 of 5 information. + */ +@interface ZXITFReader : ZXOneDReader + +- (ZXIntArray *)decodeStart:(ZXBitArray *)row; +- (ZXIntArray *)decodeEnd:(ZXBitArray *)row; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXITFReader.m b/iDearQRCode/Tools/ZXingObjC/oned/ZXITFReader.m new file mode 100755 index 0000000..c9b41d0 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXITFReader.m @@ -0,0 +1,356 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitArray.h" +#import "ZXDecodeHints.h" +#import "ZXErrors.h" +#import "ZXIntArray.h" +#import "ZXITFReader.h" +#import "ZXResult.h" +#import "ZXResultPoint.h" + +static float ZX_ITF_MAX_AVG_VARIANCE = 0.38f; +static float ZX_ITF_MAX_INDIVIDUAL_VARIANCE = 0.78f; + +static const int ZX_ITF_W = 3; // Pixel width of a wide line +static const int ZX_ITF_N = 1; // Pixel width of a narrow line + +/** Valid ITF lengths. Anything longer than the largest value is also allowed. */ +const int ZX_ITF_DEFAULT_ALLOWED_LENGTHS[] = { 6, 8, 10, 12, 14 }; + +/** + * Start/end guard pattern. + * + * Note: The end pattern is reversed because the row is reversed before + * searching for the END_PATTERN + */ +const int ZX_ITF_ITF_START_PATTERN[] = {ZX_ITF_N, ZX_ITF_N, ZX_ITF_N, ZX_ITF_N}; +const int ZX_ITF_END_PATTERN_REVERSED[] = {ZX_ITF_N, ZX_ITF_N, ZX_ITF_W}; + +/** + * Patterns of Wide / Narrow lines to indicate each digit + */ +const int ZX_ITF_PATTERNS_LEN = 10; +const int ZX_ITF_PATTERNS[ZX_ITF_PATTERNS_LEN][5] = { + {ZX_ITF_N, ZX_ITF_N, ZX_ITF_W, ZX_ITF_W, ZX_ITF_N}, // 0 + {ZX_ITF_W, ZX_ITF_N, ZX_ITF_N, ZX_ITF_N, ZX_ITF_W}, // 1 + {ZX_ITF_N, ZX_ITF_W, ZX_ITF_N, ZX_ITF_N, ZX_ITF_W}, // 2 + {ZX_ITF_W, ZX_ITF_W, ZX_ITF_N, ZX_ITF_N, ZX_ITF_N}, // 3 + {ZX_ITF_N, ZX_ITF_N, ZX_ITF_W, ZX_ITF_N, ZX_ITF_W}, // 4 + {ZX_ITF_W, ZX_ITF_N, ZX_ITF_W, ZX_ITF_N, ZX_ITF_N}, // 5 + {ZX_ITF_N, ZX_ITF_W, ZX_ITF_W, ZX_ITF_N, ZX_ITF_N}, // 6 + {ZX_ITF_N, ZX_ITF_N, ZX_ITF_N, ZX_ITF_W, ZX_ITF_W}, // 7 + {ZX_ITF_W, ZX_ITF_N, ZX_ITF_N, ZX_ITF_W, ZX_ITF_N}, // 8 + {ZX_ITF_N, ZX_ITF_W, ZX_ITF_N, ZX_ITF_W, ZX_ITF_N} // 9 +}; + +@interface ZXITFReader () + +@property (nonatomic, assign) int narrowLineWidth; + +@end + +@implementation ZXITFReader + +- (id)init { + if (self = [super init]) { + _narrowLineWidth = -1; + } + + return self; +} + +- (ZXResult *)decodeRow:(int)rowNumber row:(ZXBitArray *)row hints:(ZXDecodeHints *)hints error:(NSError **)error { + // Find out where the Middle section (payload) starts & ends + ZXIntArray *startRange = [self decodeStart:row]; + ZXIntArray *endRange = [self decodeEnd:row]; + if (!startRange || !endRange) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + + NSMutableString *resultString = [NSMutableString stringWithCapacity:20]; + if (![self decodeMiddle:row payloadStart:startRange.array[1] payloadEnd:endRange.array[0] resultString:resultString]) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + + NSArray *allowedLengths = nil; + if (hints != nil) { + allowedLengths = hints.allowedLengths; + } + if (allowedLengths == nil) { + NSMutableArray *temp = [NSMutableArray array]; + for (int i = 0; i < sizeof(ZX_ITF_DEFAULT_ALLOWED_LENGTHS) / sizeof(int); i++) { + [temp addObject:@(ZX_ITF_DEFAULT_ALLOWED_LENGTHS[i])]; + } + allowedLengths = [NSArray arrayWithArray:temp]; + } + + // To avoid false positives with 2D barcodes (and other patterns), make + // an assumption that the decoded string must be a 'standard' length if it's short + NSUInteger length = [resultString length]; + BOOL lengthOK = NO; + int maxAllowedLength = 0; + for (NSNumber *i in allowedLengths) { + int allowedLength = [i intValue]; + if (length == allowedLength) { + lengthOK = YES; + break; + } + if (allowedLength > maxAllowedLength) { + maxAllowedLength = allowedLength; + } + } + if (!lengthOK && length > maxAllowedLength) { + lengthOK = YES; + } + if (!lengthOK) { + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + + return [ZXResult resultWithText:resultString + rawBytes:nil + resultPoints:@[[[ZXResultPoint alloc] initWithX:startRange.array[1] y:(float)rowNumber], + [[ZXResultPoint alloc] initWithX:endRange.array[0] y:(float)rowNumber]] + format:kBarcodeFormatITF]; +} + +/** + * @param row row of black/white values to search + * @param payloadStart offset of start pattern + * @param resultString NSMutableString to append decoded chars to + * @return NO if decoding could not complete successfully + */ +- (BOOL)decodeMiddle:(ZXBitArray *)row payloadStart:(int)payloadStart payloadEnd:(int)payloadEnd resultString:(NSMutableString *)resultString { + // Digits are interleaved in pairs - 5 black lines for one digit, and the + // 5 + // interleaved white lines for the second digit. + // Therefore, need to scan 10 lines and then + // split these into two arrays + ZXIntArray *counterDigitPair = [[ZXIntArray alloc] initWithLength:10]; + ZXIntArray *counterBlack = [[ZXIntArray alloc] initWithLength:5]; + ZXIntArray *counterWhite = [[ZXIntArray alloc] initWithLength:5]; + + while (payloadStart < payloadEnd) { + // Get 10 runs of black/white. + if (![ZXOneDReader recordPattern:row start:payloadStart counters:counterDigitPair]) { + return NO; + } + // Split them into each array + for (int k = 0; k < 5; k++) { + int twoK = 2 * k; + counterBlack.array[k] = counterDigitPair.array[twoK]; + counterWhite.array[k] = counterDigitPair.array[twoK + 1]; + } + + int bestMatch = [self decodeDigit:counterBlack]; + if (bestMatch == -1) { + return NO; + } + [resultString appendFormat:@"%C", (unichar)('0' + bestMatch)]; + bestMatch = [self decodeDigit:counterWhite]; + if (bestMatch == -1) { + return NO; + } + [resultString appendFormat:@"%C", (unichar)('0' + bestMatch)]; + + for (int i = 0; i < counterDigitPair.length; i++) { + payloadStart += counterDigitPair.array[i]; + } + } + return YES; +} + +/** + * Identify where the start of the middle / payload section starts. + * + * @param row row of black/white values to search + * @return Array, containing index of start of 'start block' and end of + * 'start block' + */ +- (ZXIntArray *)decodeStart:(ZXBitArray *)row { + int endStart = [self skipWhiteSpace:row]; + if (endStart == -1) { + return nil; + } + ZXIntArray *startPattern = [self findGuardPattern:row rowOffset:endStart pattern:ZX_ITF_ITF_START_PATTERN patternLen:sizeof(ZX_ITF_ITF_START_PATTERN)/sizeof(int)]; + if (!startPattern) { + return nil; + } + + self.narrowLineWidth = (startPattern.array[1] - startPattern.array[0]) / 4; + + if (![self validateQuietZone:row startPattern:startPattern.array[0]]) { + return nil; + } + + return startPattern; +} + +/** + * The start & end patterns must be pre/post fixed by a quiet zone. This + * zone must be at least 10 times the width of a narrow line. Scan back until + * we either get to the start of the barcode or match the necessary number of + * quiet zone pixels. + * + * Note: Its assumed the row is reversed when using this method to find + * quiet zone after the end pattern. + * + * ref: http://www.barcode-1.net/i25code.html + * + * @param row bit array representing the scanned barcode. + * @param startPattern index into row of the start or end pattern. + * @return NO if the quiet zone cannot be found, a ReaderException is thrown. + */ +- (BOOL)validateQuietZone:(ZXBitArray *)row startPattern:(int)startPattern { + int quietCount = self.narrowLineWidth * 10; + + // if there are not so many pixel at all let's try as many as possible + quietCount = quietCount < startPattern ? quietCount : startPattern; + + for (int i = startPattern - 1; quietCount > 0 && i >= 0; i--) { + if ([row get:i]) { + break; + } + quietCount--; + } + if (quietCount != 0) { + return NO; + } + return YES; +} + +/** + * Skip all whitespace until we get to the first black line. + * + * @param row row of black/white values to search + * @return index of the first black line or -1 if no black lines are found in the row + */ +- (int)skipWhiteSpace:(ZXBitArray *)row { + int width = [row size]; + int endStart = [row nextSet:0]; + if (endStart == width) { + return -1; + } + return endStart; +} + +/** + * Identify where the end of the middle / payload section ends. + * + * @param row row of black/white values to search + * @return Array, containing index of start of 'end block' and end of 'end + * block' + */ +- (ZXIntArray *)decodeEnd:(ZXBitArray *)row { + [row reverse]; + + int endStart = [self skipWhiteSpace:row]; + if (endStart == -1) { + [row reverse]; + return nil; + } + ZXIntArray *endPattern = [self findGuardPattern:row rowOffset:endStart pattern:ZX_ITF_END_PATTERN_REVERSED patternLen:sizeof(ZX_ITF_END_PATTERN_REVERSED)/sizeof(int)]; + if (!endPattern) { + [row reverse]; + return nil; + } + if (![self validateQuietZone:row startPattern:endPattern.array[0]]) { + [row reverse]; + return nil; + } + int temp = endPattern.array[0]; + endPattern.array[0] = [row size] - endPattern.array[1]; + endPattern.array[1] = [row size] - temp; + [row reverse]; + return endPattern; +} + +/** + * @param row row of black/white values to search + * @param rowOffset position to start search + * @param pattern pattern of counts of number of black and white pixels that are + * being searched for as a pattern + * @return start/end horizontal offset of guard pattern, as an array of two + * ints or nil if pattern is not found + */ +- (ZXIntArray *)findGuardPattern:(ZXBitArray *)row rowOffset:(int)rowOffset pattern:(const int[])pattern patternLen:(int)patternLen { + int patternLength = patternLen; + ZXIntArray *counters = [[ZXIntArray alloc] initWithLength:patternLength]; + int32_t *array = counters.array; + int width = row.size; + BOOL isWhite = NO; + + int counterPosition = 0; + int patternStart = rowOffset; + for (int x = rowOffset; x < width; x++) { + if ([row get:x] ^ isWhite) { + array[counterPosition]++; + } else { + if (counterPosition == patternLength - 1) { + if ([ZXOneDReader patternMatchVariance:counters pattern:pattern maxIndividualVariance:ZX_ITF_MAX_INDIVIDUAL_VARIANCE] < ZX_ITF_MAX_AVG_VARIANCE) { + return [[ZXIntArray alloc] initWithInts:patternStart, x, -1]; + } + patternStart += array[0] + array[1]; + for (int y = 2; y < patternLength; y++) { + array[y - 2] = array[y]; + } + array[patternLength - 2] = 0; + array[patternLength - 1] = 0; + counterPosition--; + } else { + counterPosition++; + } + array[counterPosition] = 1; + isWhite = !isWhite; + } + } + + return nil; +} + +/** + * Attempts to decode a sequence of ITF black/white lines into single + * digit. + * + * @param counters the counts of runs of observed black/white/black/... values + * @return The decoded digit or -1 if digit cannot be decoded + */ +- (int)decodeDigit:(ZXIntArray *)counters { + float bestVariance = ZX_ITF_MAX_AVG_VARIANCE; // worst variance we'll accept + int bestMatch = -1; + int max = ZX_ITF_PATTERNS_LEN; + for (int i = 0; i < max; i++) { + int pattern[counters.length]; + for (int ind = 0; ind < counters.length; ind++){ + pattern[ind] = ZX_ITF_PATTERNS[i][ind]; + } + float variance = [ZXOneDReader patternMatchVariance:counters pattern:pattern maxIndividualVariance:ZX_ITF_MAX_INDIVIDUAL_VARIANCE]; + if (variance < bestVariance) { + bestVariance = variance; + bestMatch = i; + } + } + if (bestMatch >= 0) { + return bestMatch; + } else { + return -1; + } +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXITFWriter.h b/iDearQRCode/Tools/ZXingObjC/oned/ZXITFWriter.h new file mode 100755 index 0000000..6b02789 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXITFWriter.h @@ -0,0 +1,24 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXOneDimensionalCodeWriter.h" + +/** + * This object renders a ITF code as a ZXBitMatrix. + */ +@interface ZXITFWriter : ZXOneDimensionalCodeWriter + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXITFWriter.m b/iDearQRCode/Tools/ZXingObjC/oned/ZXITFWriter.m new file mode 100755 index 0000000..5a58048 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXITFWriter.m @@ -0,0 +1,62 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBoolArray.h" +#import "ZXITFReader.h" +#import "ZXITFWriter.h" + +const int ZX_ITF_WRITER_START_PATTERN[] = {1, 1, 1, 1}; +const int ZX_ITF_WRITER_END_PATTERN[] = {3, 1, 1}; + +@implementation ZXITFWriter + +- (ZXBitMatrix *)encode:(NSString *)contents format:(ZXBarcodeFormat)format width:(int)width height:(int)height hints:(ZXEncodeHints *)hints error:(NSError **)error { + if (format != kBarcodeFormatITF) { + [NSException raise:NSInvalidArgumentException format:@"Can only encode ITF"]; + } + + return [super encode:contents format:format width:width height:height hints:hints error:error]; +} + +- (ZXBoolArray *)encode:(NSString *)contents { + int length = (int)[contents length]; + if (length % 2 != 0) { + [NSException raise:NSInvalidArgumentException format:@"The length of the input should be even"]; + } + if (length > 80) { + [NSException raise:NSInvalidArgumentException format:@"Requested contents should be less than 80 digits long, but got %d", length]; + } + + ZXBoolArray *result = [[ZXBoolArray alloc] initWithLength:9 + 9 * length]; + int pos = [self appendPattern:result pos:0 pattern:ZX_ITF_WRITER_START_PATTERN patternLen:sizeof(ZX_ITF_WRITER_START_PATTERN)/sizeof(int) startColor:YES]; + for (int i = 0; i < length; i += 2) { + int one = [[contents substringWithRange:NSMakeRange(i, 1)] intValue]; + int two = [[contents substringWithRange:NSMakeRange(i + 1, 1)] intValue]; + const int encodingLen = 18; + int encoding[encodingLen]; + memset(encoding, 0, encodingLen * sizeof(int)); + for (int j = 0; j < 5; j++) { + encoding[2 * j] = ZX_ITF_PATTERNS[one][j]; + encoding[2 * j + 1] = ZX_ITF_PATTERNS[two][j]; + } + pos += [super appendPattern:result pos:pos pattern:encoding patternLen:encodingLen startColor:YES]; + } + [self appendPattern:result pos:pos pattern:ZX_ITF_WRITER_END_PATTERN patternLen:sizeof(ZX_ITF_WRITER_END_PATTERN)/sizeof(int) startColor:YES]; + + return result; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXMultiFormatOneDReader.h b/iDearQRCode/Tools/ZXingObjC/oned/ZXMultiFormatOneDReader.h new file mode 100755 index 0000000..71a4eb2 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXMultiFormatOneDReader.h @@ -0,0 +1,25 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXOneDReader.h" + +@class ZXDecodeHints; + +@interface ZXMultiFormatOneDReader : ZXOneDReader + +- (id)initWithHints:(ZXDecodeHints *)hints; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXMultiFormatOneDReader.m b/iDearQRCode/Tools/ZXingObjC/oned/ZXMultiFormatOneDReader.m new file mode 100755 index 0000000..d47e2b2 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXMultiFormatOneDReader.m @@ -0,0 +1,111 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXCodaBarReader.h" +#import "ZXCode128Reader.h" +#import "ZXCode39Reader.h" +#import "ZXCode93Reader.h" +#import "ZXDecodeHints.h" +#import "ZXErrors.h" +#import "ZXITFReader.h" +#import "ZXMultiFormatOneDReader.h" +#import "ZXMultiFormatUPCEANReader.h" +#import "ZXRSS14Reader.h" +#import "ZXRSSExpandedReader.h" + +@interface ZXMultiFormatOneDReader () + +@property (nonatomic, strong, readonly) NSMutableArray *readers; + +@end + +@implementation ZXMultiFormatOneDReader + +- (id)initWithHints:(ZXDecodeHints *)hints { + if (self = [super init]) { + BOOL useCode39CheckDigit = hints != nil && hints.assumeCode39CheckDigit; + _readers = [NSMutableArray array]; + if (hints != nil) { + if ([hints containsFormat:kBarcodeFormatEan13] || + [hints containsFormat:kBarcodeFormatUPCA] || + [hints containsFormat:kBarcodeFormatEan8] || + [hints containsFormat:kBarcodeFormatUPCE]) { + [_readers addObject:[[ZXMultiFormatUPCEANReader alloc] initWithHints:hints]]; + } + + if ([hints containsFormat:kBarcodeFormatCode39]) { + [_readers addObject:[[ZXCode39Reader alloc] initUsingCheckDigit:useCode39CheckDigit]]; + } + + if ([hints containsFormat:kBarcodeFormatCode93]) { + [_readers addObject:[[ZXCode93Reader alloc] init]]; + } + + if ([hints containsFormat:kBarcodeFormatCode128]) { + [_readers addObject:[[ZXCode128Reader alloc] init]]; + } + + if ([hints containsFormat:kBarcodeFormatITF]) { + [_readers addObject:[[ZXITFReader alloc] init]]; + } + + if ([hints containsFormat:kBarcodeFormatCodabar]) { + [_readers addObject:[[ZXCodaBarReader alloc] init]]; + } + + if ([hints containsFormat:kBarcodeFormatRSS14]) { + [_readers addObject:[[ZXRSS14Reader alloc] init]]; + } + + if ([hints containsFormat:kBarcodeFormatRSSExpanded]) { + [_readers addObject:[[ZXRSSExpandedReader alloc] init]]; + } + } + + if ([_readers count] == 0) { + [_readers addObject:[[ZXMultiFormatUPCEANReader alloc] initWithHints:hints]]; + [_readers addObject:[[ZXCode39Reader alloc] init]]; + [_readers addObject:[[ZXCodaBarReader alloc] init]]; + [_readers addObject:[[ZXCode93Reader alloc] init]]; + [_readers addObject:[[ZXCode128Reader alloc] init]]; + [_readers addObject:[[ZXITFReader alloc] init]]; + [_readers addObject:[[ZXRSS14Reader alloc] init]]; + [_readers addObject:[[ZXRSSExpandedReader alloc] init]]; + } + } + + return self; +} + +- (ZXResult *)decodeRow:(int)rowNumber row:(ZXBitArray *)row hints:(ZXDecodeHints *)hints error:(NSError **)error { + for (ZXOneDReader *reader in self.readers) { + ZXResult *result = [reader decodeRow:rowNumber row:row hints:hints error:error]; + if (result) { + return result; + } + } + + if (error) *error = ZXNotFoundErrorInstance(); + return nil; +} + +- (void)reset { + for (id reader in self.readers) { + [reader reset]; + } +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXMultiFormatUPCEANReader.h b/iDearQRCode/Tools/ZXingObjC/oned/ZXMultiFormatUPCEANReader.h new file mode 100755 index 0000000..4fcc093 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXMultiFormatUPCEANReader.h @@ -0,0 +1,30 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXOneDReader.h" + +@class ZXDecodeHints; + +/** + * A reader that can read all available UPC/EAN formats. If a caller wants to try to + * read all such formats, it is most efficient to use this implementation rather than invoke + * individual readers. + */ +@interface ZXMultiFormatUPCEANReader : ZXOneDReader + +- (id)initWithHints:(ZXDecodeHints *)hints; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXMultiFormatUPCEANReader.m b/iDearQRCode/Tools/ZXingObjC/oned/ZXMultiFormatUPCEANReader.m new file mode 100755 index 0000000..fbbee67 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXMultiFormatUPCEANReader.m @@ -0,0 +1,112 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXDecodeHints.h" +#import "ZXEAN8Reader.h" +#import "ZXEAN13Reader.h" +#import "ZXErrors.h" +#import "ZXMultiFormatUPCEANReader.h" +#import "ZXReader.h" +#import "ZXResult.h" +#import "ZXUPCAReader.h" +#import "ZXUPCEReader.h" + +@interface ZXMultiFormatUPCEANReader () + +@property (nonatomic, strong, readonly) NSMutableArray *readers; + +@end + +@implementation ZXMultiFormatUPCEANReader + +- (id)initWithHints:(ZXDecodeHints *)hints { + if (self = [super init]) { + _readers = [NSMutableArray array]; + + if (hints != nil) { + if ([hints containsFormat:kBarcodeFormatEan13]) { + [_readers addObject:[[ZXEAN13Reader alloc] init]]; + } else if ([hints containsFormat:kBarcodeFormatUPCA]) { + [_readers addObject:[[ZXUPCAReader alloc] init]]; + } + + if ([hints containsFormat:kBarcodeFormatEan8]) { + [_readers addObject:[[ZXEAN8Reader alloc] init]]; + } + + if ([hints containsFormat:kBarcodeFormatUPCE]) { + [_readers addObject:[[ZXUPCEReader alloc] init]]; + } + } + + if ([_readers count] == 0) { + [_readers addObject:[[ZXEAN13Reader alloc] init]]; + [_readers addObject:[[ZXEAN8Reader alloc] init]]; + [_readers addObject:[[ZXUPCEReader alloc] init]]; + } + } + + return self; +} + +- (ZXResult *)decodeRow:(int)rowNumber row:(ZXBitArray *)row hints:(ZXDecodeHints *)hints error:(NSError **)error { + NSRange startGuardPattern = [ZXUPCEANReader findStartGuardPattern:row error:error]; + if (startGuardPattern.location == NSNotFound) { + return nil; + } + for (ZXUPCEANReader *reader in self.readers) { + ZXResult *result = [reader decodeRow:rowNumber row:row startGuardRange:startGuardPattern hints:hints error:error]; + if (!result) { + continue; + } + + // Special case: a 12-digit code encoded in UPC-A is identical to a "0" + // followed by those 12 digits encoded as EAN-13. Each will recognize such a code, + // UPC-A as a 12-digit string and EAN-13 as a 13-digit string starting with "0". + // Individually these are correct and their readers will both read such a code + // and correctly call it EAN-13, or UPC-A, respectively. + // + // In this case, if we've been looking for both types, we'd like to call it + // a UPC-A code. But for efficiency we only run the EAN-13 decoder to also read + // UPC-A. So we special case it here, and convert an EAN-13 result to a UPC-A + // result if appropriate. + // + // But, don't return UPC-A if UPC-A was not a requested format! + BOOL ean13MayBeUPCA = kBarcodeFormatEan13 == result.barcodeFormat && [result.text characterAtIndex:0] == '0'; + BOOL canReturnUPCA = hints == nil || [hints numberOfPossibleFormats] == 0 || [hints containsFormat:kBarcodeFormatUPCA]; + if (ean13MayBeUPCA && canReturnUPCA) { + // Transfer the metdata across + ZXResult *resultUPCA = [ZXResult resultWithText:[result.text substringFromIndex:1] + rawBytes:result.rawBytes + resultPoints:result.resultPoints + format:kBarcodeFormatUPCA]; + [resultUPCA putAllMetadata:result.resultMetadata]; + return resultUPCA; + } + return result; + } + + if (error) *error = ZXNotFoundErrorInstance(); + return nil; +} + +- (void)reset { + for (id reader in self.readers) { + [reader reset]; + } +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXOneDReader.h b/iDearQRCode/Tools/ZXingObjC/oned/ZXOneDReader.h new file mode 100755 index 0000000..9b77421 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXOneDReader.h @@ -0,0 +1,32 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXReader.h" + +@class ZXBitArray, ZXDecodeHints, ZXIntArray, ZXResult; + +/** + * Encapsulates functionality and implementation that is common to all families + * of one-dimensional barcodes. + */ +@interface ZXOneDReader : NSObject + ++ (BOOL)recordPattern:(ZXBitArray *)row start:(int)start counters:(ZXIntArray *)counters; ++ (BOOL)recordPatternInReverse:(ZXBitArray *)row start:(int)start counters:(ZXIntArray *)counters; ++ (float)patternMatchVariance:(ZXIntArray *)counters pattern:(const int[])pattern maxIndividualVariance:(float)maxIndividualVariance; +- (ZXResult *)decodeRow:(int)rowNumber row:(ZXBitArray *)row hints:(ZXDecodeHints *)hints error:(NSError **)error; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXOneDReader.m b/iDearQRCode/Tools/ZXingObjC/oned/ZXOneDReader.m new file mode 100755 index 0000000..7e4f685 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXOneDReader.m @@ -0,0 +1,267 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBinaryBitmap.h" +#import "ZXBitArray.h" +#import "ZXDecodeHints.h" +#import "ZXErrors.h" +#import "ZXIntArray.h" +#import "ZXOneDReader.h" +#import "ZXResult.h" +#import "ZXResultPoint.h" + +@implementation ZXOneDReader + +- (ZXResult *)decode:(ZXBinaryBitmap *)image error:(NSError **)error { + return [self decode:image hints:nil error:error]; +} + +// Note that we don't try rotation without the try harder flag, even if rotation was supported. +- (ZXResult *)decode:(ZXBinaryBitmap *)image hints:(ZXDecodeHints *)hints error:(NSError **)error { + NSError *decodeError = nil; + ZXResult *result = [self doDecode:image hints:hints error:&decodeError]; + if (result) { + return result; + } else if (decodeError.code == ZXNotFoundError) { + BOOL tryHarder = hints != nil && hints.tryHarder; + if (tryHarder && [image rotateSupported]) { + ZXBinaryBitmap *rotatedImage = [image rotateCounterClockwise]; + ZXResult *result = [self doDecode:rotatedImage hints:hints error:error]; + if (!result) { + return nil; + } + // Record that we found it rotated 90 degrees CCW / 270 degrees CW + NSMutableDictionary *metadata = [result resultMetadata]; + int orientation = 270; + if (metadata != nil && metadata[@(kResultMetadataTypeOrientation)]) { + // But if we found it reversed in doDecode(), add in that result here: + orientation = (orientation + [((NSNumber *)metadata[@(kResultMetadataTypeOrientation)]) intValue]) % 360; + } + [result putMetadata:kResultMetadataTypeOrientation value:@(orientation)]; + // Update result points + NSMutableArray *points = [result resultPoints]; + if (points != nil) { + int height = [rotatedImage height]; + for (int i = 0; i < [points count]; i++) { + points[i] = [[ZXResultPoint alloc] initWithX:height - [(ZXResultPoint *)points[i] y] + y:[(ZXResultPoint *)points[i] x]]; + } + } + return result; + } + } + + if (error) *error = decodeError; + return nil; +} + +- (void)reset { + // do nothing +} + +/** + * We're going to examine rows from the middle outward, searching alternately above and below the + * middle, and farther out each time. rowStep is the number of rows between each successive + * attempt above and below the middle. So we'd scan row middle, then middle - rowStep, then + * middle + rowStep, then middle - (2 * rowStep), etc. + * rowStep is bigger as the image is taller, but is always at least 1. We've somewhat arbitrarily + * decided that moving up and down by about 1/16 of the image is pretty good; we try more of the + * image if "trying harder". + * + * @param image The image to decode + * @param hints Any hints that were requested + * @return The contents of the decoded barcode or nil if an error occurs + */ +- (ZXResult *)doDecode:(ZXBinaryBitmap *)image hints:(ZXDecodeHints *)hints error:(NSError **)error { + int width = image.width; + int height = image.height; + ZXBitArray *row = [[ZXBitArray alloc] initWithSize:width]; + int middle = height >> 1; + BOOL tryHarder = hints != nil && hints.tryHarder; + int rowStep = MAX(1, height >> (tryHarder ? 8 : 5)); + int maxLines; + if (tryHarder) { + maxLines = height; + } else { + maxLines = 15; + } + + for (int x = 0; x < maxLines; x++) { + int rowStepsAboveOrBelow = (x + 1) / 2; + BOOL isAbove = (x & 0x01) == 0; + int rowNumber = middle + rowStep * (isAbove ? rowStepsAboveOrBelow : -rowStepsAboveOrBelow); + if (rowNumber < 0 || rowNumber >= height) { + break; + } + + NSError *rowError = nil; + row = [image blackRow:rowNumber row:row error:&rowError]; + if (!row && rowError.code == ZXNotFoundError) { + continue; + } else if (!row) { + if (error) *error = rowError; + return nil; + } + + for (int attempt = 0; attempt < 2; attempt++) { + if (attempt == 1) { + [row reverse]; + if (hints != nil && hints.resultPointCallback) { + hints = [hints copy]; + hints.resultPointCallback = nil; + } + } + + ZXResult *result = [self decodeRow:rowNumber row:row hints:hints error:nil]; + if (result) { + if (attempt == 1) { + [result putMetadata:kResultMetadataTypeOrientation value:@180]; + NSMutableArray *points = [result resultPoints]; + if (points != nil) { + points[0] = [[ZXResultPoint alloc] initWithX:width - [(ZXResultPoint *)points[0] x] + y:[(ZXResultPoint *)points[0] y]]; + points[1] = [[ZXResultPoint alloc] initWithX:width - [(ZXResultPoint *)points[1] x] + y:[(ZXResultPoint *)points[1] y]]; + } + } + return result; + } + } + } + + if (error) *error = ZXNotFoundErrorInstance(); + return nil; +} + +/** + * Records the size of successive runs of white and black pixels in a row, starting at a given point. + * The values are recorded in the given array, and the number of runs recorded is equal to the size + * of the array. If the row starts on a white pixel at the given start point, then the first count + * recorded is the run of white pixels starting from that point; likewise it is the count of a run + * of black pixels if the row begin on a black pixels at that point. + * + * @param row row to count from + * @param start offset into row to start at + * @param counters array into which to record counts or nil if counters cannot be filled entirely + * from row before running out of pixels + */ ++ (BOOL)recordPattern:(ZXBitArray *)row start:(int)start counters:(ZXIntArray *)counters { + int numCounters = counters.length; + [counters clear]; + int32_t *array = counters.array; + int end = row.size; + if (start >= end) { + return NO; + } + BOOL isWhite = ![row get:start]; + int counterPosition = 0; + int i = start; + + while (i < end) { + if ([row get:i] ^ isWhite) { + array[counterPosition]++; + } else { + counterPosition++; + if (counterPosition == numCounters) { + break; + } else { + array[counterPosition] = 1; + isWhite = !isWhite; + } + } + i++; + } + + if (!(counterPosition == numCounters || (counterPosition == numCounters - 1 && i == end))) { + return NO; + } + return YES; +} + ++ (BOOL)recordPatternInReverse:(ZXBitArray *)row start:(int)start counters:(ZXIntArray *)counters { + int numTransitionsLeft = counters.length; + BOOL last = [row get:start]; + while (start > 0 && numTransitionsLeft >= 0) { + if ([row get:--start] != last) { + numTransitionsLeft--; + last = !last; + } + } + + if (numTransitionsLeft >= 0 || ![self recordPattern:row start:start + 1 counters:counters]) { + return NO; + } + return YES; +} + +/** + * Determines how closely a set of observed counts of runs of black/white values matches a given + * target pattern. This is reported as the ratio of the total variance from the expected pattern + * proportions across all pattern elements, to the length of the pattern. + * + * @param counters observed counters + * @param pattern expected pattern + * @param maxIndividualVariance The most any counter can differ before we give up + * @return ratio of total variance between counters and pattern compared to total pattern size + */ ++ (float)patternMatchVariance:(ZXIntArray *)counters pattern:(const int[])pattern maxIndividualVariance:(float)maxIndividualVariance { + int numCounters = counters.length; + int total = 0; + int patternLength = 0; + + int32_t *array = counters.array; + for (int i = 0; i < numCounters; i++) { + total += array[i]; + patternLength += pattern[i]; + } + + if (total < patternLength || patternLength == 0) { + return FLT_MAX; + } + float unitBarWidth = (float) total / patternLength; + maxIndividualVariance *= unitBarWidth; + + float totalVariance = 0.0f; + for (int x = 0; x < numCounters; x++) { + int counter = array[x]; + float scaledPattern = pattern[x] * unitBarWidth; + float variance = counter > scaledPattern ? counter - scaledPattern : scaledPattern - counter; + if (variance > maxIndividualVariance) { + return FLT_MAX; + } + totalVariance += variance; + } + + return totalVariance / total; +} + +/** + * Attempts to decode a one-dimensional barcode format given a single row of + * an image. + * + * @param rowNumber row number from top of the row + * @param row the black/white pixel data of the row + * @param hints decode hints + * @return ZXResult containing encoded string and start/end of barcode or nil + * if an error occurs or barcode cannot be found + */ +- (ZXResult *)decodeRow:(int)rowNumber row:(ZXBitArray *)row hints:(ZXDecodeHints *)hints error:(NSError **)error { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)] + userInfo:nil]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXOneDimensionalCodeWriter.h b/iDearQRCode/Tools/ZXingObjC/oned/ZXOneDimensionalCodeWriter.h new file mode 100755 index 0000000..170e00d --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXOneDimensionalCodeWriter.h @@ -0,0 +1,30 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXWriter.h" + +@class ZXBoolArray; + +/** + * Encapsulates functionality and implementation that is common to one-dimensional barcodes. + */ +@interface ZXOneDimensionalCodeWriter : NSObject + +- (ZXBoolArray *)encode:(NSString *)contents; +- (int)appendPattern:(ZXBoolArray *)target pos:(int)pos pattern:(const int[])pattern patternLen:(int)patternLen startColor:(BOOL)startColor; +- (int)defaultMargin; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXOneDimensionalCodeWriter.m b/iDearQRCode/Tools/ZXingObjC/oned/ZXOneDimensionalCodeWriter.m new file mode 100755 index 0000000..eb69f84 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXOneDimensionalCodeWriter.m @@ -0,0 +1,115 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitMatrix.h" +#import "ZXBoolArray.h" +#import "ZXEncodeHints.h" +#import "ZXOneDimensionalCodeWriter.h" + +@implementation ZXOneDimensionalCodeWriter + +- (ZXBitMatrix *)encode:(NSString *)contents format:(ZXBarcodeFormat)format width:(int)width height:(int)height error:(NSError **)error { + return [self encode:contents format:format width:width height:height hints:nil error:error]; +} + +/** + * Encode the contents following specified format. + * width and height are required size. This method may return bigger size + * ZXBitMatrix when specified size is too small. The user can set both {width and + * height to zero to get minimum size barcode. If negative value is set to width + * or height, IllegalArgumentException is thrown. + */ +- (ZXBitMatrix *)encode:(NSString *)contents format:(ZXBarcodeFormat)format width:(int)width height:(int)height + hints:(ZXEncodeHints *)hints error:(NSError **)error { + if (contents.length == 0) { + @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Found empty contents" userInfo:nil]; + } + + if (width < 0 || height < 0) { + @throw [NSException exceptionWithName:NSInvalidArgumentException + reason:[NSString stringWithFormat:@"Negative size is not allowed. Input: %dx%d", width, height] + userInfo:nil]; + } + + int sidesMargin = [self defaultMargin]; + if (hints && hints.margin) { + sidesMargin = hints.margin.intValue; + } + + ZXBoolArray *code = [self encode:contents]; + return [self renderResult:code width:width height:height sidesMargin:sidesMargin]; +} + +/** + * @return a byte array of horizontal pixels (0 = white, 1 = black) + */ +- (ZXBitMatrix *)renderResult:(ZXBoolArray *)code width:(int)width height:(int)height sidesMargin:(int)sidesMargin { + int inputWidth = code.length; + // Add quiet zone on both sides. + int fullWidth = inputWidth + sidesMargin; + int outputWidth = MAX(width, fullWidth); + int outputHeight = MAX(1, height); + + int multiple = outputWidth / fullWidth; + int leftPadding = (outputWidth - (inputWidth * multiple)) / 2; + + ZXBitMatrix *output = [[ZXBitMatrix alloc] initWithWidth:outputWidth height:outputHeight]; + for (int inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX += multiple) { + if (code.array[inputX]) { + [output setRegionAtLeft:outputX top:0 width:multiple height:outputHeight]; + } + } + return output; +} + +/** + * Appends the given pattern to the target array starting at pos. + * + * @param startColor starting color - false for white, true for black + * @return the number of elements added to target. + */ +- (int)appendPattern:(ZXBoolArray *)target pos:(int)pos pattern:(const int[])pattern patternLen:(int)patternLen startColor:(BOOL)startColor { + BOOL color = startColor; + int numAdded = 0; + for (int i = 0; i < patternLen; i++) { + for (int j = 0; j < pattern[i]; j++) { + target.array[pos++] = color; + } + numAdded += pattern[i]; + color = !color; // flip color after each segment + } + return numAdded; +} + +- (int)defaultMargin { + // CodaBar spec requires a side margin to be more than ten times wider than narrow space. + // This seems like a decent idea for a default for all formats. + return 10; +} + +/** + * Encode the contents to boolean array expression of one-dimensional barcode. + * Start code and end code should be included in result, and side margins should not be included. + * + * @return a ZXBoolArray of horizontal pixels (false = white, true = black) + */ +- (ZXBoolArray *)encode:(NSString *)contents { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)] + userInfo:nil]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCAReader.h b/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCAReader.h new file mode 100755 index 0000000..097443c --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCAReader.h @@ -0,0 +1,24 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXUPCEANReader.h" + +/** + * Implements decoding of the UPC-A format. + */ +@interface ZXUPCAReader : ZXUPCEANReader + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCAReader.m b/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCAReader.m new file mode 100755 index 0000000..659a71e --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCAReader.m @@ -0,0 +1,114 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXEAN13Reader.h" +#import "ZXErrors.h" +#import "ZXResult.h" +#import "ZXUPCAReader.h" + +@interface ZXUPCAReader () + +@property (nonatomic, strong, readonly) ZXUPCEANReader *ean13Reader; + +@end + +@implementation ZXUPCAReader + +- (id)init { + if (self = [super init]) { + _ean13Reader = [[ZXEAN13Reader alloc] init]; + } + + return self; +} + +- (ZXResult *)decodeRow:(int)rowNumber row:(ZXBitArray *)row startGuardRange:(NSRange)startGuardRange hints:(ZXDecodeHints *)hints error:(NSError **)error { + ZXResult *result = [self.ean13Reader decodeRow:rowNumber row:row startGuardRange:startGuardRange hints:hints error:error]; + if (result) { + result = [self maybeReturnResult:result]; + if (!result) { + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + return result; + } else { + return nil; + } +} + +- (ZXResult *)decodeRow:(int)rowNumber row:(ZXBitArray *)row hints:(ZXDecodeHints *)hints error:(NSError **)error { + ZXResult *result = [self.ean13Reader decodeRow:rowNumber row:row hints:hints error:error]; + if (result) { + result = [self maybeReturnResult:result]; + if (!result) { + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + return result; + } else { + return nil; + } +} + +- (ZXResult *)decode:(ZXBinaryBitmap *)image error:(NSError **)error { + ZXResult *result = [self.ean13Reader decode:image error:error]; + if (result) { + result = [self maybeReturnResult:result]; + if (!result) { + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + return result; + } else { + return nil; + } +} + +- (ZXResult *)decode:(ZXBinaryBitmap *)image hints:(ZXDecodeHints *)hints error:(NSError **)error { + ZXResult *result = [self.ean13Reader decode:image hints:hints error:error]; + if (result) { + result = [self maybeReturnResult:result]; + if (!result) { + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + return result; + } else { + return nil; + } +} + +- (ZXBarcodeFormat)barcodeFormat { + return kBarcodeFormatUPCA; +} + +- (int)decodeMiddle:(ZXBitArray *)row startRange:(NSRange)startRange result:(NSMutableString *)result error:(NSError **)error { + return [self.ean13Reader decodeMiddle:row startRange:startRange result:result error:error]; +} + +- (ZXResult *)maybeReturnResult:(ZXResult *)result { + NSString *text = result.text; + if ([text characterAtIndex:0] == '0') { + return [ZXResult resultWithText:[text substringFromIndex:1] + rawBytes:nil + resultPoints:result.resultPoints + format:kBarcodeFormatUPCA]; + } else { + return nil; + } +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCAWriter.h b/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCAWriter.h new file mode 100755 index 0000000..0011de8 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCAWriter.h @@ -0,0 +1,24 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXWriter.h" + +/** + * This object renders a UPC-A code as a ZXBitMatrix. + */ +@interface ZXUPCAWriter : NSObject + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCAWriter.m b/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCAWriter.m new file mode 100755 index 0000000..6cbc3d1 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCAWriter.m @@ -0,0 +1,67 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXEAN13Writer.h" +#import "ZXUPCAWriter.h" + +@implementation ZXUPCAWriter + +- (ZXEAN13Writer *)subWriter { + static ZXEAN13Writer *subWriter = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + subWriter = [[ZXEAN13Writer alloc] init]; + }); + + return subWriter; +} + +- (ZXBitMatrix *)encode:(NSString *)contents format:(ZXBarcodeFormat)format width:(int)width height:(int)height error:(NSError **)error { + return [self encode:contents format:format width:width height:height hints:nil error:error]; +} + +- (ZXBitMatrix *)encode:(NSString *)contents format:(ZXBarcodeFormat)format width:(int)width height:(int)height hints:(ZXEncodeHints *)hints error:(NSError **)error { + if (format != kBarcodeFormatUPCA) { + @throw [NSException exceptionWithName:NSInvalidArgumentException + reason:[NSString stringWithFormat:@"Can only encode UPC-A, but got %d", format] + userInfo:nil]; + } + return [self.subWriter encode:[self preencode:contents] format:kBarcodeFormatEan13 width:width height:height hints:hints error:error]; +} + +/** + * Transform a UPC-A code into the equivalent EAN-13 code, and add a check digit if it is not + * already present. + */ +- (NSString *)preencode:(NSString *)contents { + NSUInteger length = [contents length]; + if (length == 11) { + int sum = 0; + + for (int i = 0; i < 11; ++i) { + sum += ([contents characterAtIndex:i] - '0') * (i % 2 == 0 ? 3 : 1); + } + + contents = [contents stringByAppendingFormat:@"%d", (1000 - sum) % 10]; + } else if (length != 12) { + @throw [NSException exceptionWithName:NSInvalidArgumentException + reason:[NSString stringWithFormat:@"Requested contents should be 11 or 12 digits long, but got %ld", (unsigned long)[contents length]] + userInfo:nil]; + } + return [NSString stringWithFormat:@"0%@", contents]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEANExtension2Support.h b/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEANExtension2Support.h new file mode 100755 index 0000000..c185589 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEANExtension2Support.h @@ -0,0 +1,27 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXBitArray, ZXResult; + +/** + * @see UPCEANExtension5Support + */ +@interface ZXUPCEANExtension2Support : NSObject + +- (ZXResult *)decodeRow:(int)rowNumber row:(ZXBitArray *)row extensionStartRange:(NSRange)extensionStartRange error:(NSError **)error; +- (int)decodeMiddle:(ZXBitArray *)row startRange:(NSRange)startRange result:(NSMutableString *)result error:(NSError **)error; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEANExtension2Support.m b/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEANExtension2Support.m new file mode 100755 index 0000000..4188518 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEANExtension2Support.m @@ -0,0 +1,114 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBarcodeFormat.h" +#import "ZXBitArray.h" +#import "ZXErrors.h" +#import "ZXIntArray.h" +#import "ZXResult.h" +#import "ZXResultMetadataType.h" +#import "ZXResultPoint.h" +#import "ZXUPCEANExtension2Support.h" +#import "ZXUPCEANReader.h" + +@interface ZXUPCEANExtension2Support () + +@property (nonatomic, strong, readonly) ZXIntArray *decodeMiddleCounters; + +@end + +@implementation ZXUPCEANExtension2Support + +- (id)init { + if (self = [super init]) { + _decodeMiddleCounters = [[ZXIntArray alloc] initWithLength:4]; + } + + return self; +} + +- (ZXResult *)decodeRow:(int)rowNumber row:(ZXBitArray *)row extensionStartRange:(NSRange)extensionStartRange error:(NSError **)error { + NSMutableString *resultString = [NSMutableString string]; + int end = [self decodeMiddle:row startRange:extensionStartRange result:resultString error:error]; + if (end == -1) { + return nil; + } + + NSMutableDictionary *extensionData = [self parseExtensionString:resultString]; + + ZXResult *extensionResult = [[ZXResult alloc] initWithText:resultString + rawBytes:nil + resultPoints:@[[[ZXResultPoint alloc] initWithX:(extensionStartRange.location + NSMaxRange(extensionStartRange)) / 2.0f y:rowNumber], + [[ZXResultPoint alloc] initWithX:end y:rowNumber]] + format:kBarcodeFormatUPCEANExtension]; + if (extensionData != nil) { + [extensionResult putAllMetadata:extensionData]; + } + return extensionResult; +} + +- (int)decodeMiddle:(ZXBitArray *)row startRange:(NSRange)startRange result:(NSMutableString *)result error:(NSError **)error { + ZXIntArray *counters = self.decodeMiddleCounters; + [counters clear]; + int end = [row size]; + int rowOffset = (int)NSMaxRange(startRange); + + int checkParity = 0; + + for (int x = 0; x < 2 && rowOffset < end; x++) { + int bestMatch = [ZXUPCEANReader decodeDigit:row counters:counters rowOffset:rowOffset patternType:ZX_UPC_EAN_PATTERNS_L_AND_G_PATTERNS error:error]; + if (bestMatch == -1) { + return -1; + } + [result appendFormat:@"%C", (unichar)('0' + bestMatch % 10)]; + rowOffset += [counters sum]; + if (bestMatch >= 10) { + checkParity |= 1 << (1 - x); + } + if (x != 1) { + // Read off separator if not last + rowOffset = [row nextSet:rowOffset]; + rowOffset = [row nextUnset:rowOffset]; + } + } + + if (result.length != 2) { + if (error) *error = ZXNotFoundErrorInstance(); + return -1; + } + + if ([result intValue] % 4 != checkParity) { + if (error) *error = ZXNotFoundErrorInstance(); + return -1; + } + + return rowOffset; +} + +/** + * @param raw raw content of extension + * @return formatted interpretation of raw content as a NSDictionary mapping + * one ZXResultMetadataType to appropriate value, or nil if not known + */ +- (NSMutableDictionary *)parseExtensionString:(NSString *)raw { + if (raw.length != 2) { + return nil; + } + return [NSMutableDictionary dictionaryWithObject:@([raw intValue]) + forKey:@(kResultMetadataTypeIssueNumber)]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEANExtension5Support.h b/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEANExtension5Support.h new file mode 100755 index 0000000..fed1545 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEANExtension5Support.h @@ -0,0 +1,27 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXBitArray, ZXResult; + +/** + * @see UPCEANExtension2Support + */ +@interface ZXUPCEANExtension5Support : NSObject + +- (ZXResult *)decodeRow:(int)rowNumber row:(ZXBitArray *)row extensionStartRange:(NSRange)extensionStartRange error:(NSError **)error; +- (int)decodeMiddle:(ZXBitArray *)row startRange:(NSRange)startRange result:(NSMutableString *)result error:(NSError **)error; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEANExtension5Support.m b/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEANExtension5Support.m new file mode 100755 index 0000000..081372a --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEANExtension5Support.m @@ -0,0 +1,183 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBarcodeFormat.h" +#import "ZXBitArray.h" +#import "ZXErrors.h" +#import "ZXIntArray.h" +#import "ZXResult.h" +#import "ZXResultMetadataType.h" +#import "ZXResultPoint.h" +#import "ZXUPCEANExtension5Support.h" +#import "ZXUPCEANReader.h" + +const int ZX_UPCEAN_CHECK_DIGIT_ENCODINGS[] = { + 0x18, 0x14, 0x12, 0x11, 0x0C, 0x06, 0x03, 0x0A, 0x09, 0x05 +}; + +@interface ZXUPCEANExtension5Support () + +@property (nonatomic, strong, readonly) ZXIntArray *decodeMiddleCounters; + +@end + +@implementation ZXUPCEANExtension5Support + +- (id)init { + if (self = [super init]) { + _decodeMiddleCounters = [[ZXIntArray alloc] initWithLength:4]; + } + + return self; +} + +- (ZXResult *)decodeRow:(int)rowNumber row:(ZXBitArray *)row extensionStartRange:(NSRange)extensionStartRange error:(NSError **)error { + NSMutableString *resultString = [NSMutableString string]; + int end = [self decodeMiddle:row startRange:extensionStartRange result:resultString error:error]; + if (end == -1) { + return nil; + } + + NSMutableDictionary *extensionData = [self parseExtensionString:resultString]; + + ZXResult *extensionResult = [[ZXResult alloc] initWithText:resultString + rawBytes:nil + resultPoints:@[[[ZXResultPoint alloc] initWithX:(extensionStartRange.location + NSMaxRange(extensionStartRange)) / 2.0f y:rowNumber], + [[ZXResultPoint alloc] initWithX:end y:rowNumber]] + format:kBarcodeFormatUPCEANExtension]; + if (extensionData != nil) { + [extensionResult putAllMetadata:extensionData]; + } + return extensionResult; +} + +- (int)decodeMiddle:(ZXBitArray *)row startRange:(NSRange)startRange result:(NSMutableString *)result error:(NSError **)error { + ZXIntArray *counters = self.decodeMiddleCounters; + [counters clear]; + + int end = [row size]; + int rowOffset = (int)NSMaxRange(startRange); + + int lgPatternFound = 0; + + for (int x = 0; x < 5 && rowOffset < end; x++) { + int bestMatch = [ZXUPCEANReader decodeDigit:row counters:counters rowOffset:rowOffset patternType:ZX_UPC_EAN_PATTERNS_L_AND_G_PATTERNS error:error]; + if (bestMatch == -1) { + return -1; + } + [result appendFormat:@"%C", (unichar)('0' + bestMatch % 10)]; + rowOffset += [counters sum]; + if (bestMatch >= 10) { + lgPatternFound |= 1 << (4 - x); + } + if (x != 4) { + // Read off separator if not last + rowOffset = [row nextSet:rowOffset]; + rowOffset = [row nextUnset:rowOffset]; + } + } + + if (result.length != 5) { + if (error) *error = ZXNotFoundErrorInstance(); + return -1; + } + + int checkDigit = [self determineCheckDigit:lgPatternFound]; + if (checkDigit == -1) { + if (error) *error = ZXNotFoundErrorInstance(); + return -1; + } else if ([self extensionChecksum:result] != checkDigit) { + if (error) *error = ZXNotFoundErrorInstance(); + return -1; + } + + return rowOffset; +} + +- (int)extensionChecksum:(NSString *)s { + int length = (int)[s length]; + int sum = 0; + for (int i = length - 2; i >= 0; i -= 2) { + sum += (int)[s characterAtIndex:i] - (int)'0'; + } + sum *= 3; + for (int i = length - 1; i >= 0; i -= 2) { + sum += (int)[s characterAtIndex:i] - (int)'0'; + } + sum *= 3; + return sum % 10; +} + +- (int)determineCheckDigit:(int)lgPatternFound { + for (int d = 0; d < 10; d++) { + if (lgPatternFound == ZX_UPCEAN_CHECK_DIGIT_ENCODINGS[d]) { + return d; + } + } + return -1; +} + +/** + * @param raw raw content of extension + * @return formatted interpretation of raw content as a NSDictionary mapping + * one ZXResultMetadataType to appropriate value, or nil if not known + */ +- (NSMutableDictionary *)parseExtensionString:(NSString *)raw { + if (raw.length != 5) { + return nil; + } + id value = [self parseExtension5String:raw]; + if (value) { + return [NSMutableDictionary dictionaryWithObject:value forKey:@(kResultMetadataTypeSuggestedPrice)]; + } else { + return nil; + } +} + +- (NSString *)parseExtension5String:(NSString *)raw { + NSString *currency; + switch ([raw characterAtIndex:0]) { + case '0': + currency = @"£"; + break; + case '5': + currency = @"$"; + break; + case '9': + if ([@"90000" isEqualToString:raw]) { + return nil; + } + if ([@"99991" isEqualToString:raw]) { + return @"0.00"; + } + if ([@"99990" isEqualToString:raw]) { + return @"Used"; + } + currency = @""; + break; + default: + currency = @""; + break; + } + int rawAmount = [[raw substringFromIndex:1] intValue]; + NSString *unitsString = [@(rawAmount / 100) stringValue]; + int hundredths = rawAmount % 100; + NSString *hundredthsString = hundredths < 10 ? + [NSString stringWithFormat:@"0%d", hundredths] : [@(hundredths) stringValue]; + return [NSString stringWithFormat:@"%@%@.%@", currency, unitsString, hundredthsString]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEANExtensionSupport.h b/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEANExtensionSupport.h new file mode 100755 index 0000000..b94101c --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEANExtensionSupport.h @@ -0,0 +1,23 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXBitArray, ZXResult; + +@interface ZXUPCEANExtensionSupport : NSObject + +- (ZXResult *)decodeRow:(int)rowNumber row:(ZXBitArray *)row rowOffset:(int)rowOffset error:(NSError **)error; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEANExtensionSupport.m b/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEANExtensionSupport.m new file mode 100755 index 0000000..affe80b --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEANExtensionSupport.m @@ -0,0 +1,62 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXUPCEANExtensionSupport.h" +#import "ZXUPCEANExtension2Support.h" +#import "ZXUPCEANExtension5Support.h" +#import "ZXUPCEANReader.h" + +const int ZX_UPCEAN_EXTENSION_START_PATTERN[] = {1,1,2}; + +@interface ZXUPCEANExtensionSupport () + +@property (nonatomic, strong, readonly) ZXUPCEANExtension2Support *twoSupport; +@property (nonatomic, strong, readonly) ZXUPCEANExtension5Support *fiveSupport; + +@end + +@implementation ZXUPCEANExtensionSupport + +- (id)init { + if (self = [super init]) { + _twoSupport = [[ZXUPCEANExtension2Support alloc] init]; + _fiveSupport = [[ZXUPCEANExtension5Support alloc] init]; + } + + return self; +} + +- (ZXResult *)decodeRow:(int)rowNumber row:(ZXBitArray *)row rowOffset:(int)rowOffset error:(NSError **)error { + NSRange extensionStartRange = [ZXUPCEANReader findGuardPattern:row + rowOffset:rowOffset + whiteFirst:NO + pattern:ZX_UPCEAN_EXTENSION_START_PATTERN + patternLen:sizeof(ZX_UPCEAN_EXTENSION_START_PATTERN)/sizeof(int) + error:error]; + + if (extensionStartRange.location == NSNotFound) { + return nil; + } + + ZXResult *result = [self.fiveSupport decodeRow:rowNumber row:row extensionStartRange:extensionStartRange error:error]; + if (!result) { + result = [self.twoSupport decodeRow:rowNumber row:row extensionStartRange:extensionStartRange error:error]; + } + + return result; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEANReader.h b/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEANReader.h new file mode 100755 index 0000000..535640b --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEANReader.h @@ -0,0 +1,116 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBarcodeFormat.h" +#import "ZXOneDReader.h" + +typedef enum { + ZX_UPC_EAN_PATTERNS_L_PATTERNS = 0, + ZX_UPC_EAN_PATTERNS_L_AND_G_PATTERNS +} ZX_UPC_EAN_PATTERNS; + +extern const int ZX_UPC_EAN_START_END_PATTERN_LEN; +extern const int ZX_UPC_EAN_START_END_PATTERN[]; +extern const int ZX_UPC_EAN_MIDDLE_PATTERN_LEN; +extern const int ZX_UPC_EAN_MIDDLE_PATTERN[]; +extern const int ZX_UPC_EAN_L_PATTERNS_LEN; +extern const int ZX_UPC_EAN_L_PATTERNS_SUB_LEN; +extern const int ZX_UPC_EAN_L_PATTERNS[][4]; +extern const int ZX_UPC_EAN_L_AND_G_PATTERNS_LEN; +extern const int ZX_UPC_EAN_L_AND_G_PATTERNS_SUB_LEN; +extern const int ZX_UPC_EAN_L_AND_G_PATTERNS[][4]; + +@class ZXDecodeHints, ZXEANManufacturerOrgSupport, ZXIntArray, ZXResult, ZXUPCEANExtensionSupport; + +/** + * Encapsulates functionality and implementation that is common to UPC and EAN families + * of one-dimensional barcodes. + */ +@interface ZXUPCEANReader : ZXOneDReader + ++ (NSRange)findStartGuardPattern:(ZXBitArray *)row error:(NSError **)error; + +/** + * Like decodeRow:row:hints:, but allows caller to inform method about where the UPC/EAN start pattern is + * found. This allows this to be computed once and reused across many implementations. + */ +- (ZXResult *)decodeRow:(int)rowNumber row:(ZXBitArray *)row startGuardRange:(NSRange)startGuardRange hints:(ZXDecodeHints *)hints error:(NSError **)error; + +/** + * @return checkStandardUPCEANChecksum: + */ +- (BOOL)checkChecksum:(NSString *)s error:(NSError **)error; + +/** + * Computes the UPC/EAN checksum on a string of digits, and reports + * whether the checksum is correct or not. + * + * @param s string of digits to check + * @return YES iff string of digits passes the UPC/EAN checksum algorithm + * @return NO if the string does not contain only digits + */ ++ (BOOL)checkStandardUPCEANChecksum:(NSString *)s; + +- (NSRange)decodeEnd:(ZXBitArray *)row endStart:(int)endStart error:(NSError **)error; + ++ (NSRange)findGuardPattern:(ZXBitArray *)row rowOffset:(int)rowOffset whiteFirst:(BOOL)whiteFirst pattern:(const int[])pattern patternLen:(int)patternLen error:(NSError **)error; + +/** + * @param row row of black/white values to search + * @param rowOffset position to start search + * @param whiteFirst if true, indicates that the pattern specifies white/black/white/... + * pixel counts, otherwise, it is interpreted as black/white/black/... + * @param pattern pattern of counts of number of black and white pixels that are being + * searched for as a pattern + * @param counters array of counters, as long as pattern, to re-use + * @return start/end horizontal offset of guard pattern, as an array of two ints + */ ++ (NSRange)findGuardPattern:(ZXBitArray *)row rowOffset:(int)rowOffset whiteFirst:(BOOL)whiteFirst pattern:(const int[])pattern patternLen:(int)patternLen counters:(ZXIntArray *)counters error:(NSError **)error; + +/** + * Attempts to decode a single UPC/EAN-encoded digit. + * + * @param row row of black/white values to decode + * @param counters the counts of runs of observed black/white/black/... values + * @param rowOffset horizontal offset to start decoding from + * @param patterns the set of patterns to use to decode -- sometimes different encodings + * for the digits 0-9 are used, and this indicates the encodings for 0 to 9 that should + * be used + * @return horizontal offset of first pixel beyond the decoded digit + * @return -1 if digit cannot be decoded + */ ++ (int)decodeDigit:(ZXBitArray *)row counters:(ZXIntArray *)counters rowOffset:(int)rowOffset patternType:(ZX_UPC_EAN_PATTERNS)patternType error:(NSError **)error; + +/** + * Get the format of this decoder. + * + * @return The 1D format. + */ +- (ZXBarcodeFormat)barcodeFormat; + +/** + * Subclasses override this to decode the portion of a barcode between the start + * and end guard patterns. + * + * @param row row of black/white values to search + * @param startRange start/end offset of start guard pattern + * @param resultString NSMutableString to append decoded chars to + * @return horizontal offset of first pixel after the "middle" that was decoded + * @return -1 if decoding could not complete successfully + */ +- (int)decodeMiddle:(ZXBitArray *)row startRange:(NSRange)startRange result:(NSMutableString *)result error:(NSError **)error; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEANReader.m b/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEANReader.m new file mode 100755 index 0000000..1c6edf0 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEANReader.m @@ -0,0 +1,385 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitArray.h" +#import "ZXDecodeHints.h" +#import "ZXEANManufacturerOrgSupport.h" +#import "ZXErrors.h" +#import "ZXIntArray.h" +#import "ZXResult.h" +#import "ZXResultPoint.h" +#import "ZXResultPointCallback.h" +#import "ZXUPCEANReader.h" +#import "ZXUPCEANExtensionSupport.h" + +static float ZX_UPC_EAN_MAX_AVG_VARIANCE = 0.48f; +static float ZX_UPC_EAN_MAX_INDIVIDUAL_VARIANCE = 0.7f; + +/** + * Start/end guard pattern. + */ +const int ZX_UPC_EAN_START_END_PATTERN_LEN = 3; +const int ZX_UPC_EAN_START_END_PATTERN[ZX_UPC_EAN_START_END_PATTERN_LEN] = {1, 1, 1}; + +/** + * Pattern marking the middle of a UPC/EAN pattern, separating the two halves. + */ +const int ZX_UPC_EAN_MIDDLE_PATTERN_LEN = 5; +const int ZX_UPC_EAN_MIDDLE_PATTERN[ZX_UPC_EAN_MIDDLE_PATTERN_LEN] = {1, 1, 1, 1, 1}; + +/** + * "Odd", or "L" patterns used to encode UPC/EAN digits. + */ +const int ZX_UPC_EAN_L_PATTERNS_LEN = 10; +const int ZX_UPC_EAN_L_PATTERNS_SUB_LEN = 4; +const int ZX_UPC_EAN_L_PATTERNS[ZX_UPC_EAN_L_PATTERNS_LEN][ZX_UPC_EAN_L_PATTERNS_SUB_LEN] = { + {3, 2, 1, 1}, // 0 + {2, 2, 2, 1}, // 1 + {2, 1, 2, 2}, // 2 + {1, 4, 1, 1}, // 3 + {1, 1, 3, 2}, // 4 + {1, 2, 3, 1}, // 5 + {1, 1, 1, 4}, // 6 + {1, 3, 1, 2}, // 7 + {1, 2, 1, 3}, // 8 + {3, 1, 1, 2} // 9 +}; + +/** + * As above but also including the "even", or "G" patterns used to encode UPC/EAN digits. + */ +const int ZX_UPC_EAN_L_AND_G_PATTERNS_LEN = 20; +const int ZX_UPC_EAN_L_AND_G_PATTERNS_SUB_LEN = 4; +const int ZX_UPC_EAN_L_AND_G_PATTERNS[ZX_UPC_EAN_L_AND_G_PATTERNS_LEN][ZX_UPC_EAN_L_AND_G_PATTERNS_SUB_LEN] = { + {3, 2, 1, 1}, // 0 + {2, 2, 2, 1}, // 1 + {2, 1, 2, 2}, // 2 + {1, 4, 1, 1}, // 3 + {1, 1, 3, 2}, // 4 + {1, 2, 3, 1}, // 5 + {1, 1, 1, 4}, // 6 + {1, 3, 1, 2}, // 7 + {1, 2, 1, 3}, // 8 + {3, 1, 1, 2}, // 9 + {1, 1, 2, 3}, // 10 reversed 0 + {1, 2, 2, 2}, // 11 reversed 1 + {2, 2, 1, 2}, // 12 reversed 2 + {1, 1, 4, 1}, // 13 reversed 3 + {2, 3, 1, 1}, // 14 reversed 4 + {1, 3, 2, 1}, // 15 reversed 5 + {4, 1, 1, 1}, // 16 reversed 6 + {2, 1, 3, 1}, // 17 reversed 7 + {3, 1, 2, 1}, // 18 reversed 8 + {2, 1, 1, 3} // 19 reversed 9 +}; + +@interface ZXUPCEANReader () + +@property (nonatomic, strong, readonly) NSMutableString *decodeRowNSMutableString; +@property (nonatomic, strong, readonly) ZXUPCEANExtensionSupport *extensionReader; +@property (nonatomic, strong, readonly) ZXEANManufacturerOrgSupport *eanManSupport; + +@end + +@implementation ZXUPCEANReader + +- (id)init { + if (self = [super init]) { + _decodeRowNSMutableString = [NSMutableString stringWithCapacity:20]; + _extensionReader = [[ZXUPCEANExtensionSupport alloc] init]; + _eanManSupport = [[ZXEANManufacturerOrgSupport alloc] init]; + } + + return self; +} + ++ (NSRange)findStartGuardPattern:(ZXBitArray *)row error:(NSError **)error { + BOOL foundStart = NO; + NSRange startRange = NSMakeRange(NSNotFound, 0); + int nextStart = 0; + ZXIntArray *counters = [[ZXIntArray alloc] initWithLength:ZX_UPC_EAN_START_END_PATTERN_LEN]; + while (!foundStart) { + [counters clear]; + startRange = [self findGuardPattern:row rowOffset:nextStart + whiteFirst:NO + pattern:ZX_UPC_EAN_START_END_PATTERN + patternLen:ZX_UPC_EAN_START_END_PATTERN_LEN + counters:counters + error:error]; + if (startRange.location == NSNotFound) { + return startRange; + } + int start = (int)startRange.location; + nextStart = (int)NSMaxRange(startRange); + // Make sure there is a quiet zone at least as big as the start pattern before the barcode. + // If this check would run off the left edge of the image, do not accept this barcode, + // as it is very likely to be a false positive. + int quietStart = start - (nextStart - start); + if (quietStart >= 0) { + foundStart = [row isRange:quietStart end:start value:NO]; + } + } + return startRange; +} + +- (ZXResult *)decodeRow:(int)rowNumber row:(ZXBitArray *)row hints:(ZXDecodeHints *)hints error:(NSError **)error { + return [self decodeRow:rowNumber row:row startGuardRange:[[self class] findStartGuardPattern:row error:error] hints:hints error:error]; +} + +- (ZXResult *)decodeRow:(int)rowNumber row:(ZXBitArray *)row startGuardRange:(NSRange)startGuardRange hints:(ZXDecodeHints *)hints error:(NSError **)error { + id resultPointCallback = hints == nil ? nil : hints.resultPointCallback; + + if (resultPointCallback != nil) { + [resultPointCallback foundPossibleResultPoint:[[ZXResultPoint alloc] initWithX:(startGuardRange.location + NSMaxRange(startGuardRange)) / 2.0f y:rowNumber]]; + } + + NSMutableString *result = [NSMutableString string]; + int endStart = [self decodeMiddle:row startRange:startGuardRange result:result error:error]; + if (endStart == -1) { + return nil; + } + + if (resultPointCallback != nil) { + [resultPointCallback foundPossibleResultPoint:[[ZXResultPoint alloc] initWithX:endStart y:rowNumber]]; + } + + NSRange endRange = [self decodeEnd:row endStart:endStart error:error]; + if (endRange.location == NSNotFound) { + return nil; + } + + if (resultPointCallback != nil) { + [resultPointCallback foundPossibleResultPoint:[[ZXResultPoint alloc] initWithX:(endRange.location + NSMaxRange(endRange)) / 2.0f y:rowNumber]]; + } + + // Make sure there is a quiet zone at least as big as the end pattern after the barcode. The + // spec might want more whitespace, but in practice this is the maximum we can count on. + int end = (int)NSMaxRange(endRange); + int quietEnd = end + (end - (int)endRange.location); + if (quietEnd >= [row size] || ![row isRange:end end:quietEnd value:NO]) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + + NSString *resultString = [result description]; + // UPC/EAN should never be less than 8 chars anyway + if ([resultString length] < 8) { + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + if (![self checkChecksum:resultString error:error]) { + if (error) *error = ZXChecksumErrorInstance(); + return nil; + } + + float left = (float)(NSMaxRange(startGuardRange) + startGuardRange.location) / 2.0f; + float right = (float)(NSMaxRange(endRange) + endRange.location) / 2.0f; + ZXBarcodeFormat format = [self barcodeFormat]; + + ZXResult *decodeResult = [ZXResult resultWithText:resultString + rawBytes:nil + resultPoints:@[[[ZXResultPoint alloc] initWithX:left y:(float)rowNumber], [[ZXResultPoint alloc] initWithX:right y:(float)rowNumber]] + format:format]; + + int extensionLength = 0; + + ZXResult *extensionResult = [self.extensionReader decodeRow:rowNumber row:row rowOffset:(int)NSMaxRange(endRange) error:error]; + if (extensionResult) { + [decodeResult putMetadata:kResultMetadataTypeUPCEANExtension value:extensionResult.text]; + [decodeResult putAllMetadata:[extensionResult resultMetadata]]; + [decodeResult addResultPoints:[extensionResult resultPoints]]; + extensionLength = (int)[extensionResult.text length]; + } + + ZXIntArray *allowedExtensions = hints == nil ? nil : hints.allowedEANExtensions; + if (allowedExtensions != nil) { + BOOL valid = NO; + for (int i = 0; i < allowedExtensions.length; i++) { + if (extensionLength == allowedExtensions.array[i]) { + valid = YES; + break; + } + } + if (!valid) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + } + + if (format == kBarcodeFormatEan13 || format == kBarcodeFormatUPCA) { + NSString *countryID = [self.eanManSupport lookupCountryIdentifier:resultString]; + if (countryID != nil) { + [decodeResult putMetadata:kResultMetadataTypePossibleCountry value:countryID]; + } + } + return decodeResult; +} + +- (BOOL)checkChecksum:(NSString *)s error:(NSError **)error { + if ([[self class] checkStandardUPCEANChecksum:s]) { + return YES; + } else { + if (error) *error = ZXFormatErrorInstance(); + return NO; + } +} + ++ (BOOL)checkStandardUPCEANChecksum:(NSString *)s { + int length = (int)[s length]; + if (length == 0) { + return NO; + } + int sum = 0; + + for (int i = length - 2; i >= 0; i -= 2) { + int digit = (int)[s characterAtIndex:i] - (int)'0'; + if (digit < 0 || digit > 9) { + return NO; + } + sum += digit; + } + + sum *= 3; + + for (int i = length - 1; i >= 0; i -= 2) { + int digit = (int)[s characterAtIndex:i] - (int)'0'; + if (digit < 0 || digit > 9) { + return NO; + } + sum += digit; + } + + return sum % 10 == 0; +} + +- (NSRange)decodeEnd:(ZXBitArray *)row endStart:(int)endStart error:(NSError **)error { + return [[self class] findGuardPattern:row + rowOffset:endStart + whiteFirst:NO + pattern:ZX_UPC_EAN_START_END_PATTERN + patternLen:ZX_UPC_EAN_START_END_PATTERN_LEN + error:error]; +} + ++ (NSRange)findGuardPattern:(ZXBitArray *)row rowOffset:(int)rowOffset whiteFirst:(BOOL)whiteFirst pattern:(const int[])pattern patternLen:(int)patternLen error:(NSError **)error { + ZXIntArray *counters = [[ZXIntArray alloc] initWithLength:patternLen]; + return [self findGuardPattern:row rowOffset:rowOffset whiteFirst:whiteFirst pattern:pattern patternLen:patternLen counters:counters error:error]; +} + ++ (NSRange)findGuardPattern:(ZXBitArray *)row rowOffset:(int)rowOffset whiteFirst:(BOOL)whiteFirst pattern:(const int[])pattern patternLen:(int)patternLen counters:(ZXIntArray *)counters error:(NSError **)error { + int patternLength = patternLen; + int width = row.size; + BOOL isWhite = whiteFirst; + rowOffset = whiteFirst ? [row nextUnset:rowOffset] : [row nextSet:rowOffset]; + int counterPosition = 0; + int patternStart = rowOffset; + int32_t *array = counters.array; + for (int x = rowOffset; x < width; x++) { + if ([row get:x] ^ isWhite) { + array[counterPosition]++; + } else { + if (counterPosition == patternLength - 1) { + if ([self patternMatchVariance:counters pattern:pattern maxIndividualVariance:ZX_UPC_EAN_MAX_INDIVIDUAL_VARIANCE] < ZX_UPC_EAN_MAX_AVG_VARIANCE) { + return NSMakeRange(patternStart, x - patternStart); + } + patternStart += array[0] + array[1]; + + for (int y = 2; y < patternLength; y++) { + array[y - 2] = array[y]; + } + + array[patternLength - 2] = 0; + array[patternLength - 1] = 0; + counterPosition--; + } else { + counterPosition++; + } + array[counterPosition] = 1; + isWhite = !isWhite; + } + } + + if (error) *error = ZXNotFoundErrorInstance(); + return NSMakeRange(NSNotFound, 0); +} + +/** + * Attempts to decode a single UPC/EAN-encoded digit. + */ ++ (int)decodeDigit:(ZXBitArray *)row counters:(ZXIntArray *)counters rowOffset:(int)rowOffset patternType:(ZX_UPC_EAN_PATTERNS)patternType error:(NSError **)error { + if (![self recordPattern:row start:rowOffset counters:counters]) { + if (error) *error = ZXNotFoundErrorInstance(); + return -1; + } + float bestVariance = ZX_UPC_EAN_MAX_AVG_VARIANCE; + int bestMatch = -1; + int max = 0; + switch (patternType) { + case ZX_UPC_EAN_PATTERNS_L_PATTERNS: + max = ZX_UPC_EAN_L_PATTERNS_LEN; + for (int i = 0; i < max; i++) { + int pattern[counters.length]; + for (int j = 0; j < counters.length; j++){ + pattern[j] = ZX_UPC_EAN_L_PATTERNS[i][j]; + } + + float variance = [self patternMatchVariance:counters pattern:pattern maxIndividualVariance:ZX_UPC_EAN_MAX_INDIVIDUAL_VARIANCE]; + if (variance < bestVariance) { + bestVariance = variance; + bestMatch = i; + } + } + break; + case ZX_UPC_EAN_PATTERNS_L_AND_G_PATTERNS: + max = ZX_UPC_EAN_L_AND_G_PATTERNS_LEN; + for (int i = 0; i < max; i++) { + int pattern[counters.length]; + for (int j = 0; j< counters.length; j++){ + pattern[j] = ZX_UPC_EAN_L_AND_G_PATTERNS[i][j]; + } + + float variance = [self patternMatchVariance:counters pattern:pattern maxIndividualVariance:ZX_UPC_EAN_MAX_INDIVIDUAL_VARIANCE]; + if (variance < bestVariance) { + bestVariance = variance; + bestMatch = i; + } + } + break; + default: + break; + } + + if (bestMatch >= 0) { + return bestMatch; + } else { + if (error) *error = ZXNotFoundErrorInstance(); + return -1; + } +} + +- (ZXBarcodeFormat)barcodeFormat { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)] + userInfo:nil]; +} + +- (int)decodeMiddle:(ZXBitArray *)row startRange:(NSRange)startRange result:(NSMutableString *)result error:(NSError **)error { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)] + userInfo:nil]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEANWriter.h b/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEANWriter.h new file mode 100755 index 0000000..ce78196 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEANWriter.h @@ -0,0 +1,25 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXOneDimensionalCodeWriter.h" + +/** + * Encapsulates functionality and implementation that is common to UPC and EAN families + * of one-dimensional barcodes. + */ +@interface ZXUPCEANWriter : ZXOneDimensionalCodeWriter + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEANWriter.m b/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEANWriter.m new file mode 100755 index 0000000..27ba383 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEANWriter.m @@ -0,0 +1,29 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBarcodeFormat.h" +#import "ZXBitMatrix.h" +#import "ZXUPCEANReader.h" +#import "ZXUPCEANWriter.h" + +@implementation ZXUPCEANWriter + +- (int)defaultMargin { + // Use a different default more appropriate for UPC/EAN + return ZX_UPC_EAN_START_END_PATTERN_LEN; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEReader.h b/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEReader.h new file mode 100755 index 0000000..7553319 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEReader.h @@ -0,0 +1,29 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBarcodeFormat.h" +#import "ZXUPCEANReader.h" + +/** + * Implements decoding of the UPC-E format. + * + * http://www.barcodeisland.com/upce.phtml is a great reference for UPC-E information. + */ +@interface ZXUPCEReader : ZXUPCEANReader + ++ (NSString *)convertUPCEtoUPCA:(NSString *)upce; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEReader.m b/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEReader.m new file mode 100755 index 0000000..949861b --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXUPCEReader.m @@ -0,0 +1,154 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitArray.h" +#import "ZXErrors.h" +#import "ZXIntArray.h" +#import "ZXUPCEReader.h" + +/** + * The pattern that marks the middle, and end, of a UPC-E pattern. + * There is no "second half" to a UPC-E barcode. + */ +const int ZX_UCPE_MIDDLE_END_PATTERN[] = {1, 1, 1, 1, 1, 1}; + +/** + * See ZX_UCPE_L_AND_G_PATTERNS; these values similarly represent patterns of + * even-odd parity encodings of digits that imply both the number system (0 or 1) + * used, and the check digit. + */ +const int ZX_UCPE_NUMSYS_AND_CHECK_DIGIT_PATTERNS[][10] = { + {0x38, 0x34, 0x32, 0x31, 0x2C, 0x26, 0x23, 0x2A, 0x29, 0x25}, + {0x07, 0x0B, 0x0D, 0x0E, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A} +}; + +@interface ZXUPCEReader () + +@property (nonatomic, strong, readonly) ZXIntArray *decodeMiddleCounters; + +@end + +@implementation ZXUPCEReader + +- (id)init { + if (self = [super init]) { + _decodeMiddleCounters = [[ZXIntArray alloc] initWithLength:4]; + } + + return self; +} + +- (int)decodeMiddle:(ZXBitArray *)row startRange:(NSRange)startRange result:(NSMutableString *)result error:(NSError **)error { + ZXIntArray *counters = self.decodeMiddleCounters; + [counters clear]; + + int end = [row size]; + int rowOffset = (int)NSMaxRange(startRange); + int lgPatternFound = 0; + + for (int x = 0; x < 6 && rowOffset < end; x++) { + int bestMatch = [ZXUPCEANReader decodeDigit:row counters:counters rowOffset:rowOffset patternType:ZX_UPC_EAN_PATTERNS_L_AND_G_PATTERNS error:error]; + if (bestMatch == -1) { + return -1; + } + [result appendFormat:@"%C", (unichar)('0' + bestMatch % 10)]; + + rowOffset += [counters sum]; + + if (bestMatch >= 10) { + lgPatternFound |= 1 << (5 - x); + } + } + + if (![self determineNumSysAndCheckDigit:result lgPatternFound:lgPatternFound]) { + if (error) *error = ZXNotFoundErrorInstance(); + return -1; + } + return rowOffset; +} + +- (NSRange)decodeEnd:(ZXBitArray *)row endStart:(int)endStart error:(NSError **)error { + return [ZXUPCEANReader findGuardPattern:row + rowOffset:endStart + whiteFirst:YES + pattern:ZX_UCPE_MIDDLE_END_PATTERN + patternLen:sizeof(ZX_UCPE_MIDDLE_END_PATTERN) / sizeof(int) + error:error]; +} + +- (BOOL)checkChecksum:(NSString *)s error:(NSError **)error { + return [super checkChecksum:[ZXUPCEReader convertUPCEtoUPCA:s] error:error]; +} + +- (BOOL)determineNumSysAndCheckDigit:(NSMutableString *)resultString lgPatternFound:(int)lgPatternFound { + for (int numSys = 0; numSys <= 1; numSys++) { + for (int d = 0; d < 10; d++) { + if (lgPatternFound == ZX_UCPE_NUMSYS_AND_CHECK_DIGIT_PATTERNS[numSys][d]) { + [resultString insertString:[NSString stringWithFormat:@"%C", (unichar)('0' + numSys)] atIndex:0]; + [resultString appendFormat:@"%C", (unichar)('0' + d)]; + return YES; + } + } + } + + return NO; +} + +- (ZXBarcodeFormat)barcodeFormat { + return kBarcodeFormatUPCE; +} + +/** + * Expands a UPC-E value back into its full, equivalent UPC-A code value. + * + * @param upce UPC-E code as string of digits + * @return equivalent UPC-A code as string of digits + */ ++ (NSString *)convertUPCEtoUPCA:(NSString *)upce { + NSString *upceChars = [upce substringWithRange:NSMakeRange(1, 6)]; + NSMutableString *result = [NSMutableString stringWithCapacity:12]; + [result appendFormat:@"%C", [upce characterAtIndex:0]]; + unichar lastChar = [upceChars characterAtIndex:5]; + switch (lastChar) { + case '0': + case '1': + case '2': + [result appendString:[upceChars substringToIndex:2]]; + [result appendFormat:@"%C", lastChar]; + [result appendString:@"0000"]; + [result appendString:[upceChars substringWithRange:NSMakeRange(2, 3)]]; + break; + case '3': + [result appendString:[upceChars substringToIndex:3]]; + [result appendString:@"00000"]; + [result appendString:[upceChars substringWithRange:NSMakeRange(3, 2)]]; + break; + case '4': + [result appendString:[upceChars substringToIndex:4]]; + [result appendString:@"00000"]; + [result appendString:[upceChars substringWithRange:NSMakeRange(4, 1)]]; + break; + default: + [result appendString:[upceChars substringToIndex:5]]; + [result appendString:@"0000"]; + [result appendFormat:@"%C", lastChar]; + break; + } + [result appendFormat:@"%C", [upce characterAtIndex:7]]; + return result; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/ZXingObjCOneD.h b/iDearQRCode/Tools/ZXingObjC/oned/ZXingObjCOneD.h new file mode 100755 index 0000000..205b3e1 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/ZXingObjCOneD.h @@ -0,0 +1,92 @@ +/* + * Copyright 2014 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _ZXINGOBJC_ONED_ + +#define _ZXINGOBJC_ONED_ + +// OneD + +#import "ZXAbstractExpandedDecoder.h" +#import "ZXAbstractRSSReader.h" +#import "ZXCodaBarReader.h" +#import "ZXCodaBarWriter.h" +#import "ZXCode128Reader.h" +#import "ZXCode128Writer.h" +#import "ZXCode39Reader.h" +#import "ZXCode39Writer.h" +#import "ZXCode93Reader.h" +#import "ZXEAN13Reader.h" +#import "ZXEAN13Writer.h" +#import "ZXEAN8Reader.h" +#import "ZXEAN8Writer.h" +#import "ZXITFReader.h" +#import "ZXITFWriter.h" +#import "ZXMultiFormatOneDReader.h" +#import "ZXMultiFormatUPCEANReader.h" +#import "ZXOneDimensionalCodeWriter.h" +#import "ZXOneDReader.h" +#import "ZXRSS14Reader.h" +#import "ZXRSSDataCharacter.h" +#import "ZXRSSExpandedReader.h" +#import "ZXRSSFinderPattern.h" +#import "ZXRSSUtils.h" +#import "ZXUPCAReader.h" +#import "ZXUPCAWriter.h" +#import "ZXUPCEANReader.h" +#import "ZXUPCEANWriter.h" +#import "ZXUPCEReader.h" + +// Result Parsers + +#import "ZXAddressBookAUResultParser.h" +#import "ZXAddressBookDoCoMoResultParser.h" +#import "ZXAddressBookParsedResult.h" +#import "ZXBizcardResultParser.h" +#import "ZXBookmarkDoCoMoResultParser.h" +#import "ZXCalendarParsedResult.h" +#import "ZXEmailAddressParsedResult.h" +#import "ZXEmailAddressResultParser.h" +#import "ZXEmailDoCoMoResultParser.h" +#import "ZXExpandedProductParsedResult.h" +#import "ZXExpandedProductResultParser.h" +#import "ZXGeoParsedResult.h" +#import "ZXGeoResultParser.h" +#import "ZXISBNParsedResult.h" +#import "ZXISBNResultParser.h" +#import "ZXParsedResult.h" +#import "ZXParsedResultType.h" +#import "ZXProductParsedResult.h" +#import "ZXProductResultParser.h" +#import "ZXResultParser.h" +#import "ZXSMSMMSResultParser.h" +#import "ZXSMSParsedResult.h" +#import "ZXSMSTOMMSTOResultParser.h" +#import "ZXSMTPResultParser.h" +#import "ZXTelParsedResult.h" +#import "ZXTelResultParser.h" +#import "ZXTextParsedResult.h" +#import "ZXURIParsedResult.h" +#import "ZXURIResultParser.h" +#import "ZXURLTOResultParser.h" +#import "ZXVCardResultParser.h" +#import "ZXVEventResultParser.h" +#import "ZXVINParsedResult.h" +#import "ZXVINResultParser.h" +#import "ZXWifiParsedResult.h" +#import "ZXWifiResultParser.h" + +#endif diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/ZXAbstractRSSReader.h b/iDearQRCode/Tools/ZXingObjC/oned/rss/ZXAbstractRSSReader.h new file mode 100755 index 0000000..4723841 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/ZXAbstractRSSReader.h @@ -0,0 +1,43 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXOneDReader.h" + +@class ZXIntArray; + +typedef enum { + ZX_RSS_PATTERNS_RSS14_PATTERNS = 0, + ZX_RSS_PATTERNS_RSS_EXPANDED_PATTERNS +} ZX_RSS_PATTERNS; + +@interface ZXAbstractRSSReader : ZXOneDReader + +@property (nonatomic, strong, readonly) ZXIntArray *decodeFinderCounters; +@property (nonatomic, strong, readonly) ZXIntArray *dataCharacterCounters; +@property (nonatomic, assign, readonly) float *oddRoundingErrors; +@property (nonatomic, assign, readonly) unsigned int oddRoundingErrorsLen; +@property (nonatomic, assign, readonly) float *evenRoundingErrors; +@property (nonatomic, assign, readonly) unsigned int evenRoundingErrorsLen; +@property (nonatomic, strong, readonly) ZXIntArray *oddCounts; +@property (nonatomic, strong, readonly) ZXIntArray *evenCounts; + ++ (int)parseFinderValue:(ZXIntArray *)counters finderPatternType:(ZX_RSS_PATTERNS)finderPatternType; ++ (int)count:(ZXIntArray *)array; ++ (void)increment:(ZXIntArray *)array errors:(float *)errors; ++ (void)decrement:(ZXIntArray *)array errors:(float *)errors; ++ (BOOL)isFinderPattern:(ZXIntArray *)counters; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/ZXAbstractRSSReader.m b/iDearQRCode/Tools/ZXingObjC/oned/rss/ZXAbstractRSSReader.m new file mode 100755 index 0000000..66bb065 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/ZXAbstractRSSReader.m @@ -0,0 +1,161 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAbstractRSSReader.h" +#import "ZXIntArray.h" + +static float ZX_RSS_MAX_AVG_VARIANCE = 0.2f; +static float ZX_RSS_MAX_INDIVIDUAL_VARIANCE = 0.45f; + +float const ZX_RSS_MIN_FINDER_PATTERN_RATIO = 9.5f / 12.0f; +float const ZX_RSS_MAX_FINDER_PATTERN_RATIO = 12.5f / 14.0f; + +#define ZX_RSS14_FINDER_PATTERNS_LEN 9 +#define ZX_RSS14_FINDER_PATTERNS_SUB_LEN 4 +const int ZX_RSS14_FINDER_PATTERNS[ZX_RSS14_FINDER_PATTERNS_LEN][ZX_RSS14_FINDER_PATTERNS_SUB_LEN] = { + {3,8,2,1}, + {3,5,5,1}, + {3,3,7,1}, + {3,1,9,1}, + {2,7,4,1}, + {2,5,6,1}, + {2,3,8,1}, + {1,5,7,1}, + {1,3,9,1}, +}; + +#define ZX_RSS_EXPANDED_FINDER_PATTERNS_LEN 6 +#define ZX_RSS_EXPANDED_FINDER_PATTERNS_SUB_LEN 4 +const int ZX_RSS_EXPANDED_FINDER_PATTERNS[ZX_RSS_EXPANDED_FINDER_PATTERNS_LEN][ZX_RSS_EXPANDED_FINDER_PATTERNS_SUB_LEN] = { + {1,8,4,1}, // A + {3,6,4,1}, // B + {3,4,6,1}, // C + {3,2,8,1}, // D + {2,6,5,1}, // E + {2,2,9,1} // F +}; + +@implementation ZXAbstractRSSReader + +- (id)init { + if (self = [super init]) { + _decodeFinderCounters = [[ZXIntArray alloc] initWithLength:4]; + _dataCharacterCounters = [[ZXIntArray alloc] initWithLength:8]; + + _oddRoundingErrorsLen = 4; + _oddRoundingErrors = (float *)malloc(_oddRoundingErrorsLen * sizeof(float)); + memset(_oddRoundingErrors, 0, _oddRoundingErrorsLen * sizeof(float)); + + _evenRoundingErrorsLen = 4; + _evenRoundingErrors = (float *)malloc(_evenRoundingErrorsLen * sizeof(float)); + memset(_evenRoundingErrors, 0, _evenRoundingErrorsLen * sizeof(float)); + + _oddCounts = [[ZXIntArray alloc] initWithLength:_dataCharacterCounters.length / 2]; + _evenCounts = [[ZXIntArray alloc] initWithLength:_dataCharacterCounters.length / 2]; + } + + return self; +} + +- (void)dealloc { + if (_oddRoundingErrors != NULL) { + free(_oddRoundingErrors); + _oddRoundingErrors = NULL; + } + + if (_evenRoundingErrors != NULL) { + free(_evenRoundingErrors); + _evenRoundingErrors = NULL; + } +} + ++ (int)parseFinderValue:(ZXIntArray *)counters finderPatternType:(ZX_RSS_PATTERNS)finderPatternType { + switch (finderPatternType) { + case ZX_RSS_PATTERNS_RSS14_PATTERNS: + for (int value = 0; value < ZX_RSS14_FINDER_PATTERNS_LEN; value++) { + if ([self patternMatchVariance:counters pattern:ZX_RSS14_FINDER_PATTERNS[value] maxIndividualVariance:ZX_RSS_MAX_INDIVIDUAL_VARIANCE] < ZX_RSS_MAX_AVG_VARIANCE) { + return value; + } + } + break; + + case ZX_RSS_PATTERNS_RSS_EXPANDED_PATTERNS: + for (int value = 0; value < ZX_RSS_EXPANDED_FINDER_PATTERNS_LEN; value++) { + if ([self patternMatchVariance:counters pattern:ZX_RSS_EXPANDED_FINDER_PATTERNS[value] maxIndividualVariance:ZX_RSS_MAX_INDIVIDUAL_VARIANCE] < ZX_RSS_MAX_AVG_VARIANCE) { + return value; + } + } + break; + + default: + break; + } + + return -1; +} + ++ (int)count:(ZXIntArray *)array { + return [array sum]; +} + ++ (void)increment:(ZXIntArray *)array errors:(float *)errors { + int index = 0; + float biggestError = errors[0]; + for (int i = 1; i < array.length; i++) { + if (errors[i] > biggestError) { + biggestError = errors[i]; + index = i; + } + } + array.array[index]++; +} + ++ (void)decrement:(ZXIntArray *)array errors:(float *)errors { + int index = 0; + float biggestError = errors[0]; + for (int i = 1; i < array.length; i++) { + if (errors[i] < biggestError) { + biggestError = errors[i]; + index = i; + } + } + array.array[index]--; +} + ++ (BOOL)isFinderPattern:(ZXIntArray *)counters { + int32_t *array = counters.array; + int firstTwoSum = array[0] + array[1]; + int sum = firstTwoSum + array[2] + array[3]; + float ratio = (float)firstTwoSum / (float)sum; + if (ratio >= ZX_RSS_MIN_FINDER_PATTERN_RATIO && ratio <= ZX_RSS_MAX_FINDER_PATTERN_RATIO) { + int minCounter = INT_MAX; + int maxCounter = INT_MIN; + for (int i = 0; i < counters.length; i++) { + int counter = array[i]; + if (counter > maxCounter) { + maxCounter = counter; + } + if (counter < minCounter) { + minCounter = counter; + } + } + + return maxCounter < 10 * minCounter; + } + return NO; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/ZXRSS14Reader.h b/iDearQRCode/Tools/ZXingObjC/oned/rss/ZXRSS14Reader.h new file mode 100755 index 0000000..49db392 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/ZXRSS14Reader.h @@ -0,0 +1,26 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAbstractRSSReader.h" + +@class ZXDecodeHints, ZXResult; + +/** + * Decodes RSS-14, including truncated and stacked variants. See ISO/IEC 24724:2006. + */ +@interface ZXRSS14Reader : ZXAbstractRSSReader + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/ZXRSS14Reader.m b/iDearQRCode/Tools/ZXingObjC/oned/rss/ZXRSS14Reader.m new file mode 100755 index 0000000..0653bf3 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/ZXRSS14Reader.m @@ -0,0 +1,440 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitArray.h" +#import "ZXBarcodeFormat.h" +#import "ZXDecodeHints.h" +#import "ZXErrors.h" +#import "ZXIntArray.h" +#import "ZXResult.h" +#import "ZXResultPointCallback.h" +#import "ZXRSS14Reader.h" +#import "ZXRSSFinderPattern.h" +#import "ZXRSSPair.h" +#import "ZXRSSUtils.h" + +const int ZX_RSS14_OUTSIDE_EVEN_TOTAL_SUBSET[5] = {1,10,34,70,126}; +const int ZX_RSS14_INSIDE_ODD_TOTAL_SUBSET[4] = {4,20,48,81}; +const int ZX_RSS14_OUTSIDE_GSUM[5] = {0,161,961,2015,2715}; +const int ZX_RSS14_INSIDE_GSUM[4] = {0,336,1036,1516}; +const int ZX_RSS14_OUTSIDE_ODD_WIDEST[5] = {8,6,4,3,1}; +const int ZX_RSS14_INSIDE_ODD_WIDEST[4] = {2,4,6,8}; + +@interface ZXRSS14Reader () + +@property (nonatomic, strong, readonly) NSMutableArray *possibleLeftPairs; +@property (nonatomic, strong, readonly) NSMutableArray *possibleRightPairs; + +@end + +@implementation ZXRSS14Reader + +- (id)init { + if (self = [super init]) { + _possibleLeftPairs = [NSMutableArray array]; + _possibleRightPairs = [NSMutableArray array]; + } + + return self; +} + +- (ZXResult *)decodeRow:(int)rowNumber row:(ZXBitArray *)row hints:(ZXDecodeHints *)hints error:(NSError **)error { + ZXRSSPair *leftPair = [self decodePair:row right:NO rowNumber:rowNumber hints:hints]; + [self addOrTally:self.possibleLeftPairs pair:leftPair]; + [row reverse]; + ZXRSSPair *rightPair = [self decodePair:row right:YES rowNumber:rowNumber hints:hints]; + [self addOrTally:self.possibleRightPairs pair:rightPair]; + [row reverse]; + + for (ZXRSSPair *left in self.possibleLeftPairs) { + if ([left count] > 1) { + for (ZXRSSPair *right in self.possibleRightPairs) { + if ([right count] > 1) { + if ([self checkChecksum:left rightPair:right]) { + return [self constructResult:left rightPair:right]; + } + } + } + } + } + + if (error) *error = ZXNotFoundErrorInstance(); + return nil; +} + +- (void)addOrTally:(NSMutableArray *)possiblePairs pair:(ZXRSSPair *)pair { + if (pair == nil) { + return; + } + BOOL found = NO; + for (ZXRSSPair *other in possiblePairs) { + if (other.value == pair.value) { + [other incrementCount]; + found = YES; + break; + } + } + + if (!found) { + [possiblePairs addObject:pair]; + } +} + +- (void)reset { + [self.possibleLeftPairs removeAllObjects]; + [self.possibleRightPairs removeAllObjects]; +} + +- (ZXResult *)constructResult:(ZXRSSPair *)leftPair rightPair:(ZXRSSPair *)rightPair { + long long symbolValue = 4537077LL * leftPair.value + rightPair.value; + NSString *text = [@(symbolValue) stringValue]; + NSMutableString *buffer = [NSMutableString stringWithCapacity:14]; + + for (int i = 13 - (int)[text length]; i > 0; i--) { + [buffer appendString:@"0"]; + } + + [buffer appendString:text]; + int checkDigit = 0; + + for (int i = 0; i < 13; i++) { + int digit = [buffer characterAtIndex:i] - '0'; + checkDigit += (i & 0x01) == 0 ? 3 * digit : digit; + } + + checkDigit = 10 - (checkDigit % 10); + if (checkDigit == 10) { + checkDigit = 0; + } + [buffer appendFormat:@"%d", checkDigit]; + NSArray *leftPoints = [[leftPair finderPattern] resultPoints]; + NSArray *rightPoints = [[rightPair finderPattern] resultPoints]; + return [ZXResult resultWithText:buffer + rawBytes:nil + resultPoints:@[leftPoints[0], leftPoints[1], rightPoints[0], rightPoints[1]] + format:kBarcodeFormatRSS14]; +} + +- (BOOL)checkChecksum:(ZXRSSPair *)leftPair rightPair:(ZXRSSPair *)rightPair { +// int leftFPValue = leftPair.finderPattern.value; +// int rightFPValue = rightPair.finderPattern.value; +// if ((leftFPValue == 0 && rightFPValue == 8) || (leftFPValue == 8 && rightFPValue == 0)) { +// } + int checkValue = (leftPair.checksumPortion + 16 * rightPair.checksumPortion) % 79; + int targetCheckValue = 9 * leftPair.finderPattern.value + rightPair.finderPattern.value; + if (targetCheckValue > 72) { + targetCheckValue--; + } + if (targetCheckValue > 8) { + targetCheckValue--; + } + return checkValue == targetCheckValue; +} + +- (ZXRSSPair *)decodePair:(ZXBitArray *)row right:(BOOL)right rowNumber:(int)rowNumber hints:(ZXDecodeHints *)hints { + ZXIntArray *startEnd = [self findFinderPattern:row rowOffset:0 rightFinderPattern:right]; + if (!startEnd) { + return nil; + } + ZXRSSFinderPattern *pattern = [self parseFoundFinderPattern:row rowNumber:rowNumber right:right startEnd:startEnd]; + if (!pattern) { + return nil; + } + id resultPointCallback = hints == nil ? nil : hints.resultPointCallback; + if (resultPointCallback != nil) { + float center = (startEnd.array[0] + startEnd.array[1]) / 2.0f; + if (right) { + center = [row size] - 1 - center; + } + [resultPointCallback foundPossibleResultPoint:[[ZXResultPoint alloc] initWithX:center y:rowNumber]]; + } + ZXRSSDataCharacter *outside = [self decodeDataCharacter:row pattern:pattern outsideChar:YES]; + ZXRSSDataCharacter *inside = [self decodeDataCharacter:row pattern:pattern outsideChar:NO]; + if (!outside || !inside) { + return nil; + } + return [[ZXRSSPair alloc] initWithValue:1597 * outside.value + inside.value + checksumPortion:outside.checksumPortion + 4 * inside.checksumPortion + finderPattern:pattern]; +} + +- (ZXRSSDataCharacter *)decodeDataCharacter:(ZXBitArray *)row pattern:(ZXRSSFinderPattern *)pattern outsideChar:(BOOL)outsideChar { + ZXIntArray *counters = self.dataCharacterCounters; + [counters clear]; + int32_t *array = counters.array; + + if (outsideChar) { + if (![ZXOneDReader recordPatternInReverse:row start:[pattern startEnd].array[0] counters:counters]) { + return nil; + } + } else { + if (![ZXOneDReader recordPattern:row start:[pattern startEnd].array[1] counters:counters]) { + return nil; + } + + for (int i = 0, j = counters.length - 1; i < j; i++, j--) { + int temp = array[i]; + array[i] = array[j]; + array[j] = temp; + } + } + + int numModules = outsideChar ? 16 : 15; + float elementWidth = (float)[ZXAbstractRSSReader count:counters] / (float)numModules; + + for (int i = 0; i < counters.length; i++) { + float value = (float) array[i] / elementWidth; + int count = (int)(value + 0.5f); + if (count < 1) { + count = 1; + } else if (count > 8) { + count = 8; + } + int offset = i / 2; + if ((i & 0x01) == 0) { + self.oddCounts.array[offset] = count; + self.oddRoundingErrors[offset] = value - count; + } else { + self.evenCounts.array[offset] = count; + self.evenRoundingErrors[offset] = value - count; + } + } + + if (![self adjustOddEvenCounts:outsideChar numModules:numModules]) { + return nil; + } + + int oddSum = 0; + int oddChecksumPortion = 0; + for (int i = self.oddCounts.length - 1; i >= 0; i--) { + oddChecksumPortion *= 9; + oddChecksumPortion += self.oddCounts.array[i]; + oddSum += self.oddCounts.array[i]; + } + int evenChecksumPortion = 0; + int evenSum = 0; + for (int i = self.evenCounts.length - 1; i >= 0; i--) { + evenChecksumPortion *= 9; + evenChecksumPortion += self.evenCounts.array[i]; + evenSum += self.evenCounts.array[i]; + } + int checksumPortion = oddChecksumPortion + 3 * evenChecksumPortion; + + if (outsideChar) { + if ((oddSum & 0x01) != 0 || oddSum > 12 || oddSum < 4) { + return nil; + } + int group = (12 - oddSum) / 2; + int oddWidest = ZX_RSS14_OUTSIDE_ODD_WIDEST[group]; + int evenWidest = 9 - oddWidest; + int vOdd = [ZXRSSUtils rssValue:self.oddCounts maxWidth:oddWidest noNarrow:NO]; + int vEven = [ZXRSSUtils rssValue:self.evenCounts maxWidth:evenWidest noNarrow:YES]; + int tEven = ZX_RSS14_OUTSIDE_EVEN_TOTAL_SUBSET[group]; + int gSum = ZX_RSS14_OUTSIDE_GSUM[group]; + return [[ZXRSSDataCharacter alloc] initWithValue:vOdd * tEven + vEven + gSum checksumPortion:checksumPortion]; + } else { + if ((evenSum & 0x01) != 0 || evenSum > 10 || evenSum < 4) { + return nil; + } + int group = (10 - evenSum) / 2; + int oddWidest = ZX_RSS14_INSIDE_ODD_WIDEST[group]; + int evenWidest = 9 - oddWidest; + int vOdd = [ZXRSSUtils rssValue:self.oddCounts maxWidth:oddWidest noNarrow:YES]; + int vEven = [ZXRSSUtils rssValue:self.evenCounts maxWidth:evenWidest noNarrow:NO]; + int tOdd = ZX_RSS14_INSIDE_ODD_TOTAL_SUBSET[group]; + int gSum = ZX_RSS14_INSIDE_GSUM[group]; + return [[ZXRSSDataCharacter alloc] initWithValue:vEven * tOdd + vOdd + gSum checksumPortion:checksumPortion]; + } +} + +- (ZXIntArray *)findFinderPattern:(ZXBitArray *)row rowOffset:(int)rowOffset rightFinderPattern:(BOOL)rightFinderPattern { + ZXIntArray *counters = self.decodeFinderCounters; + [counters clear]; + int32_t *array = counters.array; + + int width = row.size; + BOOL isWhite = NO; + while (rowOffset < width) { + isWhite = ![row get:rowOffset]; + if (rightFinderPattern == isWhite) { + break; + } + rowOffset++; + } + + int counterPosition = 0; + int patternStart = rowOffset; + for (int x = rowOffset; x < width; x++) { + if ([row get:x] ^ isWhite) { + array[counterPosition]++; + } else { + if (counterPosition == 3) { + if ([ZXAbstractRSSReader isFinderPattern:counters]) { + return [[ZXIntArray alloc] initWithInts:patternStart, x, -1]; + } + patternStart += array[0] + array[1]; + array[0] = array[2]; + array[1] = array[3]; + array[2] = 0; + array[3] = 0; + counterPosition--; + } else { + counterPosition++; + } + array[counterPosition] = 1; + isWhite = !isWhite; + } + } + + return nil; +} + +- (ZXRSSFinderPattern *)parseFoundFinderPattern:(ZXBitArray *)row rowNumber:(int)rowNumber right:(BOOL)right startEnd:(ZXIntArray *)startEnd { + BOOL firstIsBlack = [row get:startEnd.array[0]]; + int firstElementStart = startEnd.array[0] - 1; + + while (firstElementStart >= 0 && firstIsBlack ^ [row get:firstElementStart]) { + firstElementStart--; + } + + firstElementStart++; + int firstCounter = startEnd.array[0] - firstElementStart; + + ZXIntArray *counters = self.decodeFinderCounters; + int32_t *array = counters.array; + for (int i = counters.length - 1; i > 0; i--) { + array[i] = array[i-1]; + } + array[0] = firstCounter; + int value = [ZXAbstractRSSReader parseFinderValue:counters finderPatternType:ZX_RSS_PATTERNS_RSS14_PATTERNS]; + if (value == -1) { + return nil; + } + int start = firstElementStart; + int end = startEnd.array[1]; + if (right) { + start = [row size] - 1 - start; + end = [row size] - 1 - end; + } + return [[ZXRSSFinderPattern alloc] initWithValue:value + startEnd:[[ZXIntArray alloc] initWithInts:firstElementStart, startEnd.array[1], -1] + start:start + end:end + rowNumber:rowNumber]; +} + +- (BOOL)adjustOddEvenCounts:(BOOL)outsideChar numModules:(int)numModules { + int oddSum = [ZXAbstractRSSReader count:self.oddCounts]; + int evenSum = [ZXAbstractRSSReader count:self.evenCounts]; + int mismatch = oddSum + evenSum - numModules; + BOOL oddParityBad = (oddSum & 0x01) == (outsideChar ? 1 : 0); + BOOL evenParityBad = (evenSum & 0x01) == 1; + + BOOL incrementOdd = NO; + BOOL decrementOdd = NO; + BOOL incrementEven = NO; + BOOL decrementEven = NO; + + if (outsideChar) { + if (oddSum > 12) { + decrementOdd = YES; + } else if (oddSum < 4) { + incrementOdd = YES; + } + if (evenSum > 12) { + decrementEven = YES; + } else if (evenSum < 4) { + incrementEven = YES; + } + } else { + if (oddSum > 11) { + decrementOdd = YES; + } else if (oddSum < 5) { + incrementOdd = YES; + } + if (evenSum > 10) { + decrementEven = YES; + } else if (evenSum < 4) { + incrementEven = YES; + } + } + + if (mismatch == 1) { + if (oddParityBad) { + if (evenParityBad) { + return NO; + } + decrementOdd = YES; + } else { + if (!evenParityBad) { + return NO; + } + decrementEven = YES; + } + } else if (mismatch == -1) { + if (oddParityBad) { + if (evenParityBad) { + return NO; + } + incrementOdd = YES; + } else { + if (!evenParityBad) { + return NO; + } + incrementEven = YES; + } + } else if (mismatch == 0) { + if (oddParityBad) { + if (!evenParityBad) { + return NO; + } + if (oddSum < evenSum) { + incrementOdd = YES; + decrementEven = YES; + } else { + decrementOdd = YES; + incrementEven = YES; + } + } else { + if (evenParityBad) { + return NO; + } + } + } else { + return NO; + } + if (incrementOdd) { + if (decrementOdd) { + return NO; + } + [ZXAbstractRSSReader increment:self.oddCounts errors:self.oddRoundingErrors]; + } + if (decrementOdd) { + [ZXAbstractRSSReader decrement:self.oddCounts errors:self.oddRoundingErrors]; + } + if (incrementEven) { + if (decrementEven) { + return NO; + } + [ZXAbstractRSSReader increment:self.evenCounts errors:self.oddRoundingErrors]; + } + if (decrementEven) { + [ZXAbstractRSSReader decrement:self.evenCounts errors:self.evenRoundingErrors]; + } + return YES; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/ZXRSSDataCharacter.h b/iDearQRCode/Tools/ZXingObjC/oned/rss/ZXRSSDataCharacter.h new file mode 100755 index 0000000..78a9901 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/ZXRSSDataCharacter.h @@ -0,0 +1,24 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@interface ZXRSSDataCharacter : NSObject + +@property (nonatomic, assign, readonly) int value; +@property (nonatomic, assign, readonly) int checksumPortion; + +- (id)initWithValue:(int)value checksumPortion:(int)checksumPortion; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/ZXRSSDataCharacter.m b/iDearQRCode/Tools/ZXingObjC/oned/rss/ZXRSSDataCharacter.m new file mode 100755 index 0000000..c862338 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/ZXRSSDataCharacter.m @@ -0,0 +1,47 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXRSSDataCharacter.h" + +@implementation ZXRSSDataCharacter + +- (id)initWithValue:(int)value checksumPortion:(int)checksumPortion { + if (self = [super init]) { + _value = value; + _checksumPortion = checksumPortion; + } + + return self; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"%d(%d)", self.value, self.checksumPortion]; +} + +- (BOOL)isEqual:(id)object { + if (![object isKindOfClass:[ZXRSSDataCharacter class]]) { + return NO; + } + + ZXRSSDataCharacter *that = (ZXRSSDataCharacter *)object; + return (self.value == that.value) && (self.checksumPortion == that.checksumPortion); +} + +- (NSUInteger)hash { + return self.value ^ self.checksumPortion; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/ZXRSSFinderPattern.h b/iDearQRCode/Tools/ZXingObjC/oned/rss/ZXRSSFinderPattern.h new file mode 100755 index 0000000..f10eb1e --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/ZXRSSFinderPattern.h @@ -0,0 +1,29 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXResultPoint.h" + +@class ZXIntArray; + +@interface ZXRSSFinderPattern : NSObject + +@property (nonatomic, assign, readonly) int value; +@property (nonatomic, strong, readonly) ZXIntArray *startEnd; +@property (nonatomic, strong, readonly) NSMutableArray *resultPoints; + +- (id)initWithValue:(int)value startEnd:(ZXIntArray *)startEnd start:(int)start end:(int)end rowNumber:(int)rowNumber; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/ZXRSSFinderPattern.m b/iDearQRCode/Tools/ZXingObjC/oned/rss/ZXRSSFinderPattern.m new file mode 100755 index 0000000..97af13c --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/ZXRSSFinderPattern.m @@ -0,0 +1,45 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXRSSFinderPattern.h" + +@implementation ZXRSSFinderPattern + +- (id)initWithValue:(int)value startEnd:(ZXIntArray *)startEnd start:(int)start end:(int)end rowNumber:(int)rowNumber { + if (self = [super init]) { + _value = value; + _startEnd = startEnd; + _resultPoints = [@[[[ZXResultPoint alloc] initWithX:(float)start y:(float)rowNumber], + [[ZXResultPoint alloc] initWithX:(float)end y:(float)rowNumber]] mutableCopy]; + } + + return self; +} + +- (BOOL)isEqual:(id)object { + if (![object isKindOfClass:[ZXRSSFinderPattern class]]) { + return NO; + } + + ZXRSSFinderPattern *that = (ZXRSSFinderPattern *)object; + return self.value == that.value; +} + +- (NSUInteger)hash { + return self.value; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/ZXRSSPair.h b/iDearQRCode/Tools/ZXingObjC/oned/rss/ZXRSSPair.h new file mode 100755 index 0000000..2815220 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/ZXRSSPair.h @@ -0,0 +1,29 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXRSSDataCharacter.h" + +@class ZXRSSFinderPattern; + +@interface ZXRSSPair : ZXRSSDataCharacter + +@property (nonatomic, assign, readonly) int count; +@property (nonatomic, strong, readonly) ZXRSSFinderPattern *finderPattern; + +- (id)initWithValue:(int)value checksumPortion:(int)checksumPortion finderPattern:(ZXRSSFinderPattern *)finderPattern; +- (void)incrementCount; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/ZXRSSPair.m b/iDearQRCode/Tools/ZXingObjC/oned/rss/ZXRSSPair.m new file mode 100755 index 0000000..ee2b8f9 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/ZXRSSPair.m @@ -0,0 +1,40 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXRSSFinderPattern.h" +#import "ZXRSSPair.h" + +@interface ZXRSSPair () + +@property (nonatomic, assign) int count; + +@end + +@implementation ZXRSSPair + +- (id)initWithValue:(int)value checksumPortion:(int)checksumPortion finderPattern:(ZXRSSFinderPattern *)finderPattern { + if (self = [super initWithValue:value checksumPortion:checksumPortion]) { + _finderPattern = finderPattern; + } + + return self; +} + +- (void)incrementCount { + self.count++; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/ZXRSSUtils.h b/iDearQRCode/Tools/ZXingObjC/oned/rss/ZXRSSUtils.h new file mode 100755 index 0000000..03b7105 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/ZXRSSUtils.h @@ -0,0 +1,28 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXIntArray; + +/** + * Adapted from listings in ISO/IEC 24724 Appendix B and Appendix G. + */ +@interface ZXRSSUtils : NSObject + +//+ (NSArray *)rssWidths:(int)val n:(int)n elements:(int)elements maxWidth:(int)maxWidth noNarrow:(BOOL)noNarrow; ++ (int)rssValue:(ZXIntArray *)widths maxWidth:(int)maxWidth noNarrow:(BOOL)noNarrow; +//+ (NSArray *)elements:(NSArray *)eDist N:(int)N K:(int)K; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/ZXRSSUtils.m b/iDearQRCode/Tools/ZXingObjC/oned/rss/ZXRSSUtils.m new file mode 100755 index 0000000..aa46919 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/ZXRSSUtils.m @@ -0,0 +1,156 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXIntArray.h" +#import "ZXRSSUtils.h" + +@implementation ZXRSSUtils + +/* ++ (NSArray *)rssWidths:(int)val n:(int)n elements:(int)elements maxWidth:(int)maxWidth noNarrow:(BOOL)noNarrow { + NSMutableArray *widths = [NSMutableArray arrayWithCapacity:elements]; + int bar; + int narrowMask = 0; + for (bar = 0; bar < elements - 1; bar++) { + narrowMask |= 1 << bar; + int elmWidth = 1; + int subVal; + while (YES) { + subVal = [self combins:n - elmWidth - 1 r:elements - bar - 2]; + if (noNarrow && (narrowMask == 0) && (n - elmWidth - (elements - bar - 1) >= elements - bar - 1)) { + subVal -= [self combins:n - elmWidth - (elements - bar) r:elements - bar - 2]; + } + if (elements - bar - 1 > 1) { + int lessVal = 0; + for (int mxwElement = n - elmWidth - (elements - bar - 2); mxwElement > maxWidth; mxwElement--) { + lessVal += [self combins:n - elmWidth - mxwElement - 1 r:elements - bar - 3]; + } + subVal -= lessVal * (elements - 1 - bar); + } else if (n - elmWidth > maxWidth) { + subVal--; + } + val -= subVal; + if (val < 0) { + break; + } + elmWidth++; + narrowMask &= ~(1 << bar); + } + val += subVal; + n -= elmWidth; + [widths addObject:@(elmWidth)]; + } + + [widths addObject:@(n)]; + return widths; +} +*/ + ++ (int)rssValue:(ZXIntArray *)widths maxWidth:(int)maxWidth noNarrow:(BOOL)noNarrow { + int elements = widths.length; + int n = 0; + for (int i = 0; i < elements; i++) { + n += widths.array[i]; + } + int val = 0; + int narrowMask = 0; + for (int bar = 0; bar < elements - 1; bar++) { + int elmWidth; + for (elmWidth = 1, narrowMask |= 1 << bar; + elmWidth < widths.array[bar]; + elmWidth++, narrowMask &= ~(1 << bar)) { + int subVal = [self combins:n - elmWidth - 1 r:elements - bar - 2]; + if (noNarrow && (narrowMask == 0) && + (n - elmWidth - (elements - bar - 1) >= elements - bar - 1)) { + subVal -= [self combins:n - elmWidth - (elements - bar) + r:elements - bar - 2]; + } + if (elements - bar - 1 > 1) { + int lessVal = 0; + for (int mxwElement = n - elmWidth - (elements - bar - 2); + mxwElement > maxWidth; mxwElement--) { + lessVal += [self combins:n - elmWidth - mxwElement - 1 + r:elements - bar - 3]; + } + subVal -= lessVal * (elements - 1 - bar); + } else if (n - elmWidth > maxWidth) { + subVal--; + } + val += subVal; + } + n -= elmWidth; + } + return val; +} + ++ (int)combins:(int)n r:(int)r { + int maxDenom; + int minDenom; + if (n - r > r) { + minDenom = r; + maxDenom = n - r; + } else { + minDenom = n - r; + maxDenom = r; + } + int val = 1; + int j = 1; + for (int i = n; i > maxDenom; i--) { + val *= i; + if (j <= minDenom) { + val /= j; + j++; + } + } + while (j <= minDenom) { + val /= j; + j++; + } + return val; +} + +/* ++ (NSArray *)elements:(NSArray *)eDist N:(int)N K:(int)K { + NSMutableArray *widths = [NSMutableArray arrayWithCapacity:[eDist count] + 2]; + int twoK = 2 * K; + [widths addObject:@1]; + int i; + int minEven = 10; + int barSum = 1; + for (i = 1; i < twoK - 2; i += 2) { + [widths addObject:@([eDist[i - 1] intValue] - [widths[i - 1] intValue])]; + [widths addObject:@([eDist[i] intValue] - [widths[i] intValue])]; + barSum += [widths[i] intValue] + [widths[i + 1] intValue]; + if ([widths[i] intValue] < minEven) { + minEven = [widths[i] intValue]; + } + } + + [widths addObject:@(N - barSum)]; + if ([widths[twoK - 1] intValue] < minEven) { + minEven = [widths[twoK - 1] intValue]; + } + if (minEven > 1) { + for (i = 0; i < twoK; i += 2) { + widths[i] = @([widths[i] intValue] + minEven - 1); + widths[i + 1] = @([widths[i + 1] intValue] - minEven - 1); + } + } + return widths; +} +*/ + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/ZXBitArrayBuilder.h b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/ZXBitArrayBuilder.h new file mode 100755 index 0000000..058b7cb --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/ZXBitArrayBuilder.h @@ -0,0 +1,23 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXBitArray; + +@interface ZXBitArrayBuilder : NSObject + ++ (ZXBitArray *)buildBitArray:(NSArray *)pairs; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/ZXBitArrayBuilder.m b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/ZXBitArrayBuilder.m new file mode 100755 index 0000000..c8ff3b0 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/ZXBitArrayBuilder.m @@ -0,0 +1,70 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitArray.h" +#import "ZXBitArrayBuilder.h" +#import "ZXRSSDataCharacter.h" +#import "ZXRSSExpandedPair.h" + +@implementation ZXBitArrayBuilder + ++ (ZXBitArray *)buildBitArray:(NSArray *)pairs { + int charNumber = ((int)[pairs count] * 2) - 1; + if ([pairs[pairs.count - 1] rightChar] == nil) { + charNumber -= 1; + } + + int size = 12 * charNumber; + + ZXBitArray *binary = [[ZXBitArray alloc] initWithSize:size]; + int accPos = 0; + + ZXRSSExpandedPair *firstPair = pairs[0]; + int firstValue = [[firstPair rightChar] value]; + for (int i = 11; i >= 0; --i) { + if ((firstValue & (1 << i)) != 0) { + [binary set:accPos]; + } + accPos++; + } + + for (int i = 1; i < [pairs count]; ++i) { + ZXRSSExpandedPair *currentPair = pairs[i]; + int leftValue = [[currentPair leftChar] value]; + + for (int j = 11; j >= 0; --j) { + if ((leftValue & (1 << j)) != 0) { + [binary set:accPos]; + } + accPos++; + } + + if ([currentPair rightChar] != nil) { + int rightValue = [[currentPair rightChar] value]; + + for (int j = 11; j >= 0; --j) { + if ((rightValue & (1 << j)) != 0) { + [binary set:accPos]; + } + accPos++; + } + } + } + + return binary; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/ZXRSSExpandedPair.h b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/ZXRSSExpandedPair.h new file mode 100755 index 0000000..58c9047 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/ZXRSSExpandedPair.h @@ -0,0 +1,29 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXRSSDataCharacter, ZXRSSFinderPattern; + +@interface ZXRSSExpandedPair : NSObject + +@property (nonatomic, strong, readonly) ZXRSSDataCharacter *leftChar; +@property (nonatomic, strong, readonly) ZXRSSDataCharacter *rightChar; +@property (nonatomic, strong, readonly) ZXRSSFinderPattern *finderPattern; +@property (nonatomic, assign, readonly) BOOL mayBeLast; +@property (nonatomic, assign, readonly) BOOL mustBeLast; + +- (id)initWithLeftChar:(ZXRSSDataCharacter *)leftChar rightChar:(ZXRSSDataCharacter *)rightChar finderPattern:(ZXRSSFinderPattern *)finderPattern mayBeLast:(BOOL)mayBeLast; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/ZXRSSExpandedPair.m b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/ZXRSSExpandedPair.m new file mode 100755 index 0000000..879abe5 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/ZXRSSExpandedPair.m @@ -0,0 +1,67 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXRSSDataCharacter.h" +#import "ZXRSSExpandedPair.h" +#import "ZXRSSFinderPattern.h" + +@implementation ZXRSSExpandedPair + +- (id)initWithLeftChar:(ZXRSSDataCharacter *)leftChar rightChar:(ZXRSSDataCharacter *)rightChar + finderPattern:(ZXRSSFinderPattern *)finderPattern mayBeLast:(BOOL)mayBeLast { + if (self = [super init]) { + _leftChar = leftChar; + _rightChar = rightChar; + _finderPattern = finderPattern; + _mayBeLast = mayBeLast; + } + + return self; +} + +- (BOOL)mustBeLast { + return self.rightChar == nil; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"[ %@, %@ : %@ ]", + self.leftChar, self.rightChar, + self.finderPattern == nil ? @"null" : [NSString stringWithFormat:@"%d", self.finderPattern.value]]; +} + +- (BOOL)isEqual:(id)object { + if (![object isKindOfClass:[ZXRSSExpandedPair class]]) { + return NO; + } + ZXRSSExpandedPair *that = (ZXRSSExpandedPair *)object; + return [ZXRSSExpandedPair isEqualOrNil:self.leftChar toObject:that.leftChar] && + [ZXRSSExpandedPair isEqualOrNil:self.rightChar toObject:that.rightChar] && + [ZXRSSExpandedPair isEqualOrNil:self.finderPattern toObject:that.finderPattern]; +} + ++ (BOOL)isEqualOrNil:(id)o1 toObject:(id)o2 { + return o1 == nil ? o2 == nil : [o1 isEqual:o2]; +} + +- (NSUInteger)hash { + return [self hashNotNil:self.leftChar] ^ [self hashNotNil:self.rightChar] ^ [self hashNotNil:self.finderPattern]; +} + +- (NSUInteger)hashNotNil:(NSObject *)o { + return o == nil ? 0 : o.hash; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/ZXRSSExpandedReader.h b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/ZXRSSExpandedReader.h new file mode 100755 index 0000000..73541f7 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/ZXRSSExpandedReader.h @@ -0,0 +1,27 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAbstractRSSReader.h" + +@class ZXRSSDataCharacter, ZXRSSFinderPattern; + +@interface ZXRSSExpandedReader : ZXAbstractRSSReader + +@property (nonatomic, strong, readonly) NSMutableArray *rows; + +- (ZXRSSDataCharacter *)decodeDataCharacter:(ZXBitArray *)row pattern:(ZXRSSFinderPattern *)pattern isOddPattern:(BOOL)isOddPattern leftChar:(BOOL)leftChar; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/ZXRSSExpandedReader.m b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/ZXRSSExpandedReader.m new file mode 100755 index 0000000..4c680d7 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/ZXRSSExpandedReader.m @@ -0,0 +1,742 @@ + /* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAbstractExpandedDecoder.h" +#import "ZXBitArray.h" +#import "ZXBitArrayBuilder.h" +#import "ZXErrors.h" +#import "ZXIntArray.h" +#import "ZXResult.h" +#import "ZXRSSDataCharacter.h" +#import "ZXRSSExpandedPair.h" +#import "ZXRSSExpandedReader.h" +#import "ZXRSSExpandedRow.h" +#import "ZXRSSFinderPattern.h" +#import "ZXRSSUtils.h" + +const int ZX_SYMBOL_WIDEST[] = {7, 5, 4, 3, 1}; +const int ZX_EVEN_TOTAL_SUBSET[] = {4, 20, 52, 104, 204}; +const int ZX_GSUM[] = {0, 348, 1388, 2948, 3988}; + +const int ZX_WEIGHTS[][8] = { + { 1, 3, 9, 27, 81, 32, 96, 77}, + { 20, 60, 180, 118, 143, 7, 21, 63}, + {189, 145, 13, 39, 117, 140, 209, 205}, + {193, 157, 49, 147, 19, 57, 171, 91}, + { 62, 186, 136, 197, 169, 85, 44, 132}, + {185, 133, 188, 142, 4, 12, 36, 108}, + {113, 128, 173, 97, 80, 29, 87, 50}, + {150, 28, 84, 41, 123, 158, 52, 156}, + { 46, 138, 203, 187, 139, 206, 196, 166}, + { 76, 17, 51, 153, 37, 111, 122, 155}, + { 43, 129, 176, 106, 107, 110, 119, 146}, + { 16, 48, 144, 10, 30, 90, 59, 177}, + {109, 116, 137, 200, 178, 112, 125, 164}, + { 70, 210, 208, 202, 184, 130, 179, 115}, + {134, 191, 151, 31, 93, 68, 204, 190}, + {148, 22, 66, 198, 172, 94, 71, 2}, + { 6, 18, 54, 162, 64, 192,154, 40}, + {120, 149, 25, 75, 14, 42,126, 167}, + { 79, 26, 78, 23, 69, 207,199, 175}, + {103, 98, 83, 38, 114, 131, 182, 124}, + {161, 61, 183, 127, 170, 88, 53, 159}, + { 55, 165, 73, 8, 24, 72, 5, 15}, + { 45, 135, 194, 160, 58, 174, 100, 89} +}; + +const int ZX_FINDER_PAT_A = 0; +const int ZX_FINDER_PAT_B = 1; +const int ZX_FINDER_PAT_C = 2; +const int ZX_FINDER_PAT_D = 3; +const int ZX_FINDER_PAT_E = 4; +const int ZX_FINDER_PAT_F = 5; + +#define ZX_FINDER_PATTERN_SEQUENCES_LEN 10 +#define ZX_FINDER_PATTERN_SEQUENCES_SUBLEN 11 +const int ZX_FINDER_PATTERN_SEQUENCES[ZX_FINDER_PATTERN_SEQUENCES_LEN][ZX_FINDER_PATTERN_SEQUENCES_SUBLEN] = { + { ZX_FINDER_PAT_A, ZX_FINDER_PAT_A }, + { ZX_FINDER_PAT_A, ZX_FINDER_PAT_B, ZX_FINDER_PAT_B }, + { ZX_FINDER_PAT_A, ZX_FINDER_PAT_C, ZX_FINDER_PAT_B, ZX_FINDER_PAT_D }, + { ZX_FINDER_PAT_A, ZX_FINDER_PAT_E, ZX_FINDER_PAT_B, ZX_FINDER_PAT_D, ZX_FINDER_PAT_C }, + { ZX_FINDER_PAT_A, ZX_FINDER_PAT_E, ZX_FINDER_PAT_B, ZX_FINDER_PAT_D, ZX_FINDER_PAT_D, ZX_FINDER_PAT_F }, + { ZX_FINDER_PAT_A, ZX_FINDER_PAT_E, ZX_FINDER_PAT_B, ZX_FINDER_PAT_D, ZX_FINDER_PAT_E, ZX_FINDER_PAT_F, ZX_FINDER_PAT_F }, + { ZX_FINDER_PAT_A, ZX_FINDER_PAT_A, ZX_FINDER_PAT_B, ZX_FINDER_PAT_B, ZX_FINDER_PAT_C, ZX_FINDER_PAT_C, ZX_FINDER_PAT_D, ZX_FINDER_PAT_D }, + { ZX_FINDER_PAT_A, ZX_FINDER_PAT_A, ZX_FINDER_PAT_B, ZX_FINDER_PAT_B, ZX_FINDER_PAT_C, ZX_FINDER_PAT_C, ZX_FINDER_PAT_D, ZX_FINDER_PAT_E, ZX_FINDER_PAT_E }, + { ZX_FINDER_PAT_A, ZX_FINDER_PAT_A, ZX_FINDER_PAT_B, ZX_FINDER_PAT_B, ZX_FINDER_PAT_C, ZX_FINDER_PAT_C, ZX_FINDER_PAT_D, ZX_FINDER_PAT_E, ZX_FINDER_PAT_F, ZX_FINDER_PAT_F }, + { ZX_FINDER_PAT_A, ZX_FINDER_PAT_A, ZX_FINDER_PAT_B, ZX_FINDER_PAT_B, ZX_FINDER_PAT_C, ZX_FINDER_PAT_D, ZX_FINDER_PAT_D, ZX_FINDER_PAT_E, ZX_FINDER_PAT_E, ZX_FINDER_PAT_F, ZX_FINDER_PAT_F }, +}; + +@interface ZXRSSExpandedReader () + +@property (nonatomic, strong, readonly) ZXIntArray *startEnd; +@property (nonatomic, strong, readonly) NSMutableArray *pairs; +@property (nonatomic, strong) NSMutableArray *rows; +@property (nonatomic, assign) BOOL startFromEven; + +@end + +@implementation ZXRSSExpandedReader + +- (id)init { + if (self = [super init]) { + _pairs = [NSMutableArray array]; + _rows = [NSMutableArray array]; + _startFromEven = NO; + _startEnd = [[ZXIntArray alloc] initWithLength:2]; + } + + return self; +} + +- (ZXResult *)decodeRow:(int)rowNumber row:(ZXBitArray *)row hints:(ZXDecodeHints *)hints error:(NSError **)error { + // Rows can start with even pattern in case in prev rows there where odd number of patters. + // So lets try twice + [self.pairs removeAllObjects]; + self.startFromEven = NO; + NSMutableArray* pairs = [self decodeRow2pairs:rowNumber row:row error:error]; + if (pairs) { + ZXResult *result = [self constructResult:pairs error:error]; + if (result) { + return result; + } + } + + [self.pairs removeAllObjects]; + self.startFromEven = YES; + pairs = [self decodeRow2pairs:rowNumber row:row error:error]; + if (!pairs) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + + return [self constructResult:pairs error:error]; +} + +- (void)reset { + [self.pairs removeAllObjects]; + [self.rows removeAllObjects]; +} + +- (NSMutableArray *)decodeRow2pairs:(int)rowNumber row:(ZXBitArray *)row error:(NSError **)error { + while (YES) { + ZXRSSExpandedPair *nextPair = [self retrieveNextPair:row previousPairs:self.pairs rowNumber:rowNumber]; + if (!nextPair) { + if ([self.pairs count] == 0) { + return nil; + } + break; + } + [self.pairs addObject:nextPair]; + } + + // TODO: verify sequence of finder patterns as in checkPairSequence() + if ([self checkChecksum]) { + return self.pairs; + } + + BOOL tryStackedDecode = [self.rows count] > 0; + BOOL wasReversed = NO; // TODO: deal with reversed rows + [self storeRow:rowNumber wasReversed:wasReversed]; + if (tryStackedDecode) { + // When the image is 180-rotated, then rows are sorted in wrong dirrection. + // Try twice with both the directions. + NSMutableArray *ps = [self checkRows:NO]; + if (ps) { + return ps; + } + ps = [self checkRows:YES]; + if (ps) { + return ps; + } + } + + return nil; +} + +- (NSMutableArray *)checkRows:(BOOL)reverse { + // Limit number of rows we are checking + // We use recursive algorithm with pure complexity and don't want it to take forever + // Stacked barcode can have up to 11 rows, so 25 seems resonable enough + if (self.rows.count > 25) { + [self.rows removeAllObjects]; + return nil; + } + + [self.pairs removeAllObjects]; + if (reverse) { + self.rows = [[[self.rows reverseObjectEnumerator] allObjects] mutableCopy]; + } + + NSMutableArray *ps = [self checkRows:[NSMutableArray array] current:0]; + + if (reverse) { + self.rows = [[[self.rows reverseObjectEnumerator] allObjects] mutableCopy]; + } + + return ps; +} + +// Try to construct a valid rows sequence +// Recursion is used to implement backtracking +- (NSMutableArray *)checkRows:(NSMutableArray *)collectedRows current:(int)currentRow { + for (int i = currentRow; i < [self.rows count]; i++) { + ZXRSSExpandedRow *row = self.rows[i]; + [self.pairs removeAllObjects]; + NSUInteger size = [collectedRows count]; + for (int j = 0; j < size; j++) { + [self.pairs addObjectsFromArray:[collectedRows[j] pairs]]; + } + [self.pairs addObjectsFromArray:row.pairs]; + + if (![self isValidSequence:self.pairs]) { + continue; + } + + if ([self checkChecksum]) { + return self.pairs; + } + + NSMutableArray *rs = [NSMutableArray array]; + [rs addObjectsFromArray:collectedRows]; + [rs addObject:row]; + NSMutableArray *ps = [self checkRows:rs current:i + 1]; + if (ps) { + return ps; + } + } + return nil; +} + +// Whether the pairs form a valid find pattern seqience, +// either complete or a prefix +- (BOOL)isValidSequence:(NSArray *)pairs { + int count = (int)[pairs count]; + for (int i = 0, sz = 2; i < ZX_FINDER_PATTERN_SEQUENCES_LEN; i++, sz++) { + if (count > sz) { + continue; + } + + BOOL stop = YES; + for (int j = 0; j < count; j++) { + if ([[pairs[j] finderPattern] value] != ZX_FINDER_PATTERN_SEQUENCES[i][j]) { + stop = NO; + break; + } + } + + if (stop) { + return YES; + } + } + + return NO; +} + +- (void)storeRow:(int)rowNumber wasReversed:(BOOL)wasReversed { + // Discard if duplicate above or below; otherwise insert in order by row number. + int insertPos = 0; + BOOL prevIsSame = NO; + BOOL nextIsSame = NO; + while (insertPos < [self.rows count]) { + ZXRSSExpandedRow *erow = self.rows[insertPos]; + if (erow.rowNumber > rowNumber) { + nextIsSame = [erow isEquivalent:self.pairs]; + break; + } + prevIsSame = [erow isEquivalent:self.pairs]; + insertPos++; + } + if (nextIsSame || prevIsSame) { + return; + } + + // When the row was partially decoded (e.g. 2 pairs found instead of 3), + // it will prevent us from detecting the barcode. + // Try to merge partial rows + + // Check whether the row is part of an allready detected row + if ([self isPartialRow:self.pairs of:self.rows]) { + return; + } + + [self.rows insertObject:[[ZXRSSExpandedRow alloc] initWithPairs:self.pairs rowNumber:rowNumber wasReversed:wasReversed] atIndex:insertPos]; + + [self removePartialRows:self.pairs from:self.rows]; +} + +// Remove all the rows that contains only specified pairs +- (void)removePartialRows:(NSArray *)pairs from:(NSMutableArray *)rows { + NSMutableArray *toRemove = [NSMutableArray array]; + for (ZXRSSExpandedRow *r in rows) { + if ([r.pairs count] == [pairs count]) { + continue; + } + BOOL allFound = YES; + for (ZXRSSExpandedPair *p in r.pairs) { + BOOL found = NO; + for (ZXRSSExpandedPair *pp in pairs) { + if ([p isEqual:pp]) { + found = YES; + break; + } + } + if (!found) { + allFound = NO; + break; + } + } + if (allFound) { + [toRemove addObject:r]; + } + } + + for (ZXRSSExpandedRow *r in toRemove) { + [rows removeObject:r]; + } +} + +- (BOOL)isPartialRow:(NSArray *)pairs of:(NSArray *)rows { + for (ZXRSSExpandedRow *r in rows) { + BOOL allFound = YES; + for (ZXRSSExpandedPair *p in pairs) { + BOOL found = NO; + for (ZXRSSExpandedPair *pp in r.pairs) { + if ([p isEqual:pp]) { + found = YES; + break; + } + } + if (!found) { + allFound = NO; + break; + } + } + if (allFound) { + // the row 'r' contain all the pairs from 'pairs' + return YES; + } + } + return NO; +} + +- (ZXResult *)constructResult:(NSMutableArray *)pairs error:(NSError **)error { + ZXBitArray *binary = [ZXBitArrayBuilder buildBitArray:pairs]; + + ZXAbstractExpandedDecoder *decoder = [ZXAbstractExpandedDecoder createDecoder:binary]; + NSString *resultingString = [decoder parseInformationWithError:error]; + if (!resultingString) { + return nil; + } + + NSArray *firstPoints = [[((ZXRSSExpandedPair *)_pairs[0]) finderPattern] resultPoints]; + NSArray *lastPoints = [[((ZXRSSExpandedPair *)[_pairs lastObject]) finderPattern] resultPoints]; + + return [ZXResult resultWithText:resultingString + rawBytes:nil + resultPoints:@[firstPoints[0], firstPoints[1], lastPoints[0], lastPoints[1]] + format:kBarcodeFormatRSSExpanded]; +} + +- (BOOL)checkChecksum { + ZXRSSExpandedPair *firstPair = self.pairs[0]; + ZXRSSDataCharacter *checkCharacter = firstPair.leftChar; + ZXRSSDataCharacter *firstCharacter = firstPair.rightChar; + + if (!firstCharacter) { + return NO; + } + + int checksum = [firstCharacter checksumPortion]; + int s = 2; + + for (int i = 1; i < self.pairs.count; ++i) { + ZXRSSExpandedPair *currentPair = self.pairs[i]; + checksum += currentPair.leftChar.checksumPortion; + s++; + ZXRSSDataCharacter *currentRightChar = currentPair.rightChar; + if (currentRightChar != nil) { + checksum += currentRightChar.checksumPortion; + s++; + } + } + + checksum %= 211; + + int checkCharacterValue = 211 * (s - 4) + checksum; + + return checkCharacterValue == checkCharacter.value; +} + +- (int)nextSecondBar:(ZXBitArray *)row initialPos:(int)initialPos { + int currentPos; + if ([row get:initialPos]) { + currentPos = [row nextUnset:initialPos]; + currentPos = [row nextSet:currentPos]; + } else { + currentPos = [row nextSet:initialPos]; + currentPos = [row nextUnset:currentPos]; + } + return currentPos; +} + +- (ZXRSSExpandedPair *)retrieveNextPair:(ZXBitArray *)row previousPairs:(NSMutableArray *)previousPairs rowNumber:(int)rowNumber { + BOOL isOddPattern = [previousPairs count] % 2 == 0; + if (self.startFromEven) { + isOddPattern = !isOddPattern; + } + + ZXRSSFinderPattern *pattern; + + BOOL keepFinding = YES; + int forcedOffset = -1; + do { + if (![self findNextPair:row previousPairs:previousPairs forcedOffset:forcedOffset]) { + return nil; + } + pattern = [self parseFoundFinderPattern:row rowNumber:rowNumber oddPattern:isOddPattern]; + if (pattern == nil) { + forcedOffset = [self nextSecondBar:row initialPos:self.startEnd.array[0]]; + } else { + keepFinding = NO; + } + } while (keepFinding); + + // When stacked symbol is split over multiple rows, there's no way to guess if this pair can be last or not. + // boolean mayBeLast = checkPairSequence(previousPairs, pattern); + + ZXRSSDataCharacter *leftChar = [self decodeDataCharacter:row pattern:pattern isOddPattern:isOddPattern leftChar:YES]; + if (!leftChar) { + return nil; + } + + if (previousPairs.count > 0 && [[previousPairs lastObject] mustBeLast]) { + return nil; + } + + ZXRSSDataCharacter *rightChar = [self decodeDataCharacter:row pattern:pattern isOddPattern:isOddPattern leftChar:NO]; + BOOL mayBeLast = YES; + return [[ZXRSSExpandedPair alloc] initWithLeftChar:leftChar rightChar:rightChar finderPattern:pattern mayBeLast:mayBeLast]; +} + +- (BOOL)findNextPair:(ZXBitArray *)row previousPairs:(NSMutableArray *)previousPairs forcedOffset:(int)forcedOffset { + ZXIntArray *counters = self.decodeFinderCounters; + [counters clear]; + + int width = row.size; + + int rowOffset; + if (forcedOffset >= 0) { + rowOffset = forcedOffset; + } else if ([previousPairs count] == 0) { + rowOffset = 0; + } else { + ZXRSSExpandedPair *lastPair = [previousPairs lastObject]; + rowOffset = [[lastPair finderPattern] startEnd].array[1]; + } + BOOL searchingEvenPair = [previousPairs count] % 2 != 0; + if (self.startFromEven) { + searchingEvenPair = !searchingEvenPair; + } + + BOOL isWhite = NO; + while (rowOffset < width) { + isWhite = ![row get:rowOffset]; + if (!isWhite) { + break; + } + rowOffset++; + } + + int counterPosition = 0; + int patternStart = rowOffset; + int32_t *array = counters.array; + for (int x = rowOffset; x < width; x++) { + if ([row get:x] ^ isWhite) { + array[counterPosition]++; + } else { + if (counterPosition == 3) { + if (searchingEvenPair) { + [self reverseCounters:counters]; + } + + if ([ZXAbstractRSSReader isFinderPattern:counters]) { + self.startEnd.array[0] = patternStart; + self.startEnd.array[1] = x; + return YES; + } + + if (searchingEvenPair) { + [self reverseCounters:counters]; + } + + patternStart += array[0] + array[1]; + array[0] = array[2]; + array[1] = array[3]; + array[2] = 0; + array[3] = 0; + counterPosition--; + } else { + counterPosition++; + } + array[counterPosition] = 1; + isWhite = !isWhite; + } + } + return NO; +} + +- (void)reverseCounters:(ZXIntArray *)counters { + int length = counters.length; + int32_t *array = counters.array; + for (int i = 0; i < length / 2; ++i) { + int tmp = array[i]; + array[i] = array[length - i - 1]; + array[length - i - 1] = tmp; + } +} + +- (ZXRSSFinderPattern *)parseFoundFinderPattern:(ZXBitArray *)row rowNumber:(int)rowNumber oddPattern:(BOOL)oddPattern { + // Actually we found elements 2-5. + int firstCounter; + int start; + int end; + + if (oddPattern) { + // If pattern number is odd, we need to locate element 1 *before *the current block. + + int firstElementStart = self.startEnd.array[0] - 1; + // Locate element 1 + while (firstElementStart >= 0 && ![row get:firstElementStart]) { + firstElementStart--; + } + + firstElementStart++; + firstCounter = self.startEnd.array[0] - firstElementStart; + start = firstElementStart; + end = self.startEnd.array[1]; + } else { + // If pattern number is even, the pattern is reversed, so we need to locate element 1 *after *the current block. + + start = self.startEnd.array[0]; + + end = [row nextUnset:self.startEnd.array[1] + 1]; + firstCounter = end - self.startEnd.array[1]; + } + + // Make 'counters' hold 1-4 + ZXIntArray *counters = [[ZXIntArray alloc] initWithLength:self.decodeFinderCounters.length]; + for (int i = 1; i < counters.length; i++) { + counters.array[i] = self.decodeFinderCounters.array[i - 1]; + } + + counters.array[0] = firstCounter; + memcpy(self.decodeFinderCounters.array, counters.array, counters.length * sizeof(int32_t)); + + int value = [ZXAbstractRSSReader parseFinderValue:counters finderPatternType:ZX_RSS_PATTERNS_RSS_EXPANDED_PATTERNS]; + if (value == -1) { + return nil; + } + return [[ZXRSSFinderPattern alloc] initWithValue:value startEnd:[[ZXIntArray alloc] initWithInts:start, end, -1] start:start end:end rowNumber:rowNumber]; +} + +- (ZXRSSDataCharacter *)decodeDataCharacter:(ZXBitArray *)row pattern:(ZXRSSFinderPattern *)pattern isOddPattern:(BOOL)isOddPattern leftChar:(BOOL)leftChar { + ZXIntArray *counters = self.dataCharacterCounters; + [counters clear]; + + if (leftChar) { + if (![ZXOneDReader recordPatternInReverse:row start:[pattern startEnd].array[0] counters:counters]) { + return nil; + } + } else { + if (![ZXOneDReader recordPattern:row start:[pattern startEnd].array[1] counters:counters]) { + return nil; + } + // reverse it + int32_t *array = counters.array; + for (int i = 0, j = counters.length - 1; i < j; i++, j--) { + int temp = array[i]; + array[i] = array[j]; + array[j] = temp; + } + }//counters[] has the pixels of the module + + int numModules = 17; //left and right data characters have all the same length + float elementWidth = (float)[ZXAbstractRSSReader count:counters] / (float)numModules; + + // Sanity check: element width for pattern and the character should match + float expectedElementWidth = (pattern.startEnd.array[1] - pattern.startEnd.array[0]) / 15.0f; + if (fabsf(elementWidth - expectedElementWidth) / expectedElementWidth > 0.3f) { + return nil; + } + + int32_t *array = counters.array; + for (int i = 0; i < counters.length; i++) { + float value = 1.0f * array[i] / elementWidth; + int count = (int)(value + 0.5f); + if (count < 1) { + if (value < 0.3f) { + return nil; + } + count = 1; + } else if (count > 8) { + if (value > 8.7f) { + return nil; + } + count = 8; + } + int offset = i / 2; + if ((i & 0x01) == 0) { + self.oddCounts.array[offset] = count; + self.oddRoundingErrors[offset] = value - count; + } else { + self.evenCounts.array[offset] = count; + self.evenRoundingErrors[offset] = value - count; + } + } + + if (![self adjustOddEvenCounts:numModules]) { + return nil; + } + + int weightRowNumber = 4 * pattern.value + (isOddPattern ? 0 : 2) + (leftChar ? 0 : 1) - 1; + + int oddSum = 0; + int oddChecksumPortion = 0; + for (int i = self.oddCounts.length - 1; i >= 0; i--) { + if ([self isNotA1left:pattern isOddPattern:isOddPattern leftChar:leftChar]) { + int weight = ZX_WEIGHTS[weightRowNumber][2 * i]; + oddChecksumPortion += self.oddCounts.array[i] * weight; + } + oddSum += self.oddCounts.array[i]; + } + int evenChecksumPortion = 0; + //int evenSum = 0; + for (int i = self.evenCounts.length - 1; i >= 0; i--) { + if ([self isNotA1left:pattern isOddPattern:isOddPattern leftChar:leftChar]) { + int weight = ZX_WEIGHTS[weightRowNumber][2 * i + 1]; + evenChecksumPortion += self.evenCounts.array[i] * weight; + } + //evenSum += self.evenCounts[i]; + } + int checksumPortion = oddChecksumPortion + evenChecksumPortion; + + if ((oddSum & 0x01) != 0 || oddSum > 13 || oddSum < 4) { + return nil; + } + + int group = (13 - oddSum) / 2; + int oddWidest = ZX_SYMBOL_WIDEST[group]; + int evenWidest = 9 - oddWidest; + int vOdd = [ZXRSSUtils rssValue:self.oddCounts maxWidth:oddWidest noNarrow:YES]; + int vEven = [ZXRSSUtils rssValue:self.evenCounts maxWidth:evenWidest noNarrow:NO]; + int tEven = ZX_EVEN_TOTAL_SUBSET[group]; + int gSum = ZX_GSUM[group]; + int value = vOdd * tEven + vEven + gSum; + return [[ZXRSSDataCharacter alloc] initWithValue:value checksumPortion:checksumPortion]; +} + +- (BOOL)isNotA1left:(ZXRSSFinderPattern *)pattern isOddPattern:(BOOL)isOddPattern leftChar:(BOOL)leftChar { + return !([pattern value] == 0 && isOddPattern && leftChar); +} + +- (BOOL)adjustOddEvenCounts:(int)numModules { + int oddSum = [ZXAbstractRSSReader count:self.oddCounts]; + int evenSum = [ZXAbstractRSSReader count:self.evenCounts]; + int mismatch = oddSum + evenSum - numModules; + BOOL oddParityBad = (oddSum & 0x01) == 1; + BOOL evenParityBad = (evenSum & 0x01) == 0; + BOOL incrementOdd = NO; + BOOL decrementOdd = NO; + if (oddSum > 13) { + decrementOdd = YES; + } else if (oddSum < 4) { + incrementOdd = YES; + } + BOOL incrementEven = NO; + BOOL decrementEven = NO; + if (evenSum > 13) { + decrementEven = YES; + } else if (evenSum < 4) { + incrementEven = YES; + } + + if (mismatch == 1) { + if (oddParityBad) { + if (evenParityBad) { + return NO; + } + decrementOdd = YES; + } else { + if (!evenParityBad) { + return NO; + } + decrementEven = YES; + } + } else if (mismatch == -1) { + if (oddParityBad) { + if (evenParityBad) { + return NO; + } + incrementOdd = YES; + } else { + if (!evenParityBad) { + return NO; + } + incrementEven = YES; + } + } else if (mismatch == 0) { + if (oddParityBad) { + if (!evenParityBad) { + return NO; + } + if (oddSum < evenSum) { + incrementOdd = YES; + decrementEven = YES; + } else { + decrementOdd = YES; + incrementEven = YES; + } + } else { + if (evenParityBad) { + return NO; + } + } + } else { + return NO; + } + + if (incrementOdd) { + if (decrementOdd) { + return NO; + } + [ZXAbstractRSSReader increment:self.oddCounts errors:self.oddRoundingErrors]; + } + if (decrementOdd) { + [ZXAbstractRSSReader decrement:self.oddCounts errors:self.oddRoundingErrors]; + } + if (incrementEven) { + if (decrementEven) { + return NO; + } + [ZXAbstractRSSReader increment:self.evenCounts errors:self.oddRoundingErrors]; + } + if (decrementEven) { + [ZXAbstractRSSReader decrement:self.evenCounts errors:self.evenRoundingErrors]; + } + return YES; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/ZXRSSExpandedRow.h b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/ZXRSSExpandedRow.h new file mode 100755 index 0000000..d693366 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/ZXRSSExpandedRow.h @@ -0,0 +1,31 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * One row of an RSS Expanded Stacked symbol, consisting of 1+ expanded pairs. + */ +@interface ZXRSSExpandedRow : NSObject + +@property (nonatomic, strong, readonly) NSArray *pairs; +@property (nonatomic, assign, readonly) int rowNumber; +/** Did this row of the image have to be reversed (mirrored) to recognize the pairs? */ +@property (nonatomic, assign, readonly) BOOL wasReversed; + +- (id)initWithPairs:(NSArray *)pairs rowNumber:(int)rowNumber wasReversed:(BOOL)wasReversed; +- (BOOL)isReversed; +- (BOOL)isEquivalent:(NSArray *)otherPairs; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/ZXRSSExpandedRow.m b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/ZXRSSExpandedRow.m new file mode 100755 index 0000000..3629849 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/ZXRSSExpandedRow.m @@ -0,0 +1,58 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXRSSExpandedRow.h" + +@implementation ZXRSSExpandedRow + +- (id)initWithPairs:(NSArray *)pairs rowNumber:(int)rowNumber wasReversed:(BOOL)wasReversed { + if (self = [super init]) { + _pairs = [NSArray arrayWithArray:pairs]; + _rowNumber = rowNumber; + _wasReversed = wasReversed; + } + + return self; +} + +- (BOOL)isReversed { + return self.wasReversed; +} + +- (BOOL)isEquivalent:(NSArray *)otherPairs { + return [self.pairs isEqualToArray:otherPairs]; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"{%@}", self.pairs]; +} + +/** + * Two rows are equal if they contain the same pairs in the same order. + */ +- (BOOL)isEqual:(id)object { + if (![object isKindOfClass:[ZXRSSExpandedRow class]]) { + return NO; + } + ZXRSSExpandedRow *that = (ZXRSSExpandedRow *)object; + return [self.pairs isEqual:that.pairs] && (self.wasReversed == that.wasReversed); +} + +- (NSUInteger)hash { + return self.pairs.hash ^ @(self.wasReversed).hash; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI013103decoder.h b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI013103decoder.h new file mode 100755 index 0000000..c8b40e7 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI013103decoder.h @@ -0,0 +1,21 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAI013x0xDecoder.h" + +@interface ZXAI013103decoder : ZXAI013x0xDecoder + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI013103decoder.m b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI013103decoder.m new file mode 100755 index 0000000..06ce8d0 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI013103decoder.m @@ -0,0 +1,30 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAI013103decoder.h" +#import "ZXBitArray.h" + +@implementation ZXAI013103decoder + +- (void)addWeightCode:(NSMutableString *)buf weight:(int)weight { + [buf appendString:@"(3103)"]; +} + +- (int)checkWeight:(int)weight { + return weight; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01320xDecoder.h b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01320xDecoder.h new file mode 100755 index 0000000..ea1d339 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01320xDecoder.h @@ -0,0 +1,21 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAI013x0xDecoder.h" + +@interface ZXAI01320xDecoder : ZXAI013x0xDecoder + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01320xDecoder.m b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01320xDecoder.m new file mode 100755 index 0000000..714331c --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01320xDecoder.m @@ -0,0 +1,36 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAI01320xDecoder.h" + +@implementation ZXAI01320xDecoder + +- (void)addWeightCode:(NSMutableString *)buf weight:(int)weight { + if (weight < 10000) { + [buf appendString:@"(3202)"]; + } else { + [buf appendString:@"(3203)"]; + } +} + +- (int)checkWeight:(int)weight { + if (weight < 10000) { + return weight; + } + return weight - 10000; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01392xDecoder.h b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01392xDecoder.h new file mode 100755 index 0000000..4ae02cc --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01392xDecoder.h @@ -0,0 +1,21 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAI01decoder.h" + +@interface ZXAI01392xDecoder : ZXAI01decoder + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01392xDecoder.m b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01392xDecoder.m new file mode 100755 index 0000000..6013336 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01392xDecoder.m @@ -0,0 +1,42 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAI01392xDecoder.h" +#import "ZXBitArray.h" +#import "ZXErrors.h" +#import "ZXRSSExpandedDecodedInformation.h" +#import "ZXRSSExpandedGeneralAppIdDecoder.h" + +const int ZX_AI01392x_HEADER_SIZE = 5 + 1 + 2; +const int ZX_AI01392x_LAST_DIGIT_SIZE = 2; + +@implementation ZXAI01392xDecoder + +- (NSString *)parseInformationWithError:(NSError **)error { + if (self.information.size < ZX_AI01392x_HEADER_SIZE + ZX_AI01_GTIN_SIZE) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + NSMutableString *buf = [NSMutableString string]; + [self encodeCompressedGtin:buf currentPos:ZX_AI01392x_HEADER_SIZE]; + int lastAIdigit = [self.generalDecoder extractNumericValueFromBitArray:ZX_AI01392x_HEADER_SIZE + ZX_AI01_GTIN_SIZE bits:ZX_AI01392x_LAST_DIGIT_SIZE]; + [buf appendFormat:@"(392%d)", lastAIdigit]; + ZXRSSExpandedDecodedInformation *decodedInformation = [self.generalDecoder decodeGeneralPurposeField:ZX_AI01392x_HEADER_SIZE + ZX_AI01_GTIN_SIZE + ZX_AI01392x_LAST_DIGIT_SIZE remaining:nil]; + [buf appendString:decodedInformation.theNewString]; + return buf; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01393xDecoder.h b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01393xDecoder.h new file mode 100755 index 0000000..9fac134 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01393xDecoder.h @@ -0,0 +1,21 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAI01decoder.h" + +@interface ZXAI01393xDecoder : ZXAI01decoder + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01393xDecoder.m b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01393xDecoder.m new file mode 100755 index 0000000..fcde532 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01393xDecoder.m @@ -0,0 +1,61 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAI01393xDecoder.h" +#import "ZXBitArray.h" +#import "ZXErrors.h" +#import "ZXRSSExpandedDecodedInformation.h" +#import "ZXRSSExpandedGeneralAppIdDecoder.h" + +@implementation ZXAI01393xDecoder + +const int ZX_AI01393xDecoder_HEADER_SIZE = 5 + 1 + 2; +const int ZX_AI01393xDecoder_LAST_DIGIT_SIZE = 2; +const int ZX_AI01393xDecoder_FIRST_THREE_DIGITS_SIZE = 10; + +- (NSString *)parseInformationWithError:(NSError **)error { + if (self.information.size < ZX_AI01393xDecoder_HEADER_SIZE + ZX_AI01_GTIN_SIZE) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + + NSMutableString *buf = [NSMutableString string]; + + [self encodeCompressedGtin:buf currentPos:ZX_AI01393xDecoder_HEADER_SIZE]; + + int lastAIdigit = [self.generalDecoder extractNumericValueFromBitArray:ZX_AI01393xDecoder_HEADER_SIZE + ZX_AI01_GTIN_SIZE + bits:ZX_AI01393xDecoder_LAST_DIGIT_SIZE]; + + [buf appendFormat:@"(393%d)", lastAIdigit]; + + int firstThreeDigits = [self.generalDecoder extractNumericValueFromBitArray:ZX_AI01393xDecoder_HEADER_SIZE + ZX_AI01_GTIN_SIZE + ZX_AI01393xDecoder_LAST_DIGIT_SIZE + bits:ZX_AI01393xDecoder_FIRST_THREE_DIGITS_SIZE]; + if (firstThreeDigits / 100 == 0) { + [buf appendString:@"0"]; + } + if (firstThreeDigits / 10 == 0) { + [buf appendString:@"0"]; + } + [buf appendFormat:@"%d", firstThreeDigits]; + + ZXRSSExpandedDecodedInformation *generalInformation = [self.generalDecoder decodeGeneralPurposeField:ZX_AI01393xDecoder_HEADER_SIZE + ZX_AI01_GTIN_SIZE + ZX_AI01393xDecoder_LAST_DIGIT_SIZE + ZX_AI01393xDecoder_FIRST_THREE_DIGITS_SIZE + remaining:nil]; + [buf appendString:generalInformation.theNewString]; + + return buf; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI013x0x1xDecoder.h b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI013x0x1xDecoder.h new file mode 100755 index 0000000..3f2211d --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI013x0x1xDecoder.h @@ -0,0 +1,23 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAI01weightDecoder.h" + +@interface ZXAI013x0x1xDecoder : ZXAI01weightDecoder + +- (id)initWithInformation:(ZXBitArray *)information firstAIdigits:(NSString *)firstAIdigits dateCode:(NSString *)dateCode; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI013x0x1xDecoder.m b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI013x0x1xDecoder.m new file mode 100755 index 0000000..41fe6f2 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI013x0x1xDecoder.m @@ -0,0 +1,90 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAI013x0x1xDecoder.h" +#import "ZXBitArray.h" +#import "ZXErrors.h" +#import "ZXRSSExpandedGeneralAppIdDecoder.h" + +const int ZX_AI013x0x1x_HEADER_SIZE = 7 + 1; +const int ZX_AI013x0x1x_WEIGHT_SIZE = 20; +const int ZX_AI013x0x1x_DATE_SIZE = 16; + +@interface ZXAI013x0x1xDecoder () + +@property (nonatomic, copy, readonly) NSString *dateCode; +@property (nonatomic, copy, readonly) NSString *firstAIdigits; + +@end + +@implementation ZXAI013x0x1xDecoder + +- (id)initWithInformation:(ZXBitArray *)information firstAIdigits:(NSString *)firstAIdigits dateCode:(NSString *)dateCode { + if (self = [super initWithInformation:information]) { + _dateCode = dateCode; + _firstAIdigits = firstAIdigits; + } + + return self; +} + +- (NSString *)parseInformationWithError:(NSError **)error { + if (self.information.size != ZX_AI013x0x1x_HEADER_SIZE + ZX_AI01_GTIN_SIZE + ZX_AI013x0x1x_WEIGHT_SIZE + ZX_AI013x0x1x_DATE_SIZE) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + NSMutableString *buf = [NSMutableString string]; + [self encodeCompressedGtin:buf currentPos:ZX_AI013x0x1x_HEADER_SIZE]; + [self encodeCompressedWeight:buf currentPos:ZX_AI013x0x1x_HEADER_SIZE + ZX_AI01_GTIN_SIZE weightSize:ZX_AI013x0x1x_WEIGHT_SIZE]; + [self encodeCompressedDate:buf currentPos:ZX_AI013x0x1x_HEADER_SIZE + ZX_AI01_GTIN_SIZE + ZX_AI013x0x1x_WEIGHT_SIZE]; + return buf; +} + +- (void)encodeCompressedDate:(NSMutableString *)buf currentPos:(int)currentPos { + int numericDate = [self.generalDecoder extractNumericValueFromBitArray:currentPos bits:ZX_AI013x0x1x_DATE_SIZE]; + if (numericDate == 38400) { + return; + } + [buf appendFormat:@"(%@)", self.dateCode]; + int day = numericDate % 32; + numericDate /= 32; + int month = numericDate % 12 + 1; + numericDate /= 12; + int year = numericDate; + if (year / 10 == 0) { + [buf appendString:@"0"]; + } + [buf appendFormat:@"%d", year]; + if (month / 10 == 0) { + [buf appendString:@"0"]; + } + [buf appendFormat:@"%d", month]; + if (day / 10 == 0) { + [buf appendString:@"0"]; + } + [buf appendFormat:@"%d", day]; +} + +- (void)addWeightCode:(NSMutableString *)buf weight:(int)weight { + int lastAI = weight / 100000; + [buf appendFormat:@"(%@%d)", self.firstAIdigits, lastAI]; +} + +- (int)checkWeight:(int)weight { + return weight % 100000; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI013x0xDecoder.h b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI013x0xDecoder.h new file mode 100755 index 0000000..0f02d6c --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI013x0xDecoder.h @@ -0,0 +1,21 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAI01weightDecoder.h" + +@interface ZXAI013x0xDecoder : ZXAI01weightDecoder + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI013x0xDecoder.m b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI013x0xDecoder.m new file mode 100755 index 0000000..6a410c7 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI013x0xDecoder.m @@ -0,0 +1,40 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAI013x0xDecoder.h" +#import "ZXBitArray.h" +#import "ZXErrors.h" + +const int ZX_AI013x0x_HEADER_SIZE = 4 + 1; +const int ZX_AI013x0x_WEIGHT_SIZE = 15; + +@implementation ZXAI013x0xDecoder + +- (NSString *)parseInformationWithError:(NSError **)error { + if (self.information.size != ZX_AI013x0x_HEADER_SIZE + ZX_AI01_GTIN_SIZE + ZX_AI013x0x_WEIGHT_SIZE) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + + NSMutableString *buf = [NSMutableString string]; + + [self encodeCompressedGtin:buf currentPos:ZX_AI013x0x_HEADER_SIZE]; + [self encodeCompressedWeight:buf currentPos:ZX_AI013x0x_HEADER_SIZE + ZX_AI01_GTIN_SIZE weightSize:ZX_AI013x0x_WEIGHT_SIZE]; + + return buf; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01AndOtherAIs.h b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01AndOtherAIs.h new file mode 100755 index 0000000..4299580 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01AndOtherAIs.h @@ -0,0 +1,21 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAI01decoder.h" + +@interface ZXAI01AndOtherAIs : ZXAI01decoder + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01AndOtherAIs.m b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01AndOtherAIs.m new file mode 100755 index 0000000..3b410af --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01AndOtherAIs.m @@ -0,0 +1,37 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAI01AndOtherAIs.h" +#import "ZXRSSExpandedGeneralAppIdDecoder.h" + +const int ZX_AI01_HEADER_SIZE = 1 + 1 + 2; + +@implementation ZXAI01AndOtherAIs + +- (NSString *)parseInformationWithError:(NSError **)error { + NSMutableString *buff = [NSMutableString string]; + + [buff appendString:@"(01)"]; + int initialGtinPosition = (int)[buff length]; + int firstGtinDigit = [self.generalDecoder extractNumericValueFromBitArray:ZX_AI01_HEADER_SIZE bits:4]; + [buff appendFormat:@"%d", firstGtinDigit]; + + [self encodeCompressedGtinWithoutAI:buff currentPos:ZX_AI01_HEADER_SIZE + 4 initialBufferPosition:initialGtinPosition]; + + return [self.generalDecoder decodeAllCodes:buff initialPosition:ZX_AI01_HEADER_SIZE + 44 error:error]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01decoder.h b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01decoder.h new file mode 100755 index 0000000..49117a7 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01decoder.h @@ -0,0 +1,26 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAbstractExpandedDecoder.h" + +extern const int ZX_AI01_GTIN_SIZE; + +@interface ZXAI01decoder : ZXAbstractExpandedDecoder + +- (void)encodeCompressedGtin:(NSMutableString *)buf currentPos:(int)currentPos; +- (void)encodeCompressedGtinWithoutAI:(NSMutableString *)buf currentPos:(int)currentPos initialBufferPosition:(int)initialBufferPosition; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01decoder.m b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01decoder.m new file mode 100755 index 0000000..8696d1c --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01decoder.m @@ -0,0 +1,63 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAI01decoder.h" +#import "ZXBitArray.h" +#import "ZXRSSExpandedGeneralAppIdDecoder.h" + +const int ZX_AI01_GTIN_SIZE = 40; + +@implementation ZXAI01decoder + +- (void)encodeCompressedGtin:(NSMutableString *)buf currentPos:(int)currentPos { + [buf appendString:@"(01)"]; + int initialPosition = (int)[buf length]; + [buf appendString:@"9"]; + + [self encodeCompressedGtinWithoutAI:buf currentPos:currentPos initialBufferPosition:initialPosition]; +} + +- (void)encodeCompressedGtinWithoutAI:(NSMutableString *)buf currentPos:(int)currentPos initialBufferPosition:(int)initialBufferPosition { + for (int i = 0; i < 4; ++i) { + int currentBlock = [self.generalDecoder extractNumericValueFromBitArray:currentPos + 10 * i bits:10]; + if (currentBlock / 100 == 0) { + [buf appendString:@"0"]; + } + if (currentBlock / 10 == 0) { + [buf appendString:@"0"]; + } + [buf appendFormat:@"%d", currentBlock]; + } + + [self appendCheckDigit:buf currentPos:initialBufferPosition]; +} + +- (void)appendCheckDigit:(NSMutableString *)buf currentPos:(int)currentPos { + int checkDigit = 0; + for (int i = 0; i < 13; i++) { + int digit = [buf characterAtIndex:i + currentPos] - '0'; + checkDigit += (i & 0x01) == 0 ? 3 * digit : digit; + } + + checkDigit = 10 - (checkDigit % 10); + if (checkDigit == 10) { + checkDigit = 0; + } + + [buf appendFormat:@"%d", checkDigit]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01weightDecoder.h b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01weightDecoder.h new file mode 100755 index 0000000..670fa44 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01weightDecoder.h @@ -0,0 +1,25 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAI01decoder.h" + +@interface ZXAI01weightDecoder : ZXAI01decoder + +- (void)encodeCompressedWeight:(NSMutableString *)buf currentPos:(int)currentPos weightSize:(int)weightSize; +- (void)addWeightCode:(NSMutableString *)buf weight:(int)weight; +- (int)checkWeight:(int)weight; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01weightDecoder.m b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01weightDecoder.m new file mode 100755 index 0000000..b89bc96 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAI01weightDecoder.m @@ -0,0 +1,51 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAI01weightDecoder.h" +#import "ZXRSSExpandedGeneralAppIdDecoder.h" + +@implementation ZXAI01weightDecoder + +- (void)encodeCompressedWeight:(NSMutableString *)buf currentPos:(int)currentPos weightSize:(int)weightSize { + int originalWeightNumeric = [self.generalDecoder extractNumericValueFromBitArray:currentPos bits:weightSize]; + [self addWeightCode:buf weight:originalWeightNumeric]; + + int weightNumeric = [self checkWeight:originalWeightNumeric]; + + int currentDivisor = 100000; + for (int i = 0; i < 5; ++i) { + if (weightNumeric / currentDivisor == 0) { + [buf appendString:@"0"]; + } + currentDivisor /= 10; + } + + [buf appendFormat:@"%d", weightNumeric]; +} + +- (void)addWeightCode:(NSMutableString *)buf weight:(int)weight { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)] + userInfo:nil]; +} + +- (int)checkWeight:(int)weight { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)] + userInfo:nil]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAbstractExpandedDecoder.h b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAbstractExpandedDecoder.h new file mode 100755 index 0000000..f272ca2 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAbstractExpandedDecoder.h @@ -0,0 +1,28 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXBitArray, ZXRSSExpandedGeneralAppIdDecoder; + +@interface ZXAbstractExpandedDecoder : NSObject + +@property (nonatomic, strong, readonly) ZXRSSExpandedGeneralAppIdDecoder *generalDecoder; +@property (nonatomic, strong, readonly) ZXBitArray *information; + +- (id)initWithInformation:(ZXBitArray *)information; +- (NSString *)parseInformationWithError:(NSError **)error; ++ (ZXAbstractExpandedDecoder *)createDecoder:(ZXBitArray *)information; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAbstractExpandedDecoder.m b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAbstractExpandedDecoder.m new file mode 100755 index 0000000..6fe8492 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAbstractExpandedDecoder.m @@ -0,0 +1,95 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAbstractExpandedDecoder.h" +#import "ZXAI013103decoder.h" +#import "ZXAI01320xDecoder.h" +#import "ZXAI01392xDecoder.h" +#import "ZXAI01393xDecoder.h" +#import "ZXAI013x0x1xDecoder.h" +#import "ZXAI01AndOtherAIs.h" +#import "ZXAnyAIDecoder.h" +#import "ZXBitArray.h" +#import "ZXRSSExpandedGeneralAppIdDecoder.h" + +@implementation ZXAbstractExpandedDecoder + +- (id)initWithInformation:(ZXBitArray *)information { + if (self = [super init]) { + _information = information; + _generalDecoder = [[ZXRSSExpandedGeneralAppIdDecoder alloc] initWithInformation:information]; + } + + return self; +} + +- (NSString *)parseInformationWithError:(NSError **)error { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)] + userInfo:nil]; +} + ++ (ZXAbstractExpandedDecoder *)createDecoder:(ZXBitArray *)information { + if ([information get:1]) { + return [[ZXAI01AndOtherAIs alloc] initWithInformation:information]; + } + if (![information get:2]) { + return [[ZXAnyAIDecoder alloc] initWithInformation:information]; + } + + int fourBitEncodationMethod = [ZXRSSExpandedGeneralAppIdDecoder extractNumericValueFromBitArray:information pos:1 bits:4]; + + switch (fourBitEncodationMethod) { + case 4: + return [[ZXAI013103decoder alloc] initWithInformation:information]; + case 5: + return [[ZXAI01320xDecoder alloc] initWithInformation:information]; + } + + int fiveBitEncodationMethod = [ZXRSSExpandedGeneralAppIdDecoder extractNumericValueFromBitArray:information pos:1 bits:5]; + switch (fiveBitEncodationMethod) { + case 12: + return [[ZXAI01392xDecoder alloc] initWithInformation:information]; + case 13: + return [[ZXAI01393xDecoder alloc] initWithInformation:information]; + } + + int sevenBitEncodationMethod = [ZXRSSExpandedGeneralAppIdDecoder extractNumericValueFromBitArray:information pos:1 bits:7]; + switch (sevenBitEncodationMethod) { + case 56: + return [[ZXAI013x0x1xDecoder alloc] initWithInformation:information firstAIdigits:@"310" dateCode:@"11"]; + case 57: + return [[ZXAI013x0x1xDecoder alloc] initWithInformation:information firstAIdigits:@"320" dateCode:@"11"]; + case 58: + return [[ZXAI013x0x1xDecoder alloc] initWithInformation:information firstAIdigits:@"310" dateCode:@"13"]; + case 59: + return [[ZXAI013x0x1xDecoder alloc] initWithInformation:information firstAIdigits:@"320" dateCode:@"13"]; + case 60: + return [[ZXAI013x0x1xDecoder alloc] initWithInformation:information firstAIdigits:@"310" dateCode:@"15"]; + case 61: + return [[ZXAI013x0x1xDecoder alloc] initWithInformation:information firstAIdigits:@"320" dateCode:@"15"]; + case 62: + return [[ZXAI013x0x1xDecoder alloc] initWithInformation:information firstAIdigits:@"310" dateCode:@"17"]; + case 63: + return [[ZXAI013x0x1xDecoder alloc] initWithInformation:information firstAIdigits:@"320" dateCode:@"17"]; + } + + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"unknown decoder: %@", information] + userInfo:nil]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAnyAIDecoder.h b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAnyAIDecoder.h new file mode 100755 index 0000000..3dfda95 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAnyAIDecoder.h @@ -0,0 +1,21 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAbstractExpandedDecoder.h" + +@interface ZXAnyAIDecoder : ZXAbstractExpandedDecoder + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAnyAIDecoder.m b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAnyAIDecoder.m new file mode 100755 index 0000000..ec3fdfc --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXAnyAIDecoder.m @@ -0,0 +1,29 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXAnyAIDecoder.h" +#import "ZXRSSExpandedGeneralAppIdDecoder.h" + +const int ZX_ANY_AI_HEADER_SIZE = 2 + 1 + 2; + +@implementation ZXAnyAIDecoder + +- (NSString *)parseInformationWithError:(NSError **)error { + NSMutableString *buf = [NSMutableString string]; + return [self.generalDecoder decodeAllCodes:buf initialPosition:ZX_ANY_AI_HEADER_SIZE error:error]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedBlockParsedResult.h b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedBlockParsedResult.h new file mode 100755 index 0000000..691ebd7 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedBlockParsedResult.h @@ -0,0 +1,27 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXRSSExpandedDecodedInformation; + +@interface ZXRSSExpandedBlockParsedResult : NSObject + +@property (nonatomic, strong, readonly) ZXRSSExpandedDecodedInformation *decodedInformation; +@property (nonatomic, assign, readonly) BOOL finished; + +- (id)initWithFinished:(BOOL)finished; +- (id)initWithInformation:(ZXRSSExpandedDecodedInformation *)information finished:(BOOL)finished; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedBlockParsedResult.m b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedBlockParsedResult.m new file mode 100755 index 0000000..0b5c6cd --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedBlockParsedResult.m @@ -0,0 +1,35 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXRSSExpandedBlockParsedResult.h" +#import "ZXRSSExpandedDecodedInformation.h" + +@implementation ZXRSSExpandedBlockParsedResult + +- (id)initWithFinished:(BOOL)finished { + return [self initWithInformation:nil finished:finished]; +} + +- (id)initWithInformation:(ZXRSSExpandedDecodedInformation *)information finished:(BOOL)finished { + if (self = [super init]) { + _decodedInformation = information; + _finished = finished; + } + + return self; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedCurrentParsingState.h b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedCurrentParsingState.h new file mode 100755 index 0000000..b4c88c8 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedCurrentParsingState.h @@ -0,0 +1,28 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@interface ZXRSSExpandedCurrentParsingState : NSObject + +@property (nonatomic, assign) int position; + +- (BOOL)alpha; +- (BOOL)numeric; +- (BOOL)isoIec646; +- (void)setNumeric; +- (void)setAlpha; +- (void)setIsoIec646; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedCurrentParsingState.m b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedCurrentParsingState.m new file mode 100755 index 0000000..c21dedf --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedCurrentParsingState.m @@ -0,0 +1,65 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXRSSExpandedCurrentParsingState.h" + +enum { + ZX_NUMERIC_STATE, + ZX_ALPHA_STATE, + ZX_ISO_IEC_646_STATE +}; + +@interface ZXRSSExpandedCurrentParsingState () + +@property (nonatomic, assign) int encoding; + +@end + +@implementation ZXRSSExpandedCurrentParsingState + +- (id)init { + if (self = [super init]) { + _position = 0; + _encoding = ZX_NUMERIC_STATE; + } + return self; +} + +- (BOOL)alpha { + return self.encoding == ZX_ALPHA_STATE; +} + +- (BOOL)numeric { + return self.encoding == ZX_NUMERIC_STATE; +} + +- (BOOL)isoIec646 { + return self.encoding == ZX_ISO_IEC_646_STATE; +} + +- (void)setNumeric { + self.encoding = ZX_NUMERIC_STATE; +} + +- (void)setAlpha { + self.encoding = ZX_ALPHA_STATE; +} + +- (void)setIsoIec646 { + self.encoding = ZX_ISO_IEC_646_STATE; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedDecodedChar.h b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedDecodedChar.h new file mode 100755 index 0000000..b879132 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedDecodedChar.h @@ -0,0 +1,28 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXRSSExpandedDecodedObject.h" + +extern unichar const ZX_FNC1_CHAR; + +@interface ZXRSSExpandedDecodedChar : ZXRSSExpandedDecodedObject + +@property (nonatomic, assign, readonly) unichar value; + +- (id)initWithNewPosition:(int)newPosition value:(unichar)value; +- (BOOL)fnc1; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedDecodedChar.m b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedDecodedChar.m new file mode 100755 index 0000000..e5fff1d --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedDecodedChar.m @@ -0,0 +1,35 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXRSSExpandedDecodedChar.h" + +unichar const ZX_FNC1_CHAR = '$'; // It's not in Alphanumeric neither in ISO/IEC 646 charset + +@implementation ZXRSSExpandedDecodedChar + +- (id)initWithNewPosition:(int)newPosition value:(unichar)value { + if (self = [super initWithNewPosition:newPosition]) { + _value = value; + } + + return self; +} + +- (BOOL)fnc1 { + return self.value == ZX_FNC1_CHAR; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedDecodedInformation.h b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedDecodedInformation.h new file mode 100755 index 0000000..14ba181 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedDecodedInformation.h @@ -0,0 +1,28 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXRSSExpandedDecodedObject.h" + +@interface ZXRSSExpandedDecodedInformation : ZXRSSExpandedDecodedObject + +@property (nonatomic, copy, readonly) NSString *theNewString; +@property (nonatomic, assign, readonly) int remainingValue; +@property (nonatomic, assign, readonly) BOOL remaining; + +- (id)initWithNewPosition:(int)newPosition newString:(NSString *)newString; +- (id)initWithNewPosition:(int)newPosition newString:(NSString *)newString remainingValue:(int)remainingValue; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedDecodedInformation.m b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedDecodedInformation.m new file mode 100755 index 0000000..6111339 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedDecodedInformation.m @@ -0,0 +1,41 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXRSSExpandedDecodedInformation.h" + +@implementation ZXRSSExpandedDecodedInformation + +- (id)initWithNewPosition:(int)newPosition newString:(NSString *)newString { + if (self = [super initWithNewPosition:newPosition]) { + _remaining = NO; + _remainingValue = 0; + _theNewString = newString; + } + + return self; +} + +- (id)initWithNewPosition:(int)newPosition newString:(NSString *)newString remainingValue:(int)remainingValue { + if (self = [super initWithNewPosition:newPosition]) { + _remaining = YES; + _remainingValue = remainingValue; + _theNewString = newString; + } + + return self; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedDecodedNumeric.h b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedDecodedNumeric.h new file mode 100755 index 0000000..576531c --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedDecodedNumeric.h @@ -0,0 +1,32 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXRSSExpandedDecodedObject.h" + +extern const int ZX_FNC1_INT; + +@interface ZXRSSExpandedDecodedNumeric : ZXRSSExpandedDecodedObject + +@property (nonatomic, assign, readonly) int firstDigit; +@property (nonatomic, assign, readonly) int secondDigit; +@property (nonatomic, assign, readonly) int value; + +- (id)initWithNewPosition:(int)newPosition firstDigit:(int)firstDigit secondDigit:(int)secondDigit; +- (BOOL)firstDigitFNC1; +- (BOOL)secondDigitFNC1; +- (BOOL)anyFNC1; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedDecodedNumeric.m b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedDecodedNumeric.m new file mode 100755 index 0000000..523c83d --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedDecodedNumeric.m @@ -0,0 +1,52 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXRSSExpandedDecodedNumeric.h" + +const int ZX_FNC1_INT = 10; + +@implementation ZXRSSExpandedDecodedNumeric + +- (id)initWithNewPosition:(int)newPosition firstDigit:(int)firstDigit secondDigit:(int)secondDigit { + if (firstDigit < 0 || firstDigit > 10 || secondDigit < 0 || secondDigit > 10) { + return nil; + } + + if (self = [super initWithNewPosition:newPosition]) { + _firstDigit = firstDigit; + _secondDigit = secondDigit; + } + + return self; +} + +- (int)value { + return self.firstDigit * 10 + self.secondDigit; +} + +- (BOOL)firstDigitFNC1 { + return self.firstDigit == ZX_FNC1_INT; +} + +- (BOOL)secondDigitFNC1 { + return self.secondDigit == ZX_FNC1_INT; +} + +- (BOOL)anyFNC1 { + return self.firstDigit == ZX_FNC1_INT || self.secondDigit == ZX_FNC1_INT; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedDecodedObject.h b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedDecodedObject.h new file mode 100755 index 0000000..5dce8c8 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedDecodedObject.h @@ -0,0 +1,23 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@interface ZXRSSExpandedDecodedObject : NSObject + +@property (nonatomic, assign, readonly) int theNewPosition; + +- (id)initWithNewPosition:(int)newPosition; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedDecodedObject.m b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedDecodedObject.m new file mode 100755 index 0000000..ea1793e --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedDecodedObject.m @@ -0,0 +1,29 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXRSSExpandedDecodedObject.h" + +@implementation ZXRSSExpandedDecodedObject + +- (id)initWithNewPosition:(int)newPosition { + if (self = [super init]) { + _theNewPosition = newPosition; + } + + return self; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedFieldParser.h b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedFieldParser.h new file mode 100755 index 0000000..767bc23 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedFieldParser.h @@ -0,0 +1,21 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@interface ZXRSSExpandedFieldParser : NSObject + ++ (NSString *)parseFieldsInGeneralPurpose:(NSString *)rawInformation error:(NSError **)error; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedFieldParser.m b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedFieldParser.m new file mode 100755 index 0000000..f7299f8 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedFieldParser.m @@ -0,0 +1,319 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXErrors.h" +#import "ZXRSSExpandedFieldParser.h" + +static NSObject *VARIABLE_LENGTH = nil; +static NSArray *TWO_DIGIT_DATA_LENGTH = nil; +static NSArray *THREE_DIGIT_DATA_LENGTH = nil; +static NSArray *THREE_DIGIT_PLUS_DIGIT_DATA_LENGTH = nil; +static NSArray *FOUR_DIGIT_DATA_LENGTH = nil; + +@implementation ZXRSSExpandedFieldParser + ++ (void)initialize { + if ([self class] != [ZXRSSExpandedFieldParser class]) return; + + if (VARIABLE_LENGTH == nil) { + VARIABLE_LENGTH = [[NSObject alloc] init]; + } + + if (TWO_DIGIT_DATA_LENGTH == nil) { + TWO_DIGIT_DATA_LENGTH = @[@[@"00", @18], + @[@"01", @14], + @[@"02", @14], + + @[@"10", VARIABLE_LENGTH, @20], + @[@"11", @6], + @[@"12", @6], + @[@"13", @6], + @[@"15", @6], + @[@"17", @6], + + @[@"20", @2], + @[@"21", VARIABLE_LENGTH, @20], + @[@"22", VARIABLE_LENGTH, @29], + + @[@"30", VARIABLE_LENGTH, @8], + @[@"37", VARIABLE_LENGTH, @8], + + //internal company codes + @[@"90", VARIABLE_LENGTH, @30], + @[@"91", VARIABLE_LENGTH, @30], + @[@"92", VARIABLE_LENGTH, @30], + @[@"93", VARIABLE_LENGTH, @30], + @[@"94", VARIABLE_LENGTH, @30], + @[@"95", VARIABLE_LENGTH, @30], + @[@"96", VARIABLE_LENGTH, @30], + @[@"97", VARIABLE_LENGTH, @30], + @[@"98", VARIABLE_LENGTH, @30], + @[@"99", VARIABLE_LENGTH, @30]]; + } + + if (THREE_DIGIT_DATA_LENGTH == nil) { + THREE_DIGIT_DATA_LENGTH = @[@[@"240", VARIABLE_LENGTH, @30], + @[@"241", VARIABLE_LENGTH, @30], + @[@"242", VARIABLE_LENGTH, @6], + @[@"250", VARIABLE_LENGTH, @30], + @[@"251", VARIABLE_LENGTH, @30], + @[@"253", VARIABLE_LENGTH, @17], + @[@"254", VARIABLE_LENGTH, @20], + + @[@"400", VARIABLE_LENGTH, @30], + @[@"401", VARIABLE_LENGTH, @30], + @[@"402", @17], + @[@"403", VARIABLE_LENGTH, @30], + @[@"410", @13], + @[@"411", @13], + @[@"412", @13], + @[@"413", @13], + @[@"414", @13], + @[@"420", VARIABLE_LENGTH, @20], + @[@"421", VARIABLE_LENGTH, @15], + @[@"422", @3], + @[@"423", VARIABLE_LENGTH, @15], + @[@"424", @3], + @[@"425", @3], + @[@"426", @3]]; + + } + + if (THREE_DIGIT_PLUS_DIGIT_DATA_LENGTH == nil) { + THREE_DIGIT_PLUS_DIGIT_DATA_LENGTH = @[@[@"310", @6], + @[@"311", @6], + @[@"312", @6], + @[@"313", @6], + @[@"314", @6], + @[@"315", @6], + @[@"316", @6], + @[@"320", @6], + @[@"321", @6], + @[@"322", @6], + @[@"323", @6], + @[@"324", @6], + @[@"325", @6], + @[@"326", @6], + @[@"327", @6], + @[@"328", @6], + @[@"329", @6], + @[@"330", @6], + @[@"331", @6], + @[@"332", @6], + @[@"333", @6], + @[@"334", @6], + @[@"335", @6], + @[@"336", @6], + @[@"340", @6], + @[@"341", @6], + @[@"342", @6], + @[@"343", @6], + @[@"344", @6], + @[@"345", @6], + @[@"346", @6], + @[@"347", @6], + @[@"348", @6], + @[@"349", @6], + @[@"350", @6], + @[@"351", @6], + @[@"352", @6], + @[@"353", @6], + @[@"354", @6], + @[@"355", @6], + @[@"356", @6], + @[@"357", @6], + @[@"360", @6], + @[@"361", @6], + @[@"362", @6], + @[@"363", @6], + @[@"364", @6], + @[@"365", @6], + @[@"366", @6], + @[@"367", @6], + @[@"368", @6], + @[@"369", @6], + @[@"390", VARIABLE_LENGTH, @15], + @[@"391", VARIABLE_LENGTH, @18], + @[@"392", VARIABLE_LENGTH, @15], + @[@"393", VARIABLE_LENGTH, @18], + @[@"703", VARIABLE_LENGTH, @30]]; + } + + if (FOUR_DIGIT_DATA_LENGTH == nil) { + FOUR_DIGIT_DATA_LENGTH = @[@[@"7001", @13], + @[@"7002", VARIABLE_LENGTH, @30], + @[@"7003", @10], + + @[@"8001", @14], + @[@"8002", VARIABLE_LENGTH, @20], + @[@"8003", VARIABLE_LENGTH, @30], + @[@"8004", VARIABLE_LENGTH, @30], + @[@"8005", @6], + @[@"8006", @18], + @[@"8007", VARIABLE_LENGTH, @30], + @[@"8008", VARIABLE_LENGTH, @12], + @[@"8018", @18], + @[@"8020", VARIABLE_LENGTH, @25], + @[@"8100", @6], + @[@"8101", @10], + @[@"8102", @2], + @[@"8110", VARIABLE_LENGTH, @70], + @[@"8200", VARIABLE_LENGTH, @70]]; + } +} + ++ (NSString *)parseFieldsInGeneralPurpose:(NSString *)rawInformation error:(NSError **)error { + if ([rawInformation length] == 0) { + return @""; + } + if ([rawInformation length] < 2) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + NSString *firstTwoDigits = [rawInformation substringWithRange:NSMakeRange(0, 2)]; + + for (int i = 0; i < [TWO_DIGIT_DATA_LENGTH count]; ++i) { + if ([TWO_DIGIT_DATA_LENGTH[i][0] isEqualToString:firstTwoDigits]) { + if ([TWO_DIGIT_DATA_LENGTH[i][1] isEqual:VARIABLE_LENGTH]) { + return [self processVariableAI:2 + variableFieldSize:[TWO_DIGIT_DATA_LENGTH[i][2] intValue] + rawInformation:rawInformation]; + } + NSString *result = [self processFixedAI:2 + fieldSize:[TWO_DIGIT_DATA_LENGTH[i][1] intValue] + rawInformation:rawInformation]; + if (!result) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + return result; + } + } + + if ([rawInformation length] < 3) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + NSString *firstThreeDigits = [rawInformation substringWithRange:NSMakeRange(0, 3)]; + + for (int i = 0; i < [THREE_DIGIT_DATA_LENGTH count]; ++i) { + if ([THREE_DIGIT_DATA_LENGTH[i][0] isEqualToString:firstThreeDigits]) { + if ([THREE_DIGIT_DATA_LENGTH[i][1] isEqual:VARIABLE_LENGTH]) { + return [self processVariableAI:3 + variableFieldSize:[THREE_DIGIT_DATA_LENGTH[i][2] intValue] + rawInformation:rawInformation]; + } + NSString *result = [self processFixedAI:3 + fieldSize:[THREE_DIGIT_DATA_LENGTH[i][1] intValue] + rawInformation:rawInformation]; + if (!result) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + return result; + } + } + + for (int i = 0; i < [THREE_DIGIT_PLUS_DIGIT_DATA_LENGTH count]; ++i) { + if ([THREE_DIGIT_PLUS_DIGIT_DATA_LENGTH[i][0] isEqualToString:firstThreeDigits]) { + if ([THREE_DIGIT_PLUS_DIGIT_DATA_LENGTH[i][1] isEqual:VARIABLE_LENGTH]) { + return [self processVariableAI:4 + variableFieldSize:[THREE_DIGIT_PLUS_DIGIT_DATA_LENGTH[i][2] intValue] + rawInformation:rawInformation]; + } + NSString *result = [self processFixedAI:4 + fieldSize:[THREE_DIGIT_PLUS_DIGIT_DATA_LENGTH[i][1] intValue] + rawInformation:rawInformation]; + if (!result) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + return result; + } + } + + if ([rawInformation length] < 4) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + NSString *firstFourDigits = [rawInformation substringWithRange:NSMakeRange(0, 4)]; + + for (int i = 0; i < [FOUR_DIGIT_DATA_LENGTH count]; ++i) { + if ([FOUR_DIGIT_DATA_LENGTH[i][0] isEqualToString:firstFourDigits]) { + if ([FOUR_DIGIT_DATA_LENGTH[i][1] isEqual:VARIABLE_LENGTH]) { + NSString *result = [self processVariableAI:4 + variableFieldSize:[FOUR_DIGIT_DATA_LENGTH[i][2] intValue] + rawInformation:rawInformation]; + if (!result) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + return result; + } + NSString *result = [self processFixedAI:4 + fieldSize:[FOUR_DIGIT_DATA_LENGTH[i][1] intValue] + rawInformation:rawInformation]; + if (!result) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + return result; + } + } + + if (error) *error = ZXNotFoundErrorInstance(); + return nil; +} + ++ (NSString *)processFixedAI:(int)aiSize fieldSize:(int)fieldSize rawInformation:(NSString *)rawInformation { + if ([rawInformation length] < aiSize) { + return nil; + } + + NSString *ai = [rawInformation substringWithRange:NSMakeRange(0, aiSize)]; + if ([rawInformation length] < aiSize + fieldSize) { + return nil; + } + + NSString *field = [rawInformation substringWithRange:NSMakeRange(aiSize, fieldSize)]; + NSString *remaining; + if (aiSize + fieldSize == rawInformation.length) { + remaining = @""; + } else { + remaining = [rawInformation substringFromIndex:aiSize + fieldSize]; + } + + NSString *result = [NSString stringWithFormat:@"(%@)%@", ai, field]; + NSString *parsedAI = [self parseFieldsInGeneralPurpose:remaining error:nil]; + return parsedAI == nil ? result : [result stringByAppendingString:parsedAI]; +} + ++ (NSString *)processVariableAI:(int)aiSize variableFieldSize:(int)variableFieldSize rawInformation:(NSString *)rawInformation { + NSString *ai = [rawInformation substringWithRange:NSMakeRange(0, aiSize)]; + int maxSize; + if ([rawInformation length] < aiSize + variableFieldSize) { + maxSize = (int)[rawInformation length]; + } else { + maxSize = aiSize + variableFieldSize; + } + NSString *field = [rawInformation substringWithRange:NSMakeRange(aiSize, maxSize - aiSize)]; + NSString *remaining = [rawInformation substringFromIndex:maxSize]; + NSString *result = [NSString stringWithFormat:@"(%@)%@", ai, field]; + NSString *parsedAI = [self parseFieldsInGeneralPurpose:remaining error:nil]; + return parsedAI == nil ? result : [result stringByAppendingString:parsedAI]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedGeneralAppIdDecoder.h b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedGeneralAppIdDecoder.h new file mode 100755 index 0000000..451766c --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedGeneralAppIdDecoder.h @@ -0,0 +1,27 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXBitArray, ZXRSSExpandedDecodedInformation; + +@interface ZXRSSExpandedGeneralAppIdDecoder : NSObject + +- (id)initWithInformation:(ZXBitArray *)information; +- (NSString *)decodeAllCodes:(NSMutableString *)buff initialPosition:(int)initialPosition error:(NSError **)error; +- (int)extractNumericValueFromBitArray:(int)pos bits:(int)bits; ++ (int)extractNumericValueFromBitArray:(ZXBitArray *)information pos:(int)pos bits:(int)bits; +- (ZXRSSExpandedDecodedInformation *)decodeGeneralPurposeField:(int)pos remaining:(NSString *)remaining; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedGeneralAppIdDecoder.m b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedGeneralAppIdDecoder.m new file mode 100755 index 0000000..710086a --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/oned/rss/expanded/decoders/ZXRSSExpandedGeneralAppIdDecoder.m @@ -0,0 +1,517 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitArray.h" +#import "ZXErrors.h" +#import "ZXRSSExpandedBlockParsedResult.h" +#import "ZXRSSExpandedCurrentParsingState.h" +#import "ZXRSSExpandedDecodedChar.h" +#import "ZXRSSExpandedDecodedInformation.h" +#import "ZXRSSExpandedDecodedNumeric.h" +#import "ZXRSSExpandedFieldParser.h" +#import "ZXRSSExpandedGeneralAppIdDecoder.h" + +@interface ZXRSSExpandedGeneralAppIdDecoder () + +@property (nonatomic, strong, readonly) ZXBitArray *information; +@property (nonatomic, strong, readonly) ZXRSSExpandedCurrentParsingState *current; +@property (nonatomic, strong, readonly) NSMutableString *buffer; + +@end + +@implementation ZXRSSExpandedGeneralAppIdDecoder + +- (id)initWithInformation:(ZXBitArray *)information { + if (self = [super init]) { + _current = [[ZXRSSExpandedCurrentParsingState alloc] init]; + _buffer = [NSMutableString string]; + _information = information; + } + + return self; +} + +- (NSString *)decodeAllCodes:(NSMutableString *)buff initialPosition:(int)initialPosition error:(NSError **)error { + int currentPosition = initialPosition; + NSString *remaining = nil; + do { + ZXRSSExpandedDecodedInformation *info = [self decodeGeneralPurposeField:currentPosition remaining:remaining]; + if (!info) { + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + NSString *parsedFields = [ZXRSSExpandedFieldParser parseFieldsInGeneralPurpose:[info theNewString] error:error]; + if (!parsedFields) { + return nil; + } else if (parsedFields.length > 0) { + [buff appendString:parsedFields]; + } + + if ([info remaining]) { + remaining = [@([info remainingValue]) stringValue]; + } else { + remaining = nil; + } + + if (currentPosition == [info theNewPosition]) {// No step forward! + break; + } + currentPosition = [info theNewPosition]; + } while (YES); + + return buff; +} + +- (BOOL)isStillNumeric:(int)pos { + // It's numeric if it still has 7 positions + // and one of the first 4 bits is "1". + if (pos + 7 > self.information.size) { + return pos + 4 <= self.information.size; + } + + for (int i = pos; i < pos + 3; ++i) { + if ([self.information get:i]) { + return YES; + } + } + + return [self.information get:pos + 3]; +} + +- (ZXRSSExpandedDecodedNumeric *)decodeNumeric:(int)pos { + if (pos + 7 > self.information.size) { + int numeric = [self extractNumericValueFromBitArray:pos bits:4]; + if (numeric == 0) { + return [[ZXRSSExpandedDecodedNumeric alloc] initWithNewPosition:self.information.size + firstDigit:ZX_FNC1_INT + secondDigit:ZX_FNC1_INT]; + } + return [[ZXRSSExpandedDecodedNumeric alloc] initWithNewPosition:self.information.size + firstDigit:numeric - 1 + secondDigit:ZX_FNC1_INT]; + } + int numeric = [self extractNumericValueFromBitArray:pos bits:7]; + + int digit1 = (numeric - 8) / 11; + int digit2 = (numeric - 8) % 11; + + return [[ZXRSSExpandedDecodedNumeric alloc] initWithNewPosition:pos + 7 + firstDigit:digit1 + secondDigit:digit2]; +} + +- (int)extractNumericValueFromBitArray:(int)pos bits:(int)bits { + return [ZXRSSExpandedGeneralAppIdDecoder extractNumericValueFromBitArray:self.information pos:pos bits:bits]; +} + ++ (int)extractNumericValueFromBitArray:(ZXBitArray *)information pos:(int)pos bits:(int)bits { + if (bits > 32) { + [NSException raise:NSInvalidArgumentException format:@"extractNumberValueFromBitArray can't handle more than 32 bits"]; + } + + int value = 0; + for (int i = 0; i < bits; ++i) { + if ([information get:pos + i]) { + value |= 1 << (bits - i - 1); + } + } + + return value; +} + +- (ZXRSSExpandedDecodedInformation *)decodeGeneralPurposeField:(int)pos remaining:(NSString *)remaining { + [self.buffer setString:@""]; + + if (remaining != nil) { + [self.buffer appendString:remaining]; + } + + self.current.position = pos; + + NSError *error; + ZXRSSExpandedDecodedInformation *lastDecoded = [self parseBlocksWithError:&error]; + if (error) { + return nil; + } + + if (lastDecoded != nil && [lastDecoded remaining]) { + return [[ZXRSSExpandedDecodedInformation alloc] initWithNewPosition:self.current.position + newString:self.buffer + remainingValue:lastDecoded.remainingValue]; + } + return [[ZXRSSExpandedDecodedInformation alloc] initWithNewPosition:self.current.position newString:self.buffer]; +} + +- (ZXRSSExpandedDecodedInformation *)parseBlocksWithError:(NSError **)error { + BOOL isFinished; + ZXRSSExpandedBlockParsedResult *result; + do { + int initialPosition = self.current.position; + + NSError *localError; + if (self.current.alpha) { + result = [self parseAlphaBlock]; + isFinished = result.finished; + } else if (self.current.isoIec646) { + result = [self parseIsoIec646BlockWithError:&localError]; + isFinished = result.finished; + } else { + result = [self parseNumericBlockWithError:&localError]; + isFinished = result.finished; + } + + if (localError) { + if (error) *error = localError; + return nil; + } + + BOOL positionChanged = initialPosition != self.current.position; + if (!positionChanged && !isFinished) { + break; + } + } while (!isFinished); + return result.decodedInformation; +} + +- (ZXRSSExpandedBlockParsedResult *)parseNumericBlockWithError:(NSError **)error { + while ([self isStillNumeric:self.current.position]) { + ZXRSSExpandedDecodedNumeric *numeric = [self decodeNumeric:self.current.position]; + if (!numeric) { + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + self.current.position = numeric.theNewPosition; + + if ([numeric firstDigitFNC1]) { + ZXRSSExpandedDecodedInformation *information; + if ([numeric secondDigitFNC1]) { + information = [[ZXRSSExpandedDecodedInformation alloc] initWithNewPosition:self.current.position + newString:self.buffer]; + } else { + information = [[ZXRSSExpandedDecodedInformation alloc] initWithNewPosition:self.current.position + newString:self.buffer + remainingValue:numeric.secondDigit]; + } + return [[ZXRSSExpandedBlockParsedResult alloc] initWithInformation:information finished:YES]; + } + [self.buffer appendFormat:@"%d", numeric.firstDigit]; + + if (numeric.secondDigitFNC1) { + ZXRSSExpandedDecodedInformation *information = [[ZXRSSExpandedDecodedInformation alloc] initWithNewPosition:self.current.position + newString:self.buffer]; + return [[ZXRSSExpandedBlockParsedResult alloc] initWithInformation:information finished:YES]; + } + [self.buffer appendFormat:@"%d", numeric.secondDigit]; + } + + if ([self isNumericToAlphaNumericLatch:self.current.position]) { + [self.current setAlpha]; + self.current.position += 4; + } + return [[ZXRSSExpandedBlockParsedResult alloc] initWithFinished:NO]; +} + +- (ZXRSSExpandedBlockParsedResult *)parseIsoIec646BlockWithError:(NSError **)error { + while ([self isStillIsoIec646:self.current.position]) { + ZXRSSExpandedDecodedChar *iso = [self decodeIsoIec646:self.current.position]; + if (!iso) { + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + self.current.position = iso.theNewPosition; + + if (iso.fnc1) { + ZXRSSExpandedDecodedInformation *information = [[ZXRSSExpandedDecodedInformation alloc] initWithNewPosition:self.current.position + newString:self.buffer]; + return [[ZXRSSExpandedBlockParsedResult alloc] initWithInformation:information finished:YES]; + } + [self.buffer appendFormat:@"%C", iso.value]; + } + + if ([self isAlphaOr646ToNumericLatch:self.current.position]) { + self.current.position += 3; + [self.current setNumeric]; + } else if ([self isAlphaTo646ToAlphaLatch:self.current.position]) { + if (self.current.position + 5 < self.information.size) { + self.current.position += 5; + } else { + self.current.position = self.information.size; + } + + [self.current setAlpha]; + } + return [[ZXRSSExpandedBlockParsedResult alloc] initWithFinished:NO]; +} + +- (ZXRSSExpandedBlockParsedResult *)parseAlphaBlock { + while ([self isStillAlpha:self.current.position]) { + ZXRSSExpandedDecodedChar *alpha = [self decodeAlphanumeric:self.current.position]; + self.current.position = alpha.theNewPosition; + + if (alpha.fnc1) { + ZXRSSExpandedDecodedInformation *information = [[ZXRSSExpandedDecodedInformation alloc] initWithNewPosition:self.current.position + newString:self.buffer]; + return [[ZXRSSExpandedBlockParsedResult alloc] initWithInformation:information finished:YES]; + } + + [self.buffer appendFormat:@"%C", alpha.value]; + } + + if ([self isAlphaOr646ToNumericLatch:self.current.position]) { + self.current.position += 3; + [self.current setNumeric]; + } else if ([self isAlphaTo646ToAlphaLatch:self.current.position]) { + if (self.current.position + 5 < self.information.size) { + self.current.position += 5; + } else { + self.current.position = self.information.size; + } + + [self.current setIsoIec646]; + } + return [[ZXRSSExpandedBlockParsedResult alloc] initWithFinished:NO]; +} + +- (BOOL)isStillIsoIec646:(int)pos { + if (pos + 5 > self.information.size) { + return NO; + } + + int fiveBitValue = [self extractNumericValueFromBitArray:pos bits:5]; + if (fiveBitValue >= 5 && fiveBitValue < 16) { + return YES; + } + + if (pos + 7 > self.information.size) { + return NO; + } + + int sevenBitValue = [self extractNumericValueFromBitArray:pos bits:7]; + if (sevenBitValue >= 64 && sevenBitValue < 116) { + return YES; + } + + if (pos + 8 > self.information.size) { + return NO; + } + + int eightBitValue = [self extractNumericValueFromBitArray:pos bits:8]; + return eightBitValue >= 232 && eightBitValue < 253; +} + +- (ZXRSSExpandedDecodedChar *)decodeIsoIec646:(int)pos { + int fiveBitValue = [self extractNumericValueFromBitArray:pos bits:5]; + if (fiveBitValue == 15) { + return [[ZXRSSExpandedDecodedChar alloc] initWithNewPosition:pos + 5 value:ZX_FNC1_CHAR]; + } + + if (fiveBitValue >= 5 && fiveBitValue < 15) { + return [[ZXRSSExpandedDecodedChar alloc] initWithNewPosition:pos + 5 value:(unichar)('0' + fiveBitValue - 5)]; + } + + int sevenBitValue = [self extractNumericValueFromBitArray:pos bits:7]; + + if (sevenBitValue >= 64 && sevenBitValue < 90) { + return [[ZXRSSExpandedDecodedChar alloc] initWithNewPosition:pos + 7 value:(unichar)(sevenBitValue + 1)]; + } + + if (sevenBitValue >= 90 && sevenBitValue < 116) { + return [[ZXRSSExpandedDecodedChar alloc] initWithNewPosition:pos + 7 value:(unichar)(sevenBitValue + 7)]; + } + + int eightBitValue = [self extractNumericValueFromBitArray:pos bits:8]; + unichar c; + switch (eightBitValue) { + case 232: + c = '!'; + break; + case 233: + c = '"'; + break; + case 234: + c ='%'; + break; + case 235: + c = '&'; + break; + case 236: + c = '\''; + break; + case 237: + c = '('; + break; + case 238: + c = ')'; + break; + case 239: + c = '*'; + break; + case 240: + c = '+'; + break; + case 241: + c = ','; + break; + case 242: + c = '-'; + break; + case 243: + c = '.'; + break; + case 244: + c = '/'; + break; + case 245: + c = ':'; + break; + case 246: + c = ';'; + break; + case 247: + c = '<'; + break; + case 248: + c = '='; + break; + case 249: + c = '>'; + break; + case 250: + c = '?'; + break; + case 251: + c = '_'; + break; + case 252: + c = ' '; + break; + default: + return nil; + } + return [[ZXRSSExpandedDecodedChar alloc] initWithNewPosition:pos + 8 value:c]; +} + +- (BOOL)isStillAlpha:(int)pos { + if (pos + 5 > self.information.size) { + return NO; + } + + // We now check if it's a valid 5-bit value (0..9 and FNC1) + int fiveBitValue = [self extractNumericValueFromBitArray:pos bits:5]; + if (fiveBitValue >= 5 && fiveBitValue < 16) { + return YES; + } + + if (pos + 6 > self.information.size) { + return NO; + } + + int sixBitValue = [self extractNumericValueFromBitArray:pos bits:6]; + return sixBitValue >= 16 && sixBitValue < 63; // 63 not included +} + +- (ZXRSSExpandedDecodedChar *)decodeAlphanumeric:(int)pos { + int fiveBitValue = [self extractNumericValueFromBitArray:pos bits:5]; + if (fiveBitValue == 15) { + return [[ZXRSSExpandedDecodedChar alloc] initWithNewPosition:pos + 5 value:ZX_FNC1_CHAR]; + } + + if (fiveBitValue >= 5 && fiveBitValue < 15) { + return [[ZXRSSExpandedDecodedChar alloc] initWithNewPosition:pos + 5 value:(unichar)('0' + fiveBitValue - 5)]; + } + + int sixBitValue = [self extractNumericValueFromBitArray:pos bits:6]; + + if (sixBitValue >= 32 && sixBitValue < 58) { + return [[ZXRSSExpandedDecodedChar alloc] initWithNewPosition:pos + 6 value:(unichar)(sixBitValue + 33)]; + } + + unichar c; + switch (sixBitValue){ + case 58: + c = '*'; + break; + case 59: + c = ','; + break; + case 60: + c = '-'; + break; + case 61: + c = '.'; + break; + case 62: + c = '/'; + break; + default: + @throw [NSException exceptionWithName:@"RuntimeException" + reason:[NSString stringWithFormat:@"Decoding invalid alphanumeric value: %d", sixBitValue] + userInfo:nil]; + } + + return [[ZXRSSExpandedDecodedChar alloc] initWithNewPosition:pos + 6 value:c]; +} + +- (BOOL)isAlphaTo646ToAlphaLatch:(int)pos { + if (pos + 1 > self.information.size) { + return NO; + } + + for (int i = 0; i < 5 && i + pos < self.information.size; ++i) { + if (i == 2) { + if (![self.information get:pos + 2]) { + return NO; + } + } else if ([self.information get:pos + i]) { + return NO; + } + } + + return YES; +} + +- (BOOL)isAlphaOr646ToNumericLatch:(int)pos { + // Next is alphanumeric if there are 3 positions and they are all zeros + if (pos + 3 > self.information.size) { + return NO; + } + + for (int i = pos; i < pos + 3; ++i) { + if ([self.information get:i]) { + return NO; + } + } + + return YES; +} + +- (BOOL)isNumericToAlphaNumericLatch:(int)pos { + // Next is alphanumeric if there are 4 positions and they are all zeros, or + // if there is a subset of this just before the end of the symbol + if (pos + 1 > self.information.size) { + return NO; + } + + for (int i = 0; i < 4 && i + pos < self.information.size; ++i) { + if ([self.information get:pos + i]) { + return NO; + } + } + + return YES; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/ZXPDF417Common.h b/iDearQRCode/Tools/ZXingObjC/pdf417/ZXPDF417Common.h new file mode 100755 index 0000000..62efac2 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/ZXPDF417Common.h @@ -0,0 +1,42 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define ZX_PDF417_SYMBOL_TABLE_LEN 2787 +extern const int ZX_PDF417_SYMBOL_TABLE[]; + +extern const int ZX_PDF417_NUMBER_OF_CODEWORDS; +extern const int ZX_PDF417_MIN_ROWS_IN_BARCODE; +extern const int ZX_PDF417_MAX_ROWS_IN_BARCODE; +extern const int ZX_PDF417_MAX_CODEWORDS_IN_BARCODE; +extern const int ZX_PDF417_MODULES_IN_CODEWORD; +extern const int ZX_PDF417_MODULES_IN_STOP_PATTERN; +#define ZX_PDF417_BARS_IN_MODULE 8 + +@class ZXIntArray; + +@interface ZXPDF417Common : NSObject + ++ (int)bitCountSum:(NSArray *)moduleBitCount; ++ (ZXIntArray *)toIntArray:(NSArray *)list; + +/** + * Translate the symbol into a codeword. + * + * @return the codeword corresponding to the symbol. + */ ++ (int)codeword:(int)symbol; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/ZXPDF417Common.m b/iDearQRCode/Tools/ZXingObjC/pdf417/ZXPDF417Common.m new file mode 100755 index 0000000..9e94654 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/ZXPDF417Common.m @@ -0,0 +1,468 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXIntArray.h" +#import "ZXPDF417.h" +#import "ZXPDF417Common.h" + +const int ZX_PDF417_NUMBER_OF_CODEWORDS = 929; +// Maximum Codewords (Data + Error). +const int ZX_PDF417_MAX_CODEWORDS_IN_BARCODE = ZX_PDF417_NUMBER_OF_CODEWORDS - 1; +const int ZX_PDF417_MIN_ROWS_IN_BARCODE = 3; +const int ZX_PDF417_MAX_ROWS_IN_BARCODE = 90; +// One left row indication column + max 30 data columns + one right row indicator column +//const int ZX_PDF417_MAX_CODEWORDS_IN_ROW = 32; +const int ZX_PDF417_MODULES_IN_CODEWORD = 17; +const int ZX_PDF417_MODULES_IN_STOP_PATTERN = 18; + +const int ZX_PDF417_COMMON_CODEWORD_TABLE[]; + +@implementation ZXPDF417Common + ++ (int)bitCountSum:(NSArray *)moduleBitCount { + int bitCountSum = 0; + for (NSNumber *count in moduleBitCount) { + bitCountSum += [count intValue]; + } + return bitCountSum; +} + ++ (ZXIntArray *)toIntArray:(NSArray *)list { + ZXIntArray *result = [[ZXIntArray alloc] initWithLength:(unsigned int)[list count]]; + int i = 0; + for (NSNumber *integer in list) { + result.array[i++] = (int32_t)[integer intValue]; + } + return result; +} + ++ (int)codeword:(int)symbol { + int i = [self binarySearch:symbol & 0x3FFFF]; + if (i == -1) { + return -1; + } + return (ZX_PDF417_COMMON_CODEWORD_TABLE[i] - 1) % ZX_PDF417_NUMBER_OF_CODEWORDS; +} + +/** + * Use a binary search to find the index of the codeword corresponding to + * this symbol. + * + * @param symbol the symbol from the barcode. + * @return the index into the codeword table. + */ ++ (int)binarySearch:(int)symbol { + int first = 0; + int upto = ZX_PDF417_SYMBOL_TABLE_LEN; + while (first < upto) { + int mid = (first + upto) / 2; // Compute mid point. + if (symbol < ZX_PDF417_SYMBOL_TABLE[mid]) { + upto = mid; // continue search in bottom half. + } else if (symbol > ZX_PDF417_SYMBOL_TABLE[mid]) { + first = mid + 1; // continue search in top half. + } else { + return mid; // Found it. return position + } + } + return -1; +} + +@end + +/** + * The sorted table of all possible symbols. Extracted from the PDF417 + * specification. The index of a symbol in this table corresponds to the + * index into the codeword table. + */ +const int ZX_PDF417_SYMBOL_TABLE[ZX_PDF417_SYMBOL_TABLE_LEN] = { + 0x1025e, 0x1027a, 0x1029e, 0x102bc, 0x102f2, 0x102f4, 0x1032e, 0x1034e, 0x1035c, 0x10396, 0x103a6, 0x103ac, + 0x10422, 0x10428, 0x10436, 0x10442, 0x10444, 0x10448, 0x10450, 0x1045e, 0x10466, 0x1046c, 0x1047a, 0x10482, + 0x1049e, 0x104a0, 0x104bc, 0x104c6, 0x104d8, 0x104ee, 0x104f2, 0x104f4, 0x10504, 0x10508, 0x10510, 0x1051e, + 0x10520, 0x1053c, 0x10540, 0x10578, 0x10586, 0x1058c, 0x10598, 0x105b0, 0x105be, 0x105ce, 0x105dc, 0x105e2, + 0x105e4, 0x105e8, 0x105f6, 0x1062e, 0x1064e, 0x1065c, 0x1068e, 0x1069c, 0x106b8, 0x106de, 0x106fa, 0x10716, + 0x10726, 0x1072c, 0x10746, 0x1074c, 0x10758, 0x1076e, 0x10792, 0x10794, 0x107a2, 0x107a4, 0x107a8, 0x107b6, + 0x10822, 0x10828, 0x10842, 0x10848, 0x10850, 0x1085e, 0x10866, 0x1086c, 0x1087a, 0x10882, 0x10884, 0x10890, + 0x1089e, 0x108a0, 0x108bc, 0x108c6, 0x108cc, 0x108d8, 0x108ee, 0x108f2, 0x108f4, 0x10902, 0x10908, 0x1091e, + 0x10920, 0x1093c, 0x10940, 0x10978, 0x10986, 0x10998, 0x109b0, 0x109be, 0x109ce, 0x109dc, 0x109e2, 0x109e4, + 0x109e8, 0x109f6, 0x10a08, 0x10a10, 0x10a1e, 0x10a20, 0x10a3c, 0x10a40, 0x10a78, 0x10af0, 0x10b06, 0x10b0c, + 0x10b18, 0x10b30, 0x10b3e, 0x10b60, 0x10b7c, 0x10b8e, 0x10b9c, 0x10bb8, 0x10bc2, 0x10bc4, 0x10bc8, 0x10bd0, + 0x10bde, 0x10be6, 0x10bec, 0x10c2e, 0x10c4e, 0x10c5c, 0x10c62, 0x10c64, 0x10c68, 0x10c76, 0x10c8e, 0x10c9c, + 0x10cb8, 0x10cc2, 0x10cc4, 0x10cc8, 0x10cd0, 0x10cde, 0x10ce6, 0x10cec, 0x10cfa, 0x10d0e, 0x10d1c, 0x10d38, + 0x10d70, 0x10d7e, 0x10d82, 0x10d84, 0x10d88, 0x10d90, 0x10d9e, 0x10da0, 0x10dbc, 0x10dc6, 0x10dcc, 0x10dd8, + 0x10dee, 0x10df2, 0x10df4, 0x10e16, 0x10e26, 0x10e2c, 0x10e46, 0x10e58, 0x10e6e, 0x10e86, 0x10e8c, 0x10e98, + 0x10eb0, 0x10ebe, 0x10ece, 0x10edc, 0x10f0a, 0x10f12, 0x10f14, 0x10f22, 0x10f28, 0x10f36, 0x10f42, 0x10f44, + 0x10f48, 0x10f50, 0x10f5e, 0x10f66, 0x10f6c, 0x10fb2, 0x10fb4, 0x11022, 0x11028, 0x11042, 0x11048, 0x11050, + 0x1105e, 0x1107a, 0x11082, 0x11084, 0x11090, 0x1109e, 0x110a0, 0x110bc, 0x110c6, 0x110cc, 0x110d8, 0x110ee, + 0x110f2, 0x110f4, 0x11102, 0x1111e, 0x11120, 0x1113c, 0x11140, 0x11178, 0x11186, 0x11198, 0x111b0, 0x111be, + 0x111ce, 0x111dc, 0x111e2, 0x111e4, 0x111e8, 0x111f6, 0x11208, 0x1121e, 0x11220, 0x11278, 0x112f0, 0x1130c, + 0x11330, 0x1133e, 0x11360, 0x1137c, 0x1138e, 0x1139c, 0x113b8, 0x113c2, 0x113c8, 0x113d0, 0x113de, 0x113e6, + 0x113ec, 0x11408, 0x11410, 0x1141e, 0x11420, 0x1143c, 0x11440, 0x11478, 0x114f0, 0x115e0, 0x1160c, 0x11618, + 0x11630, 0x1163e, 0x11660, 0x1167c, 0x116c0, 0x116f8, 0x1171c, 0x11738, 0x11770, 0x1177e, 0x11782, 0x11784, + 0x11788, 0x11790, 0x1179e, 0x117a0, 0x117bc, 0x117c6, 0x117cc, 0x117d8, 0x117ee, 0x1182e, 0x11834, 0x1184e, + 0x1185c, 0x11862, 0x11864, 0x11868, 0x11876, 0x1188e, 0x1189c, 0x118b8, 0x118c2, 0x118c8, 0x118d0, 0x118de, + 0x118e6, 0x118ec, 0x118fa, 0x1190e, 0x1191c, 0x11938, 0x11970, 0x1197e, 0x11982, 0x11984, 0x11990, 0x1199e, + 0x119a0, 0x119bc, 0x119c6, 0x119cc, 0x119d8, 0x119ee, 0x119f2, 0x119f4, 0x11a0e, 0x11a1c, 0x11a38, 0x11a70, + 0x11a7e, 0x11ae0, 0x11afc, 0x11b08, 0x11b10, 0x11b1e, 0x11b20, 0x11b3c, 0x11b40, 0x11b78, 0x11b8c, 0x11b98, + 0x11bb0, 0x11bbe, 0x11bce, 0x11bdc, 0x11be2, 0x11be4, 0x11be8, 0x11bf6, 0x11c16, 0x11c26, 0x11c2c, 0x11c46, + 0x11c4c, 0x11c58, 0x11c6e, 0x11c86, 0x11c98, 0x11cb0, 0x11cbe, 0x11cce, 0x11cdc, 0x11ce2, 0x11ce4, 0x11ce8, + 0x11cf6, 0x11d06, 0x11d0c, 0x11d18, 0x11d30, 0x11d3e, 0x11d60, 0x11d7c, 0x11d8e, 0x11d9c, 0x11db8, 0x11dc4, + 0x11dc8, 0x11dd0, 0x11dde, 0x11de6, 0x11dec, 0x11dfa, 0x11e0a, 0x11e12, 0x11e14, 0x11e22, 0x11e24, 0x11e28, + 0x11e36, 0x11e42, 0x11e44, 0x11e50, 0x11e5e, 0x11e66, 0x11e6c, 0x11e82, 0x11e84, 0x11e88, 0x11e90, 0x11e9e, + 0x11ea0, 0x11ebc, 0x11ec6, 0x11ecc, 0x11ed8, 0x11eee, 0x11f1a, 0x11f2e, 0x11f32, 0x11f34, 0x11f4e, 0x11f5c, + 0x11f62, 0x11f64, 0x11f68, 0x11f76, 0x12048, 0x1205e, 0x12082, 0x12084, 0x12090, 0x1209e, 0x120a0, 0x120bc, + 0x120d8, 0x120f2, 0x120f4, 0x12108, 0x1211e, 0x12120, 0x1213c, 0x12140, 0x12178, 0x12186, 0x12198, 0x121b0, + 0x121be, 0x121e2, 0x121e4, 0x121e8, 0x121f6, 0x12204, 0x12210, 0x1221e, 0x12220, 0x12278, 0x122f0, 0x12306, + 0x1230c, 0x12330, 0x1233e, 0x12360, 0x1237c, 0x1238e, 0x1239c, 0x123b8, 0x123c2, 0x123c8, 0x123d0, 0x123e6, + 0x123ec, 0x1241e, 0x12420, 0x1243c, 0x124f0, 0x125e0, 0x12618, 0x1263e, 0x12660, 0x1267c, 0x126c0, 0x126f8, + 0x12738, 0x12770, 0x1277e, 0x12782, 0x12784, 0x12790, 0x1279e, 0x127a0, 0x127bc, 0x127c6, 0x127cc, 0x127d8, + 0x127ee, 0x12820, 0x1283c, 0x12840, 0x12878, 0x128f0, 0x129e0, 0x12bc0, 0x12c18, 0x12c30, 0x12c3e, 0x12c60, + 0x12c7c, 0x12cc0, 0x12cf8, 0x12df0, 0x12e1c, 0x12e38, 0x12e70, 0x12e7e, 0x12ee0, 0x12efc, 0x12f04, 0x12f08, + 0x12f10, 0x12f20, 0x12f3c, 0x12f40, 0x12f78, 0x12f86, 0x12f8c, 0x12f98, 0x12fb0, 0x12fbe, 0x12fce, 0x12fdc, + 0x1302e, 0x1304e, 0x1305c, 0x13062, 0x13068, 0x1308e, 0x1309c, 0x130b8, 0x130c2, 0x130c8, 0x130d0, 0x130de, + 0x130ec, 0x130fa, 0x1310e, 0x13138, 0x13170, 0x1317e, 0x13182, 0x13184, 0x13190, 0x1319e, 0x131a0, 0x131bc, + 0x131c6, 0x131cc, 0x131d8, 0x131f2, 0x131f4, 0x1320e, 0x1321c, 0x13270, 0x1327e, 0x132e0, 0x132fc, 0x13308, + 0x1331e, 0x13320, 0x1333c, 0x13340, 0x13378, 0x13386, 0x13398, 0x133b0, 0x133be, 0x133ce, 0x133dc, 0x133e2, + 0x133e4, 0x133e8, 0x133f6, 0x1340e, 0x1341c, 0x13438, 0x13470, 0x1347e, 0x134e0, 0x134fc, 0x135c0, 0x135f8, + 0x13608, 0x13610, 0x1361e, 0x13620, 0x1363c, 0x13640, 0x13678, 0x136f0, 0x1370c, 0x13718, 0x13730, 0x1373e, + 0x13760, 0x1377c, 0x1379c, 0x137b8, 0x137c2, 0x137c4, 0x137c8, 0x137d0, 0x137de, 0x137e6, 0x137ec, 0x13816, + 0x13826, 0x1382c, 0x13846, 0x1384c, 0x13858, 0x1386e, 0x13874, 0x13886, 0x13898, 0x138b0, 0x138be, 0x138ce, + 0x138dc, 0x138e2, 0x138e4, 0x138e8, 0x13906, 0x1390c, 0x13930, 0x1393e, 0x13960, 0x1397c, 0x1398e, 0x1399c, + 0x139b8, 0x139c8, 0x139d0, 0x139de, 0x139e6, 0x139ec, 0x139fa, 0x13a06, 0x13a0c, 0x13a18, 0x13a30, 0x13a3e, + 0x13a60, 0x13a7c, 0x13ac0, 0x13af8, 0x13b0e, 0x13b1c, 0x13b38, 0x13b70, 0x13b7e, 0x13b88, 0x13b90, 0x13b9e, + 0x13ba0, 0x13bbc, 0x13bcc, 0x13bd8, 0x13bee, 0x13bf2, 0x13bf4, 0x13c12, 0x13c14, 0x13c22, 0x13c24, 0x13c28, + 0x13c36, 0x13c42, 0x13c48, 0x13c50, 0x13c5e, 0x13c66, 0x13c6c, 0x13c82, 0x13c84, 0x13c90, 0x13c9e, 0x13ca0, + 0x13cbc, 0x13cc6, 0x13ccc, 0x13cd8, 0x13cee, 0x13d02, 0x13d04, 0x13d08, 0x13d10, 0x13d1e, 0x13d20, 0x13d3c, + 0x13d40, 0x13d78, 0x13d86, 0x13d8c, 0x13d98, 0x13db0, 0x13dbe, 0x13dce, 0x13ddc, 0x13de4, 0x13de8, 0x13df6, + 0x13e1a, 0x13e2e, 0x13e32, 0x13e34, 0x13e4e, 0x13e5c, 0x13e62, 0x13e64, 0x13e68, 0x13e76, 0x13e8e, 0x13e9c, + 0x13eb8, 0x13ec2, 0x13ec4, 0x13ec8, 0x13ed0, 0x13ede, 0x13ee6, 0x13eec, 0x13f26, 0x13f2c, 0x13f3a, 0x13f46, + 0x13f4c, 0x13f58, 0x13f6e, 0x13f72, 0x13f74, 0x14082, 0x1409e, 0x140a0, 0x140bc, 0x14104, 0x14108, 0x14110, + 0x1411e, 0x14120, 0x1413c, 0x14140, 0x14178, 0x1418c, 0x14198, 0x141b0, 0x141be, 0x141e2, 0x141e4, 0x141e8, + 0x14208, 0x14210, 0x1421e, 0x14220, 0x1423c, 0x14240, 0x14278, 0x142f0, 0x14306, 0x1430c, 0x14318, 0x14330, + 0x1433e, 0x14360, 0x1437c, 0x1438e, 0x143c2, 0x143c4, 0x143c8, 0x143d0, 0x143e6, 0x143ec, 0x14408, 0x14410, + 0x1441e, 0x14420, 0x1443c, 0x14440, 0x14478, 0x144f0, 0x145e0, 0x1460c, 0x14618, 0x14630, 0x1463e, 0x14660, + 0x1467c, 0x146c0, 0x146f8, 0x1471c, 0x14738, 0x14770, 0x1477e, 0x14782, 0x14784, 0x14788, 0x14790, 0x147a0, + 0x147bc, 0x147c6, 0x147cc, 0x147d8, 0x147ee, 0x14810, 0x14820, 0x1483c, 0x14840, 0x14878, 0x148f0, 0x149e0, + 0x14bc0, 0x14c30, 0x14c3e, 0x14c60, 0x14c7c, 0x14cc0, 0x14cf8, 0x14df0, 0x14e38, 0x14e70, 0x14e7e, 0x14ee0, + 0x14efc, 0x14f04, 0x14f08, 0x14f10, 0x14f1e, 0x14f20, 0x14f3c, 0x14f40, 0x14f78, 0x14f86, 0x14f8c, 0x14f98, + 0x14fb0, 0x14fce, 0x14fdc, 0x15020, 0x15040, 0x15078, 0x150f0, 0x151e0, 0x153c0, 0x15860, 0x1587c, 0x158c0, + 0x158f8, 0x159f0, 0x15be0, 0x15c70, 0x15c7e, 0x15ce0, 0x15cfc, 0x15dc0, 0x15df8, 0x15e08, 0x15e10, 0x15e20, + 0x15e40, 0x15e78, 0x15ef0, 0x15f0c, 0x15f18, 0x15f30, 0x15f60, 0x15f7c, 0x15f8e, 0x15f9c, 0x15fb8, 0x1604e, + 0x1605c, 0x1608e, 0x1609c, 0x160b8, 0x160c2, 0x160c4, 0x160c8, 0x160de, 0x1610e, 0x1611c, 0x16138, 0x16170, + 0x1617e, 0x16184, 0x16188, 0x16190, 0x1619e, 0x161a0, 0x161bc, 0x161c6, 0x161cc, 0x161d8, 0x161f2, 0x161f4, + 0x1620e, 0x1621c, 0x16238, 0x16270, 0x1627e, 0x162e0, 0x162fc, 0x16304, 0x16308, 0x16310, 0x1631e, 0x16320, + 0x1633c, 0x16340, 0x16378, 0x16386, 0x1638c, 0x16398, 0x163b0, 0x163be, 0x163ce, 0x163dc, 0x163e2, 0x163e4, + 0x163e8, 0x163f6, 0x1640e, 0x1641c, 0x16438, 0x16470, 0x1647e, 0x164e0, 0x164fc, 0x165c0, 0x165f8, 0x16610, + 0x1661e, 0x16620, 0x1663c, 0x16640, 0x16678, 0x166f0, 0x16718, 0x16730, 0x1673e, 0x16760, 0x1677c, 0x1678e, + 0x1679c, 0x167b8, 0x167c2, 0x167c4, 0x167c8, 0x167d0, 0x167de, 0x167e6, 0x167ec, 0x1681c, 0x16838, 0x16870, + 0x168e0, 0x168fc, 0x169c0, 0x169f8, 0x16bf0, 0x16c10, 0x16c1e, 0x16c20, 0x16c3c, 0x16c40, 0x16c78, 0x16cf0, + 0x16de0, 0x16e18, 0x16e30, 0x16e3e, 0x16e60, 0x16e7c, 0x16ec0, 0x16ef8, 0x16f1c, 0x16f38, 0x16f70, 0x16f7e, + 0x16f84, 0x16f88, 0x16f90, 0x16f9e, 0x16fa0, 0x16fbc, 0x16fc6, 0x16fcc, 0x16fd8, 0x17026, 0x1702c, 0x17046, + 0x1704c, 0x17058, 0x1706e, 0x17086, 0x1708c, 0x17098, 0x170b0, 0x170be, 0x170ce, 0x170dc, 0x170e8, 0x17106, + 0x1710c, 0x17118, 0x17130, 0x1713e, 0x17160, 0x1717c, 0x1718e, 0x1719c, 0x171b8, 0x171c2, 0x171c4, 0x171c8, + 0x171d0, 0x171de, 0x171e6, 0x171ec, 0x171fa, 0x17206, 0x1720c, 0x17218, 0x17230, 0x1723e, 0x17260, 0x1727c, + 0x172c0, 0x172f8, 0x1730e, 0x1731c, 0x17338, 0x17370, 0x1737e, 0x17388, 0x17390, 0x1739e, 0x173a0, 0x173bc, + 0x173cc, 0x173d8, 0x173ee, 0x173f2, 0x173f4, 0x1740c, 0x17418, 0x17430, 0x1743e, 0x17460, 0x1747c, 0x174c0, + 0x174f8, 0x175f0, 0x1760e, 0x1761c, 0x17638, 0x17670, 0x1767e, 0x176e0, 0x176fc, 0x17708, 0x17710, 0x1771e, + 0x17720, 0x1773c, 0x17740, 0x17778, 0x17798, 0x177b0, 0x177be, 0x177dc, 0x177e2, 0x177e4, 0x177e8, 0x17822, + 0x17824, 0x17828, 0x17836, 0x17842, 0x17844, 0x17848, 0x17850, 0x1785e, 0x17866, 0x1786c, 0x17882, 0x17884, + 0x17888, 0x17890, 0x1789e, 0x178a0, 0x178bc, 0x178c6, 0x178cc, 0x178d8, 0x178ee, 0x178f2, 0x178f4, 0x17902, + 0x17904, 0x17908, 0x17910, 0x1791e, 0x17920, 0x1793c, 0x17940, 0x17978, 0x17986, 0x1798c, 0x17998, 0x179b0, + 0x179be, 0x179ce, 0x179dc, 0x179e2, 0x179e4, 0x179e8, 0x179f6, 0x17a04, 0x17a08, 0x17a10, 0x17a1e, 0x17a20, + 0x17a3c, 0x17a40, 0x17a78, 0x17af0, 0x17b06, 0x17b0c, 0x17b18, 0x17b30, 0x17b3e, 0x17b60, 0x17b7c, 0x17b8e, + 0x17b9c, 0x17bb8, 0x17bc4, 0x17bc8, 0x17bd0, 0x17bde, 0x17be6, 0x17bec, 0x17c2e, 0x17c32, 0x17c34, 0x17c4e, + 0x17c5c, 0x17c62, 0x17c64, 0x17c68, 0x17c76, 0x17c8e, 0x17c9c, 0x17cb8, 0x17cc2, 0x17cc4, 0x17cc8, 0x17cd0, + 0x17cde, 0x17ce6, 0x17cec, 0x17d0e, 0x17d1c, 0x17d38, 0x17d70, 0x17d82, 0x17d84, 0x17d88, 0x17d90, 0x17d9e, + 0x17da0, 0x17dbc, 0x17dc6, 0x17dcc, 0x17dd8, 0x17dee, 0x17e26, 0x17e2c, 0x17e3a, 0x17e46, 0x17e4c, 0x17e58, + 0x17e6e, 0x17e72, 0x17e74, 0x17e86, 0x17e8c, 0x17e98, 0x17eb0, 0x17ece, 0x17edc, 0x17ee2, 0x17ee4, 0x17ee8, + 0x17ef6, 0x1813a, 0x18172, 0x18174, 0x18216, 0x18226, 0x1823a, 0x1824c, 0x18258, 0x1826e, 0x18272, 0x18274, + 0x18298, 0x182be, 0x182e2, 0x182e4, 0x182e8, 0x182f6, 0x1835e, 0x1837a, 0x183ae, 0x183d6, 0x18416, 0x18426, + 0x1842c, 0x1843a, 0x18446, 0x18458, 0x1846e, 0x18472, 0x18474, 0x18486, 0x184b0, 0x184be, 0x184ce, 0x184dc, + 0x184e2, 0x184e4, 0x184e8, 0x184f6, 0x18506, 0x1850c, 0x18518, 0x18530, 0x1853e, 0x18560, 0x1857c, 0x1858e, + 0x1859c, 0x185b8, 0x185c2, 0x185c4, 0x185c8, 0x185d0, 0x185de, 0x185e6, 0x185ec, 0x185fa, 0x18612, 0x18614, + 0x18622, 0x18628, 0x18636, 0x18642, 0x18650, 0x1865e, 0x1867a, 0x18682, 0x18684, 0x18688, 0x18690, 0x1869e, + 0x186a0, 0x186bc, 0x186c6, 0x186cc, 0x186d8, 0x186ee, 0x186f2, 0x186f4, 0x1872e, 0x1874e, 0x1875c, 0x18796, + 0x187a6, 0x187ac, 0x187d2, 0x187d4, 0x18826, 0x1882c, 0x1883a, 0x18846, 0x1884c, 0x18858, 0x1886e, 0x18872, + 0x18874, 0x18886, 0x18898, 0x188b0, 0x188be, 0x188ce, 0x188dc, 0x188e2, 0x188e4, 0x188e8, 0x188f6, 0x1890c, + 0x18930, 0x1893e, 0x18960, 0x1897c, 0x1898e, 0x189b8, 0x189c2, 0x189c8, 0x189d0, 0x189de, 0x189e6, 0x189ec, + 0x189fa, 0x18a18, 0x18a30, 0x18a3e, 0x18a60, 0x18a7c, 0x18ac0, 0x18af8, 0x18b1c, 0x18b38, 0x18b70, 0x18b7e, + 0x18b82, 0x18b84, 0x18b88, 0x18b90, 0x18b9e, 0x18ba0, 0x18bbc, 0x18bc6, 0x18bcc, 0x18bd8, 0x18bee, 0x18bf2, + 0x18bf4, 0x18c22, 0x18c24, 0x18c28, 0x18c36, 0x18c42, 0x18c48, 0x18c50, 0x18c5e, 0x18c66, 0x18c7a, 0x18c82, + 0x18c84, 0x18c90, 0x18c9e, 0x18ca0, 0x18cbc, 0x18ccc, 0x18cf2, 0x18cf4, 0x18d04, 0x18d08, 0x18d10, 0x18d1e, + 0x18d20, 0x18d3c, 0x18d40, 0x18d78, 0x18d86, 0x18d98, 0x18dce, 0x18de2, 0x18de4, 0x18de8, 0x18e2e, 0x18e32, + 0x18e34, 0x18e4e, 0x18e5c, 0x18e62, 0x18e64, 0x18e68, 0x18e8e, 0x18e9c, 0x18eb8, 0x18ec2, 0x18ec4, 0x18ec8, + 0x18ed0, 0x18efa, 0x18f16, 0x18f26, 0x18f2c, 0x18f46, 0x18f4c, 0x18f58, 0x18f6e, 0x18f8a, 0x18f92, 0x18f94, + 0x18fa2, 0x18fa4, 0x18fa8, 0x18fb6, 0x1902c, 0x1903a, 0x19046, 0x1904c, 0x19058, 0x19072, 0x19074, 0x19086, + 0x19098, 0x190b0, 0x190be, 0x190ce, 0x190dc, 0x190e2, 0x190e8, 0x190f6, 0x19106, 0x1910c, 0x19130, 0x1913e, + 0x19160, 0x1917c, 0x1918e, 0x1919c, 0x191b8, 0x191c2, 0x191c8, 0x191d0, 0x191de, 0x191e6, 0x191ec, 0x191fa, + 0x19218, 0x1923e, 0x19260, 0x1927c, 0x192c0, 0x192f8, 0x19338, 0x19370, 0x1937e, 0x19382, 0x19384, 0x19390, + 0x1939e, 0x193a0, 0x193bc, 0x193c6, 0x193cc, 0x193d8, 0x193ee, 0x193f2, 0x193f4, 0x19430, 0x1943e, 0x19460, + 0x1947c, 0x194c0, 0x194f8, 0x195f0, 0x19638, 0x19670, 0x1967e, 0x196e0, 0x196fc, 0x19702, 0x19704, 0x19708, + 0x19710, 0x19720, 0x1973c, 0x19740, 0x19778, 0x19786, 0x1978c, 0x19798, 0x197b0, 0x197be, 0x197ce, 0x197dc, + 0x197e2, 0x197e4, 0x197e8, 0x19822, 0x19824, 0x19842, 0x19848, 0x19850, 0x1985e, 0x19866, 0x1987a, 0x19882, + 0x19884, 0x19890, 0x1989e, 0x198a0, 0x198bc, 0x198cc, 0x198f2, 0x198f4, 0x19902, 0x19908, 0x1991e, 0x19920, + 0x1993c, 0x19940, 0x19978, 0x19986, 0x19998, 0x199ce, 0x199e2, 0x199e4, 0x199e8, 0x19a08, 0x19a10, 0x19a1e, + 0x19a20, 0x19a3c, 0x19a40, 0x19a78, 0x19af0, 0x19b18, 0x19b3e, 0x19b60, 0x19b9c, 0x19bc2, 0x19bc4, 0x19bc8, + 0x19bd0, 0x19be6, 0x19c2e, 0x19c34, 0x19c4e, 0x19c5c, 0x19c62, 0x19c64, 0x19c68, 0x19c8e, 0x19c9c, 0x19cb8, + 0x19cc2, 0x19cc8, 0x19cd0, 0x19ce6, 0x19cfa, 0x19d0e, 0x19d1c, 0x19d38, 0x19d70, 0x19d7e, 0x19d82, 0x19d84, + 0x19d88, 0x19d90, 0x19da0, 0x19dcc, 0x19df2, 0x19df4, 0x19e16, 0x19e26, 0x19e2c, 0x19e46, 0x19e4c, 0x19e58, + 0x19e74, 0x19e86, 0x19e8c, 0x19e98, 0x19eb0, 0x19ebe, 0x19ece, 0x19ee2, 0x19ee4, 0x19ee8, 0x19f0a, 0x19f12, + 0x19f14, 0x19f22, 0x19f24, 0x19f28, 0x19f42, 0x19f44, 0x19f48, 0x19f50, 0x19f5e, 0x19f6c, 0x19f9a, 0x19fae, + 0x19fb2, 0x19fb4, 0x1a046, 0x1a04c, 0x1a072, 0x1a074, 0x1a086, 0x1a08c, 0x1a098, 0x1a0b0, 0x1a0be, 0x1a0e2, + 0x1a0e4, 0x1a0e8, 0x1a0f6, 0x1a106, 0x1a10c, 0x1a118, 0x1a130, 0x1a13e, 0x1a160, 0x1a17c, 0x1a18e, 0x1a19c, + 0x1a1b8, 0x1a1c2, 0x1a1c4, 0x1a1c8, 0x1a1d0, 0x1a1de, 0x1a1e6, 0x1a1ec, 0x1a218, 0x1a230, 0x1a23e, 0x1a260, + 0x1a27c, 0x1a2c0, 0x1a2f8, 0x1a31c, 0x1a338, 0x1a370, 0x1a37e, 0x1a382, 0x1a384, 0x1a388, 0x1a390, 0x1a39e, + 0x1a3a0, 0x1a3bc, 0x1a3c6, 0x1a3cc, 0x1a3d8, 0x1a3ee, 0x1a3f2, 0x1a3f4, 0x1a418, 0x1a430, 0x1a43e, 0x1a460, + 0x1a47c, 0x1a4c0, 0x1a4f8, 0x1a5f0, 0x1a61c, 0x1a638, 0x1a670, 0x1a67e, 0x1a6e0, 0x1a6fc, 0x1a702, 0x1a704, + 0x1a708, 0x1a710, 0x1a71e, 0x1a720, 0x1a73c, 0x1a740, 0x1a778, 0x1a786, 0x1a78c, 0x1a798, 0x1a7b0, 0x1a7be, + 0x1a7ce, 0x1a7dc, 0x1a7e2, 0x1a7e4, 0x1a7e8, 0x1a830, 0x1a860, 0x1a87c, 0x1a8c0, 0x1a8f8, 0x1a9f0, 0x1abe0, + 0x1ac70, 0x1ac7e, 0x1ace0, 0x1acfc, 0x1adc0, 0x1adf8, 0x1ae04, 0x1ae08, 0x1ae10, 0x1ae20, 0x1ae3c, 0x1ae40, + 0x1ae78, 0x1aef0, 0x1af06, 0x1af0c, 0x1af18, 0x1af30, 0x1af3e, 0x1af60, 0x1af7c, 0x1af8e, 0x1af9c, 0x1afb8, + 0x1afc4, 0x1afc8, 0x1afd0, 0x1afde, 0x1b042, 0x1b05e, 0x1b07a, 0x1b082, 0x1b084, 0x1b088, 0x1b090, 0x1b09e, + 0x1b0a0, 0x1b0bc, 0x1b0cc, 0x1b0f2, 0x1b0f4, 0x1b102, 0x1b104, 0x1b108, 0x1b110, 0x1b11e, 0x1b120, 0x1b13c, + 0x1b140, 0x1b178, 0x1b186, 0x1b198, 0x1b1ce, 0x1b1e2, 0x1b1e4, 0x1b1e8, 0x1b204, 0x1b208, 0x1b210, 0x1b21e, + 0x1b220, 0x1b23c, 0x1b240, 0x1b278, 0x1b2f0, 0x1b30c, 0x1b33e, 0x1b360, 0x1b39c, 0x1b3c2, 0x1b3c4, 0x1b3c8, + 0x1b3d0, 0x1b3e6, 0x1b410, 0x1b41e, 0x1b420, 0x1b43c, 0x1b440, 0x1b478, 0x1b4f0, 0x1b5e0, 0x1b618, 0x1b660, + 0x1b67c, 0x1b6c0, 0x1b738, 0x1b782, 0x1b784, 0x1b788, 0x1b790, 0x1b79e, 0x1b7a0, 0x1b7cc, 0x1b82e, 0x1b84e, + 0x1b85c, 0x1b88e, 0x1b89c, 0x1b8b8, 0x1b8c2, 0x1b8c4, 0x1b8c8, 0x1b8d0, 0x1b8e6, 0x1b8fa, 0x1b90e, 0x1b91c, + 0x1b938, 0x1b970, 0x1b97e, 0x1b982, 0x1b984, 0x1b988, 0x1b990, 0x1b99e, 0x1b9a0, 0x1b9cc, 0x1b9f2, 0x1b9f4, + 0x1ba0e, 0x1ba1c, 0x1ba38, 0x1ba70, 0x1ba7e, 0x1bae0, 0x1bafc, 0x1bb08, 0x1bb10, 0x1bb20, 0x1bb3c, 0x1bb40, + 0x1bb98, 0x1bbce, 0x1bbe2, 0x1bbe4, 0x1bbe8, 0x1bc16, 0x1bc26, 0x1bc2c, 0x1bc46, 0x1bc4c, 0x1bc58, 0x1bc72, + 0x1bc74, 0x1bc86, 0x1bc8c, 0x1bc98, 0x1bcb0, 0x1bcbe, 0x1bcce, 0x1bce2, 0x1bce4, 0x1bce8, 0x1bd06, 0x1bd0c, + 0x1bd18, 0x1bd30, 0x1bd3e, 0x1bd60, 0x1bd7c, 0x1bd9c, 0x1bdc2, 0x1bdc4, 0x1bdc8, 0x1bdd0, 0x1bde6, 0x1bdfa, + 0x1be12, 0x1be14, 0x1be22, 0x1be24, 0x1be28, 0x1be42, 0x1be44, 0x1be48, 0x1be50, 0x1be5e, 0x1be66, 0x1be82, + 0x1be84, 0x1be88, 0x1be90, 0x1be9e, 0x1bea0, 0x1bebc, 0x1becc, 0x1bef4, 0x1bf1a, 0x1bf2e, 0x1bf32, 0x1bf34, + 0x1bf4e, 0x1bf5c, 0x1bf62, 0x1bf64, 0x1bf68, 0x1c09a, 0x1c0b2, 0x1c0b4, 0x1c11a, 0x1c132, 0x1c134, 0x1c162, + 0x1c164, 0x1c168, 0x1c176, 0x1c1ba, 0x1c21a, 0x1c232, 0x1c234, 0x1c24e, 0x1c25c, 0x1c262, 0x1c264, 0x1c268, + 0x1c276, 0x1c28e, 0x1c2c2, 0x1c2c4, 0x1c2c8, 0x1c2d0, 0x1c2de, 0x1c2e6, 0x1c2ec, 0x1c2fa, 0x1c316, 0x1c326, + 0x1c33a, 0x1c346, 0x1c34c, 0x1c372, 0x1c374, 0x1c41a, 0x1c42e, 0x1c432, 0x1c434, 0x1c44e, 0x1c45c, 0x1c462, + 0x1c464, 0x1c468, 0x1c476, 0x1c48e, 0x1c49c, 0x1c4b8, 0x1c4c2, 0x1c4c8, 0x1c4d0, 0x1c4de, 0x1c4e6, 0x1c4ec, + 0x1c4fa, 0x1c51c, 0x1c538, 0x1c570, 0x1c57e, 0x1c582, 0x1c584, 0x1c588, 0x1c590, 0x1c59e, 0x1c5a0, 0x1c5bc, + 0x1c5c6, 0x1c5cc, 0x1c5d8, 0x1c5ee, 0x1c5f2, 0x1c5f4, 0x1c616, 0x1c626, 0x1c62c, 0x1c63a, 0x1c646, 0x1c64c, + 0x1c658, 0x1c66e, 0x1c672, 0x1c674, 0x1c686, 0x1c68c, 0x1c698, 0x1c6b0, 0x1c6be, 0x1c6ce, 0x1c6dc, 0x1c6e2, + 0x1c6e4, 0x1c6e8, 0x1c712, 0x1c714, 0x1c722, 0x1c728, 0x1c736, 0x1c742, 0x1c744, 0x1c748, 0x1c750, 0x1c75e, + 0x1c766, 0x1c76c, 0x1c77a, 0x1c7ae, 0x1c7d6, 0x1c7ea, 0x1c81a, 0x1c82e, 0x1c832, 0x1c834, 0x1c84e, 0x1c85c, + 0x1c862, 0x1c864, 0x1c868, 0x1c876, 0x1c88e, 0x1c89c, 0x1c8b8, 0x1c8c2, 0x1c8c8, 0x1c8d0, 0x1c8de, 0x1c8e6, + 0x1c8ec, 0x1c8fa, 0x1c90e, 0x1c938, 0x1c970, 0x1c97e, 0x1c982, 0x1c984, 0x1c990, 0x1c99e, 0x1c9a0, 0x1c9bc, + 0x1c9c6, 0x1c9cc, 0x1c9d8, 0x1c9ee, 0x1c9f2, 0x1c9f4, 0x1ca38, 0x1ca70, 0x1ca7e, 0x1cae0, 0x1cafc, 0x1cb02, + 0x1cb04, 0x1cb08, 0x1cb10, 0x1cb20, 0x1cb3c, 0x1cb40, 0x1cb78, 0x1cb86, 0x1cb8c, 0x1cb98, 0x1cbb0, 0x1cbbe, + 0x1cbce, 0x1cbdc, 0x1cbe2, 0x1cbe4, 0x1cbe8, 0x1cbf6, 0x1cc16, 0x1cc26, 0x1cc2c, 0x1cc3a, 0x1cc46, 0x1cc58, + 0x1cc72, 0x1cc74, 0x1cc86, 0x1ccb0, 0x1ccbe, 0x1ccce, 0x1cce2, 0x1cce4, 0x1cce8, 0x1cd06, 0x1cd0c, 0x1cd18, + 0x1cd30, 0x1cd3e, 0x1cd60, 0x1cd7c, 0x1cd9c, 0x1cdc2, 0x1cdc4, 0x1cdc8, 0x1cdd0, 0x1cdde, 0x1cde6, 0x1cdfa, + 0x1ce22, 0x1ce28, 0x1ce42, 0x1ce50, 0x1ce5e, 0x1ce66, 0x1ce7a, 0x1ce82, 0x1ce84, 0x1ce88, 0x1ce90, 0x1ce9e, + 0x1cea0, 0x1cebc, 0x1cecc, 0x1cef2, 0x1cef4, 0x1cf2e, 0x1cf32, 0x1cf34, 0x1cf4e, 0x1cf5c, 0x1cf62, 0x1cf64, + 0x1cf68, 0x1cf96, 0x1cfa6, 0x1cfac, 0x1cfca, 0x1cfd2, 0x1cfd4, 0x1d02e, 0x1d032, 0x1d034, 0x1d04e, 0x1d05c, + 0x1d062, 0x1d064, 0x1d068, 0x1d076, 0x1d08e, 0x1d09c, 0x1d0b8, 0x1d0c2, 0x1d0c4, 0x1d0c8, 0x1d0d0, 0x1d0de, + 0x1d0e6, 0x1d0ec, 0x1d0fa, 0x1d11c, 0x1d138, 0x1d170, 0x1d17e, 0x1d182, 0x1d184, 0x1d188, 0x1d190, 0x1d19e, + 0x1d1a0, 0x1d1bc, 0x1d1c6, 0x1d1cc, 0x1d1d8, 0x1d1ee, 0x1d1f2, 0x1d1f4, 0x1d21c, 0x1d238, 0x1d270, 0x1d27e, + 0x1d2e0, 0x1d2fc, 0x1d302, 0x1d304, 0x1d308, 0x1d310, 0x1d31e, 0x1d320, 0x1d33c, 0x1d340, 0x1d378, 0x1d386, + 0x1d38c, 0x1d398, 0x1d3b0, 0x1d3be, 0x1d3ce, 0x1d3dc, 0x1d3e2, 0x1d3e4, 0x1d3e8, 0x1d3f6, 0x1d470, 0x1d47e, + 0x1d4e0, 0x1d4fc, 0x1d5c0, 0x1d5f8, 0x1d604, 0x1d608, 0x1d610, 0x1d620, 0x1d640, 0x1d678, 0x1d6f0, 0x1d706, + 0x1d70c, 0x1d718, 0x1d730, 0x1d73e, 0x1d760, 0x1d77c, 0x1d78e, 0x1d79c, 0x1d7b8, 0x1d7c2, 0x1d7c4, 0x1d7c8, + 0x1d7d0, 0x1d7de, 0x1d7e6, 0x1d7ec, 0x1d826, 0x1d82c, 0x1d83a, 0x1d846, 0x1d84c, 0x1d858, 0x1d872, 0x1d874, + 0x1d886, 0x1d88c, 0x1d898, 0x1d8b0, 0x1d8be, 0x1d8ce, 0x1d8e2, 0x1d8e4, 0x1d8e8, 0x1d8f6, 0x1d90c, 0x1d918, + 0x1d930, 0x1d93e, 0x1d960, 0x1d97c, 0x1d99c, 0x1d9c2, 0x1d9c4, 0x1d9c8, 0x1d9d0, 0x1d9e6, 0x1d9fa, 0x1da0c, + 0x1da18, 0x1da30, 0x1da3e, 0x1da60, 0x1da7c, 0x1dac0, 0x1daf8, 0x1db38, 0x1db82, 0x1db84, 0x1db88, 0x1db90, + 0x1db9e, 0x1dba0, 0x1dbcc, 0x1dbf2, 0x1dbf4, 0x1dc22, 0x1dc42, 0x1dc44, 0x1dc48, 0x1dc50, 0x1dc5e, 0x1dc66, + 0x1dc7a, 0x1dc82, 0x1dc84, 0x1dc88, 0x1dc90, 0x1dc9e, 0x1dca0, 0x1dcbc, 0x1dccc, 0x1dcf2, 0x1dcf4, 0x1dd04, + 0x1dd08, 0x1dd10, 0x1dd1e, 0x1dd20, 0x1dd3c, 0x1dd40, 0x1dd78, 0x1dd86, 0x1dd98, 0x1ddce, 0x1dde2, 0x1dde4, + 0x1dde8, 0x1de2e, 0x1de32, 0x1de34, 0x1de4e, 0x1de5c, 0x1de62, 0x1de64, 0x1de68, 0x1de8e, 0x1de9c, 0x1deb8, + 0x1dec2, 0x1dec4, 0x1dec8, 0x1ded0, 0x1dee6, 0x1defa, 0x1df16, 0x1df26, 0x1df2c, 0x1df46, 0x1df4c, 0x1df58, + 0x1df72, 0x1df74, 0x1df8a, 0x1df92, 0x1df94, 0x1dfa2, 0x1dfa4, 0x1dfa8, 0x1e08a, 0x1e092, 0x1e094, 0x1e0a2, + 0x1e0a4, 0x1e0a8, 0x1e0b6, 0x1e0da, 0x1e10a, 0x1e112, 0x1e114, 0x1e122, 0x1e124, 0x1e128, 0x1e136, 0x1e142, + 0x1e144, 0x1e148, 0x1e150, 0x1e166, 0x1e16c, 0x1e17a, 0x1e19a, 0x1e1b2, 0x1e1b4, 0x1e20a, 0x1e212, 0x1e214, + 0x1e222, 0x1e224, 0x1e228, 0x1e236, 0x1e242, 0x1e248, 0x1e250, 0x1e25e, 0x1e266, 0x1e26c, 0x1e27a, 0x1e282, + 0x1e284, 0x1e288, 0x1e290, 0x1e2a0, 0x1e2bc, 0x1e2c6, 0x1e2cc, 0x1e2d8, 0x1e2ee, 0x1e2f2, 0x1e2f4, 0x1e31a, + 0x1e332, 0x1e334, 0x1e35c, 0x1e362, 0x1e364, 0x1e368, 0x1e3ba, 0x1e40a, 0x1e412, 0x1e414, 0x1e422, 0x1e428, + 0x1e436, 0x1e442, 0x1e448, 0x1e450, 0x1e45e, 0x1e466, 0x1e46c, 0x1e47a, 0x1e482, 0x1e484, 0x1e490, 0x1e49e, + 0x1e4a0, 0x1e4bc, 0x1e4c6, 0x1e4cc, 0x1e4d8, 0x1e4ee, 0x1e4f2, 0x1e4f4, 0x1e502, 0x1e504, 0x1e508, 0x1e510, + 0x1e51e, 0x1e520, 0x1e53c, 0x1e540, 0x1e578, 0x1e586, 0x1e58c, 0x1e598, 0x1e5b0, 0x1e5be, 0x1e5ce, 0x1e5dc, + 0x1e5e2, 0x1e5e4, 0x1e5e8, 0x1e5f6, 0x1e61a, 0x1e62e, 0x1e632, 0x1e634, 0x1e64e, 0x1e65c, 0x1e662, 0x1e668, + 0x1e68e, 0x1e69c, 0x1e6b8, 0x1e6c2, 0x1e6c4, 0x1e6c8, 0x1e6d0, 0x1e6e6, 0x1e6fa, 0x1e716, 0x1e726, 0x1e72c, + 0x1e73a, 0x1e746, 0x1e74c, 0x1e758, 0x1e772, 0x1e774, 0x1e792, 0x1e794, 0x1e7a2, 0x1e7a4, 0x1e7a8, 0x1e7b6, + 0x1e812, 0x1e814, 0x1e822, 0x1e824, 0x1e828, 0x1e836, 0x1e842, 0x1e844, 0x1e848, 0x1e850, 0x1e85e, 0x1e866, + 0x1e86c, 0x1e87a, 0x1e882, 0x1e884, 0x1e888, 0x1e890, 0x1e89e, 0x1e8a0, 0x1e8bc, 0x1e8c6, 0x1e8cc, 0x1e8d8, + 0x1e8ee, 0x1e8f2, 0x1e8f4, 0x1e902, 0x1e904, 0x1e908, 0x1e910, 0x1e920, 0x1e93c, 0x1e940, 0x1e978, 0x1e986, + 0x1e98c, 0x1e998, 0x1e9b0, 0x1e9be, 0x1e9ce, 0x1e9dc, 0x1e9e2, 0x1e9e4, 0x1e9e8, 0x1e9f6, 0x1ea04, 0x1ea08, + 0x1ea10, 0x1ea20, 0x1ea40, 0x1ea78, 0x1eaf0, 0x1eb06, 0x1eb0c, 0x1eb18, 0x1eb30, 0x1eb3e, 0x1eb60, 0x1eb7c, + 0x1eb8e, 0x1eb9c, 0x1ebb8, 0x1ebc2, 0x1ebc4, 0x1ebc8, 0x1ebd0, 0x1ebde, 0x1ebe6, 0x1ebec, 0x1ec1a, 0x1ec2e, + 0x1ec32, 0x1ec34, 0x1ec4e, 0x1ec5c, 0x1ec62, 0x1ec64, 0x1ec68, 0x1ec8e, 0x1ec9c, 0x1ecb8, 0x1ecc2, 0x1ecc4, + 0x1ecc8, 0x1ecd0, 0x1ece6, 0x1ecfa, 0x1ed0e, 0x1ed1c, 0x1ed38, 0x1ed70, 0x1ed7e, 0x1ed82, 0x1ed84, 0x1ed88, + 0x1ed90, 0x1ed9e, 0x1eda0, 0x1edcc, 0x1edf2, 0x1edf4, 0x1ee16, 0x1ee26, 0x1ee2c, 0x1ee3a, 0x1ee46, 0x1ee4c, + 0x1ee58, 0x1ee6e, 0x1ee72, 0x1ee74, 0x1ee86, 0x1ee8c, 0x1ee98, 0x1eeb0, 0x1eebe, 0x1eece, 0x1eedc, 0x1eee2, + 0x1eee4, 0x1eee8, 0x1ef12, 0x1ef22, 0x1ef24, 0x1ef28, 0x1ef36, 0x1ef42, 0x1ef44, 0x1ef48, 0x1ef50, 0x1ef5e, + 0x1ef66, 0x1ef6c, 0x1ef7a, 0x1efae, 0x1efb2, 0x1efb4, 0x1efd6, 0x1f096, 0x1f0a6, 0x1f0ac, 0x1f0ba, 0x1f0ca, + 0x1f0d2, 0x1f0d4, 0x1f116, 0x1f126, 0x1f12c, 0x1f13a, 0x1f146, 0x1f14c, 0x1f158, 0x1f16e, 0x1f172, 0x1f174, + 0x1f18a, 0x1f192, 0x1f194, 0x1f1a2, 0x1f1a4, 0x1f1a8, 0x1f1da, 0x1f216, 0x1f226, 0x1f22c, 0x1f23a, 0x1f246, + 0x1f258, 0x1f26e, 0x1f272, 0x1f274, 0x1f286, 0x1f28c, 0x1f298, 0x1f2b0, 0x1f2be, 0x1f2ce, 0x1f2dc, 0x1f2e2, + 0x1f2e4, 0x1f2e8, 0x1f2f6, 0x1f30a, 0x1f312, 0x1f314, 0x1f322, 0x1f328, 0x1f342, 0x1f344, 0x1f348, 0x1f350, + 0x1f35e, 0x1f366, 0x1f37a, 0x1f39a, 0x1f3ae, 0x1f3b2, 0x1f3b4, 0x1f416, 0x1f426, 0x1f42c, 0x1f43a, 0x1f446, + 0x1f44c, 0x1f458, 0x1f46e, 0x1f472, 0x1f474, 0x1f486, 0x1f48c, 0x1f498, 0x1f4b0, 0x1f4be, 0x1f4ce, 0x1f4dc, + 0x1f4e2, 0x1f4e4, 0x1f4e8, 0x1f4f6, 0x1f506, 0x1f50c, 0x1f518, 0x1f530, 0x1f53e, 0x1f560, 0x1f57c, 0x1f58e, + 0x1f59c, 0x1f5b8, 0x1f5c2, 0x1f5c4, 0x1f5c8, 0x1f5d0, 0x1f5de, 0x1f5e6, 0x1f5ec, 0x1f5fa, 0x1f60a, 0x1f612, + 0x1f614, 0x1f622, 0x1f624, 0x1f628, 0x1f636, 0x1f642, 0x1f644, 0x1f648, 0x1f650, 0x1f65e, 0x1f666, 0x1f67a, + 0x1f682, 0x1f684, 0x1f688, 0x1f690, 0x1f69e, 0x1f6a0, 0x1f6bc, 0x1f6cc, 0x1f6f2, 0x1f6f4, 0x1f71a, 0x1f72e, + 0x1f732, 0x1f734, 0x1f74e, 0x1f75c, 0x1f762, 0x1f764, 0x1f768, 0x1f776, 0x1f796, 0x1f7a6, 0x1f7ac, 0x1f7ba, + 0x1f7d2, 0x1f7d4, 0x1f89a, 0x1f8ae, 0x1f8b2, 0x1f8b4, 0x1f8d6, 0x1f8ea, 0x1f91a, 0x1f92e, 0x1f932, 0x1f934, + 0x1f94e, 0x1f95c, 0x1f962, 0x1f964, 0x1f968, 0x1f976, 0x1f996, 0x1f9a6, 0x1f9ac, 0x1f9ba, 0x1f9ca, 0x1f9d2, + 0x1f9d4, 0x1fa1a, 0x1fa2e, 0x1fa32, 0x1fa34, 0x1fa4e, 0x1fa5c, 0x1fa62, 0x1fa64, 0x1fa68, 0x1fa76, 0x1fa8e, + 0x1fa9c, 0x1fab8, 0x1fac2, 0x1fac4, 0x1fac8, 0x1fad0, 0x1fade, 0x1fae6, 0x1faec, 0x1fb16, 0x1fb26, 0x1fb2c, + 0x1fb3a, 0x1fb46, 0x1fb4c, 0x1fb58, 0x1fb6e, 0x1fb72, 0x1fb74, 0x1fb8a, 0x1fb92, 0x1fb94, 0x1fba2, 0x1fba4, + 0x1fba8, 0x1fbb6, 0x1fbda}; + +/** + * This table contains to codewords for all symbols. + */ +const int ZX_PDF417_COMMON_CODEWORD_TABLE[] = { + 2627, 1819, 2622, 2621, 1813, 1812, 2729, 2724, 2723, 2779, 2774, 2773, 902, 896, 908, 868, 865, 861, 859, 2511, + 873, 871, 1780, 835, 2493, 825, 2491, 842, 837, 844, 1764, 1762, 811, 810, 809, 2483, 807, 2482, 806, 2480, 815, + 814, 813, 812, 2484, 817, 816, 1745, 1744, 1742, 1746, 2655, 2637, 2635, 2626, 2625, 2623, 2628, 1820, 2752, + 2739, 2737, 2728, 2727, 2725, 2730, 2785, 2783, 2778, 2777, 2775, 2780, 787, 781, 747, 739, 736, 2413, 754, 752, + 1719, 692, 689, 681, 2371, 678, 2369, 700, 697, 694, 703, 1688, 1686, 642, 638, 2343, 631, 2341, 627, 2338, 651, + 646, 643, 2345, 654, 652, 1652, 1650, 1647, 1654, 601, 599, 2322, 596, 2321, 594, 2319, 2317, 611, 610, 608, 606, + 2324, 603, 2323, 615, 614, 612, 1617, 1616, 1614, 1612, 616, 1619, 1618, 2575, 2538, 2536, 905, 901, 898, 909, + 2509, 2507, 2504, 870, 867, 864, 860, 2512, 875, 872, 1781, 2490, 2489, 2487, 2485, 1748, 836, 834, 832, 830, + 2494, 827, 2492, 843, 841, 839, 845, 1765, 1763, 2701, 2676, 2674, 2653, 2648, 2656, 2634, 2633, 2631, 2629, + 1821, 2638, 2636, 2770, 2763, 2761, 2750, 2745, 2753, 2736, 2735, 2733, 2731, 1848, 2740, 2738, 2786, 2784, 591, + 588, 576, 569, 566, 2296, 1590, 537, 534, 526, 2276, 522, 2274, 545, 542, 539, 548, 1572, 1570, 481, 2245, 466, + 2242, 462, 2239, 492, 485, 482, 2249, 496, 494, 1534, 1531, 1528, 1538, 413, 2196, 406, 2191, 2188, 425, 419, + 2202, 415, 2199, 432, 430, 427, 1472, 1467, 1464, 433, 1476, 1474, 368, 367, 2160, 365, 2159, 362, 2157, 2155, + 2152, 378, 377, 375, 2166, 372, 2165, 369, 2162, 383, 381, 379, 2168, 1419, 1418, 1416, 1414, 385, 1411, 384, + 1423, 1422, 1420, 1424, 2461, 802, 2441, 2439, 790, 786, 783, 794, 2409, 2406, 2403, 750, 742, 738, 2414, 756, + 753, 1720, 2367, 2365, 2362, 2359, 1663, 693, 691, 684, 2373, 680, 2370, 702, 699, 696, 704, 1690, 1687, 2337, + 2336, 2334, 2332, 1624, 2329, 1622, 640, 637, 2344, 634, 2342, 630, 2340, 650, 648, 645, 2346, 655, 653, 1653, + 1651, 1649, 1655, 2612, 2597, 2595, 2571, 2568, 2565, 2576, 2534, 2529, 2526, 1787, 2540, 2537, 907, 904, 900, + 910, 2503, 2502, 2500, 2498, 1768, 2495, 1767, 2510, 2508, 2506, 869, 866, 863, 2513, 876, 874, 1782, 2720, 2713, + 2711, 2697, 2694, 2691, 2702, 2672, 2670, 2664, 1828, 2678, 2675, 2647, 2646, 2644, 2642, 1823, 2639, 1822, 2654, + 2652, 2650, 2657, 2771, 1855, 2765, 2762, 1850, 1849, 2751, 2749, 2747, 2754, 353, 2148, 344, 342, 336, 2142, + 332, 2140, 345, 1375, 1373, 306, 2130, 299, 2128, 295, 2125, 319, 314, 311, 2132, 1354, 1352, 1349, 1356, 262, + 257, 2101, 253, 2096, 2093, 274, 273, 267, 2107, 263, 2104, 280, 278, 275, 1316, 1311, 1308, 1320, 1318, 2052, + 202, 2050, 2044, 2040, 219, 2063, 212, 2060, 208, 2055, 224, 221, 2066, 1260, 1258, 1252, 231, 1248, 229, 1266, + 1264, 1261, 1268, 155, 1998, 153, 1996, 1994, 1991, 1988, 165, 164, 2007, 162, 2006, 159, 2003, 2000, 172, 171, + 169, 2012, 166, 2010, 1186, 1184, 1182, 1179, 175, 1176, 173, 1192, 1191, 1189, 1187, 176, 1194, 1193, 2313, + 2307, 2305, 592, 589, 2294, 2292, 2289, 578, 572, 568, 2297, 580, 1591, 2272, 2267, 2264, 1547, 538, 536, 529, + 2278, 525, 2275, 547, 544, 541, 1574, 1571, 2237, 2235, 2229, 1493, 2225, 1489, 478, 2247, 470, 2244, 465, 2241, + 493, 488, 484, 2250, 498, 495, 1536, 1533, 1530, 1539, 2187, 2186, 2184, 2182, 1432, 2179, 1430, 2176, 1427, 414, + 412, 2197, 409, 2195, 405, 2193, 2190, 426, 424, 421, 2203, 418, 2201, 431, 429, 1473, 1471, 1469, 1466, 434, + 1477, 1475, 2478, 2472, 2470, 2459, 2457, 2454, 2462, 803, 2437, 2432, 2429, 1726, 2443, 2440, 792, 789, 785, + 2401, 2399, 2393, 1702, 2389, 1699, 2411, 2408, 2405, 745, 741, 2415, 758, 755, 1721, 2358, 2357, 2355, 2353, + 1661, 2350, 1660, 2347, 1657, 2368, 2366, 2364, 2361, 1666, 690, 687, 2374, 683, 2372, 701, 698, 705, 1691, 1689, + 2619, 2617, 2610, 2608, 2605, 2613, 2593, 2588, 2585, 1803, 2599, 2596, 2563, 2561, 2555, 1797, 2551, 1795, 2573, + 2570, 2567, 2577, 2525, 2524, 2522, 2520, 1786, 2517, 1785, 2514, 1783, 2535, 2533, 2531, 2528, 1788, 2541, 2539, + 906, 903, 911, 2721, 1844, 2715, 2712, 1838, 1836, 2699, 2696, 2693, 2703, 1827, 1826, 1824, 2673, 2671, 2669, + 2666, 1829, 2679, 2677, 1858, 1857, 2772, 1854, 1853, 1851, 1856, 2766, 2764, 143, 1987, 139, 1986, 135, 133, + 131, 1984, 128, 1983, 125, 1981, 138, 137, 136, 1985, 1133, 1132, 1130, 112, 110, 1974, 107, 1973, 104, 1971, + 1969, 122, 121, 119, 117, 1977, 114, 1976, 124, 1115, 1114, 1112, 1110, 1117, 1116, 84, 83, 1953, 81, 1952, 78, + 1950, 1948, 1945, 94, 93, 91, 1959, 88, 1958, 85, 1955, 99, 97, 95, 1961, 1086, 1085, 1083, 1081, 1078, 100, + 1090, 1089, 1087, 1091, 49, 47, 1917, 44, 1915, 1913, 1910, 1907, 59, 1926, 56, 1925, 53, 1922, 1919, 66, 64, + 1931, 61, 1929, 1042, 1040, 1038, 71, 1035, 70, 1032, 68, 1048, 1047, 1045, 1043, 1050, 1049, 12, 10, 1869, 1867, + 1864, 1861, 21, 1880, 19, 1877, 1874, 1871, 28, 1888, 25, 1886, 22, 1883, 982, 980, 977, 974, 32, 30, 991, 989, + 987, 984, 34, 995, 994, 992, 2151, 2150, 2147, 2146, 2144, 356, 355, 354, 2149, 2139, 2138, 2136, 2134, 1359, + 343, 341, 338, 2143, 335, 2141, 348, 347, 346, 1376, 1374, 2124, 2123, 2121, 2119, 1326, 2116, 1324, 310, 308, + 305, 2131, 302, 2129, 298, 2127, 320, 318, 316, 313, 2133, 322, 321, 1355, 1353, 1351, 1357, 2092, 2091, 2089, + 2087, 1276, 2084, 1274, 2081, 1271, 259, 2102, 256, 2100, 252, 2098, 2095, 272, 269, 2108, 266, 2106, 281, 279, + 277, 1317, 1315, 1313, 1310, 282, 1321, 1319, 2039, 2037, 2035, 2032, 1203, 2029, 1200, 1197, 207, 2053, 205, + 2051, 201, 2049, 2046, 2043, 220, 218, 2064, 215, 2062, 211, 2059, 228, 226, 223, 2069, 1259, 1257, 1254, 232, + 1251, 230, 1267, 1265, 1263, 2316, 2315, 2312, 2311, 2309, 2314, 2304, 2303, 2301, 2299, 1593, 2308, 2306, 590, + 2288, 2287, 2285, 2283, 1578, 2280, 1577, 2295, 2293, 2291, 579, 577, 574, 571, 2298, 582, 581, 1592, 2263, 2262, + 2260, 2258, 1545, 2255, 1544, 2252, 1541, 2273, 2271, 2269, 2266, 1550, 535, 532, 2279, 528, 2277, 546, 543, 549, + 1575, 1573, 2224, 2222, 2220, 1486, 2217, 1485, 2214, 1482, 1479, 2238, 2236, 2234, 2231, 1496, 2228, 1492, 480, + 477, 2248, 473, 2246, 469, 2243, 490, 487, 2251, 497, 1537, 1535, 1532, 2477, 2476, 2474, 2479, 2469, 2468, 2466, + 2464, 1730, 2473, 2471, 2453, 2452, 2450, 2448, 1729, 2445, 1728, 2460, 2458, 2456, 2463, 805, 804, 2428, 2427, + 2425, 2423, 1725, 2420, 1724, 2417, 1722, 2438, 2436, 2434, 2431, 1727, 2444, 2442, 793, 791, 788, 795, 2388, + 2386, 2384, 1697, 2381, 1696, 2378, 1694, 1692, 2402, 2400, 2398, 2395, 1703, 2392, 1701, 2412, 2410, 2407, 751, + 748, 744, 2416, 759, 757, 1807, 2620, 2618, 1806, 1805, 2611, 2609, 2607, 2614, 1802, 1801, 1799, 2594, 2592, + 2590, 2587, 1804, 2600, 2598, 1794, 1793, 1791, 1789, 2564, 2562, 2560, 2557, 1798, 2554, 1796, 2574, 2572, 2569, + 2578, 1847, 1846, 2722, 1843, 1842, 1840, 1845, 2716, 2714, 1835, 1834, 1832, 1830, 1839, 1837, 2700, 2698, 2695, + 2704, 1817, 1811, 1810, 897, 862, 1777, 829, 826, 838, 1760, 1758, 808, 2481, 1741, 1740, 1738, 1743, 2624, 1818, + 2726, 2776, 782, 740, 737, 1715, 686, 679, 695, 1682, 1680, 639, 628, 2339, 647, 644, 1645, 1643, 1640, 1648, + 602, 600, 597, 595, 2320, 593, 2318, 609, 607, 604, 1611, 1610, 1608, 1606, 613, 1615, 1613, 2328, 926, 924, 892, + 886, 899, 857, 850, 2505, 1778, 824, 823, 821, 819, 2488, 818, 2486, 833, 831, 828, 840, 1761, 1759, 2649, 2632, + 2630, 2746, 2734, 2732, 2782, 2781, 570, 567, 1587, 531, 527, 523, 540, 1566, 1564, 476, 467, 463, 2240, 486, + 483, 1524, 1521, 1518, 1529, 411, 403, 2192, 399, 2189, 423, 416, 1462, 1457, 1454, 428, 1468, 1465, 2210, 366, + 363, 2158, 360, 2156, 357, 2153, 376, 373, 370, 2163, 1410, 1409, 1407, 1405, 382, 1402, 380, 1417, 1415, 1412, + 1421, 2175, 2174, 777, 774, 771, 784, 732, 725, 722, 2404, 743, 1716, 676, 674, 668, 2363, 665, 2360, 685, 1684, + 1681, 626, 624, 622, 2335, 620, 2333, 617, 2330, 641, 635, 649, 1646, 1644, 1642, 2566, 928, 925, 2530, 2527, + 894, 891, 888, 2501, 2499, 2496, 858, 856, 854, 851, 1779, 2692, 2668, 2665, 2645, 2643, 2640, 2651, 2768, 2759, + 2757, 2744, 2743, 2741, 2748, 352, 1382, 340, 337, 333, 1371, 1369, 307, 300, 296, 2126, 315, 312, 1347, 1342, + 1350, 261, 258, 250, 2097, 246, 2094, 271, 268, 264, 1306, 1301, 1298, 276, 1312, 1309, 2115, 203, 2048, 195, + 2045, 191, 2041, 213, 209, 2056, 1246, 1244, 1238, 225, 1234, 222, 1256, 1253, 1249, 1262, 2080, 2079, 154, 1997, + 150, 1995, 147, 1992, 1989, 163, 160, 2004, 156, 2001, 1175, 1174, 1172, 1170, 1167, 170, 1164, 167, 1185, 1183, + 1180, 1177, 174, 1190, 1188, 2025, 2024, 2022, 587, 586, 564, 559, 556, 2290, 573, 1588, 520, 518, 512, 2268, + 508, 2265, 530, 1568, 1565, 461, 457, 2233, 450, 2230, 446, 2226, 479, 471, 489, 1526, 1523, 1520, 397, 395, + 2185, 392, 2183, 389, 2180, 2177, 410, 2194, 402, 422, 1463, 1461, 1459, 1456, 1470, 2455, 799, 2433, 2430, 779, + 776, 773, 2397, 2394, 2390, 734, 728, 724, 746, 1717, 2356, 2354, 2351, 2348, 1658, 677, 675, 673, 670, 667, 688, + 1685, 1683, 2606, 2589, 2586, 2559, 2556, 2552, 927, 2523, 2521, 2518, 2515, 1784, 2532, 895, 893, 890, 2718, + 2709, 2707, 2689, 2687, 2684, 2663, 2662, 2660, 2658, 1825, 2667, 2769, 1852, 2760, 2758, 142, 141, 1139, 1138, + 134, 132, 129, 126, 1982, 1129, 1128, 1126, 1131, 113, 111, 108, 105, 1972, 101, 1970, 120, 118, 115, 1109, 1108, + 1106, 1104, 123, 1113, 1111, 82, 79, 1951, 75, 1949, 72, 1946, 92, 89, 86, 1956, 1077, 1076, 1074, 1072, 98, + 1069, 96, 1084, 1082, 1079, 1088, 1968, 1967, 48, 45, 1916, 42, 1914, 39, 1911, 1908, 60, 57, 54, 1923, 50, 1920, + 1031, 1030, 1028, 1026, 67, 1023, 65, 1020, 62, 1041, 1039, 1036, 1033, 69, 1046, 1044, 1944, 1943, 1941, 11, 9, + 1868, 7, 1865, 1862, 1859, 20, 1878, 16, 1875, 13, 1872, 970, 968, 966, 963, 29, 960, 26, 23, 983, 981, 978, 975, + 33, 971, 31, 990, 988, 985, 1906, 1904, 1902, 993, 351, 2145, 1383, 331, 330, 328, 326, 2137, 323, 2135, 339, + 1372, 1370, 294, 293, 291, 289, 2122, 286, 2120, 283, 2117, 309, 303, 317, 1348, 1346, 1344, 245, 244, 242, 2090, + 239, 2088, 236, 2085, 2082, 260, 2099, 249, 270, 1307, 1305, 1303, 1300, 1314, 189, 2038, 186, 2036, 183, 2033, + 2030, 2026, 206, 198, 2047, 194, 216, 1247, 1245, 1243, 1240, 227, 1237, 1255, 2310, 2302, 2300, 2286, 2284, + 2281, 565, 563, 561, 558, 575, 1589, 2261, 2259, 2256, 2253, 1542, 521, 519, 517, 514, 2270, 511, 533, 1569, + 1567, 2223, 2221, 2218, 2215, 1483, 2211, 1480, 459, 456, 453, 2232, 449, 474, 491, 1527, 1525, 1522, 2475, 2467, + 2465, 2451, 2449, 2446, 801, 800, 2426, 2424, 2421, 2418, 1723, 2435, 780, 778, 775, 2387, 2385, 2382, 2379, + 1695, 2375, 1693, 2396, 735, 733, 730, 727, 749, 1718, 2616, 2615, 2604, 2603, 2601, 2584, 2583, 2581, 2579, + 1800, 2591, 2550, 2549, 2547, 2545, 1792, 2542, 1790, 2558, 929, 2719, 1841, 2710, 2708, 1833, 1831, 2690, 2688, + 2686, 1815, 1809, 1808, 1774, 1756, 1754, 1737, 1736, 1734, 1739, 1816, 1711, 1676, 1674, 633, 629, 1638, 1636, + 1633, 1641, 598, 1605, 1604, 1602, 1600, 605, 1609, 1607, 2327, 887, 853, 1775, 822, 820, 1757, 1755, 1584, 524, + 1560, 1558, 468, 464, 1514, 1511, 1508, 1519, 408, 404, 400, 1452, 1447, 1444, 417, 1458, 1455, 2208, 364, 361, + 358, 2154, 1401, 1400, 1398, 1396, 374, 1393, 371, 1408, 1406, 1403, 1413, 2173, 2172, 772, 726, 723, 1712, 672, + 669, 666, 682, 1678, 1675, 625, 623, 621, 618, 2331, 636, 632, 1639, 1637, 1635, 920, 918, 884, 880, 889, 849, + 848, 847, 846, 2497, 855, 852, 1776, 2641, 2742, 2787, 1380, 334, 1367, 1365, 301, 297, 1340, 1338, 1335, 1343, + 255, 251, 247, 1296, 1291, 1288, 265, 1302, 1299, 2113, 204, 196, 192, 2042, 1232, 1230, 1224, 214, 1220, 210, + 1242, 1239, 1235, 1250, 2077, 2075, 151, 148, 1993, 144, 1990, 1163, 1162, 1160, 1158, 1155, 161, 1152, 157, + 1173, 1171, 1168, 1165, 168, 1181, 1178, 2021, 2020, 2018, 2023, 585, 560, 557, 1585, 516, 509, 1562, 1559, 458, + 447, 2227, 472, 1516, 1513, 1510, 398, 396, 393, 390, 2181, 386, 2178, 407, 1453, 1451, 1449, 1446, 420, 1460, + 2209, 769, 764, 720, 712, 2391, 729, 1713, 664, 663, 661, 659, 2352, 656, 2349, 671, 1679, 1677, 2553, 922, 919, + 2519, 2516, 885, 883, 881, 2685, 2661, 2659, 2767, 2756, 2755, 140, 1137, 1136, 130, 127, 1125, 1124, 1122, 1127, + 109, 106, 102, 1103, 1102, 1100, 1098, 116, 1107, 1105, 1980, 80, 76, 73, 1947, 1068, 1067, 1065, 1063, 90, 1060, + 87, 1075, 1073, 1070, 1080, 1966, 1965, 46, 43, 40, 1912, 36, 1909, 1019, 1018, 1016, 1014, 58, 1011, 55, 1008, + 51, 1029, 1027, 1024, 1021, 63, 1037, 1034, 1940, 1939, 1937, 1942, 8, 1866, 4, 1863, 1, 1860, 956, 954, 952, + 949, 946, 17, 14, 969, 967, 964, 961, 27, 957, 24, 979, 976, 972, 1901, 1900, 1898, 1896, 986, 1905, 1903, 350, + 349, 1381, 329, 327, 324, 1368, 1366, 292, 290, 287, 284, 2118, 304, 1341, 1339, 1337, 1345, 243, 240, 237, 2086, + 233, 2083, 254, 1297, 1295, 1293, 1290, 1304, 2114, 190, 187, 184, 2034, 180, 2031, 177, 2027, 199, 1233, 1231, + 1229, 1226, 217, 1223, 1241, 2078, 2076, 584, 555, 554, 552, 550, 2282, 562, 1586, 507, 506, 504, 502, 2257, 499, + 2254, 515, 1563, 1561, 445, 443, 441, 2219, 438, 2216, 435, 2212, 460, 454, 475, 1517, 1515, 1512, 2447, 798, + 797, 2422, 2419, 770, 768, 766, 2383, 2380, 2376, 721, 719, 717, 714, 731, 1714, 2602, 2582, 2580, 2548, 2546, + 2543, 923, 921, 2717, 2706, 2705, 2683, 2682, 2680, 1771, 1752, 1750, 1733, 1732, 1731, 1735, 1814, 1707, 1670, + 1668, 1631, 1629, 1626, 1634, 1599, 1598, 1596, 1594, 1603, 1601, 2326, 1772, 1753, 1751, 1581, 1554, 1552, 1504, + 1501, 1498, 1509, 1442, 1437, 1434, 401, 1448, 1445, 2206, 1392, 1391, 1389, 1387, 1384, 359, 1399, 1397, 1394, + 1404, 2171, 2170, 1708, 1672, 1669, 619, 1632, 1630, 1628, 1773, 1378, 1363, 1361, 1333, 1328, 1336, 1286, 1281, + 1278, 248, 1292, 1289, 2111, 1218, 1216, 1210, 197, 1206, 193, 1228, 1225, 1221, 1236, 2073, 2071, 1151, 1150, + 1148, 1146, 152, 1143, 149, 1140, 145, 1161, 1159, 1156, 1153, 158, 1169, 1166, 2017, 2016, 2014, 2019, 1582, + 510, 1556, 1553, 452, 448, 1506, 1500, 394, 391, 387, 1443, 1441, 1439, 1436, 1450, 2207, 765, 716, 713, 1709, + 662, 660, 657, 1673, 1671, 916, 914, 879, 878, 877, 882, 1135, 1134, 1121, 1120, 1118, 1123, 1097, 1096, 1094, + 1092, 103, 1101, 1099, 1979, 1059, 1058, 1056, 1054, 77, 1051, 74, 1066, 1064, 1061, 1071, 1964, 1963, 1007, + 1006, 1004, 1002, 999, 41, 996, 37, 1017, 1015, 1012, 1009, 52, 1025, 1022, 1936, 1935, 1933, 1938, 942, 940, + 938, 935, 932, 5, 2, 955, 953, 950, 947, 18, 943, 15, 965, 962, 958, 1895, 1894, 1892, 1890, 973, 1899, 1897, + 1379, 325, 1364, 1362, 288, 285, 1334, 1332, 1330, 241, 238, 234, 1287, 1285, 1283, 1280, 1294, 2112, 188, 185, + 181, 178, 2028, 1219, 1217, 1215, 1212, 200, 1209, 1227, 2074, 2072, 583, 553, 551, 1583, 505, 503, 500, 513, + 1557, 1555, 444, 442, 439, 436, 2213, 455, 451, 1507, 1505, 1502, 796, 763, 762, 760, 767, 711, 710, 708, 706, + 2377, 718, 715, 1710, 2544, 917, 915, 2681, 1627, 1597, 1595, 2325, 1769, 1749, 1747, 1499, 1438, 1435, 2204, + 1390, 1388, 1385, 1395, 2169, 2167, 1704, 1665, 1662, 1625, 1623, 1620, 1770, 1329, 1282, 1279, 2109, 1214, 1207, + 1222, 2068, 2065, 1149, 1147, 1144, 1141, 146, 1157, 1154, 2013, 2011, 2008, 2015, 1579, 1549, 1546, 1495, 1487, + 1433, 1431, 1428, 1425, 388, 1440, 2205, 1705, 658, 1667, 1664, 1119, 1095, 1093, 1978, 1057, 1055, 1052, 1062, + 1962, 1960, 1005, 1003, 1000, 997, 38, 1013, 1010, 1932, 1930, 1927, 1934, 941, 939, 936, 933, 6, 930, 3, 951, + 948, 944, 1889, 1887, 1884, 1881, 959, 1893, 1891, 35, 1377, 1360, 1358, 1327, 1325, 1322, 1331, 1277, 1275, + 1272, 1269, 235, 1284, 2110, 1205, 1204, 1201, 1198, 182, 1195, 179, 1213, 2070, 2067, 1580, 501, 1551, 1548, + 440, 437, 1497, 1494, 1490, 1503, 761, 709, 707, 1706, 913, 912, 2198, 1386, 2164, 2161, 1621, 1766, 2103, 1208, + 2058, 2054, 1145, 1142, 2005, 2002, 1999, 2009, 1488, 1429, 1426, 2200, 1698, 1659, 1656, 1975, 1053, 1957, 1954, + 1001, 998, 1924, 1921, 1918, 1928, 937, 934, 931, 1879, 1876, 1873, 1870, 945, 1885, 1882, 1323, 1273, 1270, + 2105, 1202, 1199, 1196, 1211, 2061, 2057, 1576, 1543, 1540, 1484, 1481, 1478, 1491, 1700}; diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/ZXPDF417Reader.h b/iDearQRCode/Tools/ZXingObjC/pdf417/ZXPDF417Reader.h new file mode 100755 index 0000000..485b91d --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/ZXPDF417Reader.h @@ -0,0 +1,30 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXMultipleBarcodeReader.h" +#import "ZXReader.h" + +@class ZXDecodeHints, ZXResult; + +/** + * This implementation can detect and decode PDF417 codes in an image. + */ +@interface ZXPDF417Reader : NSObject + +- (NSArray *)decodeMultiple:(ZXBinaryBitmap *)image error:(NSError **)error; +- (NSArray *)decodeMultiple:(ZXBinaryBitmap *)image hints:(ZXDecodeHints *)hints error:(NSError **)error; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/ZXPDF417Reader.m b/iDearQRCode/Tools/ZXingObjC/pdf417/ZXPDF417Reader.m new file mode 100755 index 0000000..39d3156 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/ZXPDF417Reader.m @@ -0,0 +1,134 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBarcodeFormat.h" +#import "ZXBinaryBitmap.h" +#import "ZXBitMatrix.h" +#import "ZXDecodeHints.h" +#import "ZXDecoderResult.h" +#import "ZXDetectorResult.h" +#import "ZXErrors.h" +#import "ZXPDF417Common.h" +#import "ZXPDF417Detector.h" +#import "ZXPDF417DetectorResult.h" +#import "ZXPDF417Reader.h" +#import "ZXPDF417ResultMetadata.h" +#import "ZXPDF417ScanningDecoder.h" +#import "ZXResult.h" +#import "ZXResultPoint.h" + +@implementation ZXPDF417Reader + +/** + * Locates and decodes a PDF417 code in an image. + * + * @return a String representing the content encoded by the PDF417 code + * @return nil if a PDF417 code cannot be found, + * @return nil if a PDF417 cannot be decoded + */ +- (ZXResult *)decode:(ZXBinaryBitmap *)image error:(NSError **)error { + return [self decode:image hints:nil error:error]; +} + +- (ZXResult *)decode:(ZXBinaryBitmap *)image hints:(ZXDecodeHints *)hints error:(NSError **)error { + NSArray *result = [self decode:image hints:hints multiple:NO error:error]; + if (!result || result.count == 0 || !result[0]) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + return result[0]; +} + +- (NSArray *)decodeMultiple:(ZXBinaryBitmap *)image error:(NSError **)error { + return [self decodeMultiple:image hints:nil error:error]; +} + +- (NSArray *)decodeMultiple:(ZXBinaryBitmap *)image hints:(ZXDecodeHints *)hints error:(NSError **)error { + return [self decode:image hints:hints multiple:YES error:error]; +} + +- (NSArray *)decode:(ZXBinaryBitmap *)image hints:(ZXDecodeHints *)hints multiple:(BOOL)multiple error:(NSError **)error { + NSMutableArray *results = [NSMutableArray array]; + ZXPDF417DetectorResult *detectorResult = [ZXPDF417Detector detect:image hints:hints multiple:multiple error:error]; + if (!detectorResult) { + return nil; + } + for (NSArray *points in detectorResult.points) { + ZXResultPoint *imageTopLeft = points[4] == [NSNull null] ? nil : points[4]; + ZXResultPoint *imageBottomLeft = points[5] == [NSNull null] ? nil : points[5]; + ZXResultPoint *imageTopRight = points[6] == [NSNull null] ? nil : points[6]; + ZXResultPoint *imageBottomRight = points[7] == [NSNull null] ? nil : points[7]; + + ZXDecoderResult *decoderResult = [ZXPDF417ScanningDecoder decode:detectorResult.bits + imageTopLeft:imageTopLeft + imageBottomLeft:imageBottomLeft + imageTopRight:imageTopRight + imageBottomRight:imageBottomRight + minCodewordWidth:[self minCodewordWidth:points] + maxCodewordWidth:[self maxCodewordWidth:points] + error:error]; + if (!decoderResult) { + return nil; + } + ZXResult *result = [[ZXResult alloc] initWithText:decoderResult.text + rawBytes:decoderResult.rawBytes + resultPoints:points + format:kBarcodeFormatPDF417]; + [result putMetadata:kResultMetadataTypeErrorCorrectionLevel value:decoderResult.ecLevel]; + ZXPDF417ResultMetadata *pdf417ResultMetadata = decoderResult.other; + if (pdf417ResultMetadata) { + [result putMetadata:kResultMetadataTypePDF417ExtraMetadata value:pdf417ResultMetadata]; + } + [results addObject:result]; + } + return [NSArray arrayWithArray:results]; +} + +- (int)maxWidth:(ZXResultPoint *)p1 p2:(ZXResultPoint *)p2 { + if (!p1 || !p2 || (id)p1 == [NSNull null] || p2 == (id)[NSNull null]) { + return 0; + } + return fabsf(p1.x - p2.x); +} + +- (int)minWidth:(ZXResultPoint *)p1 p2:(ZXResultPoint *)p2 { + if (!p1 || !p2 || (id)p1 == [NSNull null] || p2 == (id)[NSNull null]) { + return INT_MAX; + } + return fabsf(p1.x - p2.x); +} + +- (int)maxCodewordWidth:(NSArray *)p { + return MAX( + MAX([self maxWidth:p[0] p2:p[4]], [self maxWidth:p[6] p2:p[2]] * ZX_PDF417_MODULES_IN_CODEWORD / + ZX_PDF417_MODULES_IN_STOP_PATTERN), + MAX([self maxWidth:p[1] p2:p[5]], [self maxWidth:p[7] p2:p[3]] * ZX_PDF417_MODULES_IN_CODEWORD / + ZX_PDF417_MODULES_IN_STOP_PATTERN)); +} + +- (int)minCodewordWidth:(NSArray *)p { + return MIN( + MIN([self minWidth:p[0] p2:p[4]], [self minWidth:p[6] p2:p[2]] * ZX_PDF417_MODULES_IN_CODEWORD / + ZX_PDF417_MODULES_IN_STOP_PATTERN), + MIN([self minWidth:p[1] p2:p[5]], [self minWidth:p[7] p2:p[3]] * ZX_PDF417_MODULES_IN_CODEWORD / + ZX_PDF417_MODULES_IN_STOP_PATTERN)); +} + +- (void)reset { + // nothing needs to be reset +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/ZXPDF417ResultMetadata.h b/iDearQRCode/Tools/ZXingObjC/pdf417/ZXPDF417ResultMetadata.h new file mode 100755 index 0000000..1660049 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/ZXPDF417ResultMetadata.h @@ -0,0 +1,24 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@interface ZXPDF417ResultMetadata : NSObject + +@property (nonatomic, assign) int segmentIndex; +@property (nonatomic, copy) NSString *fileId; +@property (nonatomic, strong) NSArray *optionalData; +@property (nonatomic, assign) BOOL lastSegment; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/ZXPDF417ResultMetadata.m b/iDearQRCode/Tools/ZXingObjC/pdf417/ZXPDF417ResultMetadata.m new file mode 100755 index 0000000..c5e2d8a --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/ZXPDF417ResultMetadata.m @@ -0,0 +1,21 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXPDF417ResultMetadata.h" + +@implementation ZXPDF417ResultMetadata + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/ZXPDF417Writer.h b/iDearQRCode/Tools/ZXingObjC/pdf417/ZXPDF417Writer.h new file mode 100755 index 0000000..eb09e73 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/ZXPDF417Writer.h @@ -0,0 +1,21 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXWriter.h" + +@interface ZXPDF417Writer : NSObject + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/ZXPDF417Writer.m b/iDearQRCode/Tools/ZXingObjC/pdf417/ZXPDF417Writer.m new file mode 100755 index 0000000..2f5a022 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/ZXPDF417Writer.m @@ -0,0 +1,153 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitMatrix.h" +#import "ZXByteArray.h" +#import "ZXEncodeHints.h" +#import "ZXPDF417.h" +#import "ZXPDF417BarcodeMatrix.h" +#import "ZXPDF417Dimensions.h" +#import "ZXPDF417Writer.h" + +/** + * default white space (margin) around the code + */ +const int ZX_PDF417_WHITE_SPACE = 30; + +@implementation ZXPDF417Writer + +- (ZXBitMatrix *)encode:(NSString *)contents format:(ZXBarcodeFormat)format width:(int)width height:(int)height + hints:(ZXEncodeHints *)hints error:(NSError **)error { + if (format != kBarcodeFormatPDF417) { + [NSException raise:NSInvalidArgumentException format:@"Can only encode PDF_417, but got %d", format]; + } + + ZXPDF417 *encoder = [[ZXPDF417 alloc] init]; + int margin = ZX_PDF417_WHITE_SPACE; + + if (hints != nil) { + encoder.compact = hints.pdf417Compact; + encoder.compaction = hints.pdf417Compaction; + if (hints.pdf417Dimensions != nil) { + ZXPDF417Dimensions *dimensions = hints.pdf417Dimensions; + [encoder setDimensionsWithMaxCols:dimensions.maxCols + minCols:dimensions.minCols + maxRows:dimensions.maxRows + minRows:dimensions.minRows]; + } + if (hints.margin) { + margin = [hints.margin intValue]; + } + if (hints.encoding > 0) { + encoder.encoding = hints.encoding; + } + } + + return [self bitMatrixFromEncoder:encoder contents:contents width:width height:height margin:margin error:error]; +} + +- (ZXBitMatrix *)encode:(NSString *)contents format:(ZXBarcodeFormat)format width:(int)width height:(int)height error:(NSError **)error { + return [self encode:contents format:format width:width height:height hints:nil error:error]; +} + +/** + * Takes encoder, accounts for width/height, and retrieves bit matrix + */ +- (ZXBitMatrix *)bitMatrixFromEncoder:(ZXPDF417 *)encoder + contents:(NSString *)contents + width:(int)width + height:(int)height + margin:(int)margin + error:(NSError **)error { + int errorCorrectionLevel = 2; + if (![encoder generateBarcodeLogic:contents errorCorrectionLevel:errorCorrectionLevel error:error]) { + return nil; + } + + int lineThickness = 2; + int aspectRatio = 4; + NSArray *originalScale = [[encoder barcodeMatrix] scaledMatrixWithXScale:lineThickness yScale:aspectRatio * lineThickness]; + BOOL rotated = NO; + if ((height > width) ^ ([(ZXByteArray *)originalScale[0] length] < [originalScale count])) { + originalScale = [self rotateArray:originalScale]; + rotated = YES; + } + + int scaleX = width / [(ZXByteArray *)originalScale[0] length]; + int scaleY = height / [originalScale count]; + + int scale; + if (scaleX < scaleY) { + scale = scaleX; + } else { + scale = scaleY; + } + + if (scale > 1) { + NSArray *scaledMatrix = + [[encoder barcodeMatrix] scaledMatrixWithXScale:scale * lineThickness yScale:scale * aspectRatio * lineThickness]; + if (rotated) { + scaledMatrix = [self rotateArray:scaledMatrix]; + } + return [self bitMatrixFrombitArray:scaledMatrix margin:margin]; + } + return [self bitMatrixFrombitArray:originalScale margin:margin]; +} + +/** + * This takes an array holding the values of the PDF 417 + * + * @param input a byte array of information with 0 is black, and 1 is white + * @param margin border around the barcode + * @return BitMatrix of the input + */ +- (ZXBitMatrix *)bitMatrixFrombitArray:(NSArray *)input margin:(int)margin { + // Creates the bitmatrix with extra space for whtespace + ZXBitMatrix *output = [[ZXBitMatrix alloc] initWithWidth:[(ZXByteArray *)input[0] length] + 2 * margin height:(int)[input count] + 2 * margin]; + [output clear]; + for (int y = 0, yOutput = output.height - margin; y < [input count]; y++, yOutput--) { + for (int x = 0; x < [(ZXByteArray *)input[0] length]; x++) { + // Zero is white in the bytematrix + if ([(ZXByteArray *)input[y] array][x] == 1) { + [output setX:x + margin y:yOutput]; + } + } + } + return output; +} + +/** + * Takes and rotates the it 90 degrees + */ +- (NSArray *)rotateArray:(NSArray *)bitarray { + NSMutableArray *temp = [NSMutableArray array]; + for (int i = 0; i < [(ZXByteArray *)bitarray[0] length]; i++) { + [temp addObject:[[ZXByteArray alloc] initWithLength:(unsigned int)[bitarray count]]]; + } + + for (int ii = 0; ii < [bitarray count]; ii++) { + // This makes the direction consistent on screen when rotating the + // screen; + int inverseii = (int)[bitarray count] - ii - 1; + for (int jj = 0; jj < [(ZXByteArray *)bitarray[0] length]; jj++) { + ZXByteArray *b = temp[jj]; + b.array[inverseii] = [(ZXByteArray *)bitarray[ii] array][jj]; + } + } + return temp; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/ZXingObjCPDF417.h b/iDearQRCode/Tools/ZXingObjC/pdf417/ZXingObjCPDF417.h new file mode 100755 index 0000000..2c77a80 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/ZXingObjCPDF417.h @@ -0,0 +1,34 @@ +/* + * Copyright 2014 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _ZXINGOBJC_PDF417_ + +#define _ZXINGOBJC_PDF417_ + +#import "ZXModulusGF.h" +#import "ZXPDF417.h" +#import "ZXPDF417BarcodeMatrix.h" +#import "ZXPDF417Common.h" +#import "ZXPDF417Detector.h" +#import "ZXPDF417DetectorResult.h" +#import "ZXPDF417Dimensions.h" +#import "ZXPDF417ECErrorCorrection.h" +#import "ZXPDF417Reader.h" +#import "ZXPDF417ResultMetadata.h" +#import "ZXPDF417ScanningDecoder.h" +#import "ZXPDF417Writer.h" + +#endif diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417BarcodeMetadata.h b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417BarcodeMetadata.h new file mode 100755 index 0000000..f2fb7d9 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417BarcodeMetadata.h @@ -0,0 +1,28 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@interface ZXPDF417BarcodeMetadata : NSObject + +@property (nonatomic, assign, readonly) int columnCount; +@property (nonatomic, assign, readonly) int errorCorrectionLevel; +@property (nonatomic, assign, readonly) int rowCountUpperPart; +@property (nonatomic, assign, readonly) int rowCountLowerPart; +@property (nonatomic, assign, readonly) int rowCount; + +- (id)initWithColumnCount:(int)columnCount rowCountUpperPart:(int)rowCountUpperPart rowCountLowerPart:(int)rowCountLowerPart + errorCorrectionLevel:(int)errorCorrectionLevel; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417BarcodeMetadata.m b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417BarcodeMetadata.m new file mode 100755 index 0000000..1173bbe --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417BarcodeMetadata.m @@ -0,0 +1,35 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXPDF417BarcodeMetadata.h" + +@implementation ZXPDF417BarcodeMetadata + +- (id)initWithColumnCount:(int)columnCount rowCountUpperPart:(int)rowCountUpperPart rowCountLowerPart:(int)rowCountLowerPart + errorCorrectionLevel:(int)errorCorrectionLevel { + self = [super init]; + if (self) { + _columnCount = columnCount; + _errorCorrectionLevel = errorCorrectionLevel; + _rowCountUpperPart = rowCountUpperPart; + _rowCountLowerPart = rowCountLowerPart; + _rowCount = rowCountUpperPart + rowCountLowerPart; + } + + return self; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417BarcodeValue.h b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417BarcodeValue.h new file mode 100755 index 0000000..76147a2 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417BarcodeValue.h @@ -0,0 +1,34 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXIntArray; + +@interface ZXPDF417BarcodeValue : NSObject + +/** + * Add an occurrence of a value + */ +- (void)setValue:(int)value; + +/** + * Determines the maximum occurrence of a set value and returns all values which were set with this occurrence. + * @return an array of int, containing the values with the highest occurrence, or null, if no value was set + */ +- (ZXIntArray *)value; + +- (NSNumber *)confidence:(int)value; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417BarcodeValue.m b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417BarcodeValue.m new file mode 100755 index 0000000..1f3aa03 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417BarcodeValue.m @@ -0,0 +1,67 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXPDF417BarcodeValue.h" +#import "ZXPDF417Common.h" + +@interface ZXPDF417BarcodeValue () + +@property (nonatomic, strong, readonly) NSMutableDictionary *values; + +@end + +@implementation ZXPDF417BarcodeValue + +- (id)init { + self = [super init]; + if (self) { + _values = [NSMutableDictionary dictionary]; + } + + return self; +} + +- (void)setValue:(int)value { + NSNumber *confidence = self.values[@(value)]; + if (!confidence) { + confidence = @0; + } + confidence = @([confidence intValue] + 1); + self.values[@(value)] = confidence; +} + +- (ZXIntArray *)value { + int maxConfidence = -1; + NSMutableArray *result = [NSMutableArray array]; + for (NSNumber *key in [self.values allKeys]) { + NSNumber *value = self.values[key]; + if ([value intValue] > maxConfidence) { + maxConfidence = [value intValue]; + [result removeAllObjects]; + [result addObject:key]; + } else if ([value intValue] == maxConfidence) { + [result addObject:key]; + } + } + NSArray *array = [[[result sortedArrayUsingSelector:@selector(compare:)] reverseObjectEnumerator] allObjects]; + return [ZXPDF417Common toIntArray:array]; +} + +- (NSNumber *)confidence:(int)value { + return self.values[@(value)]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417BoundingBox.h b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417BoundingBox.h new file mode 100755 index 0000000..da74a78 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417BoundingBox.h @@ -0,0 +1,37 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXBitMatrix, ZXResultPoint; + +@interface ZXPDF417BoundingBox : NSObject + +@property (nonatomic, assign, readonly) int minX; +@property (nonatomic, assign, readonly) int maxX; +@property (nonatomic, assign, readonly) int minY; +@property (nonatomic, assign, readonly) int maxY; +@property (nonatomic, strong, readonly) ZXResultPoint *topLeft; +@property (nonatomic, strong, readonly) ZXResultPoint *topRight; +@property (nonatomic, strong, readonly) ZXResultPoint *bottomLeft; +@property (nonatomic, strong, readonly) ZXResultPoint *bottomRight; + +- (id)initWithImage:(ZXBitMatrix *)image topLeft:(ZXResultPoint *)topLeft bottomLeft:(ZXResultPoint *)bottomLeft + topRight:(ZXResultPoint *)topRight bottomRight:(ZXResultPoint *)bottomRight; +- (id)initWithBoundingBox:(ZXPDF417BoundingBox *)boundingBox; + ++ (ZXPDF417BoundingBox *)mergeLeftBox:(ZXPDF417BoundingBox *)leftBox rightBox:(ZXPDF417BoundingBox *)rightBox; +- (ZXPDF417BoundingBox *)addMissingRows:(int)missingStartRows missingEndRows:(int)missingEndRows isLeft:(BOOL)isLeft; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417BoundingBox.m b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417BoundingBox.m new file mode 100755 index 0000000..54a2fa7 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417BoundingBox.m @@ -0,0 +1,135 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitMatrix.h" +#import "ZXPDF417BoundingBox.h" +#import "ZXResultPoint.h" + +@interface ZXPDF417BoundingBox () + +@property (nonatomic, strong, readonly) ZXBitMatrix *image; +@property (nonatomic, assign) int minX; +@property (nonatomic, assign) int maxX; +@property (nonatomic, assign) int minY; +@property (nonatomic, assign) int maxY; + +@end + +@implementation ZXPDF417BoundingBox + +- (id)initWithImage:(ZXBitMatrix *)image topLeft:(ZXResultPoint *)topLeft bottomLeft:(ZXResultPoint *)bottomLeft + topRight:(ZXResultPoint *)topRight bottomRight:(ZXResultPoint *)bottomRight { + if ((!topLeft && !topRight) || (!bottomLeft && !bottomRight) || + (topLeft && !bottomLeft) || (topRight && !bottomRight)) { + return nil; + } + + self = [super init]; + if (self) { + _image = image; + _topLeft = topLeft; + _bottomLeft = bottomLeft; + _topRight = topRight; + _bottomRight = bottomRight; + [self calculateMinMaxValues]; + } + + return self; +} + +- (id)initWithBoundingBox:(ZXPDF417BoundingBox *)boundingBox { + return [self initWithImage:boundingBox.image topLeft:boundingBox.topLeft bottomLeft:boundingBox.bottomLeft + topRight:boundingBox.topRight bottomRight:boundingBox.bottomRight]; +} + ++ (ZXPDF417BoundingBox *)mergeLeftBox:(ZXPDF417BoundingBox *)leftBox rightBox:(ZXPDF417BoundingBox *)rightBox { + if (!leftBox) { + return rightBox; + } + if (!rightBox) { + return leftBox; + } + return [[self alloc] initWithImage:leftBox.image topLeft:leftBox.topLeft bottomLeft:leftBox.bottomLeft + topRight:rightBox.topRight bottomRight:rightBox.bottomRight]; +} + +- (ZXPDF417BoundingBox *)addMissingRows:(int)missingStartRows missingEndRows:(int)missingEndRows isLeft:(BOOL)isLeft { + ZXResultPoint *newTopLeft = self.topLeft; + ZXResultPoint *newBottomLeft = self.bottomLeft; + ZXResultPoint *newTopRight = self.topRight; + ZXResultPoint *newBottomRight = self.bottomRight; + + if (missingStartRows > 0) { + ZXResultPoint *top = isLeft ? self.topLeft : self.topRight; + int newMinY = (int) top.y - missingStartRows; + if (newMinY < 0) { + newMinY = 0; + } + // TODO use existing points to better interpolate the new x positions + ZXResultPoint *newTop = [[ZXResultPoint alloc] initWithX:top.x y:newMinY]; + if (isLeft) { + newTopLeft = newTop; + } else { + newTopRight = newTop; + } + } + + if (missingEndRows > 0) { + ZXResultPoint *bottom = isLeft ? self.bottomLeft : self.bottomRight; + int newMaxY = (int) bottom.y + missingEndRows; + if (newMaxY >= self.image.height) { + newMaxY = self.image.height - 1; + } + // TODO use existing points to better interpolate the new x positions + ZXResultPoint *newBottom = [[ZXResultPoint alloc] initWithX:bottom.x y:newMaxY]; + if (isLeft) { + newBottomLeft = newBottom; + } else { + newBottomRight = newBottom; + } + } + [self calculateMinMaxValues]; + return [[ZXPDF417BoundingBox alloc] initWithImage:self.image topLeft:newTopLeft bottomLeft:newBottomLeft topRight:newTopRight bottomRight:newBottomRight]; +} + +- (void)calculateMinMaxValues { + if (!self.topLeft) { + _topLeft = [[ZXResultPoint alloc] initWithX:0 y:self.topRight.y]; + _bottomLeft = [[ZXResultPoint alloc] initWithX:0 y:self.bottomRight.y]; + } else if (!self.topRight) { + _topRight = [[ZXResultPoint alloc] initWithX:self.image.width - 1 y:self.topLeft.y]; + _bottomRight = [[ZXResultPoint alloc] initWithX:self.image.width - 1 y:self.bottomLeft.y]; + } + + self.minX = (int) MIN(self.topLeft.x, self.bottomLeft.x); + self.maxX = (int) MAX(self.topRight.x, self.bottomRight.x); + self.minY = (int) MIN(self.topLeft.y, self.topRight.y); + self.maxY = (int) MAX(self.bottomLeft.y, self.bottomRight.y); +} + +/* +- (void)setTopRight:(ZXResultPoint *)topRight { + _topRight = topRight; + [self calculateMinMaxValues]; +} + +- (void)setBottomRight:(ZXResultPoint *)bottomRight { + _bottomRight = bottomRight; + [self calculateMinMaxValues]; +} +*/ + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417Codeword.h b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417Codeword.h new file mode 100755 index 0000000..d64bf47 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417Codeword.h @@ -0,0 +1,31 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@interface ZXPDF417Codeword : NSObject + +@property (nonatomic, assign, readonly) int startX; +@property (nonatomic, assign, readonly) int endX; +@property (nonatomic, assign, readonly) int bucket; +@property (nonatomic, assign, readonly) int value; +@property (nonatomic, assign) int rowNumber; + +- (id)initWithStartX:(int)startX endX:(int)endX bucket:(int)bucket value:(int)value; +- (BOOL)hasValidRowNumber; +- (BOOL)isValidRowNumber:(int)rowNumber; +- (void)setRowNumberAsRowIndicatorColumn; +- (int)width; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417Codeword.m b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417Codeword.m new file mode 100755 index 0000000..45a624e --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417Codeword.m @@ -0,0 +1,56 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXPDF417Codeword.h" + +const int ZX_PDF417_BARCODE_ROW_UNKNOWN = -1; + +@implementation ZXPDF417Codeword + +- (id)initWithStartX:(int)startX endX:(int)endX bucket:(int)bucket value:(int)value { + self = [super init]; + if (self) { + _startX = startX; + _endX = endX; + _bucket = bucket; + _value = value; + _rowNumber = ZX_PDF417_BARCODE_ROW_UNKNOWN; + } + + return self; +} + +- (BOOL)hasValidRowNumber { + return [self isValidRowNumber:self.rowNumber]; +} + +- (BOOL)isValidRowNumber:(int)rowNumber { + return rowNumber != ZX_PDF417_BARCODE_ROW_UNKNOWN && self.bucket == (rowNumber % 3) * 3; +} + +- (void)setRowNumberAsRowIndicatorColumn { + self.rowNumber = (self.value / 30) * 3 + self.bucket / 3; +} + +- (int)width { + return self.endX - self.startX; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"%d|%d", self.rowNumber, self.value]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417CodewordDecoder.h b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417CodewordDecoder.h new file mode 100755 index 0000000..a50e347 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417CodewordDecoder.h @@ -0,0 +1,21 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@interface ZXPDF417CodewordDecoder : NSObject + ++ (int)decodedValue:(NSArray *)moduleBitCount; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417CodewordDecoder.m b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417CodewordDecoder.m new file mode 100755 index 0000000..2a3b823 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417CodewordDecoder.m @@ -0,0 +1,114 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXPDF417CodewordDecoder.h" +#import "ZXPDF417Common.h" + +static float ZX_PDF417_RATIOS_TABLE[ZX_PDF417_SYMBOL_TABLE_LEN][ZX_PDF417_BARS_IN_MODULE]; + +@implementation ZXPDF417CodewordDecoder + ++ (void)initialize { + if ([self class] != [ZXPDF417CodewordDecoder class]) return; + + // Pre-computes the symbol ratio table. + for (int i = 0; i < ZX_PDF417_SYMBOL_TABLE_LEN; i++) { + int currentSymbol = ZX_PDF417_SYMBOL_TABLE[i]; + int currentBit = currentSymbol & 0x1; + for (int j = 0; j < ZX_PDF417_BARS_IN_MODULE; j++) { + float size = 0.0f; + while ((currentSymbol & 0x1) == currentBit) { + size += 1.0f; + currentSymbol >>= 1; + } + currentBit = currentSymbol & 0x1; + ZX_PDF417_RATIOS_TABLE[i][ZX_PDF417_BARS_IN_MODULE - j - 1] = size / ZX_PDF417_MODULES_IN_CODEWORD; + } + } +} + ++ (int)decodedValue:(NSArray *)moduleBitCount { + int decodedValue = [self decodedCodewordValue:[self sampleBitCounts:moduleBitCount]]; + if (decodedValue != -1) { + return decodedValue; + } + return [self closestDecodedValue:moduleBitCount]; +} + ++ (NSArray *)sampleBitCounts:(NSArray *)moduleBitCount { + float bitCountSum = [ZXPDF417Common bitCountSum:moduleBitCount]; + NSMutableArray *result = [NSMutableArray arrayWithCapacity:ZX_PDF417_BARS_IN_MODULE]; + for (int i = 0; i < ZX_PDF417_BARS_IN_MODULE; i++) { + [result addObject:@0]; + } + + int bitCountIndex = 0; + int sumPreviousBits = 0; + for (int i = 0; i < ZX_PDF417_MODULES_IN_CODEWORD; i++) { + float sampleIndex = + bitCountSum / (2 * ZX_PDF417_MODULES_IN_CODEWORD) + + (i * bitCountSum) / ZX_PDF417_MODULES_IN_CODEWORD; + if (sumPreviousBits + [moduleBitCount[bitCountIndex] intValue] <= sampleIndex) { + sumPreviousBits += [moduleBitCount[bitCountIndex] intValue]; + bitCountIndex++; + } + result[bitCountIndex] = @([result[bitCountIndex] intValue] + 1); + } + return result; +} + ++ (int)decodedCodewordValue:(NSArray *)moduleBitCount { + int decodedValue = [self bitValue:moduleBitCount]; + return [ZXPDF417Common codeword:decodedValue] == -1 ? -1 : decodedValue; +} + ++ (int)bitValue:(NSArray *)moduleBitCount { + long result = 0; + for (int i = 0; i < [moduleBitCount count]; i++) { + for (int bit = 0; bit < [moduleBitCount[i] intValue]; bit++) { + result = (result << 1) | (i % 2 == 0 ? 1 : 0); + } + } + return (int) result; +} + ++ (int)closestDecodedValue:(NSArray *)moduleBitCount { + int bitCountSum = [ZXPDF417Common bitCountSum:moduleBitCount]; + float bitCountRatios[ZX_PDF417_BARS_IN_MODULE]; + for (int i = 0; i < ZX_PDF417_BARS_IN_MODULE; i++) { + bitCountRatios[i] = [moduleBitCount[i] intValue] / (float) bitCountSum; + } + float bestMatchError = MAXFLOAT; + int bestMatch = -1; + for (int j = 0; j < ZX_PDF417_SYMBOL_TABLE_LEN; j++) { + float error = 0.0f; + float *ratioTableRow = ZX_PDF417_RATIOS_TABLE[j]; + for (int k = 0; k < ZX_PDF417_BARS_IN_MODULE; k++) { + float diff = ratioTableRow[k] - bitCountRatios[k]; + error += diff * diff; + if (error >= bestMatchError) { + break; + } + } + if (error < bestMatchError) { + bestMatchError = error; + bestMatch = ZX_PDF417_SYMBOL_TABLE[j]; + } + } + return bestMatch; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417DecodedBitStreamParser.h b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417DecodedBitStreamParser.h new file mode 100755 index 0000000..a90df62 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417DecodedBitStreamParser.h @@ -0,0 +1,26 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXDecoderResult, ZXIntArray; + +/** + * This class contains the methods for decoding the PDF417 codewords. + */ +@interface ZXPDF417DecodedBitStreamParser : NSObject + ++ (ZXDecoderResult *)decode:(ZXIntArray *)codewords ecLevel:(NSString *)ecLevel error:(NSError **)error; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417DecodedBitStreamParser.m b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417DecodedBitStreamParser.m new file mode 100755 index 0000000..8a8d999 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417DecodedBitStreamParser.m @@ -0,0 +1,643 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXCharacterSetECI.h" +#import "ZXDecoderResult.h" +#import "ZXErrors.h" +#import "ZXIntArray.h" +#import "ZXPDF417DecodedBitStreamParser.h" +#import "ZXPDF417ResultMetadata.h" + +typedef enum { + ZXPDF417ModeAlpha = 0, + ZXPDF417ModeLower, + ZXPDF417ModeMixed, + ZXPDF417ModePunct, + ZXPDF417ModeAlphaShift, + ZXPDF417ModePunctShift +} ZXPDF417Mode; + +const int ZX_PDF417_TEXT_COMPACTION_MODE_LATCH = 900; +const int ZX_PDF417_BYTE_COMPACTION_MODE_LATCH = 901; +const int ZX_PDF417_NUMERIC_COMPACTION_MODE_LATCH = 902; +const int ZX_PDF417_BYTE_COMPACTION_MODE_LATCH_6 = 924; +const int ZX_PDF417_ECI_USER_DEFINED = 925; +const int ZX_PDF417_ECI_GENERAL_PURPOSE = 926; +const int ZX_PDF417_ECI_CHARSET = 927; +const int ZX_PDF417_BEGIN_MACRO_PDF417_CONTROL_BLOCK = 928; +const int ZX_PDF417_BEGIN_MACRO_PDF417_OPTIONAL_FIELD = 923; +const int ZX_PDF417_MACRO_PDF417_TERMINATOR = 922; +const int ZX_PDF417_MODE_SHIFT_TO_BYTE_COMPACTION_MODE = 913; +const int ZX_PDF417_MAX_NUMERIC_CODEWORDS = 15; + +const int ZX_PDF417_PL = 25; +const int ZX_PDF417_LL = 27; +const int ZX_PDF417_AS = 27; +const int ZX_PDF417_ML = 28; +const int ZX_PDF417_AL = 28; +const int ZX_PDF417_PS = 29; +const int ZX_PDF417_PAL = 29; + +const unichar ZX_PDF417_PUNCT_CHARS[] = { + ';', '<', '>', '@', '[', '\\', ']', '_', '`', '~', '!', + '\r', '\t', ',', ':', '\n', '-', '.', '$', '/', '"', '|', '*', + '(', ')', '?', '{', '}', '\''}; + +const unichar ZX_PDF417_MIXED_CHARS[] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '&', + '\r', '\t', ',', ':', '#', '-', '.', '$', '/', '+', '%', '*', + '=', '^'}; + +const int ZX_PDF417_NUMBER_OF_SEQUENCE_CODEWORDS = 2; + +const NSStringEncoding ZX_PDF417_DECODING_DEFAULT_ENCODING = NSISOLatin1StringEncoding; + +/** + * Table containing values for the exponent of 900. + * This is used in the numeric compaction decode algorithm. + */ +static NSArray *ZX_PDF417_EXP900 = nil; + +@implementation ZXPDF417DecodedBitStreamParser + ++ (void)initialize { + if ([self class] != [ZXPDF417DecodedBitStreamParser class]) return; + + NSMutableArray *exponents = [NSMutableArray arrayWithCapacity:16]; + [exponents addObject:[NSDecimalNumber one]]; + NSDecimalNumber *nineHundred = [NSDecimalNumber decimalNumberWithString:@"900"]; + [exponents addObject:nineHundred]; + for (int i = 2; i < 16; i++) { + [exponents addObject:[exponents[i - 1] decimalNumberByMultiplyingBy:nineHundred]]; + } + ZX_PDF417_EXP900 = [[NSArray alloc] initWithArray:exponents]; +} + ++ (ZXDecoderResult *)decode:(ZXIntArray *)codewords ecLevel:(NSString *)ecLevel error:(NSError **)error { + NSMutableString *result = [NSMutableString stringWithCapacity:codewords.length * 2]; + NSStringEncoding encoding = ZX_PDF417_DECODING_DEFAULT_ENCODING; + // Get compaction mode + int codeIndex = 1; + int code = codewords.array[codeIndex++]; + ZXPDF417ResultMetadata *resultMetadata = [[ZXPDF417ResultMetadata alloc] init]; + while (codeIndex < codewords.array[0]) { + switch (code) { + case ZX_PDF417_TEXT_COMPACTION_MODE_LATCH: + codeIndex = [self textCompaction:codewords codeIndex:codeIndex result:result]; + break; + case ZX_PDF417_BYTE_COMPACTION_MODE_LATCH: + case ZX_PDF417_BYTE_COMPACTION_MODE_LATCH_6: + codeIndex = [self byteCompaction:code codewords:codewords encoding:encoding codeIndex:codeIndex result:result]; + break; + case ZX_PDF417_MODE_SHIFT_TO_BYTE_COMPACTION_MODE: + [result appendFormat:@"%C", (unichar)codewords.array[codeIndex++]]; + break; + case ZX_PDF417_NUMERIC_COMPACTION_MODE_LATCH: + codeIndex = [self numericCompaction:codewords codeIndex:codeIndex result:result]; + if (codeIndex < 0) { + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + break; + case ZX_PDF417_ECI_CHARSET: { + ZXCharacterSetECI *charsetECI = + [ZXCharacterSetECI characterSetECIByValue:codewords.array[codeIndex++]]; + encoding = charsetECI.encoding; + break; + } + case ZX_PDF417_ECI_GENERAL_PURPOSE: + // Can't do anything with generic ECI; skip its 2 characters + codeIndex += 2; + break; + case ZX_PDF417_ECI_USER_DEFINED: + // Can't do anything with user ECI; skip its 1 character + codeIndex ++; + break; + case ZX_PDF417_BEGIN_MACRO_PDF417_CONTROL_BLOCK: + codeIndex = [self decodeMacroBlock:codewords codeIndex:codeIndex resultMetadata:resultMetadata]; + if (codeIndex < 0) { + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + break; + case ZX_PDF417_BEGIN_MACRO_PDF417_OPTIONAL_FIELD: + case ZX_PDF417_MACRO_PDF417_TERMINATOR: + // Should not see these outside a macro block + if (error) *error = ZXFormatErrorInstance(); + return nil; + default: + // Default to text compaction. During testing numerous barcodes + // appeared to be missing the starting mode. In these cases defaulting + // to text compaction seems to work. + codeIndex--; + codeIndex = [self textCompaction:codewords codeIndex:codeIndex result:result]; + break; + } + if (codeIndex < codewords.length) { + code = codewords.array[codeIndex++]; + } else { + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + } + if ([result length] == 0) { + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + ZXDecoderResult *decoderResult = [[ZXDecoderResult alloc] initWithRawBytes:nil text:result byteSegments:nil ecLevel:ecLevel]; + decoderResult.other = resultMetadata; + return decoderResult; +} + ++ (int)decodeMacroBlock:(ZXIntArray *)codewords codeIndex:(int)codeIndex resultMetadata:(ZXPDF417ResultMetadata *)resultMetadata { + if (codeIndex + ZX_PDF417_NUMBER_OF_SEQUENCE_CODEWORDS > codewords.array[0]) { + // we must have at least two bytes left for the segment index + return -1; + } + ZXIntArray *segmentIndexArray = [[ZXIntArray alloc] initWithLength:ZX_PDF417_NUMBER_OF_SEQUENCE_CODEWORDS]; + for (int i = 0; i < ZX_PDF417_NUMBER_OF_SEQUENCE_CODEWORDS; i++, codeIndex++) { + segmentIndexArray.array[i] = codewords.array[codeIndex]; + } + resultMetadata.segmentIndex = [[self decodeBase900toBase10:segmentIndexArray count:ZX_PDF417_NUMBER_OF_SEQUENCE_CODEWORDS] intValue]; + + NSMutableString *fileId = [NSMutableString string]; + codeIndex = [self textCompaction:codewords codeIndex:codeIndex result:fileId]; + resultMetadata.fileId = [NSString stringWithString:fileId]; + + if (codewords.array[codeIndex] == ZX_PDF417_BEGIN_MACRO_PDF417_OPTIONAL_FIELD) { + codeIndex++; + NSMutableArray *additionalOptionCodeWords = [NSMutableArray array]; + + BOOL end = NO; + while ((codeIndex < codewords.array[0]) && !end) { + int code = codewords.array[codeIndex++]; + if (code < ZX_PDF417_TEXT_COMPACTION_MODE_LATCH) { + [additionalOptionCodeWords addObject:@(code)]; + } else { + switch (code) { + case ZX_PDF417_MACRO_PDF417_TERMINATOR: + resultMetadata.lastSegment = YES; + codeIndex++; + end = YES; + break; + default: + return -1; + } + } + } + + resultMetadata.optionalData = additionalOptionCodeWords; + } else if (codewords.array[codeIndex] == ZX_PDF417_MACRO_PDF417_TERMINATOR) { + resultMetadata.lastSegment = YES; + codeIndex++; + } + + return codeIndex; +} + +/** + * Text Compaction mode (see 5.4.1.5) permits all printable ASCII characters to be + * encoded, i.e. values 32 - 126 inclusive in accordance with ISO/IEC 646 (IRV), as + * well as selected control characters. + * + * @param codewords The array of codewords (data + error) + * @param codeIndex The current index into the codeword array. + * @param result The decoded data is appended to the result. + * @return The next index into the codeword array. + */ ++ (int)textCompaction:(ZXIntArray *)codewords codeIndex:(int)codeIndex result:(NSMutableString *)result { + // 2 character per codeword + ZXIntArray *textCompactionData = [[ZXIntArray alloc] initWithLength:(codewords.array[0] - codeIndex) * 2]; + // Used to hold the byte compaction value if there is a mode shift + ZXIntArray *byteCompactionData = [[ZXIntArray alloc] initWithLength:(codewords.array[0] - codeIndex) * 2]; + + int index = 0; + BOOL end = NO; + while ((codeIndex < codewords.array[0]) && !end) { + int code = codewords.array[codeIndex++]; + if (code < ZX_PDF417_TEXT_COMPACTION_MODE_LATCH) { + textCompactionData.array[index] = code / 30; + textCompactionData.array[index + 1] = code % 30; + index += 2; + } else { + switch (code) { + case ZX_PDF417_TEXT_COMPACTION_MODE_LATCH: + // reinitialize text compaction mode to alpha sub mode + textCompactionData.array[index++] = ZX_PDF417_TEXT_COMPACTION_MODE_LATCH; + break; + case ZX_PDF417_BYTE_COMPACTION_MODE_LATCH: + case ZX_PDF417_BYTE_COMPACTION_MODE_LATCH_6: + case ZX_PDF417_NUMERIC_COMPACTION_MODE_LATCH: + case ZX_PDF417_BEGIN_MACRO_PDF417_CONTROL_BLOCK: + case ZX_PDF417_BEGIN_MACRO_PDF417_OPTIONAL_FIELD: + case ZX_PDF417_MACRO_PDF417_TERMINATOR: + codeIndex--; + end = YES; + break; + case ZX_PDF417_MODE_SHIFT_TO_BYTE_COMPACTION_MODE: + // The Mode Shift codeword 913 shall cause a temporary + // switch from Text Compaction mode to Byte Compaction mode. + // This switch shall be in effect for only the next codeword, + // after which the mode shall revert to the prevailing sub-mode + // of the Text Compaction mode. Codeword 913 is only available + // in Text Compaction mode; its use is described in 5.4.2.4. + textCompactionData.array[index] = ZX_PDF417_MODE_SHIFT_TO_BYTE_COMPACTION_MODE; + code = codewords.array[codeIndex++]; + byteCompactionData.array[index] = code; + index++; + break; + } + } + } + + [self decodeTextCompaction:textCompactionData byteCompactionData:byteCompactionData length:index result:result]; + return codeIndex; +} + +/** + * The Text Compaction mode includes all the printable ASCII characters + * (i.e. values from 32 to 126) and three ASCII control characters: HT or tab + * (ASCII value 9), LF or line feed (ASCII value 10), and CR or carriage + * return (ASCII value 13). The Text Compaction mode also includes various latch + * and shift characters which are used exclusively within the mode. The Text + * Compaction mode encodes up to 2 characters per codeword. The compaction rules + * for converting data into PDF417 codewords are defined in 5.4.2.2. The sub-mode + * switches are defined in 5.4.2.3. + * + * @param textCompactionData The text compaction data. + * @param byteCompactionData The byte compaction data if there + * was a mode shift. + * @param length The size of the text compaction and byte compaction data. + * @param result The decoded data is appended to the result. + */ ++ (void)decodeTextCompaction:(ZXIntArray *)textCompactionData byteCompactionData:(ZXIntArray *)byteCompactionData length:(unsigned int)length result:(NSMutableString *)result { + // Beginning from an initial state of the Alpha sub-mode + // The default compaction mode for PDF417 in effect at the start of each symbol shall always be Text + // Compaction mode Alpha sub-mode (uppercase alphabetic). A latch codeword from another mode to the Text + // Compaction mode shall always switch to the Text Compaction Alpha sub-mode. + ZXPDF417Mode subMode = ZXPDF417ModeAlpha; + ZXPDF417Mode priorToShiftMode = ZXPDF417ModeAlpha; + int i = 0; + while (i < length) { + int subModeCh = textCompactionData.array[i]; + unichar ch = 0; + switch (subMode) { + case ZXPDF417ModeAlpha: + // Alpha (uppercase alphabetic) + if (subModeCh < 26) { + // Upper case Alpha Character + ch = (unichar)('A' + subModeCh); + } else { + if (subModeCh == 26) { + ch = ' '; + } else if (subModeCh == ZX_PDF417_LL) { + subMode = ZXPDF417ModeLower; + } else if (subModeCh == ZX_PDF417_ML) { + subMode = ZXPDF417ModeMixed; + } else if (subModeCh == ZX_PDF417_PS) { + // Shift to punctuation + priorToShiftMode = subMode; + subMode = ZXPDF417ModePunctShift; + } else if (subModeCh == ZX_PDF417_MODE_SHIFT_TO_BYTE_COMPACTION_MODE) { + // TODO Does this need to use the current character encoding? See other occurrences below + [result appendFormat:@"%C", (unichar)byteCompactionData.array[i]]; + } else if (subModeCh == ZX_PDF417_TEXT_COMPACTION_MODE_LATCH) { + subMode = ZXPDF417ModeAlpha; + } + } + break; + + case ZXPDF417ModeLower: + // Lower (lowercase alphabetic) + if (subModeCh < 26) { + ch = (unichar)('a' + subModeCh); + } else { + if (subModeCh == 26) { + ch = ' '; + } else if (subModeCh == ZX_PDF417_AS) { + // Shift to alpha + priorToShiftMode = subMode; + subMode = ZXPDF417ModeAlphaShift; + } else if (subModeCh == ZX_PDF417_ML) { + subMode = ZXPDF417ModeMixed; + } else if (subModeCh == ZX_PDF417_PS) { + // Shift to punctuation + priorToShiftMode = subMode; + subMode = ZXPDF417ModePunctShift; + } else if (subModeCh == ZX_PDF417_MODE_SHIFT_TO_BYTE_COMPACTION_MODE) { + [result appendFormat:@"%C", (unichar)byteCompactionData.array[i]]; + } else if (subModeCh == ZX_PDF417_TEXT_COMPACTION_MODE_LATCH) { + subMode = ZXPDF417ModeAlpha; + } + } + break; + + case ZXPDF417ModeMixed: + // Mixed (numeric and some punctuation) + if (subModeCh < ZX_PDF417_PL) { + ch = ZX_PDF417_MIXED_CHARS[subModeCh]; + } else { + if (subModeCh == ZX_PDF417_PL) { + subMode = ZXPDF417ModePunct; + } else if (subModeCh == 26) { + ch = ' '; + } else if (subModeCh == ZX_PDF417_LL) { + subMode = ZXPDF417ModeLower; + } else if (subModeCh == ZX_PDF417_AL) { + subMode = ZXPDF417ModeAlpha; + } else if (subModeCh == ZX_PDF417_PS) { + // Shift to punctuation + priorToShiftMode = subMode; + subMode = ZXPDF417ModePunctShift; + } else if (subModeCh == ZX_PDF417_MODE_SHIFT_TO_BYTE_COMPACTION_MODE) { + [result appendFormat:@"%C", (unichar)byteCompactionData.array[i]]; + } else if (subModeCh == ZX_PDF417_TEXT_COMPACTION_MODE_LATCH) { + subMode = ZXPDF417ModeAlpha; + } + } + break; + + case ZXPDF417ModePunct: + // Punctuation + if (subModeCh < ZX_PDF417_PAL) { + ch = ZX_PDF417_PUNCT_CHARS[subModeCh]; + } else { + if (subModeCh == ZX_PDF417_PAL) { + subMode = ZXPDF417ModeAlpha; + } else if (subModeCh == ZX_PDF417_MODE_SHIFT_TO_BYTE_COMPACTION_MODE) { + [result appendFormat:@"%C", (unichar)byteCompactionData.array[i]]; + } else if (ZX_PDF417_TEXT_COMPACTION_MODE_LATCH) { + subMode = ZXPDF417ModeAlpha; + } + } + break; + + case ZXPDF417ModeAlphaShift: + // Restore sub-mode + subMode = priorToShiftMode; + if (subModeCh < 26) { + ch = (unichar)('A' + subModeCh); + } else { + if (subModeCh == 26) { + ch = ' '; + } else if (subModeCh == ZX_PDF417_TEXT_COMPACTION_MODE_LATCH) { + subMode = ZXPDF417ModeAlpha; + } + } + break; + + case ZXPDF417ModePunctShift: + // Restore sub-mode + subMode = priorToShiftMode; + if (subModeCh < ZX_PDF417_PAL) { + ch = ZX_PDF417_PUNCT_CHARS[subModeCh]; + } else { + if (subModeCh == ZX_PDF417_PAL) { + subMode = ZXPDF417ModeAlpha; + } else if (subModeCh == ZX_PDF417_MODE_SHIFT_TO_BYTE_COMPACTION_MODE) { + // PS before Shift-to-Byte is used as a padding character, + // see 5.4.2.4 of the specification + [result appendFormat:@"%C", (unichar)byteCompactionData.array[i]]; + } else if (subModeCh == ZX_PDF417_TEXT_COMPACTION_MODE_LATCH) { + subMode = ZXPDF417ModeAlpha; + } + } + break; + } + if (ch != 0) { + // Append decoded character to result + [result appendFormat:@"%C", ch]; + } + i++; + } +} + +/** + * Byte Compaction mode (see 5.4.3) permits all 256 possible 8-bit byte values to be encoded. + * This includes all ASCII characters value 0 to 127 inclusive and provides for international + * character set support. + * + * @param mode The byte compaction mode i.e. 901 or 924 + * @param codewords The array of codewords (data + error) + * @param encoding Currently active character encoding + * @param codeIndex The current index into the codeword array. + * @param result The decoded data is appended to the result. + * @return The next index into the codeword array. + */ ++ (int)byteCompaction:(int)mode + codewords:(ZXIntArray *)codewords + encoding:(NSStringEncoding)encoding + codeIndex:(int)codeIndex + result:(NSMutableString *)result { + NSMutableData *decodedBytes = [NSMutableData data]; + if (mode == ZX_PDF417_BYTE_COMPACTION_MODE_LATCH) { + // Total number of Byte Compaction characters to be encoded + // is not a multiple of 6 + int count = 0; + long long value = 0; + ZXIntArray *byteCompactedCodewords = [[ZXIntArray alloc] initWithLength:6]; + BOOL end = NO; + int nextCode = codewords.array[codeIndex++]; + while ((codeIndex < codewords.array[0]) && !end) { + byteCompactedCodewords.array[count++] = nextCode; + // Base 900 + value = 900 * value + nextCode; + nextCode = codewords.array[codeIndex++]; + // perhaps it should be ok to check only nextCode >= TEXT_COMPACTION_MODE_LATCH + if (nextCode == ZX_PDF417_TEXT_COMPACTION_MODE_LATCH || + nextCode == ZX_PDF417_BYTE_COMPACTION_MODE_LATCH || + nextCode == ZX_PDF417_NUMERIC_COMPACTION_MODE_LATCH || + nextCode == ZX_PDF417_BYTE_COMPACTION_MODE_LATCH_6 || + nextCode == ZX_PDF417_BEGIN_MACRO_PDF417_CONTROL_BLOCK || + nextCode == ZX_PDF417_BEGIN_MACRO_PDF417_OPTIONAL_FIELD || + nextCode == ZX_PDF417_MACRO_PDF417_TERMINATOR) { + codeIndex--; + end = YES; + } else { + if ((count % 5 == 0) && (count > 0)) { + // Decode every 5 codewords + // Convert to Base 256 + for (int j = 0; j < 6; ++j) { + int8_t byte = (int8_t) (value >> (8 * (5 - j))); + [decodedBytes appendBytes:&byte length:1]; + } + value = 0; + count = 0; + } + } + } + + // if the end of all codewords is reached the last codeword needs to be added + if (codeIndex == codewords.array[0] && nextCode < ZX_PDF417_TEXT_COMPACTION_MODE_LATCH) { + byteCompactedCodewords.array[count++] = nextCode; + } + + // If Byte Compaction mode is invoked with codeword 901, + // the last group of codewords is interpreted directly + // as one byte per codeword, without compaction. + for (int i = 0; i < count; i++) { + int8_t byte = (int8_t)byteCompactedCodewords.array[i]; + [decodedBytes appendBytes:&byte length:1]; + } + } else if (mode == ZX_PDF417_BYTE_COMPACTION_MODE_LATCH_6) { + // Total number of Byte Compaction characters to be encoded + // is an integer multiple of 6 + int count = 0; + long long value = 0; + BOOL end = NO; + while (codeIndex < codewords.array[0] && !end) { + int code = codewords.array[codeIndex++]; + if (code < ZX_PDF417_TEXT_COMPACTION_MODE_LATCH) { + count++; + // Base 900 + value = 900 * value + code; + } else { + if (code == ZX_PDF417_TEXT_COMPACTION_MODE_LATCH || + code == ZX_PDF417_BYTE_COMPACTION_MODE_LATCH || + code == ZX_PDF417_NUMERIC_COMPACTION_MODE_LATCH || + code == ZX_PDF417_BYTE_COMPACTION_MODE_LATCH_6 || + code == ZX_PDF417_BEGIN_MACRO_PDF417_CONTROL_BLOCK || + code == ZX_PDF417_BEGIN_MACRO_PDF417_OPTIONAL_FIELD || + code == ZX_PDF417_MACRO_PDF417_TERMINATOR) { + codeIndex--; + end = YES; + } + } + if ((count % 5 == 0) && (count > 0)) { + // Decode every 5 codewords + // Convert to Base 256 + for (int j = 0; j < 6; ++j) { + int8_t byte = (int8_t) (value >> (8 * (5 - j))); + [decodedBytes appendBytes:&byte length:1]; + } + value = 0; + count = 0; + } + } + } + [result appendString:[[NSString alloc] initWithData:decodedBytes encoding:encoding]]; + return codeIndex; +} + +/** + * Numeric Compaction mode (see 5.4.4) permits efficient encoding of numeric data strings. + * + * @param codewords The array of codewords (data + error) + * @param codeIndex The current index into the codeword array. + * @param result The decoded data is appended to the result. + * @return The next index into the codeword array. + */ ++ (int)numericCompaction:(ZXIntArray *)codewords codeIndex:(int)codeIndex result:(NSMutableString *)result { + int count = 0; + BOOL end = NO; + + ZXIntArray *numericCodewords = [[ZXIntArray alloc] initWithLength:ZX_PDF417_MAX_NUMERIC_CODEWORDS]; + + while (codeIndex < codewords.array[0] && !end) { + int code = codewords.array[codeIndex++]; + if (codeIndex == codewords.array[0]) { + end = YES; + } + if (code < ZX_PDF417_TEXT_COMPACTION_MODE_LATCH) { + numericCodewords.array[count] = code; + count++; + } else { + if (code == ZX_PDF417_TEXT_COMPACTION_MODE_LATCH || + code == ZX_PDF417_BYTE_COMPACTION_MODE_LATCH || + code == ZX_PDF417_BYTE_COMPACTION_MODE_LATCH_6 || + code == ZX_PDF417_BEGIN_MACRO_PDF417_CONTROL_BLOCK || + code == ZX_PDF417_BEGIN_MACRO_PDF417_OPTIONAL_FIELD || + code == ZX_PDF417_MACRO_PDF417_TERMINATOR) { + codeIndex--; + end = YES; + } + } + if (count % ZX_PDF417_MAX_NUMERIC_CODEWORDS == 0 || + code == ZX_PDF417_NUMERIC_COMPACTION_MODE_LATCH || + end) { + // Re-invoking Numeric Compaction mode (by using codeword 902 + // while in Numeric Compaction mode) serves to terminate the + // current Numeric Compaction mode grouping as described in 5.4.4.2, + // and then to start a new one grouping. + if (count > 0) { + NSString *s = [self decodeBase900toBase10:numericCodewords count:count]; + if (s == nil) { + return -1; + } + [result appendString:s]; + count = 0; + } + } + } + return codeIndex; +} + +/** + * Convert a list of Numeric Compacted codewords from Base 900 to Base 10. + * + * @param codewords The array of codewords + * @param count The number of codewords + * @return The decoded string representing the Numeric data. + */ +/* + EXAMPLE + Encode the fifteen digit numeric string 000213298174000 + Prefix the numeric string with a 1 and set the initial value of + t = 1 000 213 298 174 000 + Calculate codeword 0 + d0 = 1 000 213 298 174 000 mod 900 = 200 + + t = 1 000 213 298 174 000 div 900 = 1 111 348 109 082 + Calculate codeword 1 + d1 = 1 111 348 109 082 mod 900 = 282 + + t = 1 111 348 109 082 div 900 = 1 234 831 232 + Calculate codeword 2 + d2 = 1 234 831 232 mod 900 = 632 + + t = 1 234 831 232 div 900 = 1 372 034 + Calculate codeword 3 + d3 = 1 372 034 mod 900 = 434 + + t = 1 372 034 div 900 = 1 524 + Calculate codeword 4u + d4 = 1 524 mod 900 = 624 + + t = 1 524 div 900 = 1 + Calculate codeword 5 + d5 = 1 mod 900 = 1 + t = 1 div 900 = 0 + Codeword sequence is: 1, 624, 434, 632, 282, 200 + + Decode the above codewords involves + 1 x 900 power of 5 + 624 x 900 power of 4 + 434 x 900 power of 3 + + 632 x 900 power of 2 + 282 x 900 power of 1 + 200 x 900 power of 0 = 1000213298174000 + + Remove leading 1 => Result is 000213298174000 + */ ++ (NSString *)decodeBase900toBase10:(ZXIntArray *)codewords count:(int)count { + NSDecimalNumber *result = [NSDecimalNumber zero]; + for (int i = 0; i < count; i++) { + result = [result decimalNumberByAdding:[ZX_PDF417_EXP900[count - i - 1] decimalNumberByMultiplyingBy:[NSDecimalNumber decimalNumberWithDecimal:[@(codewords.array[i]) decimalValue]]]]; + } + NSString *resultString = [result stringValue]; + if (![resultString hasPrefix:@"1"]) { + return nil; + } + return [resultString substringFromIndex:1]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417DetectionResult.h b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417DetectionResult.h new file mode 100755 index 0000000..33c9d44 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417DetectionResult.h @@ -0,0 +1,31 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXPDF417BoundingBox, ZXPDF417DetectionResultColumn; + +@interface ZXPDF417DetectionResult : NSObject + +@property (nonatomic, strong) ZXPDF417BoundingBox *boundingBox; + +- (id)initWithBarcodeMetadata:(ZXPDF417BarcodeMetadata *)barcodeMetadata boundingBox:(ZXPDF417BoundingBox *)boundingBox; +- (NSArray *)detectionResultColumns; +- (int)barcodeColumnCount; +- (int)barcodeRowCount; +- (int)barcodeECLevel; +- (void)setDetectionResultColumn:(int)barcodeColumn detectionResultColumn:(ZXPDF417DetectionResultColumn *)detectionResultColumn; +- (ZXPDF417DetectionResultColumn *)detectionResultColumn:(int)barcodeColumn; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417DetectionResult.m b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417DetectionResult.m new file mode 100755 index 0000000..ddf1147 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417DetectionResult.m @@ -0,0 +1,303 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXPDF417BarcodeMetadata.h" +#import "ZXPDF417BoundingBox.h" +#import "ZXPDF417Codeword.h" +#import "ZXPDF417Common.h" +#import "ZXPDF417DetectionResult.h" +#import "ZXPDF417DetectionResultColumn.h" +#import "ZXPDF417DetectionResultRowIndicatorColumn.h" + +const int ZX_PDF417_ADJUST_ROW_NUMBER_SKIP = 2; + +@interface ZXPDF417DetectionResult () + +@property (nonatomic, strong, readonly) ZXPDF417BarcodeMetadata *barcodeMetadata; +@property (nonatomic, strong, readonly) NSMutableArray *detectionResultColumnsInternal; +@property (nonatomic, assign, readonly) int barcodeColumnCount; + +@end + +@implementation ZXPDF417DetectionResult + +- (id)initWithBarcodeMetadata:(ZXPDF417BarcodeMetadata *)barcodeMetadata boundingBox:(ZXPDF417BoundingBox *)boundingBox { + self = [super init]; + if (self) { + _barcodeMetadata = barcodeMetadata; + _barcodeColumnCount = barcodeMetadata.columnCount; + _boundingBox = boundingBox; + _detectionResultColumnsInternal = [NSMutableArray arrayWithCapacity:_barcodeColumnCount + 2]; + for (int i = 0; i < _barcodeColumnCount + 2; i++) { + [_detectionResultColumnsInternal addObject:[NSNull null]]; + } + } + + return self; +} + +- (NSArray *)detectionResultColumns { + [self adjustIndicatorColumnRowNumbers:self.detectionResultColumnsInternal[0]]; + [self adjustIndicatorColumnRowNumbers:self.detectionResultColumnsInternal[self.barcodeColumnCount + 1]]; + int unadjustedCodewordCount = ZX_PDF417_MAX_CODEWORDS_IN_BARCODE; + int previousUnadjustedCount; + do { + previousUnadjustedCount = unadjustedCodewordCount; + unadjustedCodewordCount = [self adjustRowNumbers]; + } while (unadjustedCodewordCount > 0 && unadjustedCodewordCount < previousUnadjustedCount); + return self.detectionResultColumnsInternal; +} + +- (void)adjustIndicatorColumnRowNumbers:(ZXPDF417DetectionResultColumn *)detectionResultColumn { + if (detectionResultColumn && (id)detectionResultColumn != [NSNull null]) { + [(ZXPDF417DetectionResultRowIndicatorColumn *)detectionResultColumn adjustCompleteIndicatorColumnRowNumbers:self.barcodeMetadata]; + } +} + +// TODO ensure that no detected codewords with unknown row number are left +// we should be able to estimate the row height and use it as a hint for the row number +// we should also fill the rows top to bottom and bottom to top +/** + * @return number of codewords which don't have a valid row number. Note that the count is not accurate as codewords + * will be counted several times. It just serves as an indicator to see when we can stop adjusting row numbers + */ +- (int)adjustRowNumbers { + int unadjustedCount = [self adjustRowNumbersByRow]; + if (unadjustedCount == 0) { + return 0; + } + for (int barcodeColumn = 1; barcodeColumn < self.barcodeColumnCount + 1; barcodeColumn++) { + NSArray *codewords = [self.detectionResultColumnsInternal[barcodeColumn] codewords]; + for (int codewordsRow = 0; codewordsRow < [codewords count]; codewordsRow++) { + if ((id)codewords[codewordsRow] == [NSNull null]) { + continue; + } + if (![codewords[codewordsRow] hasValidRowNumber]) { + [self adjustRowNumbers:barcodeColumn codewordsRow:codewordsRow codewords:codewords]; + } + } + } + return unadjustedCount; +} + +- (int)adjustRowNumbersByRow { + [self adjustRowNumbersFromBothRI]; + // TODO we should only do full row adjustments if row numbers of left and right row indicator column match. + // Maybe it's even better to calculated the height (in codeword rows) and divide it by the number of barcode + // rows. This, together with the LRI and RRI row numbers should allow us to get a good estimate where a row + // number starts and ends. + int unadjustedCount = [self adjustRowNumbersFromLRI]; + return unadjustedCount + [self adjustRowNumbersFromRRI]; +} + +- (void)adjustRowNumbersFromBothRI { + if (self.detectionResultColumnsInternal[0] == [NSNull null] || self.detectionResultColumnsInternal[self.barcodeColumnCount + 1] == [NSNull null]) { + return; + } + NSArray *LRIcodewords = [(ZXPDF417DetectionResultColumn *)self.detectionResultColumnsInternal[0] codewords]; + NSArray *RRIcodewords = [(ZXPDF417DetectionResultColumn *)self.detectionResultColumnsInternal[self.barcodeColumnCount + 1] codewords]; + for (int codewordsRow = 0; codewordsRow < [LRIcodewords count]; codewordsRow++) { + if (LRIcodewords[codewordsRow] != [NSNull null] && + RRIcodewords[codewordsRow] != [NSNull null] && + [(ZXPDF417Codeword *)LRIcodewords[codewordsRow] rowNumber] == [(ZXPDF417Codeword *)RRIcodewords[codewordsRow] rowNumber]) { + for (int barcodeColumn = 1; barcodeColumn <= self.barcodeColumnCount; barcodeColumn++) { + ZXPDF417Codeword *codeword = [(ZXPDF417DetectionResultColumn *)self.detectionResultColumnsInternal[barcodeColumn] codewords][codewordsRow]; + if ((id)codeword == [NSNull null]) { + continue; + } + codeword.rowNumber = [(ZXPDF417Codeword *)LRIcodewords[codewordsRow] rowNumber]; + if (![codeword hasValidRowNumber]) { + [(ZXPDF417DetectionResultColumn *)self.detectionResultColumnsInternal[barcodeColumn] codewords][codewordsRow] = [NSNull null]; + } + } + } + } +} + +- (int)adjustRowNumbersFromRRI { + if (self.detectionResultColumnsInternal[self.barcodeColumnCount + 1] == [NSNull null]) { + return 0; + } + int unadjustedCount = 0; + NSArray *codewords = [self.detectionResultColumnsInternal[self.barcodeColumnCount + 1] codewords]; + for (int codewordsRow = 0; codewordsRow < [codewords count]; codewordsRow++) { + if ((id)codewords[codewordsRow] == [NSNull null]) { + continue; + } + int rowIndicatorRowNumber = [codewords[codewordsRow] rowNumber]; + int invalidRowCounts = 0; + for (int barcodeColumn = self.barcodeColumnCount + 1; barcodeColumn > 0 && invalidRowCounts < ZX_PDF417_ADJUST_ROW_NUMBER_SKIP; barcodeColumn--) { + if (self.detectionResultColumnsInternal[barcodeColumn] != [NSNull null]) { + ZXPDF417Codeword *codeword = [self.detectionResultColumnsInternal[barcodeColumn] codewords][codewordsRow]; + if ((id)codeword != [NSNull null]) { + invalidRowCounts = [self adjustRowNumberIfValid:rowIndicatorRowNumber invalidRowCounts:invalidRowCounts codeword:codeword]; + if (![codeword hasValidRowNumber]) { + unadjustedCount++; + } + } + } + } + } + return unadjustedCount; +} + +- (int)adjustRowNumbersFromLRI { + if (self.detectionResultColumnsInternal[0] == [NSNull null]) { + return 0; + } + int unadjustedCount = 0; + NSArray *codewords = [self.detectionResultColumnsInternal[0] codewords]; + for (int codewordsRow = 0; codewordsRow < [codewords count]; codewordsRow++) { + if ((id)codewords[codewordsRow] == [NSNull null]) { + continue; + } + int rowIndicatorRowNumber = [codewords[codewordsRow] rowNumber]; + int invalidRowCounts = 0; + for (int barcodeColumn = 1; barcodeColumn < self.barcodeColumnCount + 1 && invalidRowCounts < ZX_PDF417_ADJUST_ROW_NUMBER_SKIP; barcodeColumn++) { + if (self.detectionResultColumnsInternal[barcodeColumn] != [NSNull null]) { + ZXPDF417Codeword *codeword = [self.detectionResultColumnsInternal[barcodeColumn] codewords][codewordsRow]; + if ((id)codeword != [NSNull null]) { + invalidRowCounts = [self adjustRowNumberIfValid:rowIndicatorRowNumber invalidRowCounts:invalidRowCounts codeword:codeword]; + if (![codeword hasValidRowNumber]) { + unadjustedCount++; + } + } + } + } + } + return unadjustedCount; +} + +- (int)adjustRowNumberIfValid:(int)rowIndicatorRowNumber invalidRowCounts:(int)invalidRowCounts codeword:(ZXPDF417Codeword *)codeword { + if (!codeword) { + return invalidRowCounts; + } + if (![codeword hasValidRowNumber]) { + if ([codeword isValidRowNumber:rowIndicatorRowNumber]) { + [codeword setRowNumber:rowIndicatorRowNumber]; + invalidRowCounts = 0; + } else { + ++invalidRowCounts; + } + } + return invalidRowCounts; +} + +- (void)adjustRowNumbers:(int)barcodeColumn codewordsRow:(int)codewordsRow codewords:(NSArray *)codewords { + ZXPDF417Codeword *codeword = codewords[codewordsRow]; + NSArray *previousColumnCodewords = [self.detectionResultColumnsInternal[barcodeColumn - 1] codewords]; + NSArray *nextColumnCodewords = previousColumnCodewords; + if (self.detectionResultColumnsInternal[barcodeColumn + 1] != [NSNull null]) { + nextColumnCodewords = [self.detectionResultColumnsInternal[barcodeColumn + 1] codewords]; + } + + NSMutableArray *otherCodewords = [NSMutableArray arrayWithCapacity:14]; + for (int i = 0; i < 14; i++) { + [otherCodewords addObject:[NSNull null]]; + } + + otherCodewords[2] = previousColumnCodewords[codewordsRow]; + otherCodewords[3] = nextColumnCodewords[codewordsRow]; + + if (codewordsRow > 0) { + otherCodewords[0] = codewords[codewordsRow - 1]; + otherCodewords[4] = previousColumnCodewords[codewordsRow - 1]; + otherCodewords[5] = nextColumnCodewords[codewordsRow - 1]; + } + if (codewordsRow > 1) { + otherCodewords[8] = codewords[codewordsRow - 2]; + otherCodewords[10] = previousColumnCodewords[codewordsRow - 2]; + otherCodewords[11] = nextColumnCodewords[codewordsRow - 2]; + } + if (codewordsRow < [codewords count] - 1) { + otherCodewords[1] = codewords[codewordsRow + 1]; + otherCodewords[6] = previousColumnCodewords[codewordsRow + 1]; + otherCodewords[7] = nextColumnCodewords[codewordsRow + 1]; + } + if (codewordsRow < [codewords count] - 2) { + otherCodewords[9] = codewords[codewordsRow + 2]; + otherCodewords[12] = previousColumnCodewords[codewordsRow + 2]; + otherCodewords[13] = nextColumnCodewords[codewordsRow + 2]; + } + for (ZXPDF417Codeword *otherCodeword in otherCodewords) { + if ([self adjustRowNumber:codeword otherCodeword:otherCodeword]) { + return; + } + } +} + +/** + * @return true, if row number was adjusted, false otherwise + */ +- (BOOL)adjustRowNumber:(ZXPDF417Codeword *)codeword otherCodeword:(ZXPDF417Codeword *)otherCodeword { + if ((id)otherCodeword == [NSNull null]) { + return NO; + } + if ([otherCodeword hasValidRowNumber] && otherCodeword.bucket == codeword.bucket) { + [codeword setRowNumber:otherCodeword.rowNumber]; + return YES; + } + return NO; +} + +- (int)barcodeRowCount { + return self.barcodeMetadata.rowCount; +} + +- (int)barcodeECLevel { + return self.barcodeMetadata.errorCorrectionLevel; +} + +- (void)setDetectionResultColumn:(int)barcodeColumn detectionResultColumn:(ZXPDF417DetectionResultColumn *)detectionResultColumn { + if (!detectionResultColumn) { + self.detectionResultColumnsInternal[barcodeColumn] = [NSNull null]; + } else { + self.detectionResultColumnsInternal[barcodeColumn] = detectionResultColumn; + } +} + +- (ZXPDF417DetectionResultColumn *)detectionResultColumn:(int)barcodeColumn { + ZXPDF417DetectionResultColumn *result = self.detectionResultColumnsInternal[barcodeColumn]; + return (id)result == [NSNull null] ? nil : result; +} + +- (NSString *)description { + ZXPDF417DetectionResultColumn *rowIndicatorColumn = self.detectionResultColumnsInternal[0]; + if ((id)rowIndicatorColumn == [NSNull null]) { + rowIndicatorColumn = self.detectionResultColumnsInternal[self.barcodeColumnCount + 1]; + } + NSMutableString *result = [NSMutableString string]; + for (int codewordsRow = 0; codewordsRow < [rowIndicatorColumn.codewords count]; codewordsRow++) { + [result appendFormat:@"CW %3d:", codewordsRow]; + for (int barcodeColumn = 0; barcodeColumn < self.barcodeColumnCount + 2; barcodeColumn++) { + if (self.detectionResultColumnsInternal[barcodeColumn] == [NSNull null]) { + [result appendString:@" | "]; + continue; + } + ZXPDF417Codeword *codeword = [(ZXPDF417DetectionResultColumn *)self.detectionResultColumnsInternal[barcodeColumn] codewords][codewordsRow]; + if ((id)codeword == [NSNull null]) { + [result appendString:@" | "]; + continue; + } + [result appendFormat:@" %3d|%3d", codeword.rowNumber, codeword.value]; + } + [result appendString:@"\n"]; + } + + return [NSString stringWithString:result]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417DetectionResultColumn.h b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417DetectionResultColumn.h new file mode 100755 index 0000000..3a63cd9 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417DetectionResultColumn.h @@ -0,0 +1,30 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXPDF417BoundingBox, ZXPDF417Codeword; + +@interface ZXPDF417DetectionResultColumn : NSObject + +@property (nonatomic, strong, readonly) ZXPDF417BoundingBox *boundingBox; +@property (nonatomic, strong, readonly) NSMutableArray *codewords; + +- (id)initWithBoundingBox:(ZXPDF417BoundingBox *)boundingBox; +- (ZXPDF417Codeword *)codewordNearby:(int)imageRow; +- (int)imageRowToCodewordIndex:(int)imageRow; +- (void)setCodeword:(int)imageRow codeword:(ZXPDF417Codeword *)codeword; +- (ZXPDF417Codeword *)codeword:(int)imageRow; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417DetectionResultColumn.m b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417DetectionResultColumn.m new file mode 100755 index 0000000..88efbab --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417DetectionResultColumn.m @@ -0,0 +1,91 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXPDF417BoundingBox.h" +#import "ZXPDF417Codeword.h" +#import "ZXPDF417DetectionResultColumn.h" + +const int ZX_PDF417_MAX_NEARBY_DISTANCE = 5; + +@implementation ZXPDF417DetectionResultColumn + +- (id)initWithBoundingBox:(ZXPDF417BoundingBox *)boundingBox { + self = [super init]; + if (self) { + _boundingBox = [[ZXPDF417BoundingBox alloc] initWithBoundingBox:boundingBox]; + _codewords = [NSMutableArray array]; + for (int i = 0; i < boundingBox.maxY - boundingBox.minY + 1; i++) { + [_codewords addObject:[NSNull null]]; + } + } + + return self; +} + +- (ZXPDF417Codeword *)codewordNearby:(int)imageRow { + ZXPDF417Codeword *codeword = [self codeword:imageRow]; + if (codeword) { + return codeword; + } + for (int i = 1; i < ZX_PDF417_MAX_NEARBY_DISTANCE; i++) { + int nearImageRow = [self imageRowToCodewordIndex:imageRow] - i; + if (nearImageRow >= 0) { + codeword = self.codewords[nearImageRow]; + if ((id)codeword != [NSNull null]) { + return codeword; + } + } + nearImageRow = [self imageRowToCodewordIndex:imageRow] + i; + if (nearImageRow < [self.codewords count]) { + codeword = self.codewords[nearImageRow]; + if ((id)codeword != [NSNull null]) { + return codeword; + } + } + } + return nil; +} + +- (int)imageRowToCodewordIndex:(int)imageRow { + return imageRow - self.boundingBox.minY; +} + +- (void)setCodeword:(int)imageRow codeword:(ZXPDF417Codeword *)codeword { + _codewords[[self imageRowToCodewordIndex:imageRow]] = codeword; +} + +- (ZXPDF417Codeword *)codeword:(int)imageRow { + NSUInteger index = [self imageRowToCodewordIndex:imageRow]; + if (_codewords[index] == [NSNull null]) { + return nil; + } + return _codewords[index]; +} + +- (NSString *)description { + NSMutableString *result = [NSMutableString string]; + int row = 0; + for (ZXPDF417Codeword *codeword in self.codewords) { + if ((id)codeword == [NSNull null]) { + [result appendFormat:@"%3d: | \n", row++]; + continue; + } + [result appendFormat:@"%3d: %3d|%3d\n", row++, codeword.rowNumber, codeword.value]; + } + return [NSString stringWithString:result]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417DetectionResultRowIndicatorColumn.h b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417DetectionResultRowIndicatorColumn.h new file mode 100755 index 0000000..a20b039 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417DetectionResultRowIndicatorColumn.h @@ -0,0 +1,30 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXPDF417DetectionResultColumn.h" + +@class ZXIntArray, ZXPDF417BarcodeMetadata, ZXPDF417BoundingBox; + +@interface ZXPDF417DetectionResultRowIndicatorColumn : ZXPDF417DetectionResultColumn + +@property (nonatomic, assign, readonly) BOOL isLeft; + +- (id)initWithBoundingBox:(ZXPDF417BoundingBox *)boundingBox isLeft:(BOOL)isLeft; +- (BOOL)getRowHeights:(ZXIntArray **)rowHeights; +- (int)adjustCompleteIndicatorColumnRowNumbers:(ZXPDF417BarcodeMetadata *)barcodeMetadata; +- (ZXPDF417BarcodeMetadata *)barcodeMetadata; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417DetectionResultRowIndicatorColumn.m b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417DetectionResultRowIndicatorColumn.m new file mode 100755 index 0000000..05a5a03 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417DetectionResultRowIndicatorColumn.m @@ -0,0 +1,265 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXIntArray.h" +#import "ZXPDF417BarcodeMetadata.h" +#import "ZXPDF417BarcodeValue.h" +#import "ZXPDF417BoundingBox.h" +#import "ZXPDF417Codeword.h" +#import "ZXPDF417Common.h" +#import "ZXPDF417DetectionResult.h" +#import "ZXPDF417DetectionResultRowIndicatorColumn.h" +#import "ZXResultPoint.h" + +@implementation ZXPDF417DetectionResultRowIndicatorColumn + +- (id)initWithBoundingBox:(ZXPDF417BoundingBox *)boundingBox isLeft:(BOOL)isLeft { + self = [super initWithBoundingBox:boundingBox]; + if (self) { + _isLeft = isLeft; + } + + return self; +} + +- (void)setRowNumbers { + for (ZXPDF417Codeword *codeword in [self codewords]) { + if ((id)codeword != [NSNull null]) { + [codeword setRowNumberAsRowIndicatorColumn]; + } + } +} + +// TODO implement properly +// TODO maybe we should add missing codewords to store the correct row number to make +// finding row numbers for other columns easier +// use row height count to make detection of invalid row numbers more reliable +- (int)adjustCompleteIndicatorColumnRowNumbers:(ZXPDF417BarcodeMetadata *)barcodeMetadata { + [self setRowNumbers]; + [self removeIncorrectCodewords:barcodeMetadata]; + ZXResultPoint *top = self.isLeft ? self.boundingBox.topLeft : self.boundingBox.topRight; + ZXResultPoint *bottom = self.isLeft ? self.boundingBox.bottomLeft : self.boundingBox.bottomRight; + int firstRow = [self imageRowToCodewordIndex:(int) top.y]; + int lastRow = [self imageRowToCodewordIndex:(int) bottom.y]; + // We need to be careful using the average row height. Barcode could be skewed so that we have smaller and + // taller rows + float averageRowHeight = (lastRow - firstRow) / (float) barcodeMetadata.rowCount; + int barcodeRow = -1; + int maxRowHeight = 1; + int currentRowHeight = 0; + for (int codewordsRow = firstRow; codewordsRow < lastRow; codewordsRow++) { + if (self.codewords[codewordsRow] == [NSNull null]) { + continue; + } + ZXPDF417Codeword *codeword = self.codewords[codewordsRow]; + + // float expectedRowNumber = (codewordsRow - firstRow) / averageRowHeight; + // if (Math.abs(codeword.getRowNumber() - expectedRowNumber) > 2) { + // SimpleLog.log(LEVEL.WARNING, + // "Removing codeword, rowNumberSkew too high, codeword[" + codewordsRow + "]: Expected Row: " + + // expectedRowNumber + ", RealRow: " + codeword.getRowNumber() + ", value: " + codeword.getValue()); + // codewords[codewordsRow] = null; + // } + + int rowDifference = codeword.rowNumber - barcodeRow; + + // TODO improve handling with case where first row indicator doesn't start with 0 + + if (rowDifference == 0) { + currentRowHeight++; + } else if (rowDifference == 1) { + maxRowHeight = MAX(maxRowHeight, currentRowHeight); + currentRowHeight = 1; + barcodeRow = codeword.rowNumber; + } else if (rowDifference < 0 || + codeword.rowNumber >= barcodeMetadata.rowCount || + rowDifference > codewordsRow) { + self.codewords[codewordsRow] = [NSNull null]; + } else { + int checkedRows; + if (maxRowHeight > 2) { + checkedRows = (maxRowHeight - 2) * rowDifference; + } else { + checkedRows = rowDifference; + } + BOOL closePreviousCodewordFound = checkedRows >= codewordsRow; + for (int i = 1; i <= checkedRows && !closePreviousCodewordFound; i++) { + // there must be (height * rowDifference) number of codewords missing. For now we assume height = 1. + // This should hopefully get rid of most problems already. + closePreviousCodewordFound = self.codewords[codewordsRow - i] != [NSNull null]; + } + if (closePreviousCodewordFound) { + self.codewords[codewordsRow] = [NSNull null]; + } else { + barcodeRow = codeword.rowNumber; + currentRowHeight = 1; + } + } + } + return (int) (averageRowHeight + 0.5); +} + +- (BOOL)getRowHeights:(ZXIntArray **)rowHeights { + ZXPDF417BarcodeMetadata *barcodeMetadata = [self barcodeMetadata]; + if (!barcodeMetadata) { + *rowHeights = nil; + return YES; + } + [self adjustIncompleteIndicatorColumnRowNumbers:barcodeMetadata]; + ZXIntArray *result = [[ZXIntArray alloc] initWithLength:barcodeMetadata.rowCount]; + for (ZXPDF417Codeword *codeword in [self codewords]) { + if ((id)codeword != [NSNull null]) { + int rowNumber = codeword.rowNumber; + if (rowNumber >= result.length) { + *rowHeights = nil; + return NO; + } + result.array[rowNumber]++; + } // else throw exception? + } + *rowHeights = result; + return YES; +} + +// TODO maybe we should add missing codewords to store the correct row number to make +// finding row numbers for other columns easier +// use row height count to make detection of invalid row numbers more reliable +- (int)adjustIncompleteIndicatorColumnRowNumbers:(ZXPDF417BarcodeMetadata *)barcodeMetadata { + ZXResultPoint *top = self.isLeft ? self.boundingBox.topLeft : self.boundingBox.topRight; + ZXResultPoint *bottom = self.isLeft ? self.boundingBox.bottomLeft : self.boundingBox.bottomRight; + int firstRow = [self imageRowToCodewordIndex:(int) top.y]; + int lastRow = [self imageRowToCodewordIndex:(int) bottom.y]; + float averageRowHeight = (lastRow - firstRow) / (float) barcodeMetadata.rowCount; + int barcodeRow = -1; + int maxRowHeight = 1; + int currentRowHeight = 0; + for (int codewordsRow = firstRow; codewordsRow < lastRow; codewordsRow++) { + if (self.codewords[codewordsRow] == [NSNull null]) { + continue; + } + ZXPDF417Codeword *codeword = self.codewords[codewordsRow]; + + [codeword setRowNumberAsRowIndicatorColumn]; + + int rowDifference = codeword.rowNumber - barcodeRow; + + // TODO improve handling with case where first row indicator doesn't start with 0 + + if (rowDifference == 0) { + currentRowHeight++; + } else if (rowDifference == 1) { + maxRowHeight = MAX(maxRowHeight, currentRowHeight); + currentRowHeight = 1; + barcodeRow = codeword.rowNumber; + } else if (codeword.rowNumber >= barcodeMetadata.rowCount) { + self.codewords[codewordsRow] = [NSNull null]; + } else { + barcodeRow = codeword.rowNumber; + currentRowHeight = 1; + } + } + return (int) (averageRowHeight + 0.5); +} + +- (ZXPDF417BarcodeMetadata *)barcodeMetadata { + ZXPDF417BarcodeValue *barcodeColumnCount = [[ZXPDF417BarcodeValue alloc] init]; + ZXPDF417BarcodeValue *barcodeRowCountUpperPart = [[ZXPDF417BarcodeValue alloc] init]; + ZXPDF417BarcodeValue *barcodeRowCountLowerPart = [[ZXPDF417BarcodeValue alloc] init]; + ZXPDF417BarcodeValue *barcodeECLevel = [[ZXPDF417BarcodeValue alloc] init]; + for (ZXPDF417Codeword *codeword in self.codewords) { + if ((id)codeword == [NSNull null]) { + continue; + } + [codeword setRowNumberAsRowIndicatorColumn]; + int rowIndicatorValue = codeword.value % 30; + int codewordRowNumber = codeword.rowNumber; + if (!self.isLeft) { + codewordRowNumber += 2; + } + switch (codewordRowNumber % 3) { + case 0: + [barcodeRowCountUpperPart setValue:rowIndicatorValue * 3 + 1]; + break; + case 1: + [barcodeECLevel setValue:rowIndicatorValue / 3]; + [barcodeRowCountLowerPart setValue:rowIndicatorValue % 3]; + break; + case 2: + [barcodeColumnCount setValue:rowIndicatorValue + 1]; + break; + } + } + // Maybe we should check if we have ambiguous values? + if (([barcodeColumnCount value].length == 0) || + ([barcodeRowCountUpperPart value].length == 0) || + ([barcodeRowCountLowerPart value].length == 0) || + ([barcodeECLevel value].length == 0) || + [barcodeColumnCount value].array[0] < 1 || + [barcodeRowCountUpperPart value].array[0] + [barcodeRowCountLowerPart value].array[0] < ZX_PDF417_MIN_ROWS_IN_BARCODE || + [barcodeRowCountUpperPart value].array[0] + [barcodeRowCountLowerPart value].array[0] > ZX_PDF417_MAX_ROWS_IN_BARCODE) { + return nil; + } + ZXPDF417BarcodeMetadata *barcodeMetadata = [[ZXPDF417BarcodeMetadata alloc] initWithColumnCount:[barcodeColumnCount value].array[0] + rowCountUpperPart:[barcodeRowCountUpperPart value].array[0] + rowCountLowerPart:[barcodeRowCountLowerPart value].array[0] + errorCorrectionLevel:[barcodeECLevel value].array[0]]; + [self removeIncorrectCodewords:barcodeMetadata]; + return barcodeMetadata; +} + +- (void)removeIncorrectCodewords:(ZXPDF417BarcodeMetadata *)barcodeMetadata { + // Remove codewords which do not match the metadata + // TODO Maybe we should keep the incorrect codewords for the start and end positions? + for (int codewordRow = 0; codewordRow < [self.codewords count]; codewordRow++) { + ZXPDF417Codeword *codeword = self.codewords[codewordRow]; + if (self.codewords[codewordRow] == [NSNull null]) { + continue; + } + int rowIndicatorValue = codeword.value % 30; + int codewordRowNumber = codeword.rowNumber; + if (codewordRowNumber > barcodeMetadata.rowCount) { + self.codewords[codewordRow] = [NSNull null]; + continue; + } + if (!self.isLeft) { + codewordRowNumber += 2; + } + switch (codewordRowNumber % 3) { + case 0: + if (rowIndicatorValue * 3 + 1 != barcodeMetadata.rowCountUpperPart) { + self.codewords[codewordRow] = [NSNull null]; + } + break; + case 1: + if (rowIndicatorValue / 3 != barcodeMetadata.errorCorrectionLevel || + rowIndicatorValue % 3 != barcodeMetadata.rowCountLowerPart) { + self.codewords[codewordRow] = [NSNull null]; + } + break; + case 2: + if (rowIndicatorValue + 1 != barcodeMetadata.columnCount) { + self.codewords[codewordRow] = [NSNull null]; + } + break; + } + } +} + +- (NSString *)description { + return [NSString stringWithFormat:@"IsLeft: %@\n%@", @(self.isLeft), [super description]]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417ScanningDecoder.h b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417ScanningDecoder.h new file mode 100755 index 0000000..16fad12 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417ScanningDecoder.h @@ -0,0 +1,31 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXBitMatrix, ZXDecoderResult, ZXResultPoint; + +@interface ZXPDF417ScanningDecoder : NSObject + ++ (ZXDecoderResult *)decode:(ZXBitMatrix *)image + imageTopLeft:(ZXResultPoint *)imageTopLeft + imageBottomLeft:(ZXResultPoint *)imageBottomLeft + imageTopRight:(ZXResultPoint *)imageTopRight + imageBottomRight:(ZXResultPoint *)imageBottomRight + minCodewordWidth:(int)minCodewordWidth + maxCodewordWidth:(int)maxCodewordWidth + error:(NSError **)error; +- (NSString *)description:(NSArray *)barcodeMatrix; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417ScanningDecoder.m b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417ScanningDecoder.m new file mode 100755 index 0000000..43d0831 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ZXPDF417ScanningDecoder.m @@ -0,0 +1,685 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitMatrix.h" +#import "ZXDecoderResult.h" +#import "ZXErrors.h" +#import "ZXIntArray.h" +#import "ZXPDF417BarcodeMetadata.h" +#import "ZXPDF417BarcodeValue.h" +#import "ZXPDF417BoundingBox.h" +#import "ZXPDF417Codeword.h" +#import "ZXPDF417CodewordDecoder.h" +#import "ZXPDF417Common.h" +#import "ZXPDF417DecodedBitStreamParser.h" +#import "ZXPDF417DetectionResult.h" +#import "ZXPDF417DetectionResultRowIndicatorColumn.h" +#import "ZXPDF417ECErrorCorrection.h" +#import "ZXPDF417ScanningDecoder.h" +#import "ZXResultPoint.h" + +const int ZX_PDF417_CODEWORD_SKEW_SIZE = 2; + +const int ZX_PDF417_MAX_ERRORS = 3; +const int ZX_PDF417_MAX_EC_CODEWORDS = 512; +static ZXPDF417ECErrorCorrection *errorCorrection; + +@implementation ZXPDF417ScanningDecoder + ++ (void)initialize { + if ([self class] != [ZXPDF417ScanningDecoder class]) return; + + errorCorrection = [[ZXPDF417ECErrorCorrection alloc] init]; +} + +// TODO don't pass in minCodewordWidth and maxCodewordWidth, pass in barcode columns for start and stop pattern +// columns. That way width can be deducted from the pattern column. +// This approach also allows to detect more details about the barcode, e.g. if a bar type (white or black) is wider +// than it should be. This can happen if the scanner used a bad blackpoint. ++ (ZXDecoderResult *)decode:(ZXBitMatrix *)image + imageTopLeft:(ZXResultPoint *)imageTopLeft + imageBottomLeft:(ZXResultPoint *)imageBottomLeft + imageTopRight:(ZXResultPoint *)imageTopRight + imageBottomRight:(ZXResultPoint *)imageBottomRight + minCodewordWidth:(int)minCodewordWidth + maxCodewordWidth:(int)maxCodewordWidth + error:(NSError **)error { + ZXPDF417BoundingBox *boundingBox = [[ZXPDF417BoundingBox alloc] initWithImage:image topLeft:imageTopLeft bottomLeft:imageBottomLeft topRight:imageTopRight bottomRight:imageBottomRight]; + ZXPDF417DetectionResultRowIndicatorColumn *leftRowIndicatorColumn; + ZXPDF417DetectionResultRowIndicatorColumn *rightRowIndicatorColumn; + ZXPDF417DetectionResult *detectionResult; + for (int i = 0; i < 2; i++) { + if (imageTopLeft) { + leftRowIndicatorColumn = [self rowIndicatorColumn:image boundingBox:boundingBox startPoint:imageTopLeft leftToRight:YES + minCodewordWidth:minCodewordWidth maxCodewordWidth:maxCodewordWidth]; + } + if (imageTopRight) { + rightRowIndicatorColumn = [self rowIndicatorColumn:image boundingBox:boundingBox startPoint:imageTopRight leftToRight:NO + minCodewordWidth:minCodewordWidth maxCodewordWidth:maxCodewordWidth]; + } + detectionResult = [self merge:leftRowIndicatorColumn rightRowIndicatorColumn:rightRowIndicatorColumn error:error]; + if (!detectionResult) { + return nil; + } + if (i == 0 && detectionResult.boundingBox && + (detectionResult.boundingBox.minY < boundingBox.minY || + detectionResult.boundingBox.maxY > boundingBox.maxY)) { + boundingBox = [detectionResult boundingBox]; + } else { + detectionResult.boundingBox = boundingBox; + break; + } + } + int maxBarcodeColumn = detectionResult.barcodeColumnCount + 1; + [detectionResult setDetectionResultColumn:0 detectionResultColumn:leftRowIndicatorColumn]; + [detectionResult setDetectionResultColumn:maxBarcodeColumn detectionResultColumn:rightRowIndicatorColumn]; + + BOOL leftToRight = leftRowIndicatorColumn != nil; + for (int barcodeColumnCount = 1; barcodeColumnCount <= maxBarcodeColumn; barcodeColumnCount++) { + int barcodeColumn = leftToRight ? barcodeColumnCount : maxBarcodeColumn - barcodeColumnCount; + if ([detectionResult detectionResultColumn:barcodeColumn]) { + // This will be the case for the opposite row indicator column, which doesn't need to be decoded again. + continue; + } + ZXPDF417DetectionResultColumn *detectionResultColumn; + if (barcodeColumn == 0 || barcodeColumn == maxBarcodeColumn) { + detectionResultColumn = [[ZXPDF417DetectionResultRowIndicatorColumn alloc] initWithBoundingBox:boundingBox isLeft:barcodeColumn == 0]; + } else { + detectionResultColumn = [[ZXPDF417DetectionResultColumn alloc] initWithBoundingBox:boundingBox]; + } + [detectionResult setDetectionResultColumn:barcodeColumn detectionResultColumn:detectionResultColumn]; + int startColumn = -1; + int previousStartColumn = startColumn; + // TODO start at a row for which we know the start position, then detect upwards and downwards from there. + for (int imageRow = boundingBox.minY; imageRow <= boundingBox.maxY; imageRow++) { + startColumn = [self startColumn:detectionResult barcodeColumn:barcodeColumn imageRow:imageRow leftToRight:leftToRight]; + if (startColumn < 0 || startColumn > boundingBox.maxX) { + if (previousStartColumn == -1) { + continue; + } + startColumn = previousStartColumn; + } + ZXPDF417Codeword *codeword = [self detectCodeword:image minColumn:boundingBox.minX maxColumn:boundingBox.maxX leftToRight:leftToRight + startColumn:startColumn imageRow:imageRow minCodewordWidth:minCodewordWidth maxCodewordWidth:maxCodewordWidth]; + if (codeword) { + [detectionResultColumn setCodeword:imageRow codeword:codeword]; + previousStartColumn = startColumn; + minCodewordWidth = MIN(minCodewordWidth, codeword.width); + maxCodewordWidth = MAX(maxCodewordWidth, codeword.width); + } + } + } + return [self createDecoderResult:detectionResult error:error]; +} + ++ (ZXPDF417DetectionResult *)merge:(ZXPDF417DetectionResultRowIndicatorColumn *)leftRowIndicatorColumn + rightRowIndicatorColumn:(ZXPDF417DetectionResultRowIndicatorColumn *)rightRowIndicatorColumn + error:(NSError **)error { + if (!leftRowIndicatorColumn && !rightRowIndicatorColumn) { + return nil; + } + ZXPDF417BarcodeMetadata *barcodeMetadata = [self barcodeMetadata:leftRowIndicatorColumn rightRowIndicatorColumn:rightRowIndicatorColumn]; + if (!barcodeMetadata) { + return nil; + } + ZXPDF417BoundingBox *leftBoundingBox, *rightBoundingBox; + if (![self adjustBoundingBox:&leftBoundingBox rowIndicatorColumn:leftRowIndicatorColumn error:error]) { + return nil; + } + if (![self adjustBoundingBox:&rightBoundingBox rowIndicatorColumn:rightRowIndicatorColumn error:error]) { + return nil; + } + + ZXPDF417BoundingBox *boundingBox = [ZXPDF417BoundingBox mergeLeftBox:leftBoundingBox rightBox:rightBoundingBox]; + if (!boundingBox) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + return [[ZXPDF417DetectionResult alloc] initWithBarcodeMetadata:barcodeMetadata boundingBox:boundingBox]; +} + ++ (BOOL)adjustBoundingBox:(ZXPDF417BoundingBox **)boundingBox + rowIndicatorColumn:(ZXPDF417DetectionResultRowIndicatorColumn *)rowIndicatorColumn + error:(NSError **)error { + if (!rowIndicatorColumn) { + *boundingBox = nil; + return YES; + } + ZXIntArray *rowHeights; + if (![rowIndicatorColumn getRowHeights:&rowHeights]) { + if (error) *error = ZXFormatErrorInstance(); + *boundingBox = nil; + return NO; + } + if (!rowHeights) { + *boundingBox = nil; + return YES; + } + int maxRowHeight = [self max:rowHeights]; + int missingStartRows = 0; + for (int i = 0; i < rowHeights.length; i++) { + int rowHeight = rowHeights.array[i]; + missingStartRows += maxRowHeight - rowHeight; + if (rowHeight > 0) { + break; + } + } + NSArray *codewords = rowIndicatorColumn.codewords; + for (int row = 0; missingStartRows > 0 && codewords[row] == [NSNull null]; row++) { + missingStartRows--; + } + int missingEndRows = 0; + for (int row = rowHeights.length - 1; row >= 0; row--) { + missingEndRows += maxRowHeight - rowHeights.array[row]; + if (rowHeights.array[row] > 0) { + break; + } + } + for (int row = (int)[codewords count] - 1; missingEndRows > 0 && codewords[row] == [NSNull null]; row--) { + missingEndRows--; + } + *boundingBox = [rowIndicatorColumn.boundingBox addMissingRows:missingStartRows + missingEndRows:missingEndRows + isLeft:rowIndicatorColumn.isLeft]; + return *boundingBox != nil; +} + ++ (int)max:(ZXIntArray *)values { + int maxValue = -1; + for (int i = 0; i < values.length; i++) { + int value = values.array[i]; + maxValue = MAX(maxValue, value); + } + return maxValue; +} + ++ (ZXPDF417BarcodeMetadata *)barcodeMetadata:(ZXPDF417DetectionResultRowIndicatorColumn *)leftRowIndicatorColumn + rightRowIndicatorColumn:(ZXPDF417DetectionResultRowIndicatorColumn *)rightRowIndicatorColumn { + ZXPDF417BarcodeMetadata *leftBarcodeMetadata; + if (!leftRowIndicatorColumn || + !(leftBarcodeMetadata = leftRowIndicatorColumn.barcodeMetadata)) { + return rightRowIndicatorColumn ? rightRowIndicatorColumn.barcodeMetadata : nil; + } + ZXPDF417BarcodeMetadata *rightBarcodeMetadata; + if (!rightRowIndicatorColumn || + !(rightBarcodeMetadata = rightRowIndicatorColumn.barcodeMetadata)) { + return leftRowIndicatorColumn.barcodeMetadata; + } + + if (leftBarcodeMetadata.columnCount != rightBarcodeMetadata.columnCount && + leftBarcodeMetadata.errorCorrectionLevel != rightBarcodeMetadata.errorCorrectionLevel && + leftBarcodeMetadata.rowCount != rightBarcodeMetadata.rowCount) { + return nil; + } + return leftBarcodeMetadata; +} + ++ (ZXPDF417DetectionResultRowIndicatorColumn *)rowIndicatorColumn:(ZXBitMatrix *)image + boundingBox:(ZXPDF417BoundingBox *)boundingBox + startPoint:(ZXResultPoint *)startPoint + leftToRight:(BOOL)leftToRight + minCodewordWidth:(int)minCodewordWidth + maxCodewordWidth:(int)maxCodewordWidth { + ZXPDF417DetectionResultRowIndicatorColumn *rowIndicatorColumn = [[ZXPDF417DetectionResultRowIndicatorColumn alloc] initWithBoundingBox:boundingBox + isLeft:leftToRight]; + for (int i = 0; i < 2; i++) { + int increment = i == 0 ? 1 : -1; + int startColumn = (int) startPoint.x; + for (int imageRow = (int) startPoint.y; imageRow <= boundingBox.maxY && + imageRow >= boundingBox.minY; imageRow += increment) { + ZXPDF417Codeword *codeword = [self detectCodeword:image minColumn:0 maxColumn:image.width leftToRight:leftToRight startColumn:startColumn imageRow:imageRow + minCodewordWidth:minCodewordWidth maxCodewordWidth:maxCodewordWidth]; + if (codeword) { + [rowIndicatorColumn setCodeword:imageRow codeword:codeword]; + if (leftToRight) { + startColumn = codeword.startX; + } else { + startColumn = codeword.endX; + } + } + } + } + return rowIndicatorColumn; +} + ++ (BOOL)adjustCodewordCount:(ZXPDF417DetectionResult *)detectionResult barcodeMatrix:(NSArray *)barcodeMatrix { + ZXIntArray *numberOfCodewords = [(ZXPDF417BarcodeValue *)barcodeMatrix[0][1] value]; + int calculatedNumberOfCodewords = [detectionResult barcodeColumnCount] * [detectionResult barcodeRowCount]; + [self numberOfECCodeWords:detectionResult.barcodeECLevel]; + if (numberOfCodewords.length == 0) { + if (calculatedNumberOfCodewords < 1 || calculatedNumberOfCodewords > ZX_PDF417_MAX_CODEWORDS_IN_BARCODE) { + return NO; + } + [(ZXPDF417BarcodeValue *)barcodeMatrix[0][1] setValue:calculatedNumberOfCodewords]; + } else if (numberOfCodewords.array[0] != calculatedNumberOfCodewords) { + // The calculated one is more reliable as it is derived from the row indicator columns + [(ZXPDF417BarcodeValue *)barcodeMatrix[0][1] setValue:calculatedNumberOfCodewords]; + } + + return YES; +} + ++ (ZXDecoderResult *)createDecoderResult:(ZXPDF417DetectionResult *)detectionResult error:(NSError **)error { + NSArray *barcodeMatrix = [self createBarcodeMatrix:detectionResult]; + if (!barcodeMatrix) { + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + if (![self adjustCodewordCount:detectionResult barcodeMatrix:barcodeMatrix]) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + NSMutableArray *erasures = [NSMutableArray array]; + ZXIntArray *codewords = [[ZXIntArray alloc] initWithLength:detectionResult.barcodeRowCount * detectionResult.barcodeColumnCount]; + NSMutableArray *ambiguousIndexValuesList = [NSMutableArray array]; + NSMutableArray *ambiguousIndexesList = [NSMutableArray array]; + for (int row = 0; row < detectionResult.barcodeRowCount; row++) { + for (int column = 0; column < detectionResult.barcodeColumnCount; column++) { + ZXIntArray *values = [(ZXPDF417BarcodeValue *)barcodeMatrix[row][column + 1] value]; + int codewordIndex = row * detectionResult.barcodeColumnCount + column; + if (values.length == 0) { + [erasures addObject:@(codewordIndex)]; + } else if (values.length == 1) { + codewords.array[codewordIndex] = values.array[0]; + } else { + [ambiguousIndexesList addObject:@(codewordIndex)]; + [ambiguousIndexValuesList addObject:values]; + } + } + } + return [self createDecoderResultFromAmbiguousValues:detectionResult.barcodeECLevel + codewords:codewords + erasureArray:[ZXPDF417Common toIntArray:erasures] + ambiguousIndexes:[ZXPDF417Common toIntArray:ambiguousIndexesList] + ambiguousIndexValues:ambiguousIndexValuesList + error:error]; +} + +/** + * This method deals with the fact, that the decoding process doesn't always yield a single most likely value. The + * current error correction implementation doesn't deal with erasures very well, so it's better to provide a value + * for these ambiguous codewords instead of treating it as an erasure. The problem is that we don't know which of + * the ambiguous values to choose. We try decode using the first value, and if that fails, we use another of the + * ambiguous values and try to decode again. This usually only happens on very hard to read and decode barcodes, + * so decoding the normal barcodes is not affected by this. + * + * @param erasureArray contains the indexes of erasures + * @param ambiguousIndexes array with the indexes that have more than one most likely value + * @param ambiguousIndexValues two dimensional array that contains the ambiguous values. The first dimension must + * be the same length as the ambiguousIndexes array + */ ++ (ZXDecoderResult *)createDecoderResultFromAmbiguousValues:(int)ecLevel + codewords:(ZXIntArray *)codewords + erasureArray:(ZXIntArray *)erasureArray + ambiguousIndexes:(ZXIntArray *)ambiguousIndexes + ambiguousIndexValues:(NSArray *)ambiguousIndexValues + error:(NSError **)error { + ZXIntArray *ambiguousIndexCount = [[ZXIntArray alloc] initWithLength:ambiguousIndexes.length]; + + int tries = 100; + while (tries-- > 0) { + for (int i = 0; i < ambiguousIndexCount.length; i++) { + ZXIntArray *a = ambiguousIndexValues[i]; + codewords.array[ambiguousIndexes.array[i]] = a.array[(ambiguousIndexCount.array[i] + 1) % [(ZXIntArray *)ambiguousIndexValues[i] length]]; + } + NSError *e; + ZXDecoderResult *result = [self decodeCodewords:codewords ecLevel:ecLevel erasures:erasureArray error:&e]; + if (result) { + return result; + } else if (e.code != ZXChecksumError) { + if (error) *error = e; + return nil; + } + if (ambiguousIndexCount.length == 0) { + if (error) *error = ZXChecksumErrorInstance(); + return nil; + } + for (int i = 0; i < ambiguousIndexCount.length; i++) { + if (ambiguousIndexCount.array[i] < [(ZXIntArray *)ambiguousIndexValues[i] length] - 1) { + ambiguousIndexCount.array[i]++; + break; + } else { + ambiguousIndexCount.array[i] = 0; + if (i == ambiguousIndexes.length - 1) { + if (error) *error = ZXChecksumErrorInstance(); + return nil; + } + } + } + } + + if (error) *error = ZXChecksumErrorInstance(); + return nil; +} + ++ (NSArray *)createBarcodeMatrix:(ZXPDF417DetectionResult *)detectionResult { + NSMutableArray *barcodeMatrix = [NSMutableArray array]; + for (int row = 0; row < detectionResult.barcodeRowCount; row++) { + [barcodeMatrix addObject:[NSMutableArray array]]; + for (int column = 0; column < detectionResult.barcodeColumnCount + 2; column++) { + barcodeMatrix[row][column] = [[ZXPDF417BarcodeValue alloc] init]; + } + } + + int column = 0; + for (ZXPDF417DetectionResultColumn *detectionResultColumn in [detectionResult detectionResultColumns]) { + if ((id)detectionResultColumn != [NSNull null]) { + for (ZXPDF417Codeword *codeword in detectionResultColumn.codewords) { + if ((id)codeword != [NSNull null]) { + int rowNumber = codeword.rowNumber; + if (rowNumber >= 0) { + if (rowNumber >= barcodeMatrix.count) { + return nil; + } + [(ZXPDF417BarcodeValue *)barcodeMatrix[rowNumber][column] setValue:codeword.value]; + } + } + } + } + column++; + } + + return barcodeMatrix; +} + ++ (BOOL)isValidBarcodeColumn:(ZXPDF417DetectionResult *)detectionResult barcodeColumn:(int)barcodeColumn { + return barcodeColumn >= 0 && barcodeColumn <= detectionResult.barcodeColumnCount + 1; +} + ++ (int)startColumn:(ZXPDF417DetectionResult *)detectionResult + barcodeColumn:(int)barcodeColumn + imageRow:(int)imageRow + leftToRight:(BOOL)leftToRight { + int offset = leftToRight ? 1 : -1; + ZXPDF417Codeword *codeword; + if ([self isValidBarcodeColumn:detectionResult barcodeColumn:barcodeColumn - offset]) { + codeword = [[detectionResult detectionResultColumn:barcodeColumn - offset] codeword:imageRow]; + } + if (codeword) { + return leftToRight ? codeword.endX : codeword.startX; + } + codeword = [[detectionResult detectionResultColumn:barcodeColumn] codewordNearby:imageRow]; + if (codeword) { + return leftToRight ? codeword.startX : codeword.endX; + } + if ([self isValidBarcodeColumn:detectionResult barcodeColumn:barcodeColumn - offset]) { + codeword = [[detectionResult detectionResultColumn:barcodeColumn - offset] codewordNearby:imageRow]; + } + if (codeword) { + return leftToRight ? codeword.endX : codeword.startX; + } + int skippedColumns = 0; + + while ([self isValidBarcodeColumn:detectionResult barcodeColumn:barcodeColumn - offset]) { + barcodeColumn -= offset; + for (ZXPDF417Codeword *previousRowCodeword in [detectionResult detectionResultColumn:barcodeColumn].codewords) { + if ((id)previousRowCodeword != [NSNull null]) { + return (leftToRight ? previousRowCodeword.endX : previousRowCodeword.startX) + + offset * + skippedColumns * + (previousRowCodeword.endX - previousRowCodeword.startX); + } + } + skippedColumns++; + } + return leftToRight ? detectionResult.boundingBox.minX : detectionResult.boundingBox.maxX; +} + ++ (ZXPDF417Codeword *)detectCodeword:(ZXBitMatrix *)image + minColumn:(int)minColumn + maxColumn:(int)maxColumn + leftToRight:(BOOL)leftToRight + startColumn:(int)startColumn + imageRow:(int)imageRow + minCodewordWidth:(int)minCodewordWidth + maxCodewordWidth:(int)maxCodewordWidth { + startColumn = [self adjustCodewordStartColumn:image minColumn:minColumn maxColumn:maxColumn leftToRight:leftToRight codewordStartColumn:startColumn imageRow:imageRow]; + // we usually know fairly exact now how long a codeword is. We should provide minimum and maximum expected length + // and try to adjust the read pixels, e.g. remove single pixel errors or try to cut off exceeding pixels. + // min and maxCodewordWidth should not be used as they are calculated for the whole barcode an can be inaccurate + // for the current position + NSMutableArray *moduleBitCount = [self moduleBitCount:image minColumn:minColumn maxColumn:maxColumn leftToRight:leftToRight startColumn:startColumn imageRow:imageRow]; + if (!moduleBitCount) { + return nil; + } + int endColumn; + int codewordBitCount = [ZXPDF417Common bitCountSum:moduleBitCount]; + if (leftToRight) { + endColumn = startColumn + codewordBitCount; + } else { + for (int i = 0; i < [moduleBitCount count] / 2; i++) { + int tmpCount = [moduleBitCount[i] intValue]; + moduleBitCount[i] = moduleBitCount[[moduleBitCount count] - 1 - i]; + moduleBitCount[[moduleBitCount count] - 1 - i] = @(tmpCount); + } + endColumn = startColumn; + startColumn = endColumn - codewordBitCount; + } + // TODO implement check for width and correction of black and white bars + // use start (and maybe stop pattern) to determine if blackbars are wider than white bars. If so, adjust. + // should probably done only for codewords with a lot more than 17 bits. + // The following fixes 10-1.png, which has wide black bars and small white bars + // for (int i = 0; i < moduleBitCount.length; i++) { + // if (i % 2 == 0) { + // moduleBitCount[i]--; + // } else { + // moduleBitCount[i]++; + // } + // } + + // We could also use the width of surrounding codewords for more accurate results, but this seems + // sufficient for now + if (![self checkCodewordSkew:codewordBitCount minCodewordWidth:minCodewordWidth maxCodewordWidth:maxCodewordWidth]) { + // We could try to use the startX and endX position of the codeword in the same column in the previous row, + // create the bit count from it and normalize it to 8. This would help with single pixel errors. + return nil; + } + + int decodedValue = [ZXPDF417CodewordDecoder decodedValue:moduleBitCount]; + int codeword = [ZXPDF417Common codeword:decodedValue]; + if (codeword == -1) { + return nil; + } + return [[ZXPDF417Codeword alloc] initWithStartX:startColumn endX:endColumn bucket:[self codewordBucketNumber:decodedValue] value:codeword]; +} + ++ (NSMutableArray *)moduleBitCount:(ZXBitMatrix *)image + minColumn:(int)minColumn + maxColumn:(int)maxColumn + leftToRight:(BOOL)leftToRight + startColumn:(int)startColumn + imageRow:(int)imageRow { + int imageColumn = startColumn; + NSMutableArray *moduleBitCount = [NSMutableArray arrayWithCapacity:8]; + for (int i = 0; i < 8; i++) { + [moduleBitCount addObject:@0]; + } + int moduleNumber = 0; + int increment = leftToRight ? 1 : -1; + BOOL previousPixelValue = leftToRight; + while (((leftToRight && imageColumn < maxColumn) || (!leftToRight && imageColumn >= minColumn)) && + moduleNumber < [moduleBitCount count]) { + if ([image getX:imageColumn y:imageRow] == previousPixelValue) { + moduleBitCount[moduleNumber] = @([moduleBitCount[moduleNumber] intValue] + 1); + imageColumn += increment; + } else { + moduleNumber++; + previousPixelValue = !previousPixelValue; + } + } + if (moduleNumber == [moduleBitCount count] || + (((leftToRight && imageColumn == maxColumn) || (!leftToRight && imageColumn == minColumn)) && moduleNumber == [moduleBitCount count] - 1)) { + return moduleBitCount; + } + return nil; +} + ++ (int)numberOfECCodeWords:(int)barcodeECLevel { + return 2 << barcodeECLevel; +} + ++ (int)adjustCodewordStartColumn:(ZXBitMatrix *)image + minColumn:(int)minColumn + maxColumn:(int)maxColumn + leftToRight:(BOOL)leftToRight + codewordStartColumn:(int)codewordStartColumn + imageRow:(int)imageRow { + int correctedStartColumn = codewordStartColumn; + int increment = leftToRight ? -1 : 1; + // there should be no black pixels before the start column. If there are, then we need to start earlier. + for (int i = 0; i < 2; i++) { + while (((leftToRight && correctedStartColumn >= minColumn) || (!leftToRight && correctedStartColumn < maxColumn)) && + leftToRight == [image getX:correctedStartColumn y:imageRow]) { + if (abs(codewordStartColumn - correctedStartColumn) > ZX_PDF417_CODEWORD_SKEW_SIZE) { + return codewordStartColumn; + } + correctedStartColumn += increment; + } + increment = -increment; + leftToRight = !leftToRight; + } + return correctedStartColumn; +} + ++ (BOOL)checkCodewordSkew:(int)codewordSize minCodewordWidth:(int)minCodewordWidth maxCodewordWidth:(int)maxCodewordWidth { + return minCodewordWidth - ZX_PDF417_CODEWORD_SKEW_SIZE <= codewordSize && + codewordSize <= maxCodewordWidth + ZX_PDF417_CODEWORD_SKEW_SIZE; +} + ++ (ZXDecoderResult *)decodeCodewords:(ZXIntArray *)codewords ecLevel:(int)ecLevel erasures:(ZXIntArray *)erasures error:(NSError **)error { + if (codewords.length == 0) { + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + + int numECCodewords = 1 << (ecLevel + 1); + int correctedErrorsCount = [self correctErrors:codewords erasures:erasures numECCodewords:numECCodewords]; + if (correctedErrorsCount == -1) { + if (error) *error = ZXChecksumErrorInstance(); + return nil; + } + if (![self verifyCodewordCount:codewords numECCodewords:numECCodewords]) { + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + + // Decode the codewords + ZXDecoderResult *decoderResult = [ZXPDF417DecodedBitStreamParser decode:codewords ecLevel:[@(ecLevel) stringValue] error:error]; + if (!decoderResult) { + return nil; + } + decoderResult.errorsCorrected = @(correctedErrorsCount); + decoderResult.erasures = @(erasures.length); + return decoderResult; +} + +/** + * Given data and error-correction codewords received, possibly corrupted by errors, attempts to + * correct the errors in-place. + * + * @param codewords data and error correction codewords + * @param erasures positions of any known erasures + * @param numECCodewords number of error correction codewords that are available in codewords + * @throws ChecksumException if error correction fails + */ ++ (int)correctErrors:(ZXIntArray *)codewords erasures:(ZXIntArray *)erasures numECCodewords:(int)numECCodewords { + if (erasures && + (erasures.length > numECCodewords / 2 + ZX_PDF417_MAX_ERRORS || + numECCodewords < 0 || + numECCodewords > ZX_PDF417_MAX_EC_CODEWORDS)) { + // Too many errors or EC Codewords is corrupted + return -1; + } + return [errorCorrection decode:codewords numECCodewords:numECCodewords erasures:erasures]; +} + +/** + * Verify that all is OK with the codeword array. + */ ++ (BOOL)verifyCodewordCount:(ZXIntArray *)codewords numECCodewords:(int)numECCodewords { + if (codewords.length < 4) { + // Codeword array size should be at least 4 allowing for + // Count CW, At least one Data CW, Error Correction CW, Error Correction CW + return NO; + } + // The first codeword, the Symbol Length Descriptor, shall always encode the total number of data + // codewords in the symbol, including the Symbol Length Descriptor itself, data codewords and pad + // codewords, but excluding the number of error correction codewords. + int numberOfCodewords = codewords.array[0]; + if (numberOfCodewords > codewords.length) { + return NO; + } + if (numberOfCodewords == 0) { + // Reset to the length of the array - 8 (Allow for at least level 3 Error Correction (8 Error Codewords) + if (numECCodewords < codewords.length) { + codewords.array[0] = codewords.length - numECCodewords; + } else { + return NO; + } + } + + return YES; +} + ++ (NSArray *)bitCountForCodeword:(int)codeword { + NSMutableArray *result = [NSMutableArray array]; + for (int i = 0; i < 8; i++) { + [result addObject:@0]; + } + + int previousValue = 0; + int i = (int)[result count] - 1; + while (YES) { + if ((codeword & 0x1) != previousValue) { + previousValue = codeword & 0x1; + i--; + if (i < 0) { + break; + } + } + result[i] = @([result[i] intValue] + 1); + codeword >>= 1; + } + return result; +} + ++ (int)codewordBucketNumber:(int)codeword { + return [self codewordBucketNumberWithModuleBitCount:[self bitCountForCodeword:codeword]]; +} + ++ (int)codewordBucketNumberWithModuleBitCount:(NSArray *)moduleBitCount { + return ([moduleBitCount[0] intValue] - [moduleBitCount[2] intValue] + [moduleBitCount[4] intValue] - [moduleBitCount[6] intValue] + 9) % 9; +} + +- (NSString *)description:(NSArray *)barcodeMatrix { + NSMutableString *result = [NSMutableString string]; + for (int row = 0; row < [barcodeMatrix count]; row++) { + [result appendFormat:@"Row %2d: ", row]; + for (int column = 0; column < [(NSArray *)barcodeMatrix[row] count]; column++) { + ZXPDF417BarcodeValue *barcodeValue = barcodeMatrix[row][column]; + if ([barcodeValue value].length == 0) { + [result appendString:@" "]; + } else { + [result appendFormat:@"%4d(%2d)", [barcodeValue value].array[0], + [[barcodeValue confidence:[barcodeValue value].array[0]] intValue]]; + } + } + [result appendString:@"\n"]; + } + return [NSString stringWithString:result]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ec/ZXModulusGF.h b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ec/ZXModulusGF.h new file mode 100755 index 0000000..ba295e5 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ec/ZXModulusGF.h @@ -0,0 +1,40 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXModulusPoly; + +/** + * A field based on powers of a generator integer, modulo some modulus. + */ +@interface ZXModulusGF : NSObject + +@property (nonatomic, strong, readonly) ZXModulusPoly *one; +@property (nonatomic, strong, readonly) ZXModulusPoly *zero; + ++ (ZXModulusGF *)PDF417_GF; + +- (id)initWithModulus:(int)modulus generator:(int)generator; + +- (ZXModulusPoly *)buildMonomial:(int)degree coefficient:(int)coefficient; +- (int)add:(int)a b:(int)b; +- (int)subtract:(int)a b:(int)b; +- (int)exp:(int)a; +- (int)log:(int)a; +- (int)inverse:(int)a; +- (int)multiply:(int)a b:(int)b; +- (int)size; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ec/ZXModulusGF.m b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ec/ZXModulusGF.m new file mode 100755 index 0000000..468d6cf --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ec/ZXModulusGF.m @@ -0,0 +1,115 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXIntArray.h" +#import "ZXModulusGF.h" +#import "ZXModulusPoly.h" +#import "ZXPDF417Common.h" + +@interface ZXModulusGF () + +@property (nonatomic, assign, readonly) int32_t *expTable; +@property (nonatomic, assign, readonly) int32_t *logTable; +@property (nonatomic, assign, readonly) int modulus; + +@end + +@implementation ZXModulusGF + ++ (ZXModulusGF *)PDF417_GF { + static dispatch_once_t pred = 0; + __strong static id _mod = nil; + dispatch_once(&pred, ^{ + @autoreleasepool { + _mod = [[ZXModulusGF alloc] initWithModulus:ZX_PDF417_NUMBER_OF_CODEWORDS generator:3]; + } + }); + return _mod; +} + +- (id)initWithModulus:(int)modulus generator:(int)generator { + if (self = [super init]) { + _modulus = modulus; + _expTable = (int32_t *)calloc(self.modulus, sizeof(int32_t)); + _logTable = (int32_t *)calloc(self.modulus, sizeof(int32_t)); + int32_t x = 1; + for (int i = 0; i < modulus; i++) { + _expTable[i] = x; + x = (x * generator) % modulus; + } + for (int i = 0; i < self.size - 1; i++) { + _logTable[_expTable[i]] = i; + } + // logTable[0] == 0 but this should never be used + _zero = [[ZXModulusPoly alloc] initWithField:self coefficients:[[ZXIntArray alloc] initWithLength:1]]; + _one = [[ZXModulusPoly alloc] initWithField:self coefficients:[[ZXIntArray alloc] initWithInts:1, -1]]; + } + + return self; +} + +- (ZXModulusPoly *)buildMonomial:(int)degree coefficient:(int)coefficient { + if (degree < 0) { + [NSException raise:NSInvalidArgumentException format:@"Degree must be greater than 0."]; + } + if (coefficient == 0) { + return self.zero; + } + ZXIntArray *coefficients = [[ZXIntArray alloc] initWithLength:degree + 1]; + coefficients.array[0] = coefficient; + return [[ZXModulusPoly alloc] initWithField:self coefficients:coefficients]; +} + +- (int)add:(int)a b:(int)b { + return (a + b) % self.modulus; +} + +- (int)subtract:(int)a b:(int)b { + return (self.modulus + a - b) % self.modulus; +} + +- (int)exp:(int)a { + return _expTable[a]; +} + +- (int)log:(int)a { + if (a == 0) { + [NSException raise:NSInvalidArgumentException format:@"Argument must be non-zero."]; + } + return _logTable[a]; +} + +- (int)inverse:(int)a { + if (a == 0) { + [NSException raise:NSInvalidArgumentException format:@"Argument must be non-zero."]; + } + + return _expTable[_modulus - _logTable[a] - 1]; +} + +- (int)multiply:(int)a b:(int)b { + if (a == 0 || b == 0) { + return 0; + } + + return _expTable[(_logTable[a] + _logTable[b]) % (_modulus - 1)]; +} + +- (int)size { + return self.modulus; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ec/ZXModulusPoly.h b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ec/ZXModulusPoly.h new file mode 100755 index 0000000..103a8e7 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ec/ZXModulusPoly.h @@ -0,0 +1,34 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXIntArray, ZXModulusGF; + +@interface ZXModulusPoly : NSObject + +- (id)initWithField:(ZXModulusGF *)field coefficients:(ZXIntArray *)coefficients; +- (int)degree; +- (BOOL)zero; +- (int)coefficient:(int)degree; +- (int)evaluateAt:(int)a; +- (ZXModulusPoly *)add:(ZXModulusPoly *)other; +- (ZXModulusPoly *)subtract:(ZXModulusPoly *)other; +- (ZXModulusPoly *)multiply:(ZXModulusPoly *)other; +- (ZXModulusPoly *)negative; +- (ZXModulusPoly *)multiplyScalar:(int)scalar; +- (ZXModulusPoly *)multiplyByMonomial:(int)degree coefficient:(int)coefficient; +- (NSArray *)divide:(ZXModulusPoly *)other; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ec/ZXModulusPoly.m b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ec/ZXModulusPoly.m new file mode 100755 index 0000000..e28af02 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ec/ZXModulusPoly.m @@ -0,0 +1,263 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXIntArray.h" +#import "ZXModulusGF.h" +#import "ZXModulusPoly.h" + +@interface ZXModulusPoly () + +@property (nonatomic, strong, readonly) ZXIntArray *coefficients; +@property (nonatomic, weak, readonly) ZXModulusGF *field; + +@end + +@implementation ZXModulusPoly + +- (id)initWithField:(ZXModulusGF *)field coefficients:(ZXIntArray *)coefficients { + if (self = [super init]) { + if (coefficients.length == 0) { + @throw [NSException exceptionWithName:@"IllegalArgumentException" + reason:@"coefficients must have at least one element" + userInfo:nil]; + } + _field = field; + int coefficientsLength = coefficients.length; + if (coefficientsLength > 1 && coefficients.array[0] == 0) { + // Leading term must be non-zero for anything except the constant polynomial "0" + int firstNonZero = 1; + while (firstNonZero < coefficientsLength && coefficients.array[firstNonZero] == 0) { + firstNonZero++; + } + if (firstNonZero == coefficientsLength) { + _coefficients = [[ZXIntArray alloc] initWithLength:1]; + } else { + _coefficients = [[ZXIntArray alloc] initWithLength:coefficientsLength - firstNonZero]; + for (int i = 0; i < _coefficients.length; i++) { + _coefficients.array[i] = coefficients.array[firstNonZero + i]; + } + } + } else { + _coefficients = coefficients; + } + } + + return self; +} + +/** + * @return degree of this polynomial + */ +- (int)degree { + return self.coefficients.length - 1; +} + +/** + * @return true iff this polynomial is the monomial "0" + */ +- (BOOL)zero { + return self.coefficients.array[0] == 0; +} + +/** + * @return coefficient of x^degree term in this polynomial + */ +- (int)coefficient:(int)degree { + return self.coefficients.array[self.coefficients.length - 1 - degree]; +} + +/** + * @return evaluation of this polynomial at a given point + */ +- (int)evaluateAt:(int)a { + if (a == 0) { + return [self coefficient:0]; + } + int size = self.coefficients.length; + if (a == 1) { + // Just the sum of the coefficients + int result = 0; + for (int i = 0; i < size; i++) { + result = [self.field add:result b:self.coefficients.array[i]]; + } + return result; + } + int result = self.coefficients.array[0]; + for (int i = 1; i < size; i++) { + result = [self.field add:[self.field multiply:a b:result] b:self.coefficients.array[i]]; + } + return result; +} + +- (ZXModulusPoly *)add:(ZXModulusPoly *)other { + if (![self.field isEqual:other.field]) { + [NSException raise:NSInvalidArgumentException format:@"ZXModulusPolys do not have same ZXModulusGF field"]; + } + if (self.zero) { + return other; + } + if (other.zero) { + return self; + } + + ZXIntArray *smallerCoefficients = self.coefficients; + ZXIntArray *largerCoefficients = other.coefficients; + if (smallerCoefficients.length > largerCoefficients.length) { + ZXIntArray *temp = smallerCoefficients; + smallerCoefficients = largerCoefficients; + largerCoefficients = temp; + } + ZXIntArray *sumDiff = [[ZXIntArray alloc] initWithLength:largerCoefficients.length]; + int lengthDiff = largerCoefficients.length - smallerCoefficients.length; + // Copy high-order terms only found in higher-degree polynomial's coefficients + memcpy(sumDiff.array, largerCoefficients.array, lengthDiff * sizeof(int32_t)); + + for (int i = lengthDiff; i < largerCoefficients.length; i++) { + sumDiff.array[i] = [self.field add:smallerCoefficients.array[i - lengthDiff] b:largerCoefficients.array[i]]; + } + + return [[ZXModulusPoly alloc] initWithField:self.field coefficients:sumDiff]; +} + +- (ZXModulusPoly *)subtract:(ZXModulusPoly *)other { + if (![self.field isEqual:other.field]) { + [NSException raise:NSInvalidArgumentException format:@"ZXModulusPolys do not have same ZXModulusGF field"]; + } + if (self.zero) { + return self; + } + return [self add:[other negative]]; +} + +- (ZXModulusPoly *)multiply:(ZXModulusPoly *)other { + if (![self.field isEqual:other.field]) { + [NSException raise:NSInvalidArgumentException format:@"ZXModulusPolys do not have same ZXModulusGF field"]; + } + if (self.zero || other.zero) { + return self.field.zero; + } + ZXIntArray *aCoefficients = self.coefficients; + int aLength = aCoefficients.length; + ZXIntArray *bCoefficients = other.coefficients; + int bLength = bCoefficients.length; + ZXIntArray *product = [[ZXIntArray alloc] initWithLength:aLength + bLength - 1]; + for (int i = 0; i < aLength; i++) { + int aCoeff = aCoefficients.array[i]; + for (int j = 0; j < bLength; j++) { + product.array[i + j] = [self.field add:product.array[i + j] + b:[self.field multiply:aCoeff b:bCoefficients.array[j]]]; + } + } + return [[ZXModulusPoly alloc] initWithField:self.field coefficients:product]; +} + +- (ZXModulusPoly *)negative { + int size = self.coefficients.length; + ZXIntArray *negativeCoefficients = [[ZXIntArray alloc] initWithLength:size]; + for (int i = 0; i < size; i++) { + negativeCoefficients.array[i] = [self.field subtract:0 b:self.coefficients.array[i]]; + } + return [[ZXModulusPoly alloc] initWithField:self.field coefficients:negativeCoefficients]; +} + +- (ZXModulusPoly *)multiplyScalar:(int)scalar { + if (scalar == 0) { + return self.field.zero; + } + if (scalar == 1) { + return self; + } + int size = self.coefficients.length; + ZXIntArray *product = [[ZXIntArray alloc] initWithLength:size]; + for (int i = 0; i < size; i++) { + product.array[i] = [self.field multiply:self.coefficients.array[i] b:scalar]; + } + return [[ZXModulusPoly alloc] initWithField:self.field coefficients:product]; +} + +- (ZXModulusPoly *)multiplyByMonomial:(int)degree coefficient:(int)coefficient { + if (degree < 0) { + [NSException raise:NSInvalidArgumentException format:@"Degree must be greater than 0."]; + } + if (coefficient == 0) { + return self.field.zero; + } + int size = self.coefficients.length; + ZXIntArray *product = [[ZXIntArray alloc] initWithLength:size + degree]; + for (int i = 0; i < size; i++) { + product.array[i] = [self.field multiply:self.coefficients.array[i] b:coefficient]; + } + + return [[ZXModulusPoly alloc] initWithField:self.field coefficients:product]; +} + +- (NSArray *)divide:(ZXModulusPoly *)other { + if (![self.field isEqual:other.field]) { + [NSException raise:NSInvalidArgumentException format:@"ZXModulusPolys do not have same ZXModulusGF field"]; + } + if (other.zero) { + [NSException raise:NSInvalidArgumentException format:@"Divide by 0"]; + } + + ZXModulusPoly *quotient = self.field.zero; + ZXModulusPoly *remainder = self; + + int denominatorLeadingTerm = [other coefficient:other.degree]; + int inverseDenominatorLeadingTerm = [self.field inverse:denominatorLeadingTerm]; + + while ([remainder degree] >= other.degree && !remainder.zero) { + int degreeDifference = remainder.degree - other.degree; + int scale = [self.field multiply:[remainder coefficient:remainder.degree] b:inverseDenominatorLeadingTerm]; + ZXModulusPoly *term = [other multiplyByMonomial:degreeDifference coefficient:scale]; + ZXModulusPoly *iterationQuotient = [self.field buildMonomial:degreeDifference coefficient:scale]; + quotient = [quotient add:iterationQuotient]; + remainder = [remainder subtract:term]; + } + + return @[quotient, remainder]; +} + +- (NSString *)description { + NSMutableString *result = [NSMutableString stringWithCapacity:8 * [self degree]]; + for (int degree = [self degree]; degree >= 0; degree--) { + int coefficient = [self coefficient:degree]; + if (coefficient != 0) { + if (coefficient < 0) { + [result appendString:@" - "]; + coefficient = -coefficient; + } else { + if ([result length] > 0) { + [result appendString:@" + "]; + } + } + if (degree == 0 || coefficient != 1) { + [result appendFormat:@"%d", coefficient]; + } + if (degree != 0) { + if (degree == 1) { + [result appendString:@"x"]; + } else { + [result appendString:@"x^"]; + [result appendFormat:@"%d", degree]; + } + } + } + } + + return result; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ec/ZXPDF417ECErrorCorrection.h b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ec/ZXPDF417ECErrorCorrection.h new file mode 100755 index 0000000..3f89cfb --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ec/ZXPDF417ECErrorCorrection.h @@ -0,0 +1,32 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXIntArray; + +/** + * PDF417 error correction implementation. + * + * This example + * is quite useful in understanding the algorithm. + */ +@interface ZXPDF417ECErrorCorrection : NSObject + +/** + * @return number of errors + */ +- (int)decode:(ZXIntArray *)received numECCodewords:(int)numECCodewords erasures:(ZXIntArray *)erasures; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ec/ZXPDF417ECErrorCorrection.m b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ec/ZXPDF417ECErrorCorrection.m new file mode 100755 index 0000000..4b8922f --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/decoder/ec/ZXPDF417ECErrorCorrection.m @@ -0,0 +1,181 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXIntArray.h" +#import "ZXModulusGF.h" +#import "ZXModulusPoly.h" +#import "ZXPDF417ECErrorCorrection.h" + +@interface ZXPDF417ECErrorCorrection () + +@property (nonatomic, strong, readonly) ZXModulusGF *field; + +@end + +@implementation ZXPDF417ECErrorCorrection + +- (id)init { + if (self = [super init]) { + _field = [ZXModulusGF PDF417_GF]; + } + + return self; +} + +- (int)decode:(ZXIntArray *)received numECCodewords:(int)numECCodewords erasures:(ZXIntArray *)erasures { + ZXModulusPoly *poly = [[ZXModulusPoly alloc] initWithField:self.field coefficients:received]; + ZXIntArray *S = [[ZXIntArray alloc] initWithLength:numECCodewords]; + BOOL error = NO; + for (int i = numECCodewords; i > 0; i--) { + int eval = [poly evaluateAt:[self.field exp:i]]; + S.array[numECCodewords - i] = eval; + if (eval != 0) { + error = YES; + } + } + + if (!error) { + return 0; + } + + ZXModulusPoly *knownErrors = self.field.one; + if (erasures) { + for (int i = 0; i < erasures.length; i++) { + int erasure = erasures.array[i]; + int b = [self.field exp:received.length - 1 - erasure]; + // Add (1 - bx) term: + ZXModulusPoly *term = [[ZXModulusPoly alloc] initWithField:self.field coefficients:[[ZXIntArray alloc] initWithInts:[self.field subtract:0 b:b], 1, -1]]; + knownErrors = [knownErrors multiply:term]; + } + } + + ZXModulusPoly *syndrome = [[ZXModulusPoly alloc] initWithField:self.field coefficients:S]; + //[syndrome multiply:knownErrors]; + + NSArray *sigmaOmega = [self runEuclideanAlgorithm:[self.field buildMonomial:numECCodewords coefficient:1] b:syndrome R:numECCodewords]; + if (!sigmaOmega) { + return -1; + } + + ZXModulusPoly *sigma = sigmaOmega[0]; + ZXModulusPoly *omega = sigmaOmega[1]; + + //sigma = [sigma multiply:knownErrors]; + + ZXIntArray *errorLocations = [self findErrorLocations:sigma]; + if (!errorLocations) return -1; + ZXIntArray *errorMagnitudes = [self findErrorMagnitudes:omega errorLocator:sigma errorLocations:errorLocations]; + + for (int i = 0; i < errorLocations.length; i++) { + int position = received.length - 1 - [self.field log:errorLocations.array[i]]; + if (position < 0) { + return -1; + } + received.array[position] = [self.field subtract:received.array[position] b:errorMagnitudes.array[i]]; + } + + return errorLocations.length; +} + +- (NSArray *)runEuclideanAlgorithm:(ZXModulusPoly *)a b:(ZXModulusPoly *)b R:(int)R { + // Assume a's degree is >= b's + if (a.degree < b.degree) { + ZXModulusPoly *temp = a; + a = b; + b = temp; + } + + ZXModulusPoly *rLast = a; + ZXModulusPoly *r = b; + ZXModulusPoly *tLast = self.field.zero; + ZXModulusPoly *t = self.field.one; + + // Run Euclidean algorithm until r's degree is less than R/2 + while (r.degree >= R / 2) { + ZXModulusPoly *rLastLast = rLast; + ZXModulusPoly *tLastLast = tLast; + rLast = r; + tLast = t; + + // Divide rLastLast by rLast, with quotient in q and remainder in r + if (rLast.zero) { + // Oops, Euclidean algorithm already terminated? + return nil; + } + r = rLastLast; + ZXModulusPoly *q = self.field.zero; + int denominatorLeadingTerm = [rLast coefficient:rLast.degree]; + int dltInverse = [self.field inverse:denominatorLeadingTerm]; + while (r.degree >= rLast.degree && !r.zero) { + int degreeDiff = r.degree - rLast.degree; + int scale = [self.field multiply:[r coefficient:r.degree] b:dltInverse]; + q = [q add:[self.field buildMonomial:degreeDiff coefficient:scale]]; + r = [r subtract:[rLast multiplyByMonomial:degreeDiff coefficient:scale]]; + } + + t = [[[q multiply:tLast] subtract:tLastLast] negative]; + } + + int sigmaTildeAtZero = [t coefficient:0]; + if (sigmaTildeAtZero == 0) { + return nil; + } + + int inverse = [self.field inverse:sigmaTildeAtZero]; + ZXModulusPoly *sigma = [t multiplyScalar:inverse]; + ZXModulusPoly *omega = [r multiplyScalar:inverse]; + return @[sigma, omega]; +} + +- (ZXIntArray *)findErrorLocations:(ZXModulusPoly *)errorLocator { + // This is a direct application of Chien's search + int numErrors = errorLocator.degree; + ZXIntArray *result = [[ZXIntArray alloc] initWithLength:numErrors]; + int e = 0; + for (int i = 1; i < self.field.size && e < numErrors; i++) { + if ([errorLocator evaluateAt:i] == 0) { + result.array[e] = [self.field inverse:i]; + e++; + } + } + if (e != numErrors) { + return nil; + } + return result; +} + +- (ZXIntArray *)findErrorMagnitudes:(ZXModulusPoly *)errorEvaluator errorLocator:(ZXModulusPoly *)errorLocator errorLocations:(ZXIntArray *)errorLocations { + int errorLocatorDegree = errorLocator.degree; + ZXIntArray *formalDerivativeCoefficients = [[ZXIntArray alloc] initWithLength:errorLocatorDegree]; + for (int i = 1; i <= errorLocatorDegree; i++) { + formalDerivativeCoefficients.array[errorLocatorDegree - i] = + [self.field multiply:i b:[errorLocator coefficient:i]]; + } + ZXModulusPoly *formalDerivative = [[ZXModulusPoly alloc] initWithField:self.field coefficients:formalDerivativeCoefficients]; + + // This is directly applying Forney's Formula + int s = errorLocations.length; + ZXIntArray *result = [[ZXIntArray alloc] initWithLength:s]; + for (int i = 0; i < s; i++) { + int xiInverse = [self.field inverse:errorLocations.array[i]]; + int numerator = [self.field subtract:0 b:[errorEvaluator evaluateAt:xiInverse]]; + int denominator = [self.field inverse:[formalDerivative evaluateAt:xiInverse]]; + result.array[i] = [self.field multiply:numerator b:denominator]; + } + return result; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/detector/ZXPDF417Detector.h b/iDearQRCode/Tools/ZXingObjC/pdf417/detector/ZXPDF417Detector.h new file mode 100755 index 0000000..2ebaee8 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/detector/ZXPDF417Detector.h @@ -0,0 +1,36 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXBinaryBitmap, ZXBitArray, ZXBitMatrix, ZXDecodeHints, ZXPDF417DetectorResult; + +/** + * Encapsulates logic that can detect a PDF417 Code in an image, even if the + * PDF417 Code is rotated or skewed, or partially obscured. + */ +@interface ZXPDF417Detector : NSObject + +/** + * Detects a PDF417 Code in an image. Only checks 0 and 180 degree rotations. + * + * @param hints optional hints to detector + * @param multiple if true, then the image is searched for multiple codes. If false, then at most one code will + * be found and returned + * @return ZXPDF417DetectorResult encapsulating results of detecting a PDF417 code or nil + * if no PDF417 Code can be found + */ ++ (ZXPDF417DetectorResult *)detect:(ZXBinaryBitmap *)image hints:(ZXDecodeHints *)hints multiple:(BOOL)multiple error:(NSError **)error; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/detector/ZXPDF417Detector.m b/iDearQRCode/Tools/ZXingObjC/pdf417/detector/ZXPDF417Detector.m new file mode 100755 index 0000000..50333c3 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/detector/ZXPDF417Detector.m @@ -0,0 +1,348 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitArray.h" +#import "ZXBitMatrix.h" +#import "ZXBinaryBitmap.h" +#import "ZXDecodeHints.h" +#import "ZXErrors.h" +#import "ZXGridSampler.h" +#import "ZXMathUtils.h" +#import "ZXPDF417Detector.h" +#import "ZXPDF417DetectorResult.h" +#import "ZXPerspectiveTransform.h" +#import "ZXResultPoint.h" + +const int ZX_PDF417_INDEXES_START_PATTERN[] = {0, 4, 1, 5}; +const int ZX_PDF417_INDEXES_STOP_PATTERN[] = {6, 2, 7, 3}; +const float ZX_PDF417_MAX_AVG_VARIANCE = 0.42f; +const float ZX_PDF417_MAX_INDIVIDUAL_VARIANCE = 0.8f; + +// B S B S B S B S Bar/Space pattern +// 11111111 0 1 0 1 0 1 000 +const int ZX_PDF417_DETECTOR_START_PATTERN[] = {8, 1, 1, 1, 1, 1, 1, 3}; + +// 1111111 0 1 000 1 0 1 00 1 +const int ZX_PDF417_DETECTOR_STOP_PATTERN[] = {7, 1, 1, 3, 1, 1, 1, 2, 1}; +const int ZX_PDF417_MAX_PIXEL_DRIFT = 3; +const int ZX_PDF417_MAX_PATTERN_DRIFT = 5; +// if we set the value too low, then we don't detect the correct height of the bar if the start patterns are damaged. +// if we set the value too high, then we might detect the start pattern from a neighbor barcode. +const int ZX_PDF417_SKIPPED_ROW_COUNT_MAX = 25; +// A PDF471 barcode should have at least 3 rows, with each row being >= 3 times the module width. Therefore it should be at least +// 9 pixels tall. To be conservative, we use about half the size to ensure we don't miss it. +const int ZX_PDF417_ROW_STEP = 5; +const int ZX_PDF417_BARCODE_MIN_HEIGHT = 10; + +@implementation ZXPDF417Detector + ++ (ZXPDF417DetectorResult *)detect:(ZXBinaryBitmap *)image hints:(ZXDecodeHints *)hints multiple:(BOOL)multiple error:(NSError **)error { + // TODO detection improvement, tryHarder could try several different luminance thresholds/blackpoints or even + // different binarizers + //boolean tryHarder = hints != null && hints.containsKey(DecodeHintType.TRY_HARDER); + + ZXBitMatrix *bitMatrix = [image blackMatrixWithError:error]; + + NSArray *barcodeCoordinates = [self detect:multiple bitMatrix:bitMatrix error:error]; + if (!barcodeCoordinates) { + return nil; + } + if ([barcodeCoordinates count] == 0) { + bitMatrix = [bitMatrix copy]; + [bitMatrix rotate180]; + barcodeCoordinates = [self detect:multiple bitMatrix:bitMatrix error:error]; + if (!barcodeCoordinates) { + return nil; + } + } + return [[ZXPDF417DetectorResult alloc] initWithBits:bitMatrix points:barcodeCoordinates]; +} + +/** + * Detects PDF417 codes in an image. Only checks 0 degree rotation + * @param multiple if true, then the image is searched for multiple codes. If false, then at most one code will + * be found and returned + * @param bitMatrix bit matrix to detect barcodes in + * @return List of ResultPoint arrays containing the coordinates of found barcodes + */ ++ (NSArray *)detect:(BOOL)multiple bitMatrix:(ZXBitMatrix *)bitMatrix error:(NSError **)error { + NSMutableArray *barcodeCoordinates = [NSMutableArray array]; + int row = 0; + int column = 0; + BOOL foundBarcodeInRow = NO; + while (row < bitMatrix.height) { + NSArray *vertices = [self findVertices:bitMatrix startRow:row startColumn:column]; + + if (vertices[0] == [NSNull null] && vertices[3] == [NSNull null]) { + if (!foundBarcodeInRow) { + // we didn't find any barcode so that's the end of searching + break; + } + // we didn't find a barcode starting at the given column and row. Try again from the first column and slightly + // below the lowest barcode we found so far. + foundBarcodeInRow = NO; + column = 0; + for (NSArray *barcodeCoordinate in barcodeCoordinates) { + if (barcodeCoordinate[1] != [NSNull null]) { + row = MAX(row, (int) [(ZXResultPoint *)barcodeCoordinate[1] y]); + } + if (barcodeCoordinate[3] != [NSNull null]) { + row = MAX(row, (int) [(ZXResultPoint *)barcodeCoordinate[3] y]); + } + } + row += ZX_PDF417_ROW_STEP; + continue; + } + foundBarcodeInRow = YES; + [barcodeCoordinates addObject:vertices]; + if (!multiple) { + break; + } + // if we didn't find a right row indicator column, then continue the search for the next barcode after the + // start pattern of the barcode just found. + if (vertices[2] != [NSNull null]) { + column = (int) [(ZXResultPoint *)vertices[2] x]; + row = (int) [(ZXResultPoint *)vertices[2] y]; + } else { + column = (int) [(ZXResultPoint *)vertices[4] x]; + row = (int) [(ZXResultPoint *)vertices[4] y]; + } + } + return barcodeCoordinates; +} + +/** + * Locate the vertices and the codewords area of a black blob using the Start + * and Stop patterns as locators. + * + * @param matrix the scanned barcode image. + * @return an array containing the vertices: + * vertices[0] x, y top left barcode + * vertices[1] x, y bottom left barcode + * vertices[2] x, y top right barcode + * vertices[3] x, y bottom right barcode + * vertices[4] x, y top left codeword area + * vertices[5] x, y bottom left codeword area + * vertices[6] x, y top right codeword area + * vertices[7] x, y bottom right codeword area + */ ++ (NSMutableArray *)findVertices:(ZXBitMatrix *)matrix startRow:(int)startRow startColumn:(int)startColumn { + int height = matrix.height; + int width = matrix.width; + + NSMutableArray *result = [NSMutableArray arrayWithCapacity:8]; + for (int i = 0; i < 8; i++) { + [result addObject:[NSNull null]]; + } + [self copyToResult:result + tmpResult:[self findRowsWithPattern:matrix + height:height + width:width + startRow:startRow + startColumn:startColumn + pattern:ZX_PDF417_DETECTOR_START_PATTERN + patternLen:sizeof(ZX_PDF417_DETECTOR_START_PATTERN) / sizeof(int)] + destinationIndexes:ZX_PDF417_INDEXES_START_PATTERN + length:sizeof(ZX_PDF417_INDEXES_START_PATTERN) / sizeof(int)]; + + if (result[4] != [NSNull null]) { + startColumn = (int) [(ZXResultPoint *)result[4] x]; + startRow = (int) [(ZXResultPoint *)result[4] y]; + } + [self copyToResult:result + tmpResult:[self findRowsWithPattern:matrix + height:height + width:width + startRow:startRow + startColumn:startColumn + pattern:ZX_PDF417_DETECTOR_STOP_PATTERN + patternLen:sizeof(ZX_PDF417_DETECTOR_STOP_PATTERN) / sizeof(int)] + destinationIndexes:ZX_PDF417_INDEXES_STOP_PATTERN + length:sizeof(ZX_PDF417_INDEXES_STOP_PATTERN) / sizeof(int)]; + return result; +} + ++ (void)copyToResult:(NSMutableArray *)result tmpResult:(NSMutableArray *)tmpResult destinationIndexes:(const int[])destinationIndexes length:(int)length { + for (int i = 0; i < length; i++) { + result[destinationIndexes[i]] = tmpResult[i]; + } +} + ++ (NSMutableArray *)findRowsWithPattern:(ZXBitMatrix *)matrix height:(int)height width:(int)width startRow:(int)startRow + startColumn:(int)startColumn pattern:(const int[])pattern patternLen:(int)patternLen { + NSMutableArray *result = [NSMutableArray array]; + for (int i = 0; i < 4; i++) { + [result addObject:[NSNull null]]; + } + BOOL found = NO; + int counters[patternLen]; + memset(counters, 0, patternLen * sizeof(int)); + for (; startRow < height; startRow += ZX_PDF417_ROW_STEP) { + NSRange loc = [self findGuardPattern:matrix column:startColumn row:startRow width:width whiteFirst:false pattern:pattern patternLen:patternLen counters:counters]; + if (loc.location != NSNotFound) { + while (startRow > 0) { + NSRange previousRowLoc = [self findGuardPattern:matrix column:startColumn row:--startRow width:width whiteFirst:false pattern:pattern patternLen:patternLen counters:counters]; + if (previousRowLoc.location != NSNotFound) { + loc = previousRowLoc; + } else { + startRow++; + break; + } + } + result[0] = [[ZXResultPoint alloc] initWithX:loc.location y:startRow]; + result[1] = [[ZXResultPoint alloc] initWithX:NSMaxRange(loc) y:startRow]; + found = YES; + break; + } + } + int stopRow = startRow + 1; + // Last row of the current symbol that contains pattern + if (found) { + int skippedRowCount = 0; + NSRange previousRowLoc = NSMakeRange((NSUInteger) [(ZXResultPoint *)result[0] x], ((NSUInteger)[(ZXResultPoint *)result[1] x]) - ((NSUInteger)[(ZXResultPoint *)result[0] x])); + for (; stopRow < height; stopRow++) { + NSRange loc = [self findGuardPattern:matrix column:(int)previousRowLoc.location row:stopRow width:width whiteFirst:NO pattern:pattern patternLen:patternLen counters:counters]; + // a found pattern is only considered to belong to the same barcode if the start and end positions + // don't differ too much. Pattern drift should be not bigger than two for consecutive rows. With + // a higher number of skipped rows drift could be larger. To keep it simple for now, we allow a slightly + // larger drift and don't check for skipped rows. + if (loc.location != NSNotFound && + ABS((int)previousRowLoc.location - (int)loc.location) < ZX_PDF417_MAX_PATTERN_DRIFT && + ABS((int)NSMaxRange(previousRowLoc) - (int)NSMaxRange(loc)) < ZX_PDF417_MAX_PATTERN_DRIFT) { + previousRowLoc = loc; + skippedRowCount = 0; + } else { + if (skippedRowCount > ZX_PDF417_SKIPPED_ROW_COUNT_MAX) { + break; + } else { + skippedRowCount++; + } + } + } + stopRow -= skippedRowCount + 1; + result[2] = [[ZXResultPoint alloc] initWithX:previousRowLoc.location y:stopRow]; + result[3] = [[ZXResultPoint alloc] initWithX:NSMaxRange(previousRowLoc) y:stopRow]; + } + if (stopRow - startRow < ZX_PDF417_BARCODE_MIN_HEIGHT) { + for (int i = 0; i < 4; i++) { + result[i] = [NSNull null]; + } + } + return result; +} + +/** + * @param matrix row of black/white values to search + * @param column x position to start search + * @param row y position to start search + * @param width the number of pixels to search on this row + * @param pattern pattern of counts of number of black and white pixels that are + * being searched for as a pattern + * @param counters array of counters, as long as pattern, to re-use + * @return start/end horizontal offset of guard pattern, as an array of two ints. + */ ++ (NSRange)findGuardPattern:(ZXBitMatrix *)matrix + column:(int)column + row:(int)row + width:(int)width + whiteFirst:(BOOL)whiteFirst + pattern:(const int[])pattern + patternLen:(int)patternLen + counters:(int *)counters { + int patternLength = patternLen; + memset(counters, 0, patternLength * sizeof(int)); + BOOL isWhite = whiteFirst; + int patternStart = column; + int pixelDrift = 0; + + // if there are black pixels left of the current pixel shift to the left, but only for ZX_PDF417_MAX_PIXEL_DRIFT pixels + while ([matrix getX:patternStart y:row] && patternStart > 0 && pixelDrift++ < ZX_PDF417_MAX_PIXEL_DRIFT) { + patternStart--; + } + int x = patternStart; + int counterPosition = 0; + for (;x < width; x++) { + BOOL pixel = [matrix getX:x y:row]; + if (pixel ^ isWhite) { + counters[counterPosition] = counters[counterPosition] + 1; + } else { + if (counterPosition == patternLength - 1) { + if ([self patternMatchVariance:counters countersSize:patternLength pattern:pattern maxIndividualVariance:ZX_PDF417_MAX_INDIVIDUAL_VARIANCE] < ZX_PDF417_MAX_AVG_VARIANCE) { + return NSMakeRange(patternStart, x - patternStart); + } + patternStart += counters[0] + counters[1]; + for (int y = 2; y < patternLength; y++) { + counters[y - 2] = counters[y]; + } + counters[patternLength - 2] = 0; + counters[patternLength - 1] = 0; + counterPosition--; + } else { + counterPosition++; + } + counters[counterPosition] = 1; + isWhite = !isWhite; + } + } + if (counterPosition == patternLength - 1) { + if ([self patternMatchVariance:counters countersSize:patternLen pattern:pattern maxIndividualVariance:ZX_PDF417_MAX_INDIVIDUAL_VARIANCE] < ZX_PDF417_MAX_AVG_VARIANCE) { + return NSMakeRange(patternStart, x - patternStart - 1); + } + } + return NSMakeRange(NSNotFound, 0); +} + +/** + * Determines how closely a set of observed counts of runs of black/white + * values matches a given target pattern. This is reported as the ratio of + * the total variance from the expected pattern proportions across all + * pattern elements, to the length of the pattern. + * + * @param counters observed counters + * @param pattern expected pattern + * @param maxIndividualVariance The most any counter can differ before we give up + * @return ratio of total variance between counters and pattern compared to total pattern size + */ ++ (float)patternMatchVariance:(int *)counters countersSize:(int)countersSize pattern:(const int[])pattern maxIndividualVariance:(float)maxIndividualVariance { + int numCounters = countersSize; + int total = 0; + int patternLength = 0; + for (int i = 0; i < numCounters; i++) { + total += counters[i]; + patternLength += pattern[i]; + } + + if (total < patternLength || patternLength == 0) { + return FLT_MAX; + } + float unitBarWidth = (float) total / patternLength; + maxIndividualVariance *= unitBarWidth; + + float totalVariance = 0.0f; + for (int x = 0; x < numCounters; x++) { + int counter = counters[x]; + float scaledPattern = pattern[x] * unitBarWidth; + float variance = counter > scaledPattern ? counter - scaledPattern : scaledPattern - counter; + if (variance > maxIndividualVariance) { + return FLT_MAX; + } + totalVariance += variance; + } + + return totalVariance / total; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/detector/ZXPDF417DetectorResult.h b/iDearQRCode/Tools/ZXingObjC/pdf417/detector/ZXPDF417DetectorResult.h new file mode 100755 index 0000000..b7e8c92 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/detector/ZXPDF417DetectorResult.h @@ -0,0 +1,26 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXBitMatrix; + +@interface ZXPDF417DetectorResult : NSObject + +@property (nonatomic, strong, readonly) ZXBitMatrix *bits; +@property (nonatomic, strong, readonly) NSArray *points; + +- (id)initWithBits:(ZXBitMatrix *)bits points:(NSArray *)points; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/detector/ZXPDF417DetectorResult.m b/iDearQRCode/Tools/ZXingObjC/pdf417/detector/ZXPDF417DetectorResult.m new file mode 100755 index 0000000..47fa823 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/detector/ZXPDF417DetectorResult.m @@ -0,0 +1,31 @@ +/* + * Copyright 2013 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXPDF417DetectorResult.h" + +@implementation ZXPDF417DetectorResult + +- (id)initWithBits:(ZXBitMatrix *)bits points:(NSArray *)points { + self = [super init]; + if (self) { + _bits = bits; + _points = points; + } + + return self; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417.h b/iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417.h new file mode 100755 index 0000000..76a45a1 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417.h @@ -0,0 +1,55 @@ +/* + * Copyright 2006 Jeremias Maerki in part, and ZXing Authors in part + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXEncodeHints.h" + +@class ZXPDF417BarcodeMatrix, ZXIntArray; + +/** + * Top-level class for the logic part of the PDF417 implementation. + */ +@interface ZXPDF417 : NSObject + +@property (nonatomic, strong, readonly) ZXPDF417BarcodeMatrix *barcodeMatrix; +@property (nonatomic, assign) BOOL compact; +@property (nonatomic, assign) ZXPDF417Compaction compaction; +@property (nonatomic, assign) NSStringEncoding encoding; + +- (id)initWithCompact:(BOOL)compact; + +/** + * Generates the barcode logic. + * + * @param msg the message to encode + */ +- (BOOL)generateBarcodeLogic:(NSString *)msg errorCorrectionLevel:(int)errorCorrectionLevel error:(NSError **)error; + +/** + * Determine optimal nr of columns and rows for the specified number of + * codewords. + * + * @param sourceCodeWords number of code words + * @param errorCorrectionCodeWords number of error correction code words + * @return dimension object containing cols as width and rows as height + */ +- (ZXIntArray *)determineDimensions:(int)sourceCodeWords errorCorrectionCodeWords:(int)errorCorrectionCodeWords error:(NSError **)error; + +/** + * Sets max/min row/col values + */ +- (void)setDimensionsWithMaxCols:(int)maxCols minCols:(int)minCols maxRows:(int)maxRows minRows:(int)minRows; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417.m b/iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417.m new file mode 100755 index 0000000..fb1e9b7 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417.m @@ -0,0 +1,733 @@ +/* + * Copyright 2006 Jeremias Maerki in part, and ZXing Authors in part + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXErrors.h" +#import "ZXIntArray.h" +#import "ZXPDF417.h" +#import "ZXPDF417BarcodeMatrix.h" +#import "ZXPDF417BarcodeRow.h" +#import "ZXPDF417ErrorCorrection.h" +#import "ZXPDF417HighLevelEncoder.h" + +/** + * The start pattern (17 bits) + */ +const int ZX_PDF417_START_PATTERN = 0x1fea8; +/** + * The stop pattern (18 bits) + */ +const int ZX_PDF417_STOP_PATTERN = 0x3fa29; + +/** + * The codeword table from the Annex A of ISO/IEC 15438:2001(E). + */ +#define ZX_PDF417_CODEWORD_TABLE_LEN 3 +#define ZX_PDF417_CODEWORD_TABLE_SUB_LEN 929 +const int ZX_PDF417_CODEWORD_TABLE[ZX_PDF417_CODEWORD_TABLE_LEN][ZX_PDF417_CODEWORD_TABLE_SUB_LEN] = { + {0x1d5c0, 0x1eaf0, 0x1f57c, 0x1d4e0, 0x1ea78, 0x1f53e, + 0x1a8c0, 0x1d470, 0x1a860, 0x15040, 0x1a830, 0x15020, + 0x1adc0, 0x1d6f0, 0x1eb7c, 0x1ace0, 0x1d678, 0x1eb3e, + 0x158c0, 0x1ac70, 0x15860, 0x15dc0, 0x1aef0, 0x1d77c, + 0x15ce0, 0x1ae78, 0x1d73e, 0x15c70, 0x1ae3c, 0x15ef0, + 0x1af7c, 0x15e78, 0x1af3e, 0x15f7c, 0x1f5fa, 0x1d2e0, + 0x1e978, 0x1f4be, 0x1a4c0, 0x1d270, 0x1e93c, 0x1a460, + 0x1d238, 0x14840, 0x1a430, 0x1d21c, 0x14820, 0x1a418, + 0x14810, 0x1a6e0, 0x1d378, 0x1e9be, 0x14cc0, 0x1a670, + 0x1d33c, 0x14c60, 0x1a638, 0x1d31e, 0x14c30, 0x1a61c, + 0x14ee0, 0x1a778, 0x1d3be, 0x14e70, 0x1a73c, 0x14e38, + 0x1a71e, 0x14f78, 0x1a7be, 0x14f3c, 0x14f1e, 0x1a2c0, + 0x1d170, 0x1e8bc, 0x1a260, 0x1d138, 0x1e89e, 0x14440, + 0x1a230, 0x1d11c, 0x14420, 0x1a218, 0x14410, 0x14408, + 0x146c0, 0x1a370, 0x1d1bc, 0x14660, 0x1a338, 0x1d19e, + 0x14630, 0x1a31c, 0x14618, 0x1460c, 0x14770, 0x1a3bc, + 0x14738, 0x1a39e, 0x1471c, 0x147bc, 0x1a160, 0x1d0b8, + 0x1e85e, 0x14240, 0x1a130, 0x1d09c, 0x14220, 0x1a118, + 0x1d08e, 0x14210, 0x1a10c, 0x14208, 0x1a106, 0x14360, + 0x1a1b8, 0x1d0de, 0x14330, 0x1a19c, 0x14318, 0x1a18e, + 0x1430c, 0x14306, 0x1a1de, 0x1438e, 0x14140, 0x1a0b0, + 0x1d05c, 0x14120, 0x1a098, 0x1d04e, 0x14110, 0x1a08c, + 0x14108, 0x1a086, 0x14104, 0x141b0, 0x14198, 0x1418c, + 0x140a0, 0x1d02e, 0x1a04c, 0x1a046, 0x14082, 0x1cae0, + 0x1e578, 0x1f2be, 0x194c0, 0x1ca70, 0x1e53c, 0x19460, + 0x1ca38, 0x1e51e, 0x12840, 0x19430, 0x12820, 0x196e0, + 0x1cb78, 0x1e5be, 0x12cc0, 0x19670, 0x1cb3c, 0x12c60, + 0x19638, 0x12c30, 0x12c18, 0x12ee0, 0x19778, 0x1cbbe, + 0x12e70, 0x1973c, 0x12e38, 0x12e1c, 0x12f78, 0x197be, + 0x12f3c, 0x12fbe, 0x1dac0, 0x1ed70, 0x1f6bc, 0x1da60, + 0x1ed38, 0x1f69e, 0x1b440, 0x1da30, 0x1ed1c, 0x1b420, + 0x1da18, 0x1ed0e, 0x1b410, 0x1da0c, 0x192c0, 0x1c970, + 0x1e4bc, 0x1b6c0, 0x19260, 0x1c938, 0x1e49e, 0x1b660, + 0x1db38, 0x1ed9e, 0x16c40, 0x12420, 0x19218, 0x1c90e, + 0x16c20, 0x1b618, 0x16c10, 0x126c0, 0x19370, 0x1c9bc, + 0x16ec0, 0x12660, 0x19338, 0x1c99e, 0x16e60, 0x1b738, + 0x1db9e, 0x16e30, 0x12618, 0x16e18, 0x12770, 0x193bc, + 0x16f70, 0x12738, 0x1939e, 0x16f38, 0x1b79e, 0x16f1c, + 0x127bc, 0x16fbc, 0x1279e, 0x16f9e, 0x1d960, 0x1ecb8, + 0x1f65e, 0x1b240, 0x1d930, 0x1ec9c, 0x1b220, 0x1d918, + 0x1ec8e, 0x1b210, 0x1d90c, 0x1b208, 0x1b204, 0x19160, + 0x1c8b8, 0x1e45e, 0x1b360, 0x19130, 0x1c89c, 0x16640, + 0x12220, 0x1d99c, 0x1c88e, 0x16620, 0x12210, 0x1910c, + 0x16610, 0x1b30c, 0x19106, 0x12204, 0x12360, 0x191b8, + 0x1c8de, 0x16760, 0x12330, 0x1919c, 0x16730, 0x1b39c, + 0x1918e, 0x16718, 0x1230c, 0x12306, 0x123b8, 0x191de, + 0x167b8, 0x1239c, 0x1679c, 0x1238e, 0x1678e, 0x167de, + 0x1b140, 0x1d8b0, 0x1ec5c, 0x1b120, 0x1d898, 0x1ec4e, + 0x1b110, 0x1d88c, 0x1b108, 0x1d886, 0x1b104, 0x1b102, + 0x12140, 0x190b0, 0x1c85c, 0x16340, 0x12120, 0x19098, + 0x1c84e, 0x16320, 0x1b198, 0x1d8ce, 0x16310, 0x12108, + 0x19086, 0x16308, 0x1b186, 0x16304, 0x121b0, 0x190dc, + 0x163b0, 0x12198, 0x190ce, 0x16398, 0x1b1ce, 0x1638c, + 0x12186, 0x16386, 0x163dc, 0x163ce, 0x1b0a0, 0x1d858, + 0x1ec2e, 0x1b090, 0x1d84c, 0x1b088, 0x1d846, 0x1b084, + 0x1b082, 0x120a0, 0x19058, 0x1c82e, 0x161a0, 0x12090, + 0x1904c, 0x16190, 0x1b0cc, 0x19046, 0x16188, 0x12084, + 0x16184, 0x12082, 0x120d8, 0x161d8, 0x161cc, 0x161c6, + 0x1d82c, 0x1d826, 0x1b042, 0x1902c, 0x12048, 0x160c8, + 0x160c4, 0x160c2, 0x18ac0, 0x1c570, 0x1e2bc, 0x18a60, + 0x1c538, 0x11440, 0x18a30, 0x1c51c, 0x11420, 0x18a18, + 0x11410, 0x11408, 0x116c0, 0x18b70, 0x1c5bc, 0x11660, + 0x18b38, 0x1c59e, 0x11630, 0x18b1c, 0x11618, 0x1160c, + 0x11770, 0x18bbc, 0x11738, 0x18b9e, 0x1171c, 0x117bc, + 0x1179e, 0x1cd60, 0x1e6b8, 0x1f35e, 0x19a40, 0x1cd30, + 0x1e69c, 0x19a20, 0x1cd18, 0x1e68e, 0x19a10, 0x1cd0c, + 0x19a08, 0x1cd06, 0x18960, 0x1c4b8, 0x1e25e, 0x19b60, + 0x18930, 0x1c49c, 0x13640, 0x11220, 0x1cd9c, 0x1c48e, + 0x13620, 0x19b18, 0x1890c, 0x13610, 0x11208, 0x13608, + 0x11360, 0x189b8, 0x1c4de, 0x13760, 0x11330, 0x1cdde, + 0x13730, 0x19b9c, 0x1898e, 0x13718, 0x1130c, 0x1370c, + 0x113b8, 0x189de, 0x137b8, 0x1139c, 0x1379c, 0x1138e, + 0x113de, 0x137de, 0x1dd40, 0x1eeb0, 0x1f75c, 0x1dd20, + 0x1ee98, 0x1f74e, 0x1dd10, 0x1ee8c, 0x1dd08, 0x1ee86, + 0x1dd04, 0x19940, 0x1ccb0, 0x1e65c, 0x1bb40, 0x19920, + 0x1eedc, 0x1e64e, 0x1bb20, 0x1dd98, 0x1eece, 0x1bb10, + 0x19908, 0x1cc86, 0x1bb08, 0x1dd86, 0x19902, 0x11140, + 0x188b0, 0x1c45c, 0x13340, 0x11120, 0x18898, 0x1c44e, + 0x17740, 0x13320, 0x19998, 0x1ccce, 0x17720, 0x1bb98, + 0x1ddce, 0x18886, 0x17710, 0x13308, 0x19986, 0x17708, + 0x11102, 0x111b0, 0x188dc, 0x133b0, 0x11198, 0x188ce, + 0x177b0, 0x13398, 0x199ce, 0x17798, 0x1bbce, 0x11186, + 0x13386, 0x111dc, 0x133dc, 0x111ce, 0x177dc, 0x133ce, + 0x1dca0, 0x1ee58, 0x1f72e, 0x1dc90, 0x1ee4c, 0x1dc88, + 0x1ee46, 0x1dc84, 0x1dc82, 0x198a0, 0x1cc58, 0x1e62e, + 0x1b9a0, 0x19890, 0x1ee6e, 0x1b990, 0x1dccc, 0x1cc46, + 0x1b988, 0x19884, 0x1b984, 0x19882, 0x1b982, 0x110a0, + 0x18858, 0x1c42e, 0x131a0, 0x11090, 0x1884c, 0x173a0, + 0x13190, 0x198cc, 0x18846, 0x17390, 0x1b9cc, 0x11084, + 0x17388, 0x13184, 0x11082, 0x13182, 0x110d8, 0x1886e, + 0x131d8, 0x110cc, 0x173d8, 0x131cc, 0x110c6, 0x173cc, + 0x131c6, 0x110ee, 0x173ee, 0x1dc50, 0x1ee2c, 0x1dc48, + 0x1ee26, 0x1dc44, 0x1dc42, 0x19850, 0x1cc2c, 0x1b8d0, + 0x19848, 0x1cc26, 0x1b8c8, 0x1dc66, 0x1b8c4, 0x19842, + 0x1b8c2, 0x11050, 0x1882c, 0x130d0, 0x11048, 0x18826, + 0x171d0, 0x130c8, 0x19866, 0x171c8, 0x1b8e6, 0x11042, + 0x171c4, 0x130c2, 0x171c2, 0x130ec, 0x171ec, 0x171e6, + 0x1ee16, 0x1dc22, 0x1cc16, 0x19824, 0x19822, 0x11028, + 0x13068, 0x170e8, 0x11022, 0x13062, 0x18560, 0x10a40, + 0x18530, 0x10a20, 0x18518, 0x1c28e, 0x10a10, 0x1850c, + 0x10a08, 0x18506, 0x10b60, 0x185b8, 0x1c2de, 0x10b30, + 0x1859c, 0x10b18, 0x1858e, 0x10b0c, 0x10b06, 0x10bb8, + 0x185de, 0x10b9c, 0x10b8e, 0x10bde, 0x18d40, 0x1c6b0, + 0x1e35c, 0x18d20, 0x1c698, 0x18d10, 0x1c68c, 0x18d08, + 0x1c686, 0x18d04, 0x10940, 0x184b0, 0x1c25c, 0x11b40, + 0x10920, 0x1c6dc, 0x1c24e, 0x11b20, 0x18d98, 0x1c6ce, + 0x11b10, 0x10908, 0x18486, 0x11b08, 0x18d86, 0x10902, + 0x109b0, 0x184dc, 0x11bb0, 0x10998, 0x184ce, 0x11b98, + 0x18dce, 0x11b8c, 0x10986, 0x109dc, 0x11bdc, 0x109ce, + 0x11bce, 0x1cea0, 0x1e758, 0x1f3ae, 0x1ce90, 0x1e74c, + 0x1ce88, 0x1e746, 0x1ce84, 0x1ce82, 0x18ca0, 0x1c658, + 0x19da0, 0x18c90, 0x1c64c, 0x19d90, 0x1cecc, 0x1c646, + 0x19d88, 0x18c84, 0x19d84, 0x18c82, 0x19d82, 0x108a0, + 0x18458, 0x119a0, 0x10890, 0x1c66e, 0x13ba0, 0x11990, + 0x18ccc, 0x18446, 0x13b90, 0x19dcc, 0x10884, 0x13b88, + 0x11984, 0x10882, 0x11982, 0x108d8, 0x1846e, 0x119d8, + 0x108cc, 0x13bd8, 0x119cc, 0x108c6, 0x13bcc, 0x119c6, + 0x108ee, 0x119ee, 0x13bee, 0x1ef50, 0x1f7ac, 0x1ef48, + 0x1f7a6, 0x1ef44, 0x1ef42, 0x1ce50, 0x1e72c, 0x1ded0, + 0x1ef6c, 0x1e726, 0x1dec8, 0x1ef66, 0x1dec4, 0x1ce42, + 0x1dec2, 0x18c50, 0x1c62c, 0x19cd0, 0x18c48, 0x1c626, + 0x1bdd0, 0x19cc8, 0x1ce66, 0x1bdc8, 0x1dee6, 0x18c42, + 0x1bdc4, 0x19cc2, 0x1bdc2, 0x10850, 0x1842c, 0x118d0, + 0x10848, 0x18426, 0x139d0, 0x118c8, 0x18c66, 0x17bd0, + 0x139c8, 0x19ce6, 0x10842, 0x17bc8, 0x1bde6, 0x118c2, + 0x17bc4, 0x1086c, 0x118ec, 0x10866, 0x139ec, 0x118e6, + 0x17bec, 0x139e6, 0x17be6, 0x1ef28, 0x1f796, 0x1ef24, + 0x1ef22, 0x1ce28, 0x1e716, 0x1de68, 0x1ef36, 0x1de64, + 0x1ce22, 0x1de62, 0x18c28, 0x1c616, 0x19c68, 0x18c24, + 0x1bce8, 0x19c64, 0x18c22, 0x1bce4, 0x19c62, 0x1bce2, + 0x10828, 0x18416, 0x11868, 0x18c36, 0x138e8, 0x11864, + 0x10822, 0x179e8, 0x138e4, 0x11862, 0x179e4, 0x138e2, + 0x179e2, 0x11876, 0x179f6, 0x1ef12, 0x1de34, 0x1de32, + 0x19c34, 0x1bc74, 0x1bc72, 0x11834, 0x13874, 0x178f4, + 0x178f2, 0x10540, 0x10520, 0x18298, 0x10510, 0x10508, + 0x10504, 0x105b0, 0x10598, 0x1058c, 0x10586, 0x105dc, + 0x105ce, 0x186a0, 0x18690, 0x1c34c, 0x18688, 0x1c346, + 0x18684, 0x18682, 0x104a0, 0x18258, 0x10da0, 0x186d8, + 0x1824c, 0x10d90, 0x186cc, 0x10d88, 0x186c6, 0x10d84, + 0x10482, 0x10d82, 0x104d8, 0x1826e, 0x10dd8, 0x186ee, + 0x10dcc, 0x104c6, 0x10dc6, 0x104ee, 0x10dee, 0x1c750, + 0x1c748, 0x1c744, 0x1c742, 0x18650, 0x18ed0, 0x1c76c, + 0x1c326, 0x18ec8, 0x1c766, 0x18ec4, 0x18642, 0x18ec2, + 0x10450, 0x10cd0, 0x10448, 0x18226, 0x11dd0, 0x10cc8, + 0x10444, 0x11dc8, 0x10cc4, 0x10442, 0x11dc4, 0x10cc2, + 0x1046c, 0x10cec, 0x10466, 0x11dec, 0x10ce6, 0x11de6, + 0x1e7a8, 0x1e7a4, 0x1e7a2, 0x1c728, 0x1cf68, 0x1e7b6, + 0x1cf64, 0x1c722, 0x1cf62, 0x18628, 0x1c316, 0x18e68, + 0x1c736, 0x19ee8, 0x18e64, 0x18622, 0x19ee4, 0x18e62, + 0x19ee2, 0x10428, 0x18216, 0x10c68, 0x18636, 0x11ce8, + 0x10c64, 0x10422, 0x13de8, 0x11ce4, 0x10c62, 0x13de4, + 0x11ce2, 0x10436, 0x10c76, 0x11cf6, 0x13df6, 0x1f7d4, + 0x1f7d2, 0x1e794, 0x1efb4, 0x1e792, 0x1efb2, 0x1c714, + 0x1cf34, 0x1c712, 0x1df74, 0x1cf32, 0x1df72, 0x18614, + 0x18e34, 0x18612, 0x19e74, 0x18e32, 0x1bef4}, + {0x1f560, 0x1fab8, 0x1ea40, 0x1f530, 0x1fa9c, 0x1ea20, + 0x1f518, 0x1fa8e, 0x1ea10, 0x1f50c, 0x1ea08, 0x1f506, + 0x1ea04, 0x1eb60, 0x1f5b8, 0x1fade, 0x1d640, 0x1eb30, + 0x1f59c, 0x1d620, 0x1eb18, 0x1f58e, 0x1d610, 0x1eb0c, + 0x1d608, 0x1eb06, 0x1d604, 0x1d760, 0x1ebb8, 0x1f5de, + 0x1ae40, 0x1d730, 0x1eb9c, 0x1ae20, 0x1d718, 0x1eb8e, + 0x1ae10, 0x1d70c, 0x1ae08, 0x1d706, 0x1ae04, 0x1af60, + 0x1d7b8, 0x1ebde, 0x15e40, 0x1af30, 0x1d79c, 0x15e20, + 0x1af18, 0x1d78e, 0x15e10, 0x1af0c, 0x15e08, 0x1af06, + 0x15f60, 0x1afb8, 0x1d7de, 0x15f30, 0x1af9c, 0x15f18, + 0x1af8e, 0x15f0c, 0x15fb8, 0x1afde, 0x15f9c, 0x15f8e, + 0x1e940, 0x1f4b0, 0x1fa5c, 0x1e920, 0x1f498, 0x1fa4e, + 0x1e910, 0x1f48c, 0x1e908, 0x1f486, 0x1e904, 0x1e902, + 0x1d340, 0x1e9b0, 0x1f4dc, 0x1d320, 0x1e998, 0x1f4ce, + 0x1d310, 0x1e98c, 0x1d308, 0x1e986, 0x1d304, 0x1d302, + 0x1a740, 0x1d3b0, 0x1e9dc, 0x1a720, 0x1d398, 0x1e9ce, + 0x1a710, 0x1d38c, 0x1a708, 0x1d386, 0x1a704, 0x1a702, + 0x14f40, 0x1a7b0, 0x1d3dc, 0x14f20, 0x1a798, 0x1d3ce, + 0x14f10, 0x1a78c, 0x14f08, 0x1a786, 0x14f04, 0x14fb0, + 0x1a7dc, 0x14f98, 0x1a7ce, 0x14f8c, 0x14f86, 0x14fdc, + 0x14fce, 0x1e8a0, 0x1f458, 0x1fa2e, 0x1e890, 0x1f44c, + 0x1e888, 0x1f446, 0x1e884, 0x1e882, 0x1d1a0, 0x1e8d8, + 0x1f46e, 0x1d190, 0x1e8cc, 0x1d188, 0x1e8c6, 0x1d184, + 0x1d182, 0x1a3a0, 0x1d1d8, 0x1e8ee, 0x1a390, 0x1d1cc, + 0x1a388, 0x1d1c6, 0x1a384, 0x1a382, 0x147a0, 0x1a3d8, + 0x1d1ee, 0x14790, 0x1a3cc, 0x14788, 0x1a3c6, 0x14784, + 0x14782, 0x147d8, 0x1a3ee, 0x147cc, 0x147c6, 0x147ee, + 0x1e850, 0x1f42c, 0x1e848, 0x1f426, 0x1e844, 0x1e842, + 0x1d0d0, 0x1e86c, 0x1d0c8, 0x1e866, 0x1d0c4, 0x1d0c2, + 0x1a1d0, 0x1d0ec, 0x1a1c8, 0x1d0e6, 0x1a1c4, 0x1a1c2, + 0x143d0, 0x1a1ec, 0x143c8, 0x1a1e6, 0x143c4, 0x143c2, + 0x143ec, 0x143e6, 0x1e828, 0x1f416, 0x1e824, 0x1e822, + 0x1d068, 0x1e836, 0x1d064, 0x1d062, 0x1a0e8, 0x1d076, + 0x1a0e4, 0x1a0e2, 0x141e8, 0x1a0f6, 0x141e4, 0x141e2, + 0x1e814, 0x1e812, 0x1d034, 0x1d032, 0x1a074, 0x1a072, + 0x1e540, 0x1f2b0, 0x1f95c, 0x1e520, 0x1f298, 0x1f94e, + 0x1e510, 0x1f28c, 0x1e508, 0x1f286, 0x1e504, 0x1e502, + 0x1cb40, 0x1e5b0, 0x1f2dc, 0x1cb20, 0x1e598, 0x1f2ce, + 0x1cb10, 0x1e58c, 0x1cb08, 0x1e586, 0x1cb04, 0x1cb02, + 0x19740, 0x1cbb0, 0x1e5dc, 0x19720, 0x1cb98, 0x1e5ce, + 0x19710, 0x1cb8c, 0x19708, 0x1cb86, 0x19704, 0x19702, + 0x12f40, 0x197b0, 0x1cbdc, 0x12f20, 0x19798, 0x1cbce, + 0x12f10, 0x1978c, 0x12f08, 0x19786, 0x12f04, 0x12fb0, + 0x197dc, 0x12f98, 0x197ce, 0x12f8c, 0x12f86, 0x12fdc, + 0x12fce, 0x1f6a0, 0x1fb58, 0x16bf0, 0x1f690, 0x1fb4c, + 0x169f8, 0x1f688, 0x1fb46, 0x168fc, 0x1f684, 0x1f682, + 0x1e4a0, 0x1f258, 0x1f92e, 0x1eda0, 0x1e490, 0x1fb6e, + 0x1ed90, 0x1f6cc, 0x1f246, 0x1ed88, 0x1e484, 0x1ed84, + 0x1e482, 0x1ed82, 0x1c9a0, 0x1e4d8, 0x1f26e, 0x1dba0, + 0x1c990, 0x1e4cc, 0x1db90, 0x1edcc, 0x1e4c6, 0x1db88, + 0x1c984, 0x1db84, 0x1c982, 0x1db82, 0x193a0, 0x1c9d8, + 0x1e4ee, 0x1b7a0, 0x19390, 0x1c9cc, 0x1b790, 0x1dbcc, + 0x1c9c6, 0x1b788, 0x19384, 0x1b784, 0x19382, 0x1b782, + 0x127a0, 0x193d8, 0x1c9ee, 0x16fa0, 0x12790, 0x193cc, + 0x16f90, 0x1b7cc, 0x193c6, 0x16f88, 0x12784, 0x16f84, + 0x12782, 0x127d8, 0x193ee, 0x16fd8, 0x127cc, 0x16fcc, + 0x127c6, 0x16fc6, 0x127ee, 0x1f650, 0x1fb2c, 0x165f8, + 0x1f648, 0x1fb26, 0x164fc, 0x1f644, 0x1647e, 0x1f642, + 0x1e450, 0x1f22c, 0x1ecd0, 0x1e448, 0x1f226, 0x1ecc8, + 0x1f666, 0x1ecc4, 0x1e442, 0x1ecc2, 0x1c8d0, 0x1e46c, + 0x1d9d0, 0x1c8c8, 0x1e466, 0x1d9c8, 0x1ece6, 0x1d9c4, + 0x1c8c2, 0x1d9c2, 0x191d0, 0x1c8ec, 0x1b3d0, 0x191c8, + 0x1c8e6, 0x1b3c8, 0x1d9e6, 0x1b3c4, 0x191c2, 0x1b3c2, + 0x123d0, 0x191ec, 0x167d0, 0x123c8, 0x191e6, 0x167c8, + 0x1b3e6, 0x167c4, 0x123c2, 0x167c2, 0x123ec, 0x167ec, + 0x123e6, 0x167e6, 0x1f628, 0x1fb16, 0x162fc, 0x1f624, + 0x1627e, 0x1f622, 0x1e428, 0x1f216, 0x1ec68, 0x1f636, + 0x1ec64, 0x1e422, 0x1ec62, 0x1c868, 0x1e436, 0x1d8e8, + 0x1c864, 0x1d8e4, 0x1c862, 0x1d8e2, 0x190e8, 0x1c876, + 0x1b1e8, 0x1d8f6, 0x1b1e4, 0x190e2, 0x1b1e2, 0x121e8, + 0x190f6, 0x163e8, 0x121e4, 0x163e4, 0x121e2, 0x163e2, + 0x121f6, 0x163f6, 0x1f614, 0x1617e, 0x1f612, 0x1e414, + 0x1ec34, 0x1e412, 0x1ec32, 0x1c834, 0x1d874, 0x1c832, + 0x1d872, 0x19074, 0x1b0f4, 0x19072, 0x1b0f2, 0x120f4, + 0x161f4, 0x120f2, 0x161f2, 0x1f60a, 0x1e40a, 0x1ec1a, + 0x1c81a, 0x1d83a, 0x1903a, 0x1b07a, 0x1e2a0, 0x1f158, + 0x1f8ae, 0x1e290, 0x1f14c, 0x1e288, 0x1f146, 0x1e284, + 0x1e282, 0x1c5a0, 0x1e2d8, 0x1f16e, 0x1c590, 0x1e2cc, + 0x1c588, 0x1e2c6, 0x1c584, 0x1c582, 0x18ba0, 0x1c5d8, + 0x1e2ee, 0x18b90, 0x1c5cc, 0x18b88, 0x1c5c6, 0x18b84, + 0x18b82, 0x117a0, 0x18bd8, 0x1c5ee, 0x11790, 0x18bcc, + 0x11788, 0x18bc6, 0x11784, 0x11782, 0x117d8, 0x18bee, + 0x117cc, 0x117c6, 0x117ee, 0x1f350, 0x1f9ac, 0x135f8, + 0x1f348, 0x1f9a6, 0x134fc, 0x1f344, 0x1347e, 0x1f342, + 0x1e250, 0x1f12c, 0x1e6d0, 0x1e248, 0x1f126, 0x1e6c8, + 0x1f366, 0x1e6c4, 0x1e242, 0x1e6c2, 0x1c4d0, 0x1e26c, + 0x1cdd0, 0x1c4c8, 0x1e266, 0x1cdc8, 0x1e6e6, 0x1cdc4, + 0x1c4c2, 0x1cdc2, 0x189d0, 0x1c4ec, 0x19bd0, 0x189c8, + 0x1c4e6, 0x19bc8, 0x1cde6, 0x19bc4, 0x189c2, 0x19bc2, + 0x113d0, 0x189ec, 0x137d0, 0x113c8, 0x189e6, 0x137c8, + 0x19be6, 0x137c4, 0x113c2, 0x137c2, 0x113ec, 0x137ec, + 0x113e6, 0x137e6, 0x1fba8, 0x175f0, 0x1bafc, 0x1fba4, + 0x174f8, 0x1ba7e, 0x1fba2, 0x1747c, 0x1743e, 0x1f328, + 0x1f996, 0x132fc, 0x1f768, 0x1fbb6, 0x176fc, 0x1327e, + 0x1f764, 0x1f322, 0x1767e, 0x1f762, 0x1e228, 0x1f116, + 0x1e668, 0x1e224, 0x1eee8, 0x1f776, 0x1e222, 0x1eee4, + 0x1e662, 0x1eee2, 0x1c468, 0x1e236, 0x1cce8, 0x1c464, + 0x1dde8, 0x1cce4, 0x1c462, 0x1dde4, 0x1cce2, 0x1dde2, + 0x188e8, 0x1c476, 0x199e8, 0x188e4, 0x1bbe8, 0x199e4, + 0x188e2, 0x1bbe4, 0x199e2, 0x1bbe2, 0x111e8, 0x188f6, + 0x133e8, 0x111e4, 0x177e8, 0x133e4, 0x111e2, 0x177e4, + 0x133e2, 0x177e2, 0x111f6, 0x133f6, 0x1fb94, 0x172f8, + 0x1b97e, 0x1fb92, 0x1727c, 0x1723e, 0x1f314, 0x1317e, + 0x1f734, 0x1f312, 0x1737e, 0x1f732, 0x1e214, 0x1e634, + 0x1e212, 0x1ee74, 0x1e632, 0x1ee72, 0x1c434, 0x1cc74, + 0x1c432, 0x1dcf4, 0x1cc72, 0x1dcf2, 0x18874, 0x198f4, + 0x18872, 0x1b9f4, 0x198f2, 0x1b9f2, 0x110f4, 0x131f4, + 0x110f2, 0x173f4, 0x131f2, 0x173f2, 0x1fb8a, 0x1717c, + 0x1713e, 0x1f30a, 0x1f71a, 0x1e20a, 0x1e61a, 0x1ee3a, + 0x1c41a, 0x1cc3a, 0x1dc7a, 0x1883a, 0x1987a, 0x1b8fa, + 0x1107a, 0x130fa, 0x171fa, 0x170be, 0x1e150, 0x1f0ac, + 0x1e148, 0x1f0a6, 0x1e144, 0x1e142, 0x1c2d0, 0x1e16c, + 0x1c2c8, 0x1e166, 0x1c2c4, 0x1c2c2, 0x185d0, 0x1c2ec, + 0x185c8, 0x1c2e6, 0x185c4, 0x185c2, 0x10bd0, 0x185ec, + 0x10bc8, 0x185e6, 0x10bc4, 0x10bc2, 0x10bec, 0x10be6, + 0x1f1a8, 0x1f8d6, 0x11afc, 0x1f1a4, 0x11a7e, 0x1f1a2, + 0x1e128, 0x1f096, 0x1e368, 0x1e124, 0x1e364, 0x1e122, + 0x1e362, 0x1c268, 0x1e136, 0x1c6e8, 0x1c264, 0x1c6e4, + 0x1c262, 0x1c6e2, 0x184e8, 0x1c276, 0x18de8, 0x184e4, + 0x18de4, 0x184e2, 0x18de2, 0x109e8, 0x184f6, 0x11be8, + 0x109e4, 0x11be4, 0x109e2, 0x11be2, 0x109f6, 0x11bf6, + 0x1f9d4, 0x13af8, 0x19d7e, 0x1f9d2, 0x13a7c, 0x13a3e, + 0x1f194, 0x1197e, 0x1f3b4, 0x1f192, 0x13b7e, 0x1f3b2, + 0x1e114, 0x1e334, 0x1e112, 0x1e774, 0x1e332, 0x1e772, + 0x1c234, 0x1c674, 0x1c232, 0x1cef4, 0x1c672, 0x1cef2, + 0x18474, 0x18cf4, 0x18472, 0x19df4, 0x18cf2, 0x19df2, + 0x108f4, 0x119f4, 0x108f2, 0x13bf4, 0x119f2, 0x13bf2, + 0x17af0, 0x1bd7c, 0x17a78, 0x1bd3e, 0x17a3c, 0x17a1e, + 0x1f9ca, 0x1397c, 0x1fbda, 0x17b7c, 0x1393e, 0x17b3e, + 0x1f18a, 0x1f39a, 0x1f7ba, 0x1e10a, 0x1e31a, 0x1e73a, + 0x1ef7a, 0x1c21a, 0x1c63a, 0x1ce7a, 0x1defa, 0x1843a, + 0x18c7a, 0x19cfa, 0x1bdfa, 0x1087a, 0x118fa, 0x139fa, + 0x17978, 0x1bcbe, 0x1793c, 0x1791e, 0x138be, 0x179be, + 0x178bc, 0x1789e, 0x1785e, 0x1e0a8, 0x1e0a4, 0x1e0a2, + 0x1c168, 0x1e0b6, 0x1c164, 0x1c162, 0x182e8, 0x1c176, + 0x182e4, 0x182e2, 0x105e8, 0x182f6, 0x105e4, 0x105e2, + 0x105f6, 0x1f0d4, 0x10d7e, 0x1f0d2, 0x1e094, 0x1e1b4, + 0x1e092, 0x1e1b2, 0x1c134, 0x1c374, 0x1c132, 0x1c372, + 0x18274, 0x186f4, 0x18272, 0x186f2, 0x104f4, 0x10df4, + 0x104f2, 0x10df2, 0x1f8ea, 0x11d7c, 0x11d3e, 0x1f0ca, + 0x1f1da, 0x1e08a, 0x1e19a, 0x1e3ba, 0x1c11a, 0x1c33a, + 0x1c77a, 0x1823a, 0x1867a, 0x18efa, 0x1047a, 0x10cfa, + 0x11dfa, 0x13d78, 0x19ebe, 0x13d3c, 0x13d1e, 0x11cbe, + 0x13dbe, 0x17d70, 0x1bebc, 0x17d38, 0x1be9e, 0x17d1c, + 0x17d0e, 0x13cbc, 0x17dbc, 0x13c9e, 0x17d9e, 0x17cb8, + 0x1be5e, 0x17c9c, 0x17c8e, 0x13c5e, 0x17cde, 0x17c5c, + 0x17c4e, 0x17c2e, 0x1c0b4, 0x1c0b2, 0x18174, 0x18172, + 0x102f4, 0x102f2, 0x1e0da, 0x1c09a, 0x1c1ba, 0x1813a, + 0x1837a, 0x1027a, 0x106fa, 0x10ebe, 0x11ebc, 0x11e9e, + 0x13eb8, 0x19f5e, 0x13e9c, 0x13e8e, 0x11e5e, 0x13ede, + 0x17eb0, 0x1bf5c, 0x17e98, 0x1bf4e, 0x17e8c, 0x17e86, + 0x13e5c, 0x17edc, 0x13e4e, 0x17ece, 0x17e58, 0x1bf2e, + 0x17e4c, 0x17e46, 0x13e2e, 0x17e6e, 0x17e2c, 0x17e26, + 0x10f5e, 0x11f5c, 0x11f4e, 0x13f58, 0x19fae, 0x13f4c, + 0x13f46, 0x11f2e, 0x13f6e, 0x13f2c, 0x13f26}, + {0x1abe0, 0x1d5f8, 0x153c0, 0x1a9f0, 0x1d4fc, 0x151e0, + 0x1a8f8, 0x1d47e, 0x150f0, 0x1a87c, 0x15078, 0x1fad0, + 0x15be0, 0x1adf8, 0x1fac8, 0x159f0, 0x1acfc, 0x1fac4, + 0x158f8, 0x1ac7e, 0x1fac2, 0x1587c, 0x1f5d0, 0x1faec, + 0x15df8, 0x1f5c8, 0x1fae6, 0x15cfc, 0x1f5c4, 0x15c7e, + 0x1f5c2, 0x1ebd0, 0x1f5ec, 0x1ebc8, 0x1f5e6, 0x1ebc4, + 0x1ebc2, 0x1d7d0, 0x1ebec, 0x1d7c8, 0x1ebe6, 0x1d7c4, + 0x1d7c2, 0x1afd0, 0x1d7ec, 0x1afc8, 0x1d7e6, 0x1afc4, + 0x14bc0, 0x1a5f0, 0x1d2fc, 0x149e0, 0x1a4f8, 0x1d27e, + 0x148f0, 0x1a47c, 0x14878, 0x1a43e, 0x1483c, 0x1fa68, + 0x14df0, 0x1a6fc, 0x1fa64, 0x14cf8, 0x1a67e, 0x1fa62, + 0x14c7c, 0x14c3e, 0x1f4e8, 0x1fa76, 0x14efc, 0x1f4e4, + 0x14e7e, 0x1f4e2, 0x1e9e8, 0x1f4f6, 0x1e9e4, 0x1e9e2, + 0x1d3e8, 0x1e9f6, 0x1d3e4, 0x1d3e2, 0x1a7e8, 0x1d3f6, + 0x1a7e4, 0x1a7e2, 0x145e0, 0x1a2f8, 0x1d17e, 0x144f0, + 0x1a27c, 0x14478, 0x1a23e, 0x1443c, 0x1441e, 0x1fa34, + 0x146f8, 0x1a37e, 0x1fa32, 0x1467c, 0x1463e, 0x1f474, + 0x1477e, 0x1f472, 0x1e8f4, 0x1e8f2, 0x1d1f4, 0x1d1f2, + 0x1a3f4, 0x1a3f2, 0x142f0, 0x1a17c, 0x14278, 0x1a13e, + 0x1423c, 0x1421e, 0x1fa1a, 0x1437c, 0x1433e, 0x1f43a, + 0x1e87a, 0x1d0fa, 0x14178, 0x1a0be, 0x1413c, 0x1411e, + 0x141be, 0x140bc, 0x1409e, 0x12bc0, 0x195f0, 0x1cafc, + 0x129e0, 0x194f8, 0x1ca7e, 0x128f0, 0x1947c, 0x12878, + 0x1943e, 0x1283c, 0x1f968, 0x12df0, 0x196fc, 0x1f964, + 0x12cf8, 0x1967e, 0x1f962, 0x12c7c, 0x12c3e, 0x1f2e8, + 0x1f976, 0x12efc, 0x1f2e4, 0x12e7e, 0x1f2e2, 0x1e5e8, + 0x1f2f6, 0x1e5e4, 0x1e5e2, 0x1cbe8, 0x1e5f6, 0x1cbe4, + 0x1cbe2, 0x197e8, 0x1cbf6, 0x197e4, 0x197e2, 0x1b5e0, + 0x1daf8, 0x1ed7e, 0x169c0, 0x1b4f0, 0x1da7c, 0x168e0, + 0x1b478, 0x1da3e, 0x16870, 0x1b43c, 0x16838, 0x1b41e, + 0x1681c, 0x125e0, 0x192f8, 0x1c97e, 0x16de0, 0x124f0, + 0x1927c, 0x16cf0, 0x1b67c, 0x1923e, 0x16c78, 0x1243c, + 0x16c3c, 0x1241e, 0x16c1e, 0x1f934, 0x126f8, 0x1937e, + 0x1fb74, 0x1f932, 0x16ef8, 0x1267c, 0x1fb72, 0x16e7c, + 0x1263e, 0x16e3e, 0x1f274, 0x1277e, 0x1f6f4, 0x1f272, + 0x16f7e, 0x1f6f2, 0x1e4f4, 0x1edf4, 0x1e4f2, 0x1edf2, + 0x1c9f4, 0x1dbf4, 0x1c9f2, 0x1dbf2, 0x193f4, 0x193f2, + 0x165c0, 0x1b2f0, 0x1d97c, 0x164e0, 0x1b278, 0x1d93e, + 0x16470, 0x1b23c, 0x16438, 0x1b21e, 0x1641c, 0x1640e, + 0x122f0, 0x1917c, 0x166f0, 0x12278, 0x1913e, 0x16678, + 0x1b33e, 0x1663c, 0x1221e, 0x1661e, 0x1f91a, 0x1237c, + 0x1fb3a, 0x1677c, 0x1233e, 0x1673e, 0x1f23a, 0x1f67a, + 0x1e47a, 0x1ecfa, 0x1c8fa, 0x1d9fa, 0x191fa, 0x162e0, + 0x1b178, 0x1d8be, 0x16270, 0x1b13c, 0x16238, 0x1b11e, + 0x1621c, 0x1620e, 0x12178, 0x190be, 0x16378, 0x1213c, + 0x1633c, 0x1211e, 0x1631e, 0x121be, 0x163be, 0x16170, + 0x1b0bc, 0x16138, 0x1b09e, 0x1611c, 0x1610e, 0x120bc, + 0x161bc, 0x1209e, 0x1619e, 0x160b8, 0x1b05e, 0x1609c, + 0x1608e, 0x1205e, 0x160de, 0x1605c, 0x1604e, 0x115e0, + 0x18af8, 0x1c57e, 0x114f0, 0x18a7c, 0x11478, 0x18a3e, + 0x1143c, 0x1141e, 0x1f8b4, 0x116f8, 0x18b7e, 0x1f8b2, + 0x1167c, 0x1163e, 0x1f174, 0x1177e, 0x1f172, 0x1e2f4, + 0x1e2f2, 0x1c5f4, 0x1c5f2, 0x18bf4, 0x18bf2, 0x135c0, + 0x19af0, 0x1cd7c, 0x134e0, 0x19a78, 0x1cd3e, 0x13470, + 0x19a3c, 0x13438, 0x19a1e, 0x1341c, 0x1340e, 0x112f0, + 0x1897c, 0x136f0, 0x11278, 0x1893e, 0x13678, 0x19b3e, + 0x1363c, 0x1121e, 0x1361e, 0x1f89a, 0x1137c, 0x1f9ba, + 0x1377c, 0x1133e, 0x1373e, 0x1f13a, 0x1f37a, 0x1e27a, + 0x1e6fa, 0x1c4fa, 0x1cdfa, 0x189fa, 0x1bae0, 0x1dd78, + 0x1eebe, 0x174c0, 0x1ba70, 0x1dd3c, 0x17460, 0x1ba38, + 0x1dd1e, 0x17430, 0x1ba1c, 0x17418, 0x1ba0e, 0x1740c, + 0x132e0, 0x19978, 0x1ccbe, 0x176e0, 0x13270, 0x1993c, + 0x17670, 0x1bb3c, 0x1991e, 0x17638, 0x1321c, 0x1761c, + 0x1320e, 0x1760e, 0x11178, 0x188be, 0x13378, 0x1113c, + 0x17778, 0x1333c, 0x1111e, 0x1773c, 0x1331e, 0x1771e, + 0x111be, 0x133be, 0x177be, 0x172c0, 0x1b970, 0x1dcbc, + 0x17260, 0x1b938, 0x1dc9e, 0x17230, 0x1b91c, 0x17218, + 0x1b90e, 0x1720c, 0x17206, 0x13170, 0x198bc, 0x17370, + 0x13138, 0x1989e, 0x17338, 0x1b99e, 0x1731c, 0x1310e, + 0x1730e, 0x110bc, 0x131bc, 0x1109e, 0x173bc, 0x1319e, + 0x1739e, 0x17160, 0x1b8b8, 0x1dc5e, 0x17130, 0x1b89c, + 0x17118, 0x1b88e, 0x1710c, 0x17106, 0x130b8, 0x1985e, + 0x171b8, 0x1309c, 0x1719c, 0x1308e, 0x1718e, 0x1105e, + 0x130de, 0x171de, 0x170b0, 0x1b85c, 0x17098, 0x1b84e, + 0x1708c, 0x17086, 0x1305c, 0x170dc, 0x1304e, 0x170ce, + 0x17058, 0x1b82e, 0x1704c, 0x17046, 0x1302e, 0x1706e, + 0x1702c, 0x17026, 0x10af0, 0x1857c, 0x10a78, 0x1853e, + 0x10a3c, 0x10a1e, 0x10b7c, 0x10b3e, 0x1f0ba, 0x1e17a, + 0x1c2fa, 0x185fa, 0x11ae0, 0x18d78, 0x1c6be, 0x11a70, + 0x18d3c, 0x11a38, 0x18d1e, 0x11a1c, 0x11a0e, 0x10978, + 0x184be, 0x11b78, 0x1093c, 0x11b3c, 0x1091e, 0x11b1e, + 0x109be, 0x11bbe, 0x13ac0, 0x19d70, 0x1cebc, 0x13a60, + 0x19d38, 0x1ce9e, 0x13a30, 0x19d1c, 0x13a18, 0x19d0e, + 0x13a0c, 0x13a06, 0x11970, 0x18cbc, 0x13b70, 0x11938, + 0x18c9e, 0x13b38, 0x1191c, 0x13b1c, 0x1190e, 0x13b0e, + 0x108bc, 0x119bc, 0x1089e, 0x13bbc, 0x1199e, 0x13b9e, + 0x1bd60, 0x1deb8, 0x1ef5e, 0x17a40, 0x1bd30, 0x1de9c, + 0x17a20, 0x1bd18, 0x1de8e, 0x17a10, 0x1bd0c, 0x17a08, + 0x1bd06, 0x17a04, 0x13960, 0x19cb8, 0x1ce5e, 0x17b60, + 0x13930, 0x19c9c, 0x17b30, 0x1bd9c, 0x19c8e, 0x17b18, + 0x1390c, 0x17b0c, 0x13906, 0x17b06, 0x118b8, 0x18c5e, + 0x139b8, 0x1189c, 0x17bb8, 0x1399c, 0x1188e, 0x17b9c, + 0x1398e, 0x17b8e, 0x1085e, 0x118de, 0x139de, 0x17bde, + 0x17940, 0x1bcb0, 0x1de5c, 0x17920, 0x1bc98, 0x1de4e, + 0x17910, 0x1bc8c, 0x17908, 0x1bc86, 0x17904, 0x17902, + 0x138b0, 0x19c5c, 0x179b0, 0x13898, 0x19c4e, 0x17998, + 0x1bcce, 0x1798c, 0x13886, 0x17986, 0x1185c, 0x138dc, + 0x1184e, 0x179dc, 0x138ce, 0x179ce, 0x178a0, 0x1bc58, + 0x1de2e, 0x17890, 0x1bc4c, 0x17888, 0x1bc46, 0x17884, + 0x17882, 0x13858, 0x19c2e, 0x178d8, 0x1384c, 0x178cc, + 0x13846, 0x178c6, 0x1182e, 0x1386e, 0x178ee, 0x17850, + 0x1bc2c, 0x17848, 0x1bc26, 0x17844, 0x17842, 0x1382c, + 0x1786c, 0x13826, 0x17866, 0x17828, 0x1bc16, 0x17824, + 0x17822, 0x13816, 0x17836, 0x10578, 0x182be, 0x1053c, + 0x1051e, 0x105be, 0x10d70, 0x186bc, 0x10d38, 0x1869e, + 0x10d1c, 0x10d0e, 0x104bc, 0x10dbc, 0x1049e, 0x10d9e, + 0x11d60, 0x18eb8, 0x1c75e, 0x11d30, 0x18e9c, 0x11d18, + 0x18e8e, 0x11d0c, 0x11d06, 0x10cb8, 0x1865e, 0x11db8, + 0x10c9c, 0x11d9c, 0x10c8e, 0x11d8e, 0x1045e, 0x10cde, + 0x11dde, 0x13d40, 0x19eb0, 0x1cf5c, 0x13d20, 0x19e98, + 0x1cf4e, 0x13d10, 0x19e8c, 0x13d08, 0x19e86, 0x13d04, + 0x13d02, 0x11cb0, 0x18e5c, 0x13db0, 0x11c98, 0x18e4e, + 0x13d98, 0x19ece, 0x13d8c, 0x11c86, 0x13d86, 0x10c5c, + 0x11cdc, 0x10c4e, 0x13ddc, 0x11cce, 0x13dce, 0x1bea0, + 0x1df58, 0x1efae, 0x1be90, 0x1df4c, 0x1be88, 0x1df46, + 0x1be84, 0x1be82, 0x13ca0, 0x19e58, 0x1cf2e, 0x17da0, + 0x13c90, 0x19e4c, 0x17d90, 0x1becc, 0x19e46, 0x17d88, + 0x13c84, 0x17d84, 0x13c82, 0x17d82, 0x11c58, 0x18e2e, + 0x13cd8, 0x11c4c, 0x17dd8, 0x13ccc, 0x11c46, 0x17dcc, + 0x13cc6, 0x17dc6, 0x10c2e, 0x11c6e, 0x13cee, 0x17dee, + 0x1be50, 0x1df2c, 0x1be48, 0x1df26, 0x1be44, 0x1be42, + 0x13c50, 0x19e2c, 0x17cd0, 0x13c48, 0x19e26, 0x17cc8, + 0x1be66, 0x17cc4, 0x13c42, 0x17cc2, 0x11c2c, 0x13c6c, + 0x11c26, 0x17cec, 0x13c66, 0x17ce6, 0x1be28, 0x1df16, + 0x1be24, 0x1be22, 0x13c28, 0x19e16, 0x17c68, 0x13c24, + 0x17c64, 0x13c22, 0x17c62, 0x11c16, 0x13c36, 0x17c76, + 0x1be14, 0x1be12, 0x13c14, 0x17c34, 0x13c12, 0x17c32, + 0x102bc, 0x1029e, 0x106b8, 0x1835e, 0x1069c, 0x1068e, + 0x1025e, 0x106de, 0x10eb0, 0x1875c, 0x10e98, 0x1874e, + 0x10e8c, 0x10e86, 0x1065c, 0x10edc, 0x1064e, 0x10ece, + 0x11ea0, 0x18f58, 0x1c7ae, 0x11e90, 0x18f4c, 0x11e88, + 0x18f46, 0x11e84, 0x11e82, 0x10e58, 0x1872e, 0x11ed8, + 0x18f6e, 0x11ecc, 0x10e46, 0x11ec6, 0x1062e, 0x10e6e, + 0x11eee, 0x19f50, 0x1cfac, 0x19f48, 0x1cfa6, 0x19f44, + 0x19f42, 0x11e50, 0x18f2c, 0x13ed0, 0x19f6c, 0x18f26, + 0x13ec8, 0x11e44, 0x13ec4, 0x11e42, 0x13ec2, 0x10e2c, + 0x11e6c, 0x10e26, 0x13eec, 0x11e66, 0x13ee6, 0x1dfa8, + 0x1efd6, 0x1dfa4, 0x1dfa2, 0x19f28, 0x1cf96, 0x1bf68, + 0x19f24, 0x1bf64, 0x19f22, 0x1bf62, 0x11e28, 0x18f16, + 0x13e68, 0x11e24, 0x17ee8, 0x13e64, 0x11e22, 0x17ee4, + 0x13e62, 0x17ee2, 0x10e16, 0x11e36, 0x13e76, 0x17ef6, + 0x1df94, 0x1df92, 0x19f14, 0x1bf34, 0x19f12, 0x1bf32, + 0x11e14, 0x13e34, 0x11e12, 0x17e74, 0x13e32, 0x17e72, + 0x1df8a, 0x19f0a, 0x1bf1a, 0x11e0a, 0x13e1a, 0x17e3a, + 0x1035c, 0x1034e, 0x10758, 0x183ae, 0x1074c, 0x10746, + 0x1032e, 0x1076e, 0x10f50, 0x187ac, 0x10f48, 0x187a6, + 0x10f44, 0x10f42, 0x1072c, 0x10f6c, 0x10726, 0x10f66, + 0x18fa8, 0x1c7d6, 0x18fa4, 0x18fa2, 0x10f28, 0x18796, + 0x11f68, 0x18fb6, 0x11f64, 0x10f22, 0x11f62, 0x10716, + 0x10f36, 0x11f76, 0x1cfd4, 0x1cfd2, 0x18f94, 0x19fb4, + 0x18f92, 0x19fb2, 0x10f14, 0x11f34, 0x10f12, 0x13f74, + 0x11f32, 0x13f72, 0x1cfca, 0x18f8a, 0x19f9a, 0x10f0a, + 0x11f1a, 0x13f3a, 0x103ac, 0x103a6, 0x107a8, 0x183d6, + 0x107a4, 0x107a2, 0x10396, 0x107b6, 0x187d4, 0x187d2, + 0x10794, 0x10fb4, 0x10792, 0x10fb2, 0x1c7ea}}; + +const float ZX_PDF417_PREFERRED_RATIO = 3.0f; +const float ZX_PDF417_DEFAULT_MODULE_WIDTH = 0.357f; //1px in mm +const float ZX_PDF417_HEIGHT = 2.0f; //mm + +@interface ZXPDF417 () + +@property (nonatomic, strong) ZXPDF417BarcodeMatrix *barcodeMatrix; +@property (nonatomic, assign) int minCols; +@property (nonatomic, assign) int maxCols; +@property (nonatomic, assign) int minRows; +@property (nonatomic, assign) int maxRows; + +@end + +@implementation ZXPDF417 + +- (id)init { + return [self initWithCompact:NO]; +} + +- (id)initWithCompact:(BOOL)compact { + if (self = [super init]) { + _compact = compact; + _compaction = ZXPDF417CompactionAuto; + _encoding = ZX_PDF417_DEFAULT_ENCODING; + _minCols = 2; + _maxCols = 30; + _maxRows = 30; + _minRows = 2; + } + + return self; +} + +/** + * Calculates the necessary number of rows as described in annex Q of ISO/IEC 15438:2001(E). + * + * @param m the number of source codewords prior to the additional of the Symbol Length + * Descriptor and any pad codewords + * @param k the number of error correction codewords + * @param c the number of columns in the symbol in the data region (excluding start, stop and + * row indicator codewords) + * @return the number of rows in the symbol (r) + */ +- (int)calculateNumberOfRowsM:(int)m k:(int)k c:(int)c { + int r = ((m + 1 + k) / c) + 1; + if (c * r >= (m + 1 + k + c)) { + r--; + } + return r; +} + +/** + * Calculates the number of pad codewords as described in 4.9.2 of ISO/IEC 15438:2001(E). + * + * @param m the number of source codewords prior to the additional of the Symbol Length + * Descriptor and any pad codewords + * @param k the number of error correction codewords + * @param c the number of columns in the symbol in the data region (excluding start, stop and + * row indicator codewords) + * @param r the number of rows in the symbol + * @return the number of pad codewords + */ +- (int)numberOfPadCodewordsM:(int)m k:(int)k c:(int)c r:(int)r { + int n = c * r - k; + return n > m + 1 ? n - m - 1 : 0; +} + +- (void)encodeCharPattern:(int)pattern len:(int)len logic:(ZXPDF417BarcodeRow *)logic { + int map = 1 << (len - 1); + BOOL last = (pattern & map) != 0; //Initialize to inverse of first bit + int width = 0; + for (int i = 0; i < len; i++) { + BOOL black = (pattern & map) != 0; + if (last == black) { + width++; + } else { + [logic addBar:last width:width]; + + last = black; + width = 1; + } + map >>= 1; + } + [logic addBar:last width:width]; +} + +- (void)encodeLowLevel:(NSString *)fullCodewords c:(int)c r:(int)r errorCorrectionLevel:(int)errorCorrectionLevel logic:(ZXPDF417BarcodeMatrix *)logic { + int idx = 0; + for (int y = 0; y < r; y++) { + int cluster = y % 3; + [logic startRow]; + [self encodeCharPattern:ZX_PDF417_START_PATTERN len:17 logic:logic.currentRow]; + + int left; + int right; + if (cluster == 0) { + left = (30 * (y / 3)) + ((r - 1) / 3); + right = (30 * (y / 3)) + (c - 1); + } else if (cluster == 1) { + left = (30 * (y / 3)) + (errorCorrectionLevel * 3) + ((r - 1) % 3); + right = (30 * (y / 3)) + ((r - 1) / 3); + } else { + left = (30 * (y / 3)) + (c - 1); + right = (30 * (y / 3)) + (errorCorrectionLevel * 3) + ((r - 1) % 3); + } + + int pattern = ZX_PDF417_CODEWORD_TABLE[cluster][left]; + [self encodeCharPattern:pattern len:17 logic:logic.currentRow]; + + for (int x = 0; x < c; x++) { + pattern = ZX_PDF417_CODEWORD_TABLE[cluster][[fullCodewords characterAtIndex:idx]]; + [self encodeCharPattern:pattern len:17 logic:logic.currentRow]; + idx++; + } + + if (self.compact) { + [self encodeCharPattern:ZX_PDF417_STOP_PATTERN len:1 logic:logic.currentRow]; + } else { + pattern = ZX_PDF417_CODEWORD_TABLE[cluster][right]; + [self encodeCharPattern:pattern len:17 logic:logic.currentRow]; + + [self encodeCharPattern:ZX_PDF417_STOP_PATTERN len:18 logic:logic.currentRow]; + } + } +} + +- (BOOL)generateBarcodeLogic:(NSString *)msg errorCorrectionLevel:(int)anErrorCorrectionLevel error:(NSError **)error { + + //1. step: High-level encoding + int errorCorrectionCodeWords = [ZXPDF417ErrorCorrection errorCorrectionCodewordCount:anErrorCorrectionLevel]; + NSString *highLevel = [ZXPDF417HighLevelEncoder encodeHighLevel:msg compaction:self.compaction encoding:self.encoding error:error]; + if (!highLevel) { + return NO; + } + int sourceCodeWords = (int)highLevel.length; + + ZXIntArray *dimension = [self determineDimensions:sourceCodeWords errorCorrectionCodeWords:errorCorrectionCodeWords error:error]; + if (!dimension) { + return NO; + } + + int cols = dimension.array[0]; + int rows = dimension.array[1]; + + int pad = [self numberOfPadCodewordsM:sourceCodeWords k:errorCorrectionCodeWords c:cols r:rows]; + + //2. step: construct data codewords + if (sourceCodeWords + errorCorrectionCodeWords + 1 > 929) { // +1 for symbol length CW + NSDictionary *userInfo = @{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Encoded message contains to many code words, message to big (%d bytes)", (int)msg.length]}; + + if (error) *error = [[NSError alloc] initWithDomain:ZXErrorDomain code:ZXWriterError userInfo:userInfo]; + return NO; + } + + int n = sourceCodeWords + pad + 1; + NSMutableString *sb = [NSMutableString stringWithCapacity:n]; + [sb appendFormat:@"%C", (unichar)n]; + [sb appendFormat:@"%@", highLevel]; + for (int i = 0; i < pad; i++) { + [sb appendFormat:@"%C", (unichar) 900]; //PAD characters + } + NSString *dataCodewords = sb; + + //3. step: Error correction + NSString *ec = [ZXPDF417ErrorCorrection generateErrorCorrection:dataCodewords errorCorrectionLevel:anErrorCorrectionLevel]; + NSString *fullCodewords = [dataCodewords stringByAppendingString:ec]; + + //4. step: low-level encoding + self.barcodeMatrix = [[ZXPDF417BarcodeMatrix alloc] initWithHeight:rows width:cols]; + [self encodeLowLevel:fullCodewords c:cols r:rows errorCorrectionLevel:anErrorCorrectionLevel logic:self.barcodeMatrix]; + + return YES; +} + +- (ZXIntArray *)determineDimensions:(int)sourceCodeWords errorCorrectionCodeWords:(int)errorCorrectionCodeWords error:(NSError **)error { + float ratio = 0.0f; + ZXIntArray *dimension = nil; + + for (int cols = self.minCols; cols <= self.maxCols; cols++) { + + int rows = [self calculateNumberOfRowsM:sourceCodeWords k:errorCorrectionCodeWords c:cols]; + + if (rows < self.minRows) { + break; + } + + if (rows > self.maxRows) { + continue; + } + + float newRatio = ((17 * cols + 69) * ZX_PDF417_DEFAULT_MODULE_WIDTH) / (rows * ZX_PDF417_HEIGHT); + + // ignore if previous ratio is closer to preferred ratio + if (dimension && fabsf(newRatio - ZX_PDF417_PREFERRED_RATIO) > fabsf(ratio - ZX_PDF417_PREFERRED_RATIO)) { + continue; + } + + ratio = newRatio; + dimension = [[ZXIntArray alloc] initWithInts:cols, rows, -1]; + } + + // Handle case when min values were larger than necessary + if (!dimension) { + int rows = [self calculateNumberOfRowsM:sourceCodeWords k:errorCorrectionCodeWords c:self.minCols]; + if (rows < self.minRows) { + dimension = [[ZXIntArray alloc] initWithInts:self.minCols, self.minRows, -1]; + } + } + + if (!dimension) { + NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @"Unable to fit message in columns"}; + + if (error) *error = [[NSError alloc] initWithDomain:ZXErrorDomain code:ZXWriterError userInfo:userInfo]; + return nil; + } + + return dimension; +} + +- (void)setDimensionsWithMaxCols:(int)maxCols minCols:(int)minCols maxRows:(int)maxRows minRows:(int)minRows { + self.maxCols = maxCols; + self.minCols = minCols; + self.maxRows = maxRows; + self.minRows = minRows; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417BarcodeMatrix.h b/iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417BarcodeMatrix.h new file mode 100755 index 0000000..9ff0aed --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417BarcodeMatrix.h @@ -0,0 +1,38 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXPDF417BarcodeRow; + +/** + * Holds all of the information for a barcode in a format where it can be easily accessable + */ +@interface ZXPDF417BarcodeMatrix : NSObject + +@property (nonatomic, assign, readonly) int height; +@property (nonatomic, assign, readonly) int width; + +/** + * @param height the height of the matrix (Rows) + * @param width the width of the matrix (Cols) + */ +- (id)initWithHeight:(int)height width:(int)width; +- (void)startRow; +- (ZXPDF417BarcodeRow *)currentRow; +- (NSArray *)matrix; +//- (NSArray *)scaledMatrix:(int)scale; +- (NSArray *)scaledMatrixWithXScale:(int)xScale yScale:(int)yScale; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417BarcodeMatrix.m b/iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417BarcodeMatrix.m new file mode 100755 index 0000000..6e0d452 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417BarcodeMatrix.m @@ -0,0 +1,86 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXPDF417BarcodeMatrix.h" +#import "ZXPDF417BarcodeRow.h" + +@interface ZXPDF417BarcodeMatrix () + +@property (nonatomic, assign) int currentRowIndex; +@property (nonatomic, strong, readonly) NSArray *rowMatrix; + +@end + +@implementation ZXPDF417BarcodeMatrix + +- (id)initWithHeight:(int)height width:(int)width { + if (self = [super init]) { + NSMutableArray *matrix = [NSMutableArray array]; + for (int i = 0, matrixLength = height; i < matrixLength; i++) { + [matrix addObject:[ZXPDF417BarcodeRow barcodeRowWithWidth:(width + 4) * 17 + 1]]; + } + _rowMatrix = matrix; + _width = width * 17; + _height = height; + _currentRowIndex = -1; + } + + return self; +} + +- (void)setX:(int)x y:(int)y value:(int8_t)value { + [self.rowMatrix[y] setX:x value:value]; +} + +/* +- (void)setMatrixX:(int)x y:(int)y black:(BOOL)black { + [self setX:x y:y value:(int8_t)(black ? 1 : 0)]; +} +*/ + +- (void)startRow { + ++self.currentRowIndex; +} + +- (ZXPDF417BarcodeRow *)currentRow { + return self.rowMatrix[self.currentRowIndex]; +} + +- (NSArray *)matrix { + return [self scaledMatrixWithXScale:1 yScale:1]; +} + +/* +- (NSArray *)scaledMatrix:(int)scale { + return [self scaledMatrixWithXScale:scale yScale:scale]; +} +*/ + +- (NSArray *)scaledMatrixWithXScale:(int)xScale yScale:(int)yScale { + int yMax = self.height * yScale; + NSMutableArray *matrixOut = [NSMutableArray array]; + for (int i = 0; i < yMax; i++) { + [matrixOut addObject:[NSNull null]]; + } + + for (int i = 0; i < yMax; i++) { + matrixOut[yMax - i - 1] = [(ZXPDF417BarcodeRow *)self.rowMatrix[i / yScale] scaledRow:xScale]; + } + + return matrixOut; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417BarcodeRow.h b/iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417BarcodeRow.h new file mode 100755 index 0000000..a00f7b9 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417BarcodeRow.h @@ -0,0 +1,60 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXByteArray; + +@interface ZXPDF417BarcodeRow : NSObject + +@property (nonatomic, strong, readonly) ZXByteArray *row; + +/** + * Creates a Barcode row of the width + */ ++ (ZXPDF417BarcodeRow *)barcodeRowWithWidth:(int)width; + +- (id)initWithWidth:(int)width; + +/** + * Sets a specific location in the bar + * + * @param x The location in the bar + * @param value Black if true, white if false; + */ +- (void)setX:(int)x value:(int8_t)value; + +/** + * Sets a specific location in the bar + * + * @param x The location in the bar + * @param black Black if true, white if false; + */ +- (void)setX:(int)x black:(BOOL)black; + +/** + * @param black A boolean which is true if the bar black false if it is white + * @param width How many spots wide the bar is. + */ +- (void)addBar:(BOOL)black width:(int)width; + +/** + * This function scales the row + * + * @param scale How much you want the image to be scaled, must be greater than or equal to 1. + * @return the scaled row + */ +- (ZXByteArray *)scaledRow:(int)scale; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417BarcodeRow.m b/iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417BarcodeRow.m new file mode 100755 index 0000000..6237bf5 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417BarcodeRow.m @@ -0,0 +1,63 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXByteArray.h" +#import "ZXPDF417BarcodeRow.h" + +@interface ZXPDF417BarcodeRow () + +//A tacker for position in the bar +@property (nonatomic, assign) int currentLocation; + +@end + +@implementation ZXPDF417BarcodeRow + ++ (ZXPDF417BarcodeRow *)barcodeRowWithWidth:(int)width { + return [[ZXPDF417BarcodeRow alloc] initWithWidth:width]; +} + +- (id)initWithWidth:(int)width { + if (self = [super init]) { + _row = [[ZXByteArray alloc] initWithLength:width]; + _currentLocation = 0; + } + return self; +} + +- (void)setX:(int)x value:(int8_t)value { + self.row.array[x] = value; +} + +- (void)setX:(int)x black:(BOOL)black { + self.row.array[x] = (int8_t) (black ? 1 : 0); +} + +- (void)addBar:(BOOL)black width:(int)width { + for (int ii = 0; ii < width; ii++) { + [self setX:self.currentLocation++ black:black]; + } +} + +- (ZXByteArray *)scaledRow:(int)scale { + ZXByteArray *output = [[ZXByteArray alloc] initWithLength:self.row.length * scale]; + for (int i = 0; i < output.length; i++) { + output.array[i] = self.row.array[i / scale]; + } + return output; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417Dimensions.h b/iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417Dimensions.h new file mode 100755 index 0000000..0e1f155 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417Dimensions.h @@ -0,0 +1,29 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Data object to specify the minimum and maximum number of rows and columns for a PDF417 barcode. + */ +@interface ZXPDF417Dimensions : NSObject + +@property (nonatomic, assign, readonly) int minCols; +@property (nonatomic, assign, readonly) int maxCols; +@property (nonatomic, assign, readonly) int minRows; +@property (nonatomic, assign, readonly) int maxRows; + +- (id)initWithMinCols:(int)minCols maxCols:(int)maxCols minRows:(int)minRows maxRows:(int)maxRows; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417Dimensions.m b/iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417Dimensions.m new file mode 100755 index 0000000..33529ab --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417Dimensions.m @@ -0,0 +1,32 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXPDF417Dimensions.h" + +@implementation ZXPDF417Dimensions + +- (id)initWithMinCols:(int)minCols maxCols:(int)maxCols minRows:(int)minRows maxRows:(int)maxRows { + if (self = [super init]) { + _minCols = minCols; + _maxCols = maxCols; + _minRows = minRows; + _maxRows = maxRows; + } + + return self; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417ErrorCorrection.h b/iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417ErrorCorrection.h new file mode 100755 index 0000000..de8eb75 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417ErrorCorrection.h @@ -0,0 +1,51 @@ +/* + * Copyright 2006 Jeremias Maerki in part, and ZXing Authors in part + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * PDF417 error correction code following the algorithm described in ISO/IEC 15438:2001(E) in + * chapter 4.10. + */ +@interface ZXPDF417ErrorCorrection : NSObject + +/** + * Determines the number of error correction codewords for a specified error correction + * level. + * + * @param errorCorrectionLevel the error correction level (0-8) + * @return the number of codewords generated for error correction + */ + ++ (int)errorCorrectionCodewordCount:(int)errorCorrectionLevel; + +/** + * Returns the recommended minimum error correction level as described in annex E of + * ISO/IEC 15438:2001(E). + * + * @param n the number of data codewords + * @return the recommended minimum error correction level + */ ++ (int)recommendedMinimumErrorCorrectionLevel:(int)n error:(NSError **)error; + +/** + * Generates the error correction codewords according to 4.10 in ISO/IEC 15438:2001(E). + * + * @param dataCodewords the data codewords + * @param errorCorrectionLevel the error correction level (0-8) + * @return the String representing the error correction codewords + */ ++ (NSString *)generateErrorCorrection:(NSString *)dataCodewords errorCorrectionLevel:(int)errorCorrectionLevel; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417ErrorCorrection.m b/iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417ErrorCorrection.m new file mode 100755 index 0000000..9b88804 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417ErrorCorrection.m @@ -0,0 +1,176 @@ +/* + * Copyright 2006 Jeremias Maerki in part, and ZXing Authors in part + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXErrors.h" +#import "ZXPDF417ErrorCorrection.h" + +/** + * Tables of coefficients for calculating error correction words + * (see annex F, ISO/IEC 15438:2001(E)) + */ +const int ZX_PDF417_EC_COEFFICIENTS[][512] = { + {27, 917}, + {522, 568, 723, 809}, + {237, 308, 436, 284, 646, 653, 428, 379}, + {274, 562, 232, 755, 599, 524, 801, 132, 295, 116, 442, 428, 295, + 42, 176, 65}, + {361, 575, 922, 525, 176, 586, 640, 321, 536, 742, 677, 742, 687, + 284, 193, 517, 273, 494, 263, 147, 593, 800, 571, 320, 803, + 133, 231, 390, 685, 330, 63, 410}, + {539, 422, 6, 93, 862, 771, 453, 106, 610, 287, 107, 505, 733, + 877, 381, 612, 723, 476, 462, 172, 430, 609, 858, 822, 543, + 376, 511, 400, 672, 762, 283, 184, 440, 35, 519, 31, 460, + 594, 225, 535, 517, 352, 605, 158, 651, 201, 488, 502, 648, + 733, 717, 83, 404, 97, 280, 771, 840, 629, 4, 381, 843, + 623, 264, 543}, + {521, 310, 864, 547, 858, 580, 296, 379, 53, 779, 897, 444, 400, + 925, 749, 415, 822, 93, 217, 208, 928, 244, 583, 620, 246, + 148, 447, 631, 292, 908, 490, 704, 516, 258, 457, 907, 594, + 723, 674, 292, 272, 96, 684, 432, 686, 606, 860, 569, 193, + 219, 129, 186, 236, 287, 192, 775, 278, 173, 40, 379, 712, + 463, 646, 776, 171, 491, 297, 763, 156, 732, 95, 270, 447, + 90, 507, 48, 228, 821, 808, 898, 784, 663, 627, 378, 382, + 262, 380, 602, 754, 336, 89, 614, 87, 432, 670, 616, 157, + 374, 242, 726, 600, 269, 375, 898, 845, 454, 354, 130, 814, + 587, 804, 34, 211, 330, 539, 297, 827, 865, 37, 517, 834, + 315, 550, 86, 801, 4, 108, 539}, + {524, 894, 75, 766, 882, 857, 74, 204, 82, 586, 708, 250, 905, + 786, 138, 720, 858, 194, 311, 913, 275, 190, 375, 850, 438, + 733, 194, 280, 201, 280, 828, 757, 710, 814, 919, 89, 68, + 569, 11, 204, 796, 605, 540, 913, 801, 700, 799, 137, 439, + 418, 592, 668, 353, 859, 370, 694, 325, 240, 216, 257, 284, + 549, 209, 884, 315, 70, 329, 793, 490, 274, 877, 162, 749, + 812, 684, 461, 334, 376, 849, 521, 307, 291, 803, 712, 19, + 358, 399, 908, 103, 511, 51, 8, 517, 225, 289, 470, 637, + 731, 66, 255, 917, 269, 463, 830, 730, 433, 848, 585, 136, + 538, 906, 90, 2, 290, 743, 199, 655, 903, 329, 49, 802, + 580, 355, 588, 188, 462, 10, 134, 628, 320, 479, 130, 739, + 71, 263, 318, 374, 601, 192, 605, 142, 673, 687, 234, 722, + 384, 177, 752, 607, 640, 455, 193, 689, 707, 805, 641, 48, + 60, 732, 621, 895, 544, 261, 852, 655, 309, 697, 755, 756, + 60, 231, 773, 434, 421, 726, 528, 503, 118, 49, 795, 32, + 144, 500, 238, 836, 394, 280, 566, 319, 9, 647, 550, 73, + 914, 342, 126, 32, 681, 331, 792, 620, 60, 609, 441, 180, + 791, 893, 754, 605, 383, 228, 749, 760, 213, 54, 297, 134, + 54, 834, 299, 922, 191, 910, 532, 609, 829, 189, 20, 167, + 29, 872, 449, 83, 402, 41, 656, 505, 579, 481, 173, 404, + 251, 688, 95, 497, 555, 642, 543, 307, 159, 924, 558, 648, + 55, 497, 10}, + {352, 77, 373, 504, 35, 599, 428, 207, 409, 574, 118, 498, 285, + 380, 350, 492, 197, 265, 920, 155, 914, 299, 229, 643, 294, + 871, 306, 88, 87, 193, 352, 781, 846, 75, 327, 520, 435, + 543, 203, 666, 249, 346, 781, 621, 640, 268, 794, 534, 539, + 781, 408, 390, 644, 102, 476, 499, 290, 632, 545, 37, 858, + 916, 552, 41, 542, 289, 122, 272, 383, 800, 485, 98, 752, + 472, 761, 107, 784, 860, 658, 741, 290, 204, 681, 407, 855, + 85, 99, 62, 482, 180, 20, 297, 451, 593, 913, 142, 808, + 684, 287, 536, 561, 76, 653, 899, 729, 567, 744, 390, 513, + 192, 516, 258, 240, 518, 794, 395, 768, 848, 51, 610, 384, + 168, 190, 826, 328, 596, 786, 303, 570, 381, 415, 641, 156, + 237, 151, 429, 531, 207, 676, 710, 89, 168, 304, 402, 40, + 708, 575, 162, 864, 229, 65, 861, 841, 512, 164, 477, 221, + 92, 358, 785, 288, 357, 850, 836, 827, 736, 707, 94, 8, + 494, 114, 521, 2, 499, 851, 543, 152, 729, 771, 95, 248, + 361, 578, 323, 856, 797, 289, 51, 684, 466, 533, 820, 669, + 45, 902, 452, 167, 342, 244, 173, 35, 463, 651, 51, 699, + 591, 452, 578, 37, 124, 298, 332, 552, 43, 427, 119, 662, + 777, 475, 850, 764, 364, 578, 911, 283, 711, 472, 420, 245, + 288, 594, 394, 511, 327, 589, 777, 699, 688, 43, 408, 842, + 383, 721, 521, 560, 644, 714, 559, 62, 145, 873, 663, 713, + 159, 672, 729, 624, 59, 193, 417, 158, 209, 563, 564, 343, + 693, 109, 608, 563, 365, 181, 772, 677, 310, 248, 353, 708, + 410, 579, 870, 617, 841, 632, 860, 289, 536, 35, 777, 618, + 586, 424, 833, 77, 597, 346, 269, 757, 632, 695, 751, 331, + 247, 184, 45, 787, 680, 18, 66, 407, 369, 54, 492, 228, + 613, 830, 922, 437, 519, 644, 905, 789, 420, 305, 441, 207, + 300, 892, 827, 141, 537, 381, 662, 513, 56, 252, 341, 242, + 797, 838, 837, 720, 224, 307, 631, 61, 87, 560, 310, 756, + 665, 397, 808, 851, 309, 473, 795, 378, 31, 647, 915, 459, + 806, 590, 731, 425, 216, 548, 249, 321, 881, 699, 535, 673, + 782, 210, 815, 905, 303, 843, 922, 281, 73, 469, 791, 660, + 162, 498, 308, 155, 422, 907, 817, 187, 62, 16, 425, 535, + 336, 286, 437, 375, 273, 610, 296, 183, 923, 116, 667, 751, + 353, 62, 366, 691, 379, 687, 842, 37, 357, 720, 742, 330, + 5, 39, 923, 311, 424, 242, 749, 321, 54, 669, 316, 342, + 299, 534, 105, 667, 488, 640, 672, 576, 540, 316, 486, 721, + 610, 46, 656, 447, 171, 616, 464, 190, 531, 297, 321, 762, + 752, 533, 175, 134, 14, 381, 433, 717, 45, 111, 20, 596, + 284, 736, 138, 646, 411, 877, 669, 141, 919, 45, 780, 407, + 164, 332, 899, 165, 726, 600, 325, 498, 655, 357, 752, 768, + 223, 849, 647, 63, 310, 863, 251, 366, 304, 282, 738, 675, + 410, 389, 244, 31, 121, 303, 263}}; + +@implementation ZXPDF417ErrorCorrection + ++ (int)errorCorrectionCodewordCount:(int)errorCorrectionLevel { + if (errorCorrectionLevel < 0 || errorCorrectionLevel > 8) { + [NSException raise:NSInvalidArgumentException format:@"Error correction level must be between 0 and 8!"]; + } + return 1 << (errorCorrectionLevel + 1); +} + ++ (int)recommendedMinimumErrorCorrectionLevel:(int)n error:(NSError **)error { + if (n <= 0) { + [NSException raise:NSInvalidArgumentException format:@"n must be > 0"]; + } + if (n <= 40) { + return 2; + } + if (n <= 160) { + return 3; + } + if (n <= 320) { + return 4; + } + if (n <= 863) { + return 5; + } + NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @"No recommendation possible"}; + + if (error) *error = [[NSError alloc] initWithDomain:ZXErrorDomain code:ZXWriterError userInfo:userInfo]; + return -1; +} + ++ (NSString *)generateErrorCorrection:(NSString *)dataCodewords errorCorrectionLevel:(int)errorCorrectionLevel { + int k = [self errorCorrectionCodewordCount:errorCorrectionLevel]; + unichar e[k]; + memset(e, 0, k * sizeof(unichar)); + + int sld = (int)dataCodewords.length; + for (int i = 0; i < sld; i++) { + int t1 = ([dataCodewords characterAtIndex:i] + e[k - 1]) % 929; + int t2; + int t3; + for (int j = k - 1; j >= 1; j--) { + t2 = (t1 * ZX_PDF417_EC_COEFFICIENTS[errorCorrectionLevel][j]) % 929; + t3 = 929 - t2; + e[j] = (unichar) ((e[j - 1] + t3) % 929); + } + t2 = (t1 * ZX_PDF417_EC_COEFFICIENTS[errorCorrectionLevel][0]) % 929; + t3 = 929 - t2; + e[0] = (unichar) (t3 % 929); + } + NSMutableString *sb = [NSMutableString stringWithCapacity:k]; + for (int j = k - 1; j >= 0; j--) { + if (e[j] != 0) { + e[j] = (unichar) (929 - e[j]); + } + [sb appendFormat:@"%C", e[j]]; + } + return sb; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417HighLevelEncoder.h b/iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417HighLevelEncoder.h new file mode 100755 index 0000000..9ae3deb --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417HighLevelEncoder.h @@ -0,0 +1,37 @@ +/* + * Copyright 2006 Jeremias Maerki in part, and ZXing Authors in part + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXEncodeHints.h" + +extern const NSStringEncoding ZX_PDF417_DEFAULT_ENCODING; + +/** + * PDF417 high-level encoder following the algorithm described in ISO/IEC 15438:2001(E) in + * annex P. + */ +@interface ZXPDF417HighLevelEncoder : NSObject + +/** + * Performs high-level encoding of a PDF417 message using the algorithm described in annex P + * of ISO/IEC 15438:2001(E). If byte compaction has been selected, then only byte compaction + * is used. + * + * @param msg the message + * @return the encoded message (the char values range from 0 to 928) + */ ++ (NSString *)encodeHighLevel:(NSString *)msg compaction:(ZXPDF417Compaction)compaction encoding:(NSStringEncoding)encoding error:(NSError **)error; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417HighLevelEncoder.m b/iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417HighLevelEncoder.m new file mode 100755 index 0000000..ed6198b --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/pdf417/encoder/ZXPDF417HighLevelEncoder.m @@ -0,0 +1,586 @@ +/* + * Copyright 2006 Jeremias Maerki in part, and ZXing Authors in part + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXByteArray.h" +#import "ZXCharacterSetECI.h" +#import "ZXErrors.h" +#import "ZXPDF417HighLevelEncoder.h" + +/** + * code for Text compaction + */ +const int ZX_PDF417_TEXT_COMPACTION = 0; + +/** + * code for Byte compaction + */ +const int ZX_PDF417_BYTE_COMPACTION = 1; + +/** + * code for Numeric compaction + */ +const int ZX_PDF417_NUMERIC_COMPACTION = 2; + +/** + * Text compaction submode Alpha + */ +const int ZX_PDF417_SUBMODE_ALPHA = 0; + +/** + * Text compaction submode Lower + */ +const int ZX_PDF417_SUBMODE_LOWER = 1; + +/** + * Text compaction submode Mixed + */ +const int ZX_PDF417_SUBMODE_MIXED = 2; + +/** + * Text compaction submode Punctuation + */ +const int ZX_PDF417_SUBMODE_PUNCTUATION = 3; + +/** + * mode latch to Text Compaction mode + */ +const int ZX_PDF417_LATCH_TO_TEXT = 900; + +/** + * mode latch to Byte Compaction mode (number of characters NOT a multiple of 6) + */ +const int ZX_PDF417_LATCH_TO_BYTE_PADDED = 901; + +/** + * mode latch to Numeric Compaction mode + */ +const int ZX_PDF417_LATCH_TO_NUMERIC = 902; + +/** + * mode shift to Byte Compaction mode + */ +const int ZX_PDF417_SHIFT_TO_BYTE = 913; + +/** + * mode latch to Byte Compaction mode (number of characters a multiple of 6) + */ +const int ZX_PDF417_LATCH_TO_BYTE = 924; + +/** + * identifier for a user defined Extended Channel Interpretation (ECI) + */ +const int ZX_PDF417_HIGH_LEVEL_ECI_USER_DEFINED = 925; + +/** + * identifier for a general purpose ECO format + */ +const int ZX_PDF417_HIGH_LEVEL_ECI_GENERAL_PURPOSE = 926; + +/** + * identifier for an ECI of a character set of code page + */ +const int ZX_PDF417_HIGH_LEVEL_ECI_CHARSET = 927; + +/** + * Raw code table for text compaction Mixed sub-mode + */ +const int8_t ZX_PDF417_TEXT_MIXED_RAW[] = { + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 38, 13, 9, 44, 58, + 35, 45, 46, 36, 47, 43, 37, 42, 61, 94, 0, 32, 0, 0, 0}; + +/** + * Raw code table for text compaction: Punctuation sub-mode + */ +const int8_t ZX_PDF417_TEXT_PUNCTUATION_RAW[] = { + 59, 60, 62, 64, 91, 92, 93, 95, 96, 126, 33, 13, 9, 44, 58, + 10, 45, 46, 36, 47, 34, 124, 42, 40, 41, 63, 123, 125, 39, 0}; + +const int ZX_PDF417_MIXED_TABLE_LEN = 128; +unichar ZX_PDF417_MIXED_TABLE[ZX_PDF417_MIXED_TABLE_LEN]; + +const int ZX_PDF417_PUNCTUATION_LEN = 128; +unichar ZX_PDF417_PUNCTUATION[ZX_PDF417_PUNCTUATION_LEN]; + +const NSStringEncoding ZX_PDF417_DEFAULT_ENCODING = NSISOLatin1StringEncoding; + +@implementation ZXPDF417HighLevelEncoder + ++ (void)initialize { + if ([self class] != [ZXPDF417HighLevelEncoder class]) return; + + //Construct inverse lookups + for (int i = 0; i < ZX_PDF417_MIXED_TABLE_LEN; i++) { + ZX_PDF417_MIXED_TABLE[i] = 0xFF; + } + for (int8_t i = 0; i < sizeof(ZX_PDF417_TEXT_MIXED_RAW) / sizeof(int8_t); i++) { + int8_t b = ZX_PDF417_TEXT_MIXED_RAW[i]; + if (b > 0) { + ZX_PDF417_MIXED_TABLE[b] = i; + } + } + for (int i = 0; i < ZX_PDF417_PUNCTUATION_LEN; i++) { + ZX_PDF417_PUNCTUATION[i] = 0xFF; + } + for (int8_t i = 0; i < sizeof(ZX_PDF417_TEXT_PUNCTUATION_RAW) / sizeof(int8_t); i++) { + int8_t b = ZX_PDF417_TEXT_PUNCTUATION_RAW[i]; + if (b > 0) { + ZX_PDF417_PUNCTUATION[b] = i; + } + } +} + ++ (NSString *)encodeHighLevel:(NSString *)msg compaction:(ZXPDF417Compaction)compaction encoding:(NSStringEncoding)encoding error:(NSError **)error { + //the codewords 0..928 are encoded as Unicode characters + NSMutableString *sb = [NSMutableString stringWithCapacity:msg.length]; + + if (encoding == 0) { + encoding = ZX_PDF417_DEFAULT_ENCODING; + } else if (ZX_PDF417_DEFAULT_ENCODING != encoding) { + ZXCharacterSetECI *eci = [ZXCharacterSetECI characterSetECIByEncoding:encoding]; + if (![self encodingECI:eci.value sb:sb error:error]) { + return nil; + } + } + + NSUInteger len = msg.length; + int p = 0; + int textSubMode = ZX_PDF417_SUBMODE_ALPHA; + + // User selected encoding mode + ZXByteArray *bytes = nil; //Fill later and only if needed + if (compaction == ZXPDF417CompactionText) { + [self encodeText:msg startpos:p count:(int)len buffer:sb initialSubmode:textSubMode]; + } else if (compaction == ZXPDF417CompactionByte) { + bytes = [self bytesForMessage:msg encoding:encoding]; + [self encodeBinary:bytes startpos:p count:(int)msg.length startmode:ZX_PDF417_BYTE_COMPACTION buffer:sb]; + } else if (compaction == ZXPDF417CompactionNumeric) { + [sb appendFormat:@"%C", (unichar) ZX_PDF417_LATCH_TO_NUMERIC]; + [self encodeNumeric:msg startpos:p count:(int)len buffer:sb]; + } else { + int encodingMode = ZX_PDF417_TEXT_COMPACTION; //Default mode, see 4.4.2.1 + while (p < len) { + int n = [self determineConsecutiveDigitCount:msg startpos:p]; + if (n >= 13) { + [sb appendFormat:@"%C", (unichar) ZX_PDF417_LATCH_TO_NUMERIC]; + encodingMode = ZX_PDF417_NUMERIC_COMPACTION; + textSubMode = ZX_PDF417_SUBMODE_ALPHA; //Reset after latch + [self encodeNumeric:msg startpos:p count:n buffer:sb]; + p += n; + } else { + int t = [self determineConsecutiveTextCount:msg startpos:p]; + if (t >= 5 || n == len) { + if (encodingMode != ZX_PDF417_TEXT_COMPACTION) { + [sb appendFormat:@"%C", (unichar) ZX_PDF417_LATCH_TO_TEXT]; + encodingMode = ZX_PDF417_TEXT_COMPACTION; + textSubMode = ZX_PDF417_SUBMODE_ALPHA; //start with submode alpha after latch + } + textSubMode = [self encodeText:msg startpos:p count:t buffer:sb initialSubmode:textSubMode]; + p += t; + } else { + if (bytes == NULL) { + bytes = [self bytesForMessage:msg encoding:encoding]; + } + int b = [self determineConsecutiveBinaryCount:msg bytes:bytes startpos:p error:error]; + if (b == -1) { + return nil; + } else if (b == 0) { + b = 1; + } + if (b == 1 && encodingMode == ZX_PDF417_TEXT_COMPACTION) { + //Switch for one byte (instead of latch) + [self encodeBinary:bytes startpos:p count:1 startmode:ZX_PDF417_TEXT_COMPACTION buffer:sb]; + } else { + //Mode latch performed by encodeBinary + [self encodeBinary:bytes startpos:p count:b startmode:encodingMode buffer:sb]; + encodingMode = ZX_PDF417_BYTE_COMPACTION; + textSubMode = ZX_PDF417_SUBMODE_ALPHA; //Reset after latch + } + p += b; + } + } + } + } + + return sb; +} + +/** + * Encode parts of the message using Text Compaction as described in ISO/IEC 15438:2001(E), + * chapter 4.4.2. + * + * @param msg the message + * @param startpos the start position within the message + * @param count the number of characters to encode + * @param sb receives the encoded codewords + * @param initialSubmode should normally be SUBMODE_ALPHA + * @return the text submode in which this method ends + */ ++ (int)encodeText:(NSString *)msg startpos:(int)startpos count:(int)count buffer:(NSMutableString *)sb initialSubmode:(int)initialSubmode { + NSMutableString *tmp = [NSMutableString stringWithCapacity:count]; + int submode = initialSubmode; + int idx = 0; + while (true) { + unichar ch = [msg characterAtIndex:startpos + idx]; + switch (submode) { + case ZX_PDF417_SUBMODE_ALPHA: + if ([self isAlphaUpper:ch]) { + if (ch == ' ') { + [tmp appendFormat:@"%C", (unichar) 26]; //space + } else { + [tmp appendFormat:@"%C", (unichar) (ch - 65)]; + } + } else { + if ([self isAlphaLower:ch]) { + submode = ZX_PDF417_SUBMODE_LOWER; + [tmp appendFormat:@"%C", (unichar) 27]; //ll + continue; + } else if ([self isMixed:ch]) { + submode = ZX_PDF417_SUBMODE_MIXED; + [tmp appendFormat:@"%C", (unichar) 28]; //ml + continue; + } else { + [tmp appendFormat:@"%C", (unichar) 29]; //ps + [tmp appendFormat:@"%C", ZX_PDF417_PUNCTUATION[ch]]; + break; + } + } + break; + case ZX_PDF417_SUBMODE_LOWER: + if ([self isAlphaLower:ch]) { + if (ch == ' ') { + [tmp appendFormat:@"%C", (unichar) 26]; //space + } else { + [tmp appendFormat:@"%C", (unichar) (ch - 97)]; + } + } else { + if ([self isAlphaUpper:ch]) { + [tmp appendFormat:@"%C", (unichar) 27]; //as + [tmp appendFormat:@"%C", (unichar) (ch - 65)]; + //space cannot happen here, it is also in "Lower" + break; + } else if ([self isMixed:ch]) { + submode = ZX_PDF417_SUBMODE_MIXED; + [tmp appendFormat:@"%C", (unichar) 28]; //ml + continue; + } else { + [tmp appendFormat:@"%C", (unichar) 29]; //ps + [tmp appendFormat:@"%C", ZX_PDF417_PUNCTUATION[ch]]; + break; + } + } + break; + case ZX_PDF417_SUBMODE_MIXED: + if ([self isMixed:ch]) { + [tmp appendFormat:@"%C", ZX_PDF417_MIXED_TABLE[ch]]; //as + } else { + if ([self isAlphaUpper:ch]) { + submode = ZX_PDF417_SUBMODE_ALPHA; + [tmp appendFormat:@"%C", (unichar) 28]; //al + continue; + } else if ([self isAlphaLower:ch]) { + submode = ZX_PDF417_SUBMODE_LOWER; + [tmp appendFormat:@"%C", (unichar) 27]; //ll + continue; + } else { + if (startpos + idx + 1 < count) { + char next = [msg characterAtIndex:startpos + idx + 1]; + if ([self isPunctuation:next]) { + submode = ZX_PDF417_SUBMODE_PUNCTUATION; + [tmp appendFormat:@"%C", (unichar) 25]; //pl + continue; + } + } + [tmp appendFormat:@"%C", (unichar) 29]; //ps + [tmp appendFormat:@"%C", ZX_PDF417_PUNCTUATION[ch]]; + } + } + break; + default: //ZX_PDF417_SUBMODE_PUNCTUATION + if ([self isPunctuation:ch]) { + [tmp appendFormat:@"%C", ZX_PDF417_PUNCTUATION[ch]]; + } else { + submode = ZX_PDF417_SUBMODE_ALPHA; + [tmp appendFormat:@"%C", (unichar) 29]; //al + continue; + } + } + idx++; + if (idx >= count) { + break; + } + } + unichar h = 0; + NSUInteger len = tmp.length; + for (int i = 0; i < len; i++) { + BOOL odd = (i % 2) != 0; + if (odd) { + h = (unichar) ((h * 30) + [tmp characterAtIndex:i]); + [sb appendFormat:@"%C", h]; + } else { + h = [tmp characterAtIndex:i]; + } + } + if ((len % 2) != 0) { + [sb appendFormat:@"%C", (unichar) ((h * 30) + 29)]; //ps + } + return submode; +} + +/** + * Encode parts of the message using Byte Compaction as described in ISO/IEC 15438:2001(E), + * chapter 4.4.3. The Unicode characters will be converted to binary using the cp437 + * codepage. + * + * @param bytes the message converted to a byte array + * @param startpos the start position within the message + * @param count the number of bytes to encode + * @param startmode the mode from which this method starts + * @param sb receives the encoded codewords + */ ++ (void)encodeBinary:(ZXByteArray *)bytes startpos:(int)startpos count:(int)count startmode:(int)startmode buffer:(NSMutableString *)sb { + if (count == 1 && startmode == ZX_PDF417_TEXT_COMPACTION) { + [sb appendFormat:@"%C", (unichar) ZX_PDF417_SHIFT_TO_BYTE]; + } else { + BOOL sixpack = ((count % 6) == 0); + if (sixpack) { + [sb appendFormat:@"%C", (unichar) ZX_PDF417_LATCH_TO_BYTE]; + } else { + [sb appendFormat:@"%C", (unichar) ZX_PDF417_LATCH_TO_BYTE_PADDED]; + } + } + + int idx = startpos; + // Encode sixpacks + if (count >= 6) { + const int charsLen = 5; + unichar chars[charsLen]; + memset(chars, 0, charsLen * sizeof(unichar)); + while ((startpos + count - idx) >= 6) { + long t = 0; + for (int i = 0; i < 6; i++) { + t <<= 8; + t += bytes.array[idx + i] & 0xff; + } + for (int i = 0; i < 5; i++) { + chars[i] = (unichar) (t % 900); + t /= 900; + } + for (int i = charsLen - 1; i >= 0; i--) { + [sb appendFormat:@"%C", chars[i]]; + } + idx += 6; + } + } + //Encode rest (remaining n<5 bytes if any) + for (int i = idx; i < startpos + count; i++) { + int ch = bytes.array[i] & 0xff; + [sb appendFormat:@"%C", (unichar)ch]; + } +} + ++ (void)encodeNumeric:(NSString *)msg startpos:(int)startpos count:(int)count buffer:(NSMutableString *)sb { + int idx = 0; + NSMutableString *tmp = [NSMutableString stringWithCapacity:count / 3 + 1]; + NSDecimalNumber *num900 = [NSDecimalNumber decimalNumberWithDecimal:[[NSNumber numberWithInt:900] decimalValue]]; + NSDecimalNumber *num0 = [NSDecimalNumber decimalNumberWithDecimal:[[NSNumber numberWithInt:0] decimalValue]]; + while (idx < count) { + [tmp setString:@""]; + int len = MIN(44, count - idx); + NSString *part = [@"1" stringByAppendingString:[msg substringWithRange:NSMakeRange(startpos + idx, len)]]; + NSDecimalNumber *bigint = [NSDecimalNumber decimalNumberWithString:part]; + do { + NSRoundingMode roundingMode = ((bigint.floatValue < 0) ^ (num900.floatValue < 0)) ? NSRoundUp : NSRoundDown; + NSDecimalNumber *quotient = [bigint decimalNumberByDividingBy:num900 + withBehavior:[NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode:roundingMode + scale:0 + raiseOnExactness:NO + raiseOnOverflow:NO + raiseOnUnderflow:NO + raiseOnDivideByZero:NO]]; + + NSDecimalNumber *subtractAmount = [quotient decimalNumberByMultiplyingBy:num900]; + NSDecimalNumber *remainder = [bigint decimalNumberBySubtracting:subtractAmount]; + + [tmp appendFormat:@"%C", (unichar)[remainder longValue]]; + bigint = quotient; + } while (![bigint isEqualToNumber:num0]); + + //Reverse temporary string + for (int i = (int)tmp.length - 1; i >= 0; i--) { + [sb appendFormat:@"%C", [tmp characterAtIndex:i]]; + } + idx += len; + } +} + ++ (BOOL)isDigit:(unichar)ch { + return ch >= '0' && ch <= '9'; +} + ++ (BOOL)isAlphaUpper:(unichar)ch { + return ch == ' ' || (ch >= 'A' && ch <= 'Z'); +} + ++ (BOOL)isAlphaLower:(unichar)ch { + return ch == ' ' || (ch >= 'a' && ch <= 'z'); +} + ++ (BOOL)isMixed:(unichar)ch { + return ZX_PDF417_MIXED_TABLE[ch] != 0xFF; +} + ++ (BOOL)isPunctuation:(unichar)ch { + return ZX_PDF417_PUNCTUATION[ch] != 0xFF; +} + ++ (BOOL)isText:(unichar)ch { + return ch == '\t' || ch == '\n' || ch == '\r' || (ch >= 32 && ch <= 126); +} + +/** + * Determines the number of consecutive characters that are encodable using numeric compaction. + * + * @param msg the message + * @param startpos the start position within the message + * @return the requested character count + */ ++ (int)determineConsecutiveDigitCount:(NSString *)msg startpos:(int)startpos { + int count = 0; + NSUInteger len = msg.length; + int idx = startpos; + if (idx < len) { + char ch = [msg characterAtIndex:idx]; + while ([self isDigit:ch] && idx < len) { + count++; + idx++; + if (idx < len) { + ch = [msg characterAtIndex:idx]; + } + } + } + return count; +} + +/** + * Determines the number of consecutive characters that are encodable using text compaction. + * + * @param msg the message + * @param startpos the start position within the message + * @return the requested character count + */ ++ (int)determineConsecutiveTextCount:(NSString *)msg startpos:(int)startpos { + NSUInteger len = msg.length; + int idx = startpos; + while (idx < len) { + char ch = [msg characterAtIndex:idx]; + int numericCount = 0; + while (numericCount < 13 && [self isDigit:ch] && idx < len) { + numericCount++; + idx++; + if (idx < len) { + ch = [msg characterAtIndex:idx]; + } + } + if (numericCount >= 13) { + return idx - startpos - numericCount; + } + if (numericCount > 0) { + //Heuristic: All text-encodable chars or digits are binary encodable + continue; + } + ch = [msg characterAtIndex:idx]; + + //Check if character is encodable + if (![self isText:ch]) { + break; + } + idx++; + } + return idx - startpos; +} + +/** + * Determines the number of consecutive characters that are encodable using binary compaction. + * + * @param msg the message + * @param bytes the message converted to a byte array + * @param startpos the start position within the message + * @return the requested character count + */ ++ (int)determineConsecutiveBinaryCount:(NSString *)msg bytes:(ZXByteArray *)bytes startpos:(int)startpos error:(NSError **)error { + NSUInteger len = msg.length; + int idx = startpos; + while (idx < len) { + char ch = [msg characterAtIndex:idx]; + int numericCount = 0; + + while (numericCount < 13 && [self isDigit:ch]) { + numericCount++; + //textCount++; + int i = idx + numericCount; + if (i >= len) { + break; + } + ch = [msg characterAtIndex:i]; + } + if (numericCount >= 13) { + return idx - startpos; + } + ch = [msg characterAtIndex:idx]; + + //Check if character is encodable + //Sun returns a ASCII 63 (?) for a character that cannot be mapped. Let's hope all + //other VMs do the same + if (bytes.array[idx] == 63 && ch != '?') { + NSDictionary *userInfo = @{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Non-encodable character detected: %c (Unicode: %C)", ch, (unichar)ch]}; + + if (error) *error = [[NSError alloc] initWithDomain:ZXErrorDomain code:ZXWriterError userInfo:userInfo]; + return -1; + } + idx++; + } + return idx - startpos; +} + ++ (BOOL)encodingECI:(int)eci sb:(NSMutableString *)sb error:(NSError **)error { + if (eci >= 0 && eci < 900) { + [sb appendFormat:@"%C", (unichar) ZX_PDF417_HIGH_LEVEL_ECI_CHARSET]; + [sb appendFormat:@"%C", (unichar) eci]; + } else if (eci < 810900) { + [sb appendFormat:@"%C", (unichar) ZX_PDF417_HIGH_LEVEL_ECI_GENERAL_PURPOSE]; + [sb appendFormat:@"%C", (unichar) (eci / 900 - 1)]; + [sb appendFormat:@"%C", (unichar) (eci % 900)]; + } else if (eci < 811800) { + [sb appendFormat:@"%C", (unichar) ZX_PDF417_HIGH_LEVEL_ECI_USER_DEFINED]; + [sb appendFormat:@"%C", (unichar) (810900 - eci)]; + } else { + NSDictionary *userInfo = @{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"ECI number not in valid range from 0..811799, but was %d", eci]}; + + if (error) *error = [[NSError alloc] initWithDomain:ZXErrorDomain code:ZXWriterError userInfo:userInfo]; + return NO; + } + return YES; +} + ++ (ZXByteArray *)bytesForMessage:(NSString *)msg encoding:(NSStringEncoding)encoding { + NSData *data = [msg dataUsingEncoding:encoding]; + int8_t *bytes = (int8_t *)[data bytes]; + ZXByteArray *byteArray = [[ZXByteArray alloc] initWithLength:(unsigned int)[data length]]; + memcpy(byteArray.array, bytes, [data length] * sizeof(int8_t)); + return byteArray; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/ZXQRCodeReader.h b/iDearQRCode/Tools/ZXingObjC/qrcode/ZXQRCodeReader.h new file mode 100755 index 0000000..cc3c232 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/ZXQRCodeReader.h @@ -0,0 +1,28 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXReader.h" + +@class ZXQRCodeDecoder; + +/** + * This implementation can detect and decode QR Codes in an image. + */ +@interface ZXQRCodeReader : NSObject + +@property (nonatomic, strong, readonly) ZXQRCodeDecoder *decoder; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/ZXQRCodeReader.m b/iDearQRCode/Tools/ZXingObjC/qrcode/ZXQRCodeReader.m new file mode 100755 index 0000000..1bb8286 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/ZXQRCodeReader.m @@ -0,0 +1,218 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBarcodeFormat.h" +#import "ZXBinaryBitmap.h" +#import "ZXBitMatrix.h" +#import "ZXDecodeHints.h" +#import "ZXDecoderResult.h" +#import "ZXDetectorResult.h" +#import "ZXErrors.h" +#import "ZXIntArray.h" +#import "ZXQRCodeDecoder.h" +#import "ZXQRCodeDecoderMetaData.h" +#import "ZXQRCodeDetector.h" +#import "ZXQRCodeReader.h" +#import "ZXResult.h" + +@implementation ZXQRCodeReader + +- (id)init { + if (self = [super init]) { + _decoder = [[ZXQRCodeDecoder alloc] init]; + } + + return self; +} + +/** + * Locates and decodes a QR code in an image. + * + * @return a String representing the content encoded by the QR code + * @throws NotFoundException if a QR code cannot be found + * @throws FormatException if a QR code cannot be decoded + * @throws ChecksumException if error correction fails + */ +- (ZXResult *)decode:(ZXBinaryBitmap *)image error:(NSError **)error { + return [self decode:image hints:nil error:error]; +} + +- (ZXResult *)decode:(ZXBinaryBitmap *)image hints:(ZXDecodeHints *)hints error:(NSError **)error { + ZXDecoderResult *decoderResult; + NSMutableArray *points; + ZXBitMatrix *matrix = [image blackMatrixWithError:error]; + if (!matrix) { + return nil; + } + if (hints != nil && hints.pureBarcode) { + ZXBitMatrix *bits = [self extractPureBits:matrix]; + if (!bits) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + decoderResult = [self.decoder decodeMatrix:bits hints:hints error:error]; + if (!decoderResult) { + return nil; + } + points = [NSMutableArray array]; + } else { + ZXDetectorResult *detectorResult = [[[ZXQRCodeDetector alloc] initWithImage:matrix] detect:hints error:error]; + if (!detectorResult) { + return nil; + } + decoderResult = [self.decoder decodeMatrix:[detectorResult bits] hints:hints error:error]; + if (!decoderResult) { + return nil; + } + points = [[detectorResult points] mutableCopy]; + } + + // If the code was mirrored: swap the bottom-left and the top-right points. + if ([decoderResult.other isKindOfClass:[ZXQRCodeDecoderMetaData class]]) { + [(ZXQRCodeDecoderMetaData *)decoderResult.other applyMirroredCorrection:points]; + } + + ZXResult *result = [ZXResult resultWithText:decoderResult.text + rawBytes:decoderResult.rawBytes + resultPoints:points + format:kBarcodeFormatQRCode]; + NSMutableArray *byteSegments = decoderResult.byteSegments; + if (byteSegments != nil) { + [result putMetadata:kResultMetadataTypeByteSegments value:byteSegments]; + } + NSString *ecLevel = decoderResult.ecLevel; + if (ecLevel != nil) { + [result putMetadata:kResultMetadataTypeErrorCorrectionLevel value:ecLevel]; + } + if ([decoderResult hasStructuredAppend]) { + [result putMetadata:kResultMetadataTypeStructuredAppendSequence + value:@(decoderResult.structuredAppendSequenceNumber)]; + [result putMetadata:kResultMetadataTypeStructuredAppendParity + value:@(decoderResult.structuredAppendParity)]; + } + return result; +} + +- (void)reset { + // do nothing +} + +/** + * This method detects a code in a "pure" image -- that is, pure monochrome image + * which contains only an unrotated, unskewed, image of a code, with some white border + * around it. This is a specialized method that works exceptionally fast in this special + * case. + */ +- (ZXBitMatrix *)extractPureBits:(ZXBitMatrix *)image { + ZXIntArray *leftTopBlack = image.topLeftOnBit; + ZXIntArray *rightBottomBlack = image.bottomRightOnBit; + if (leftTopBlack == nil || rightBottomBlack == nil) { + return nil; + } + + float moduleSize = [self moduleSize:leftTopBlack image:image]; + if (moduleSize == -1) { + return nil; + } + + int top = leftTopBlack.array[1]; + int bottom = rightBottomBlack.array[1]; + int left = leftTopBlack.array[0]; + int right = rightBottomBlack.array[0]; + + // Sanity check! + if (left >= right || top >= bottom) { + return nil; + } + + if (bottom - top != right - left) { + // Special case, where bottom-right module wasn't black so we found something else in the last row + // Assume it's a square, so use height as the width + right = left + (bottom - top); + } + + int matrixWidth = round((right - left + 1) / moduleSize); + int matrixHeight = round((bottom - top + 1) / moduleSize); + if (matrixWidth <= 0 || matrixHeight <= 0) { + return nil; + } + if (matrixHeight != matrixWidth) { + return nil; + } + + int nudge = (int) (moduleSize / 2.0f); + top += nudge; + left += nudge; + + // But careful that this does not sample off the edge + // "right" is the farthest-right valid pixel location -- right+1 is not necessarily + // This is positive by how much the inner x loop below would be too large + int nudgedTooFarRight = left + (int) ((matrixWidth - 1) * moduleSize) - right; + if (nudgedTooFarRight > 0) { + if (nudgedTooFarRight > nudge) { + // Neither way fits; abort + return nil; + } + left -= nudgedTooFarRight; + } + // See logic above + int nudgedTooFarDown = top + (int) ((matrixHeight - 1) * moduleSize) - bottom; + if (nudgedTooFarDown > 0) { + if (nudgedTooFarDown > nudge) { + // Neither way fits; abort + return nil; + } + top -= nudgedTooFarDown; + } + + // Now just read off the bits + ZXBitMatrix *bits = [[ZXBitMatrix alloc] initWithWidth:matrixWidth height:matrixHeight]; + for (int y = 0; y < matrixHeight; y++) { + int iOffset = top + (int) (y * moduleSize); + for (int x = 0; x < matrixWidth; x++) { + if ([image getX:left + (int) (x * moduleSize) y:iOffset]) { + [bits setX:x y:y]; + } + } + } + return bits; +} + +- (float)moduleSize:(ZXIntArray *)leftTopBlack image:(ZXBitMatrix *)image { + int height = image.height; + int width = image.width; + int x = leftTopBlack.array[0]; + int y = leftTopBlack.array[1]; + BOOL inBlack = YES; + int transitions = 0; + while (x < width && y < height) { + if (inBlack != [image getX:x y:y]) { + if (++transitions == 5) { + break; + } + inBlack = !inBlack; + } + x++; + y++; + } + if (x == width || y == height) { + return -1; + } + + return (x - leftTopBlack.array[0]) / 7.0f; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/ZXQRCodeWriter.h b/iDearQRCode/Tools/ZXingObjC/qrcode/ZXQRCodeWriter.h new file mode 100755 index 0000000..647d9db --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/ZXQRCodeWriter.h @@ -0,0 +1,24 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXWriter.h" + +/** + * This object renders a QR Code as a BitMatrix 2D array of greyscale values. + */ +@interface ZXQRCodeWriter : NSObject + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/ZXQRCodeWriter.m b/iDearQRCode/Tools/ZXingObjC/qrcode/ZXQRCodeWriter.m new file mode 100755 index 0000000..575b3d3 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/ZXQRCodeWriter.m @@ -0,0 +1,94 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitMatrix.h" +#import "ZXByteMatrix.h" +#import "ZXEncodeHints.h" +#import "ZXQRCode.h" +#import "ZXQRCodeEncoder.h" +#import "ZXQRCodeErrorCorrectionLevel.h" +#import "ZXQRCodeWriter.h" + +const int ZX_QUIET_ZONE_SIZE = 4; + +@implementation ZXQRCodeWriter + +- (ZXBitMatrix *)encode:(NSString *)contents format:(ZXBarcodeFormat)format width:(int)width height:(int)height error:(NSError **)error { + return [self encode:contents format:format width:width height:height hints:nil error:error]; +} + +- (ZXBitMatrix *)encode:(NSString *)contents format:(ZXBarcodeFormat)format width:(int)width height:(int)height hints:(ZXEncodeHints *)hints error:(NSError **)error { + if ([contents length] == 0) { + [NSException raise:NSInvalidArgumentException format:@"Found empty contents"]; + } + + if (format != kBarcodeFormatQRCode) { + [NSException raise:NSInvalidArgumentException format:@"Can only encode QR_CODE"]; + } + + if (width < 0 || height < 0) { + [NSException raise:NSInvalidArgumentException format:@"Requested dimensions are too small: %dx%d", width, height]; + } + + ZXQRCodeErrorCorrectionLevel *errorCorrectionLevel = [ZXQRCodeErrorCorrectionLevel errorCorrectionLevelL]; + int quietZone = ZX_QUIET_ZONE_SIZE; + if (hints != nil) { + if (hints.errorCorrectionLevel) { + errorCorrectionLevel = hints.errorCorrectionLevel; + } + if (hints.margin) { + quietZone = [hints.margin intValue]; + } + } + + ZXQRCode *code = [ZXQRCodeEncoder encode:contents ecLevel:errorCorrectionLevel hints:hints error:error]; + return [self renderResult:code width:width height:height quietZone:quietZone]; +} + +- (ZXBitMatrix *)renderResult:(ZXQRCode *)code width:(int)width height:(int)height quietZone:(int)quietZone { + ZXByteMatrix *input = code.matrix; + if (input == nil) { + return nil; + } + int inputWidth = input.width; + int inputHeight = input.height; + int qrWidth = inputWidth + (quietZone * 2); + int qrHeight = inputHeight + (quietZone * 2); + int outputWidth = MAX(width, qrWidth); + int outputHeight = MAX(height, qrHeight); + + int multiple = MIN(outputWidth / qrWidth, outputHeight / qrHeight); + // Padding includes both the quiet zone and the extra white pixels to accommodate the requested + // dimensions. For example, if input is 25x25 the QR will be 33x33 including the quiet zone. + // If the requested size is 200x160, the multiple will be 4, for a QR of 132x132. These will + // handle all the padding from 100x100 (the actual QR) up to 200x160. + int leftPadding = (outputWidth - (inputWidth * multiple)) / 2; + int topPadding = (outputHeight - (inputHeight * multiple)) / 2; + + ZXBitMatrix *output = [[ZXBitMatrix alloc] initWithWidth:outputWidth height:outputHeight]; + + for (int inputY = 0, outputY = topPadding; inputY < inputHeight; inputY++, outputY += multiple) { + for (int inputX = 0, outputX = leftPadding; inputX < inputWidth; inputX++, outputX += multiple) { + if ([input getX:inputX y:inputY] == 1) { + [output setRegionAtLeft:outputX top:outputY width:multiple height:multiple]; + } + } + } + + return output; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/ZXingObjCQRCode.h b/iDearQRCode/Tools/ZXingObjC/qrcode/ZXingObjCQRCode.h new file mode 100755 index 0000000..0672a3b --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/ZXingObjCQRCode.h @@ -0,0 +1,39 @@ +/* + * Copyright 2014 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXingObjCCore.h" + +#ifndef _ZXINGOBJC_QRCODE_ + +#define _ZXINGOBJC_QRCODE_ + +#import "ZXQRCode.h" +#import "ZXQRCodeAlignmentPattern.h" +#import "ZXQRCodeDecoder.h" +#import "ZXQRCodeDecoderMetaData.h" +#import "ZXQRCodeDetector.h" +#import "ZXQRCodeEncoder.h" +#import "ZXQRCodeErrorCorrectionLevel.h" +#import "ZXQRCodeFinderPatternInfo.h" +#import "ZXQRCodeFinderPattern.h" +#import "ZXQRCodeFinderPatternFinder.h" +#import "ZXQRCodeFinderPatternInfo.h" +#import "ZXQRCodeMode.h" +#import "ZXQRCodeReader.h" +#import "ZXQRCodeVersion.h" +#import "ZXQRCodeWriter.h" + +#endif diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeBitMatrixParser.h b/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeBitMatrixParser.h new file mode 100755 index 0000000..ca89b37 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeBitMatrixParser.h @@ -0,0 +1,72 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXBitMatrix, ZXByteArray, ZXQRCodeFormatInformation, ZXQRCodeVersion; + +@interface ZXQRCodeBitMatrixParser : NSObject + +/** + * @param bitMatrix ZXBitMatrix to parse + * @return nil if dimension is not >= 21 and 1 mod 4 + */ +- (id)initWithBitMatrix:(ZXBitMatrix *)bitMatrix error:(NSError **)error; + +/** + * Reads format information from one of its two locations within the QR Code. + * + * @return ZXFormatInformation encapsulating the QR Code's format info + * @return nil if both format information locations cannot be parsed as + * the valid encoding of format information + */ +- (ZXQRCodeFormatInformation *)readFormatInformationWithError:(NSError **)error; + +/** + * Reads version information from one of its two locations within the QR Code. + * + * @return ZXQRCodeVersion encapsulating the QR Code's version or nil + * if both version information locations cannot be parsed as + * the valid encoding of version information + */ +- (ZXQRCodeVersion *)readVersionWithError:(NSError **)error; + +/** + * Reads the bits in the ZXBitMatrix representing the finder pattern in the + * correct order in order to reconstruct the codewords bytes contained within the + * QR Code. + * + * @return bytes encoded within the QR Code or nil if the exact number of bytes expected is not read + */ +- (ZXByteArray *)readCodewordsWithError:(NSError **)error; + +/** + * Revert the mask removal done while reading the code words. The bit matrix should revert to its original state. + */ +- (void)remask; + +/** + * Prepare the parser for a mirrored operation. + * This flag has effect only on the readFormatInformation and the + * readVersion. Before proceeding with readCodewords the + * mirror method should be called. + * + * @param mirror Whether to read version and format information mirrored. + */ +- (void)setMirror:(BOOL)mirror; + +/** Mirror the bit matrix in order to attempt a second reading. */ +- (void)mirror; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeBitMatrixParser.m b/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeBitMatrixParser.m new file mode 100755 index 0000000..0fc1062 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeBitMatrixParser.m @@ -0,0 +1,223 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitMatrix.h" +#import "ZXByteArray.h" +#import "ZXErrors.h" +#import "ZXQRCodeBitMatrixParser.h" +#import "ZXQRCodeDataMask.h" +#import "ZXQRCodeFormatInformation.h" +#import "ZXQRCodeVersion.h" + +@interface ZXQRCodeBitMatrixParser () + +@property (nonatomic, strong, readonly) ZXBitMatrix *bitMatrix; +@property (nonatomic, assign) BOOL shouldMirror; +@property (nonatomic, strong) ZXQRCodeFormatInformation *parsedFormatInfo; +@property (nonatomic, strong) ZXQRCodeVersion *parsedVersion; + +@end + +@implementation ZXQRCodeBitMatrixParser + +- (id)initWithBitMatrix:(ZXBitMatrix *)bitMatrix error:(NSError **)error { + int dimension = bitMatrix.height; + if (dimension < 21 || (dimension & 0x03) != 1) { + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + + if (self = [super init]) { + _bitMatrix = bitMatrix; + _parsedFormatInfo = nil; + _parsedVersion = nil; + } + return self; +} + +- (ZXQRCodeFormatInformation *)readFormatInformationWithError:(NSError **)error { + if (self.parsedFormatInfo != nil) { + return self.parsedFormatInfo; + } + int formatInfoBits1 = 0; + + for (int i = 0; i < 6; i++) { + formatInfoBits1 = [self copyBit:i j:8 versionBits:formatInfoBits1]; + } + + formatInfoBits1 = [self copyBit:7 j:8 versionBits:formatInfoBits1]; + formatInfoBits1 = [self copyBit:8 j:8 versionBits:formatInfoBits1]; + formatInfoBits1 = [self copyBit:8 j:7 versionBits:formatInfoBits1]; + + for (int j = 5; j >= 0; j--) { + formatInfoBits1 = [self copyBit:8 j:j versionBits:formatInfoBits1]; + } + + int dimension = self.bitMatrix.height; + int formatInfoBits2 = 0; + int jMin = dimension - 7; + + for (int j = dimension - 1; j >= jMin; j--) { + formatInfoBits2 = [self copyBit:8 j:j versionBits:formatInfoBits2]; + } + + for (int i = dimension - 8; i < dimension; i++) { + formatInfoBits2 = [self copyBit:i j:8 versionBits:formatInfoBits2]; + } + + self.parsedFormatInfo = [ZXQRCodeFormatInformation decodeFormatInformation:formatInfoBits1 maskedFormatInfo2:formatInfoBits2]; + if (self.parsedFormatInfo != nil) { + return self.parsedFormatInfo; + } + if (error) *error = ZXFormatErrorInstance(); + return nil; +} + +- (ZXQRCodeVersion *)readVersionWithError:(NSError **)error { + if (self.parsedVersion != nil) { + return self.parsedVersion; + } + int dimension = self.bitMatrix.height; + int provisionalVersion = (dimension - 17) / 4; + if (provisionalVersion <= 6) { + return [ZXQRCodeVersion versionForNumber:provisionalVersion]; + } + int versionBits = 0; + int ijMin = dimension - 11; + + for (int j = 5; j >= 0; j--) { + + for (int i = dimension - 9; i >= ijMin; i--) { + versionBits = [self copyBit:i j:j versionBits:versionBits]; + } + + } + + ZXQRCodeVersion *theParsedVersion = [ZXQRCodeVersion decodeVersionInformation:versionBits]; + if (theParsedVersion != nil && theParsedVersion.dimensionForVersion == dimension) { + self.parsedVersion = theParsedVersion; + return self.parsedVersion; + } + versionBits = 0; + + for (int i = 5; i >= 0; i--) { + for (int j = dimension - 9; j >= ijMin; j--) { + versionBits = [self copyBit:i j:j versionBits:versionBits]; + } + } + + theParsedVersion = [ZXQRCodeVersion decodeVersionInformation:versionBits]; + if (theParsedVersion != nil && theParsedVersion.dimensionForVersion == dimension) { + self.parsedVersion = theParsedVersion; + return self.parsedVersion; + } + if (error) *error = ZXFormatErrorInstance(); + return nil; +} + +- (int)copyBit:(int)i j:(int)j versionBits:(int)versionBits { + BOOL bit = self.shouldMirror ? [self.bitMatrix getX:j y:i] : [self.bitMatrix getX:i y:j]; + return bit ? (versionBits << 1) | 0x1 : versionBits << 1; +} + +- (ZXByteArray *)readCodewordsWithError:(NSError **)error { + ZXQRCodeFormatInformation *formatInfo = [self readFormatInformationWithError:error]; + if (!formatInfo) { + return nil; + } + + ZXQRCodeVersion *version = [self readVersionWithError:error]; + if (!version) { + return nil; + } + + // Get the data mask for the format used in this QR Code. This will exclude + // some bits from reading as we wind through the bit matrix. + ZXQRCodeDataMask *dataMask = [ZXQRCodeDataMask forReference:[formatInfo dataMask]]; + int dimension = self.bitMatrix.height; + [dataMask unmaskBitMatrix:self.bitMatrix dimension:dimension]; + + ZXBitMatrix *functionPattern = [version buildFunctionPattern]; + + BOOL readingUp = YES; + ZXByteArray *result = [[ZXByteArray alloc] initWithLength:version.totalCodewords]; + int resultOffset = 0; + int currentByte = 0; + int bitsRead = 0; + // Read columns in pairs, from right to left + for (int j = dimension - 1; j > 0; j -= 2) { + if (j == 6) { + // Skip whole column with vertical alignment pattern; + // saves time and makes the other code proceed more cleanly + j--; + } + // Read alternatingly from bottom to top then top to bottom + for (int count = 0; count < dimension; count++) { + int i = readingUp ? dimension - 1 - count : count; + for (int col = 0; col < 2; col++) { + // Ignore bits covered by the function pattern + if (![functionPattern getX:j - col y:i]) { + // Read a bit + bitsRead++; + currentByte <<= 1; + if ([self.bitMatrix getX:j - col y:i]) { + currentByte |= 1; + } + // If we've made a whole byte, save it off + if (bitsRead == 8) { + result.array[resultOffset++] = (int8_t) currentByte; + bitsRead = 0; + currentByte = 0; + } + } + } + } + readingUp ^= YES; // readingUp = !readingUp; // switch directions + } + if (resultOffset != [version totalCodewords]) { + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + return result; +} + +- (void)remask { + if (!self.parsedFormatInfo) { + return; // We have no format information, and have no data mask + } + ZXQRCodeDataMask *dataMask = [ZXQRCodeDataMask forReference:self.parsedFormatInfo.dataMask]; + int dimension = self.bitMatrix.height; + [dataMask unmaskBitMatrix:self.bitMatrix dimension:dimension]; +} + +- (void)setMirror:(BOOL)mirror { + self.parsedVersion = nil; + self.parsedFormatInfo = nil; + self.shouldMirror = mirror; +} + +- (void)mirror { + for (int x = 0; x < self.bitMatrix.width; x++) { + for (int y = x + 1; y < self.bitMatrix.height; y++) { + if ([self.bitMatrix getX:x y:y] != [self.bitMatrix getX:y y:x]) { + [self.bitMatrix flipX:y y:x]; + [self.bitMatrix flipX:x y:y]; + } + } + } +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeDataBlock.h b/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeDataBlock.h new file mode 100755 index 0000000..ca5a80c --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeDataBlock.h @@ -0,0 +1,44 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXByteArray, ZXQRCodeErrorCorrectionLevel, ZXQRCodeVersion; + +/** + * Encapsulates a block of data within a QR Code. QR Codes may split their data into + * multiple blocks, each of which is a unit of data and error-correction codewords. Each + * is represented by an instance of this class. + */ +@interface ZXQRCodeDataBlock : NSObject + +@property (nonatomic, strong, readonly) ZXByteArray *codewords; +@property (nonatomic, assign, readonly) int numDataCodewords; + +- (id)initWithNumDataCodewords:(int)numDataCodewords codewords:(ZXByteArray *)codewords; + +/** + * When QR Codes use multiple data blocks, they are actually interleaved. + * That is, the first byte of data block 1 to n is written, then the second bytes, and so on. This + * method will separate the data into original blocks. + * + * @param rawCodewords bytes as read directly from the QR Code + * @param version version of the QR Code + * @param ecLevel error-correction level of the QR Code + * @return DataBlocks containing original bytes, "de-interleaved" from representation in the + * QR Code + */ ++ (NSArray *)dataBlocks:(ZXByteArray *)rawCodewords version:(ZXQRCodeVersion *)version ecLevel:(ZXQRCodeErrorCorrectionLevel *)ecLevel; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeDataBlock.m b/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeDataBlock.m new file mode 100755 index 0000000..2b3a1d4 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeDataBlock.m @@ -0,0 +1,98 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXByteArray.h" +#import "ZXQRCodeDataBlock.h" +#import "ZXQRCodeErrorCorrectionLevel.h" +#import "ZXQRCodeVersion.h" + +@implementation ZXQRCodeDataBlock + +- (id)initWithNumDataCodewords:(int)numDataCodewords codewords:(ZXByteArray *)codewords { + if (self = [super init]) { + _numDataCodewords = numDataCodewords; + _codewords = codewords; + } + + return self; +} + ++ (NSArray *)dataBlocks:(ZXByteArray *)rawCodewords version:(ZXQRCodeVersion *)version ecLevel:(ZXQRCodeErrorCorrectionLevel *)ecLevel { + if (rawCodewords.length != version.totalCodewords) { + [NSException raise:NSInvalidArgumentException format:@"Invalid codewords count"]; + } + + // Figure out the number and size of data blocks used by this version and + // error correction level + ZXQRCodeECBlocks *ecBlocks = [version ecBlocksForLevel:ecLevel]; + + // First count the total number of data blocks + int totalBlocks = 0; + NSArray *ecBlockArray = ecBlocks.ecBlocks; + for (ZXQRCodeECB *ecBlock in ecBlockArray) { + totalBlocks += ecBlock.count; + } + + // Now establish DataBlocks of the appropriate size and number of data codewords + NSMutableArray *result = [NSMutableArray arrayWithCapacity:totalBlocks]; + for (ZXQRCodeECB *ecBlock in ecBlockArray) { + for (int i = 0; i < ecBlock.count; i++) { + int numDataCodewords = ecBlock.dataCodewords; + int numBlockCodewords = ecBlocks.ecCodewordsPerBlock + numDataCodewords; + [result addObject:[[ZXQRCodeDataBlock alloc] initWithNumDataCodewords:numDataCodewords codewords:[[ZXByteArray alloc] initWithLength:numBlockCodewords]]]; + } + } + + // All blocks have the same amount of data, except that the last n + // (where n may be 0) have 1 more byte. Figure out where these start. + int shorterBlocksTotalCodewords = [(ZXQRCodeDataBlock *)result[0] codewords].length; + int longerBlocksStartAt = (int)[result count] - 1; + while (longerBlocksStartAt >= 0) { + int numCodewords = [(ZXQRCodeDataBlock *)result[longerBlocksStartAt] codewords].length; + if (numCodewords == shorterBlocksTotalCodewords) { + break; + } + longerBlocksStartAt--; + } + longerBlocksStartAt++; + + int shorterBlocksNumDataCodewords = shorterBlocksTotalCodewords - ecBlocks.ecCodewordsPerBlock; + // The last elements of result may be 1 element longer; + // first fill out as many elements as all of them have + int rawCodewordsOffset = 0; + int numResultBlocks = (int)[result count]; + for (int i = 0; i < shorterBlocksNumDataCodewords; i++) { + for (int j = 0; j < numResultBlocks; j++) { + [(ZXQRCodeDataBlock *)result[j] codewords].array[i] = rawCodewords.array[rawCodewordsOffset++]; + } + } + // Fill out the last data block in the longer ones + for (int j = longerBlocksStartAt; j < numResultBlocks; j++) { + [(ZXQRCodeDataBlock *)result[j] codewords].array[shorterBlocksNumDataCodewords] = rawCodewords.array[rawCodewordsOffset++]; + } + // Now add in error correction blocks + int max = (int)[(ZXQRCodeDataBlock *)result[0] codewords].length; + for (int i = shorterBlocksNumDataCodewords; i < max; i++) { + for (int j = 0; j < numResultBlocks; j++) { + int iOffset = j < longerBlocksStartAt ? i : i + 1; + [(ZXQRCodeDataBlock *)result[j] codewords].array[iOffset] = rawCodewords.array[rawCodewordsOffset++]; + } + } + + return result; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeDataMask.h b/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeDataMask.h new file mode 100755 index 0000000..8ea4d1b --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeDataMask.h @@ -0,0 +1,48 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXBitMatrix; + +/** + * Encapsulates data masks for the data bits in a QR code, per ISO 18004:2006 6.8. Implementations + * of this class can un-mask a raw BitMatrix. For simplicity, they will unmask the entire BitMatrix, + * including areas used for finder patterns, timing patterns, etc. These areas should be unused + * after the point they are unmasked anyway. + * + * Note that the diagram in section 6.8.1 is misleading since it indicates that i is column position + * and j is row position. In fact, as the text says, i is row position and j is column position. + */ +@interface ZXQRCodeDataMask : NSObject + +/** + * Implementations of this method reverse the data masking process applied to a QR Code and + * make its bits ready to read. + * + * @param bits representation of QR Code bits + * @param dimension dimension of QR Code, represented by bits, being unmasked + */ +- (void)unmaskBitMatrix:(ZXBitMatrix *)bits dimension:(int)dimension; + +- (BOOL)isMasked:(int)i j:(int)j; + +/** + * @param reference a value between 0 and 7 indicating one of the eight possible + * data mask patterns a QR Code may use + * @return DataMask encapsulating the data mask pattern + */ ++ (ZXQRCodeDataMask *)forReference:(int)reference; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeDataMask.m b/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeDataMask.m new file mode 100755 index 0000000..108bd39 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeDataMask.m @@ -0,0 +1,196 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitMatrix.h" +#import "ZXQRCodeDataMask.h" + +/** + * 000: mask bits for which (x + y) mod 2 == 0 + */ +@interface ZXDataMask000 : ZXQRCodeDataMask + +@end + +@implementation ZXDataMask000 + +- (BOOL)isMasked:(int)i j:(int)j { + return ((i + j) & 0x01) == 0; +} + +@end + + +/** + * 001: mask bits for which x mod 2 == 0 + */ +@interface ZXDataMask001 : ZXQRCodeDataMask + +@end + +@implementation ZXDataMask001 + +- (BOOL)isMasked:(int)i j:(int)j { + return (i & 0x01) == 0; +} + +@end + + +/** + * 010: mask bits for which y mod 3 == 0 + */ +@interface ZXDataMask010 : ZXQRCodeDataMask + +@end + +@implementation ZXDataMask010 + +- (BOOL)isMasked:(int)i j:(int)j { + return j % 3 == 0; +} + +@end + + +/** + * 011: mask bits for which (x + y) mod 3 == 0 + */ +@interface ZXDataMask011 : ZXQRCodeDataMask + +@end + +@implementation ZXDataMask011 + +- (BOOL)isMasked:(int)i j:(int)j { + return (i + j) % 3 == 0; +} + +@end + + +/** + * 100: mask bits for which (x/2 + y/3) mod 2 == 0 + */ +@interface ZXDataMask100 : ZXQRCodeDataMask + +@end + +@implementation ZXDataMask100 + +- (BOOL)isMasked:(int)i j:(int)j { + return (((i / 2) + (j /3)) & 0x01) == 0; +} + +@end + + +/** + * 101: mask bits for which xy mod 2 + xy mod 3 == 0 + */ +@interface ZXDataMask101 : ZXQRCodeDataMask + +@end + +@implementation ZXDataMask101 + +- (BOOL)isMasked:(int)i j:(int)j { + int temp = i * j; + return (temp & 0x01) + (temp % 3) == 0; +} + +@end + + +/** + * 110: mask bits for which (xy mod 2 + xy mod 3) mod 2 == 0 + */ +@interface ZXDataMask110 : ZXQRCodeDataMask + +@end + +@implementation ZXDataMask110 + +- (BOOL)isMasked:(int)i j:(int)j { + int temp = i * j; + return (((temp & 0x01) + (temp % 3)) & 0x01) == 0; +} + +@end + + +/** + * 111: mask bits for which ((x+y)mod 2 + xy mod 3) mod 2 == 0 + */ +@interface ZXDataMask111 : ZXQRCodeDataMask + +@end + +@implementation ZXDataMask111 + +- (BOOL)isMasked:(int)i j:(int)j { + return ((((i + j) & 0x01) + ((i * j) % 3)) & 0x01) == 0; +} + +@end + + +@implementation ZXQRCodeDataMask + +/** + * See ISO 18004:2006 6.8.1 + */ +static NSArray *DATA_MASKS = nil; + +/** + * Implementations of this method reverse the data masking process applied to a QR Code and + * make its bits ready to read. + */ +- (void)unmaskBitMatrix:(ZXBitMatrix *)bits dimension:(int)dimension { + for (int i = 0; i < dimension; i++) { + for (int j = 0; j < dimension; j++) { + if ([self isMasked:i j:j]) { + [bits flipX:j y:i]; + } + } + } +} + +- (BOOL)isMasked:(int)i j:(int)j { + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:[NSString stringWithFormat:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)] + userInfo:nil]; +} + + ++ (ZXQRCodeDataMask *)forReference:(int)reference { + if (!DATA_MASKS) { + DATA_MASKS = @[[[ZXDataMask000 alloc] init], + [[ZXDataMask001 alloc] init], + [[ZXDataMask010 alloc] init], + [[ZXDataMask011 alloc] init], + [[ZXDataMask100 alloc] init], + [[ZXDataMask101 alloc] init], + [[ZXDataMask110 alloc] init], + [[ZXDataMask111 alloc] init]]; + } + + if (reference < 0 || reference > 7) { + [NSException raise:NSInvalidArgumentException format:@"Invalid reference value"]; + } + return DATA_MASKS[reference]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeDecodedBitStreamParser.h b/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeDecodedBitStreamParser.h new file mode 100755 index 0000000..d43a639 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeDecodedBitStreamParser.h @@ -0,0 +1,33 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXByteArray, ZXDecodeHints, ZXDecoderResult, ZXQRCodeErrorCorrectionLevel, ZXQRCodeVersion; + +/** + * QR Codes can encode text as bits in one of several modes, and can use multiple modes + * in one QR Code. This class decodes the bits back into text. + * + * See ISO 18004:2006, 6.4.3 - 6.4.7 + */ +@interface ZXQRCodeDecodedBitStreamParser : NSObject + ++ (ZXDecoderResult *)decode:(ZXByteArray *)bytes + version:(ZXQRCodeVersion *)version + ecLevel:(ZXQRCodeErrorCorrectionLevel *)ecLevel + hints:(ZXDecodeHints *)hints + error:(NSError **)error; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeDecodedBitStreamParser.m b/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeDecodedBitStreamParser.m new file mode 100755 index 0000000..b725d47 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeDecodedBitStreamParser.m @@ -0,0 +1,338 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitSource.h" +#import "ZXByteArray.h" +#import "ZXCharacterSetECI.h" +#import "ZXDecoderResult.h" +#import "ZXErrors.h" +#import "ZXQRCodeDecodedBitStreamParser.h" +#import "ZXQRCodeErrorCorrectionLevel.h" +#import "ZXQRCodeMode.h" +#import "ZXQRCodeVersion.h" +#import "ZXStringUtils.h" + +/** + * See ISO 18004:2006, 6.4.4 Table 5 + */ +const unichar ZX_ALPHANUMERIC_CHARS[45] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', + 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', + 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + ' ', '$', '%', '*', '+', '-', '.', '/', ':' +}; + +const int ZX_GB2312_SUBSET = 1; + +@implementation ZXQRCodeDecodedBitStreamParser + ++ (ZXDecoderResult *)decode:(ZXByteArray *)bytes + version:(ZXQRCodeVersion *)version + ecLevel:(ZXQRCodeErrorCorrectionLevel *)ecLevel + hints:(ZXDecodeHints *)hints + error:(NSError **)error { + ZXBitSource *bits = [[ZXBitSource alloc] initWithBytes:bytes]; + NSMutableString *result = [NSMutableString stringWithCapacity:50]; + NSMutableArray *byteSegments = [NSMutableArray arrayWithCapacity:1]; + int symbolSequence = -1; + int parityData = -1; + + ZXCharacterSetECI *currentCharacterSetECI = nil; + ZXQRCodeMode *mode; + BOOL fc1InEffect = NO; + + do { + // While still another segment to read... + if ([bits available] < 4) { + // OK, assume we're done. Really, a TERMINATOR mode should have been recorded here + mode = [ZXQRCodeMode terminatorMode]; + } else { + mode = [ZXQRCodeMode forBits:[bits readBits:4]]; // mode is encoded by 4 bits + if (!mode) { + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + } + if (![mode isEqual:[ZXQRCodeMode terminatorMode]]) { + if ([mode isEqual:[ZXQRCodeMode fnc1FirstPositionMode]] || [mode isEqual:[ZXQRCodeMode fnc1SecondPositionMode]]) { + // We do little with FNC1 except alter the parsed result a bit according to the spec + fc1InEffect = YES; + } else if ([mode isEqual:[ZXQRCodeMode structuredAppendMode]]) { + if (bits.available < 16) { + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + // sequence number and parity is added later to the result metadata + // Read next 8 bits (symbol sequence #) and 8 bits (parity data), then continue + symbolSequence = [bits readBits:8]; + parityData = [bits readBits:8]; + } else if ([mode isEqual:[ZXQRCodeMode eciMode]]) { + // Count doesn't apply to ECI + int value = [self parseECIValue:bits]; + currentCharacterSetECI = [ZXCharacterSetECI characterSetECIByValue:value]; + if (currentCharacterSetECI == nil) { + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + } else { + // First handle Hanzi mode which does not start with character count + if ([mode isEqual:[ZXQRCodeMode hanziMode]]) { + //chinese mode contains a sub set indicator right after mode indicator + int subset = [bits readBits:4]; + int countHanzi = [bits readBits:[mode characterCountBits:version]]; + if (subset == ZX_GB2312_SUBSET) { + if (![self decodeHanziSegment:bits result:result count:countHanzi]) { + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + } + } else { + // "Normal" QR code modes: + // How many characters will follow, encoded in this mode? + int count = [bits readBits:[mode characterCountBits:version]]; + if ([mode isEqual:[ZXQRCodeMode numericMode]]) { + if (![self decodeNumericSegment:bits result:result count:count]) { + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + } else if ([mode isEqual:[ZXQRCodeMode alphanumericMode]]) { + if (![self decodeAlphanumericSegment:bits result:result count:count fc1InEffect:fc1InEffect]) { + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + } else if ([mode isEqual:[ZXQRCodeMode byteMode]]) { + if (![self decodeByteSegment:bits result:result count:count currentCharacterSetECI:currentCharacterSetECI byteSegments:byteSegments hints:hints]) { + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + } else if ([mode isEqual:[ZXQRCodeMode kanjiMode]]) { + if (![self decodeKanjiSegment:bits result:result count:count]) { + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + } else { + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + } + } + } + } while (![mode isEqual:[ZXQRCodeMode terminatorMode]]); + + return [[ZXDecoderResult alloc] initWithRawBytes:bytes + text:result.description + byteSegments:byteSegments.count == 0 ? nil : byteSegments + ecLevel:ecLevel == nil ? nil : ecLevel.description + saSequence:symbolSequence + saParity:parityData]; +} + + +/** + * See specification GBT 18284-2000 + */ ++ (BOOL)decodeHanziSegment:(ZXBitSource *)bits result:(NSMutableString *)result count:(int)count { + if (count * 13 > bits.available) { + return NO; + } + + NSMutableData *buffer = [NSMutableData dataWithCapacity:2 * count]; + while (count > 0) { + int twoBytes = [bits readBits:13]; + int assembledTwoBytes = ((twoBytes / 0x060) << 8) | (twoBytes % 0x060); + if (assembledTwoBytes < 0x003BF) { + assembledTwoBytes += 0x0A1A1; + } else { + assembledTwoBytes += 0x0A6A1; + } + int8_t bytes[2]; + bytes[0] = (int8_t)((assembledTwoBytes >> 8) & 0xFF); + bytes[1] = (int8_t)(assembledTwoBytes & 0xFF); + + [buffer appendBytes:bytes length:2]; + + count--; + } + + NSString *string = [[NSString alloc] initWithData:buffer encoding:CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingGB_18030_2000)]; + if (string) { + [result appendString:string]; + } + return YES; +} + ++ (BOOL)decodeKanjiSegment:(ZXBitSource *)bits result:(NSMutableString *)result count:(int)count { + if (count * 13 > bits.available) { + return NO; + } + + NSMutableData *buffer = [NSMutableData dataWithCapacity:2 * count]; + while (count > 0) { + int twoBytes = [bits readBits:13]; + int assembledTwoBytes = ((twoBytes / 0x0C0) << 8) | (twoBytes % 0x0C0); + if (assembledTwoBytes < 0x01F00) { + assembledTwoBytes += 0x08140; + } else { + assembledTwoBytes += 0x0C140; + } + int8_t bytes[2]; + bytes[0] = (int8_t)(assembledTwoBytes >> 8); + bytes[1] = (int8_t)assembledTwoBytes; + + [buffer appendBytes:bytes length:2]; + + count--; + } + + NSString *string = [[NSString alloc] initWithData:buffer encoding:NSShiftJISStringEncoding]; + if (string) { + [result appendString:string]; + } + return YES; +} + ++ (BOOL)decodeByteSegment:(ZXBitSource *)bits result:(NSMutableString *)result count:(int)count currentCharacterSetECI:(ZXCharacterSetECI *)currentCharacterSetECI byteSegments:(NSMutableArray *)byteSegments hints:(ZXDecodeHints *)hints { + if (8 * count > bits.available) { + return NO; + } + + ZXByteArray *readBytes = [[ZXByteArray alloc] initWithLength:count]; + for (int i = 0; i < count; i++) { + readBytes.array[i] = (int8_t)[bits readBits:8]; + } + NSStringEncoding encoding; + if (currentCharacterSetECI == nil) { + encoding = [ZXStringUtils guessEncoding:readBytes hints:hints]; + } else { + encoding = [currentCharacterSetECI encoding]; + } + + NSString *string = [[NSString alloc] initWithBytes:readBytes.array length:readBytes.length encoding:encoding]; + if (string) { + [result appendString:string]; + } + + [byteSegments addObject:readBytes]; + return YES; +} + ++ (unichar)toAlphaNumericChar:(int)value { + if (value >= 45) { + return -1; + } + return ZX_ALPHANUMERIC_CHARS[value]; +} + ++ (BOOL)decodeAlphanumericSegment:(ZXBitSource *)bits result:(NSMutableString *)result count:(int)count fc1InEffect:(BOOL)fc1InEffect { + int start = (int)result.length; + + while (count > 1) { + if ([bits available] < 11) { + return NO; + } + int nextTwoCharsBits = [bits readBits:11]; + unichar next1 = [self toAlphaNumericChar:nextTwoCharsBits / 45]; + unichar next2 = [self toAlphaNumericChar:nextTwoCharsBits % 45]; + + [result appendFormat:@"%C%C", next1, next2]; + count -= 2; + } + + if (count == 1) { + if ([bits available] < 6) { + return NO; + } + unichar next1 = [self toAlphaNumericChar:[bits readBits:6]]; + [result appendFormat:@"%C", next1]; + } + if (fc1InEffect) { + for (int i = start; i < [result length]; i++) { + if ([result characterAtIndex:i] == '%') { + if (i < [result length] - 1 && [result characterAtIndex:i + 1] == '%') { + [result deleteCharactersInRange:NSMakeRange(i + 1, 1)]; + } else { + [result insertString:[NSString stringWithFormat:@"%C", (unichar)0x1D] + atIndex:i]; + } + } + } + } + return YES; +} + ++ (BOOL)decodeNumericSegment:(ZXBitSource *)bits result:(NSMutableString *)result count:(int)count { + // Read three digits at a time + while (count >= 3) { + // Each 10 bits encodes three digits + if (bits.available < 10) { + return NO; + } + int threeDigitsBits = [bits readBits:10]; + if (threeDigitsBits >= 1000) { + return NO; + } + unichar next1 = [self toAlphaNumericChar:threeDigitsBits / 100]; + unichar next2 = [self toAlphaNumericChar:(threeDigitsBits / 10) % 10]; + unichar next3 = [self toAlphaNumericChar:threeDigitsBits % 10]; + + [result appendFormat:@"%C%C%C", next1, next2, next3]; + count -= 3; + } + + if (count == 2) { + // Two digits left over to read, encoded in 7 bits + if (bits.available < 7) { + return NO; + } + int twoDigitsBits = [bits readBits:7]; + if (twoDigitsBits >= 100) { + return NO; + } + unichar next1 = [self toAlphaNumericChar:twoDigitsBits / 10]; + unichar next2 = [self toAlphaNumericChar:twoDigitsBits % 10]; + [result appendFormat:@"%C%C", next1, next2]; + } else if (count == 1) { + // One digit left over to read + if (bits.available < 4) { + return NO; + } + int digitBits = [bits readBits:4]; + if (digitBits >= 10) { + return NO; + } + unichar next1 = [self toAlphaNumericChar:digitBits]; + [result appendFormat:@"%C", next1]; + } + return YES; +} + ++ (int)parseECIValue:(ZXBitSource *)bits { + int firstByte = [bits readBits:8]; + if ((firstByte & 0x80) == 0) { + return firstByte & 0x7F; + } + if ((firstByte & 0xC0) == 0x80) { + int secondByte = [bits readBits:8]; + return ((firstByte & 0x3F) << 8) | secondByte; + } + if ((firstByte & 0xE0) == 0xC0) { + int secondThirdBytes = [bits readBits:16]; + return ((firstByte & 0x1F) << 16) | secondThirdBytes; + } + return -1; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeDecoder.h b/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeDecoder.h new file mode 100755 index 0000000..5578557 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeDecoder.h @@ -0,0 +1,50 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXBitMatrix, ZXDecodeHints, ZXDecodeHints, ZXDecoderResult; + +/** + * The main class which implements QR Code decoding -- as opposed to locating and extracting + * the QR Code from an image. + */ +@interface ZXQRCodeDecoder : NSObject + +/** + * Convenience method that can decode a QR Code represented as a 2D array of booleans. + * "true" is taken to mean a black module. + * + * @param image booleans representing white/black QR Code modules + * @return text and bytes encoded within the QR Code + * @return nil if the QR Code cannot be decoded + * @return nil if error correction fails + */ +- (ZXDecoderResult *)decode:(NSArray *)image error:(NSError **)error; + +/** + * Decodes a QR Code represented as a {@link BitMatrix}. A 1 or "true" is taken to mean a black module. + * + * @param bits booleans representing white/black QR Code modules + * @return text and bytes encoded within the QR Code + * @return nil if the QR Code cannot be decoded + * @return nil if error correction fails + */ +- (ZXDecoderResult *)decode:(NSArray *)image hints:(ZXDecodeHints *)hints error:(NSError **)error; + +- (ZXDecoderResult *)decodeMatrix:(ZXBitMatrix *)bits error:(NSError **)error; + +- (ZXDecoderResult *)decodeMatrix:(ZXBitMatrix *)bits hints:(ZXDecodeHints *)hints error:(NSError **)error; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeDecoder.m b/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeDecoder.m new file mode 100755 index 0000000..dc3de93 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeDecoder.m @@ -0,0 +1,191 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitMatrix.h" +#import "ZXBoolArray.h" +#import "ZXByteArray.h" +#import "ZXDecoderResult.h" +#import "ZXErrors.h" +#import "ZXGenericGF.h" +#import "ZXIntArray.h" +#import "ZXQRCodeBitMatrixParser.h" +#import "ZXQRCodeDataBlock.h" +#import "ZXQRCodeDecodedBitStreamParser.h" +#import "ZXQRCodeDecoder.h" +#import "ZXQRCodeDecoderMetaData.h" +#import "ZXQRCodeErrorCorrectionLevel.h" +#import "ZXQRCodeFormatInformation.h" +#import "ZXQRCodeVersion.h" +#import "ZXReedSolomonDecoder.h" + +@interface ZXQRCodeDecoder () + +@property (nonatomic, strong, readonly) ZXReedSolomonDecoder *rsDecoder; + +@end + +@implementation ZXQRCodeDecoder + +- (id)init { + if (self = [super init]) { + _rsDecoder = [[ZXReedSolomonDecoder alloc] initWithField:[ZXGenericGF QrCodeField256]]; + } + + return self; +} + +- (ZXDecoderResult *)decode:(NSArray *)image error:(NSError **)error { + return [self decode:image hints:nil error:error]; +} + +- (ZXDecoderResult *)decode:(NSArray *)image hints:(ZXDecodeHints *)hints error:(NSError **)error { + int dimension = (int)[image count]; + ZXBitMatrix *bits = [[ZXBitMatrix alloc] initWithDimension:dimension]; + for (int i = 0; i < dimension; i++) { + ZXBoolArray *b = image[i]; + for (int j = 0; j < dimension; j++) { + if (b.array[j]) { + [bits setX:j y:i]; + } + } + } + + return [self decodeMatrix:bits hints:hints error:error]; +} + +- (ZXDecoderResult *)decodeMatrix:(ZXBitMatrix *)bits error:(NSError **)error { + return [self decodeMatrix:bits hints:nil error:error]; +} + +- (ZXDecoderResult *)decodeMatrix:(ZXBitMatrix *)bits hints:(ZXDecodeHints *)hints error:(NSError **)error { + ZXQRCodeBitMatrixParser *parser = [[ZXQRCodeBitMatrixParser alloc] initWithBitMatrix:bits error:error]; + if (!parser) { + return nil; + } + ZXDecoderResult *result = [self decodeParser:parser hints:hints error:error]; + if (result) { + return result; + } + + // Revert the bit matrix + [parser remask]; + + // Will be attempting a mirrored reading of the version and format info. + [parser setMirror:YES]; + + // Preemptively read the version. + if (![parser readVersionWithError:error]) { + return nil; + } + + /* + * Since we're here, this means we have successfully detected some kind + * of version and format information when mirrored. This is a good sign, + * that the QR code may be mirrored, and we should try once more with a + * mirrored content. + */ + // Prepare for a mirrored reading. + [parser mirror]; + + result = [self decodeParser:parser hints:hints error:error]; + if (!result) { + return nil; + } + + // Success! Notify the caller that the code was mirrored. + result.other = [[ZXQRCodeDecoderMetaData alloc] initWithMirrored:YES]; + + return result; +} + +- (ZXDecoderResult *)decodeParser:(ZXQRCodeBitMatrixParser *)parser hints:(ZXDecodeHints *)hints error:(NSError **)error { + ZXQRCodeVersion *version = [parser readVersionWithError:error]; + if (!version) { + return nil; + } + ZXQRCodeFormatInformation *formatInfo = [parser readFormatInformationWithError:error]; + if (!formatInfo) { + return nil; + } + ZXQRCodeErrorCorrectionLevel *ecLevel = formatInfo.errorCorrectionLevel; + + ZXByteArray *codewords = [parser readCodewordsWithError:error]; + if (!codewords) { + return nil; + } + NSArray *dataBlocks = [ZXQRCodeDataBlock dataBlocks:codewords version:version ecLevel:ecLevel]; + + int totalBytes = 0; + for (ZXQRCodeDataBlock *dataBlock in dataBlocks) { + totalBytes += dataBlock.numDataCodewords; + } + + if (totalBytes == 0) { + return nil; + } + + ZXByteArray *resultBytes = [[ZXByteArray alloc] initWithLength:totalBytes]; + int resultOffset = 0; + + for (ZXQRCodeDataBlock *dataBlock in dataBlocks) { + ZXByteArray *codewordBytes = dataBlock.codewords; + int numDataCodewords = [dataBlock numDataCodewords]; + if (![self correctErrors:codewordBytes numDataCodewords:numDataCodewords error:error]) { + return nil; + } + for (int i = 0; i < numDataCodewords; i++) { + resultBytes.array[resultOffset++] = codewordBytes.array[i]; + } + } + + return [ZXQRCodeDecodedBitStreamParser decode:resultBytes version:version ecLevel:ecLevel hints:hints error:error]; +} + +/** + * Given data and error-correction codewords received, possibly corrupted by errors, attempts to + * correct the errors in-place using Reed-Solomon error correction. + * + * @param codewordBytes data and error correction codewords + * @param numDataCodewords number of codewords that are data bytes + * @return NO if error correction fails + */ +- (BOOL)correctErrors:(ZXByteArray *)codewordBytes numDataCodewords:(int)numDataCodewords error:(NSError **)error { + int numCodewords = (int)codewordBytes.length; + // First read into an array of ints + ZXIntArray *codewordsInts = [[ZXIntArray alloc] initWithLength:numCodewords]; + for (int i = 0; i < numCodewords; i++) { + codewordsInts.array[i] = codewordBytes.array[i] & 0xFF; + } + int numECCodewords = (int)codewordBytes.length - numDataCodewords; + NSError *decodeError = nil; + if (![self.rsDecoder decode:codewordsInts twoS:numECCodewords error:&decodeError]) { + if (decodeError.code == ZXReedSolomonError) { + if (error) *error = ZXChecksumErrorInstance(); + return NO; + } else { + if (error) *error = decodeError; + return NO; + } + } + // Copy back into array of bytes -- only need to worry about the bytes that were data + // We don't care about errors in the error-correction codewords + for (int i = 0; i < numDataCodewords; i++) { + codewordBytes.array[i] = (int8_t) codewordsInts.array[i]; + } + return YES; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeDecoderMetaData.h b/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeDecoderMetaData.h new file mode 100755 index 0000000..f31f497 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeDecoderMetaData.h @@ -0,0 +1,34 @@ +/* + * Copyright 2014 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Meta-data container for QR Code decoding. Instances of this class may be used to convey information back to the + * decoding caller. Callers are expected to process this. + */ +@interface ZXQRCodeDecoderMetaData : NSObject + +@property (nonatomic, assign, readonly) BOOL mirrored; + +- (id)initWithMirrored:(BOOL)mirrored; + +/** + * Apply the result points' order correction due to mirroring. + * + * @param points Array of points to apply mirror correction to. + */ +- (void)applyMirroredCorrection:(NSMutableArray *)points; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeDecoderMetaData.m b/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeDecoderMetaData.m new file mode 100755 index 0000000..653b760 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeDecoderMetaData.m @@ -0,0 +1,40 @@ +/* + * Copyright 2014 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXQRCodeDecoderMetaData.h" +#import "ZXResultPoint.h" + +@implementation ZXQRCodeDecoderMetaData + +- (id)initWithMirrored:(BOOL)mirrored { + if (self = [super init]) { + _mirrored = mirrored; + } + + return self; +} + +- (void)applyMirroredCorrection:(NSMutableArray *)points { + if (!self.mirrored || [points count] < 3) { + return; + } + ZXResultPoint *bottomLeft = points[0]; + points[0] = points[2]; + points[2] = bottomLeft; + // No need to 'fix' top-left and alignment pattern. +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeErrorCorrectionLevel.h b/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeErrorCorrectionLevel.h new file mode 100755 index 0000000..72230a8 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeErrorCorrectionLevel.h @@ -0,0 +1,55 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * See ISO 18004:2006, 6.5.1. This enum encapsulates the four error correction levels + * defined by the QR code standard. + */ +@interface ZXQRCodeErrorCorrectionLevel : NSObject + +@property (nonatomic, assign, readonly) int bits; +@property (nonatomic, copy, readonly) NSString *name; +@property (nonatomic, assign, readonly) int ordinal; + +- (id)initWithOrdinal:(int)anOrdinal bits:(int)bits name:(NSString *)name; + +/** + * @param bits int containing the two bits encoding a QR Code's error correction level + * @return ErrorCorrectionLevel representing the encoded error correction level + */ ++ (ZXQRCodeErrorCorrectionLevel *)forBits:(int)bits; + +/** + * L = ~7% correction + */ ++ (ZXQRCodeErrorCorrectionLevel *)errorCorrectionLevelL; + +/** + * M = ~15% correction + */ ++ (ZXQRCodeErrorCorrectionLevel *)errorCorrectionLevelM; + +/** + * Q = ~25% correction + */ ++ (ZXQRCodeErrorCorrectionLevel *)errorCorrectionLevelQ; + +/** + * H = ~30% correction + */ ++ (ZXQRCodeErrorCorrectionLevel *)errorCorrectionLevelH; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeErrorCorrectionLevel.m b/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeErrorCorrectionLevel.m new file mode 100755 index 0000000..adc913b --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeErrorCorrectionLevel.m @@ -0,0 +1,87 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXQRCodeErrorCorrectionLevel.h" + +@implementation ZXQRCodeErrorCorrectionLevel + +static NSArray *FOR_BITS = nil; + +- (id)initWithOrdinal:(int)ordinal bits:(int)bits name:(NSString *)name { + if (self = [super init]) { + _ordinal = ordinal; + _bits = bits; + _name = name; + } + + return self; +} + +- (NSString *)description { + return self.name; +} + ++ (ZXQRCodeErrorCorrectionLevel *)forBits:(int)bits { + if (!FOR_BITS) { + FOR_BITS = @[[ZXQRCodeErrorCorrectionLevel errorCorrectionLevelM], [ZXQRCodeErrorCorrectionLevel errorCorrectionLevelL], + [ZXQRCodeErrorCorrectionLevel errorCorrectionLevelH], [ZXQRCodeErrorCorrectionLevel errorCorrectionLevelQ]]; + } + + if (bits < 0 || bits >= [FOR_BITS count]) { + @throw [NSException exceptionWithName:NSInvalidArgumentException + reason:@"Invalid bits" + userInfo:nil]; + } + return FOR_BITS[bits]; +} + ++ (ZXQRCodeErrorCorrectionLevel *)errorCorrectionLevelL { + static ZXQRCodeErrorCorrectionLevel *thisLevel = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + thisLevel = [[ZXQRCodeErrorCorrectionLevel alloc] initWithOrdinal:0 bits:0x01 name:@"L"]; + }); + return thisLevel; +} + ++ (ZXQRCodeErrorCorrectionLevel *)errorCorrectionLevelM { + static ZXQRCodeErrorCorrectionLevel *thisLevel = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + thisLevel = [[ZXQRCodeErrorCorrectionLevel alloc] initWithOrdinal:1 bits:0x00 name:@"M"]; + }); + return thisLevel; +} + ++ (ZXQRCodeErrorCorrectionLevel *)errorCorrectionLevelQ { + static ZXQRCodeErrorCorrectionLevel *thisLevel = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + thisLevel = [[ZXQRCodeErrorCorrectionLevel alloc] initWithOrdinal:2 bits:0x03 name:@"Q"]; + }); + return thisLevel; +} + ++ (ZXQRCodeErrorCorrectionLevel *)errorCorrectionLevelH { + static ZXQRCodeErrorCorrectionLevel *thisLevel = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + thisLevel = [[ZXQRCodeErrorCorrectionLevel alloc] initWithOrdinal:3 bits:0x02 name:@"H"]; + }); + return thisLevel; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeFormatInformation.h b/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeFormatInformation.h new file mode 100755 index 0000000..dc7f0ef --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeFormatInformation.h @@ -0,0 +1,39 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXQRCodeErrorCorrectionLevel; + +/** + * Encapsulates a QR Code's format information, including the data mask used and + * error correction level. + */ +@interface ZXQRCodeFormatInformation : NSObject + +@property (nonatomic, strong, readonly) ZXQRCodeErrorCorrectionLevel *errorCorrectionLevel; +@property (nonatomic, assign, readonly) int8_t dataMask; + ++ (int)numBitsDiffering:(int)a b:(int)b; + +/** + * @param maskedFormatInfo1 format info indicator, with mask still applied + * @param maskedFormatInfo2 second copy of same info; both are checked at the same time + * to establish best match + * @return information about the format it specifies, or {@code null} + * if doesn't seem to match any known pattern + */ ++ (ZXQRCodeFormatInformation *)decodeFormatInformation:(int)maskedFormatInfo1 maskedFormatInfo2:(int)maskedFormatInfo2; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeFormatInformation.m b/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeFormatInformation.m new file mode 100755 index 0000000..8fed469 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeFormatInformation.m @@ -0,0 +1,138 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXQRCodeErrorCorrectionLevel.h" +#import "ZXQRCodeFormatInformation.h" + +const int ZX_FORMAT_INFO_MASK_QR = 0x5412; + +/** + * See ISO 18004:2006, Annex C, Table C.1 + */ +const int ZX_FORMAT_INFO_DECODE_LOOKUP_LEN = 32; +const int ZX_FORMAT_INFO_DECODE_LOOKUP[ZX_FORMAT_INFO_DECODE_LOOKUP_LEN][2] = { + {0x5412, 0x00}, + {0x5125, 0x01}, + {0x5E7C, 0x02}, + {0x5B4B, 0x03}, + {0x45F9, 0x04}, + {0x40CE, 0x05}, + {0x4F97, 0x06}, + {0x4AA0, 0x07}, + {0x77C4, 0x08}, + {0x72F3, 0x09}, + {0x7DAA, 0x0A}, + {0x789D, 0x0B}, + {0x662F, 0x0C}, + {0x6318, 0x0D}, + {0x6C41, 0x0E}, + {0x6976, 0x0F}, + {0x1689, 0x10}, + {0x13BE, 0x11}, + {0x1CE7, 0x12}, + {0x19D0, 0x13}, + {0x0762, 0x14}, + {0x0255, 0x15}, + {0x0D0C, 0x16}, + {0x083B, 0x17}, + {0x355F, 0x18}, + {0x3068, 0x19}, + {0x3F31, 0x1A}, + {0x3A06, 0x1B}, + {0x24B4, 0x1C}, + {0x2183, 0x1D}, + {0x2EDA, 0x1E}, + {0x2BED, 0x1F}, +}; + +/** + * Offset i holds the number of 1 bits in the binary representation of i + */ +const int ZX_BITS_SET_IN_HALF_BYTE[] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4}; + +@implementation ZXQRCodeFormatInformation + +- (id)initWithFormatInfo:(int)formatInfo { + if (self = [super init]) { + _errorCorrectionLevel = [ZXQRCodeErrorCorrectionLevel forBits:(formatInfo >> 3) & 0x03]; + _dataMask = (int8_t)(formatInfo & 0x07); + } + + return self; +} + ++ (int)numBitsDiffering:(int)a b:(int)b { + a ^= b; + return ZX_BITS_SET_IN_HALF_BYTE[a & 0x0F] + + ZX_BITS_SET_IN_HALF_BYTE[((int)((unsigned int)a) >> 4 & 0x0F)] + + ZX_BITS_SET_IN_HALF_BYTE[((int)((unsigned int)a) >> 8 & 0x0F)] + + ZX_BITS_SET_IN_HALF_BYTE[((int)((unsigned int)a) >> 12 & 0x0F)] + + ZX_BITS_SET_IN_HALF_BYTE[((int)((unsigned int)a) >> 16 & 0x0F)] + + ZX_BITS_SET_IN_HALF_BYTE[((int)((unsigned int)a) >> 20 & 0x0F)] + + ZX_BITS_SET_IN_HALF_BYTE[((int)((unsigned int)a) >> 24 & 0x0F)] + + ZX_BITS_SET_IN_HALF_BYTE[((int)((unsigned int)a) >> 28 & 0x0F)]; +} + ++ (ZXQRCodeFormatInformation *)decodeFormatInformation:(int)maskedFormatInfo1 maskedFormatInfo2:(int)maskedFormatInfo2 { + ZXQRCodeFormatInformation *formatInfo = [self doDecodeFormatInformation:maskedFormatInfo1 maskedFormatInfo2:maskedFormatInfo2]; + if (formatInfo != nil) { + return formatInfo; + } + return [self doDecodeFormatInformation:maskedFormatInfo1 ^ ZX_FORMAT_INFO_MASK_QR maskedFormatInfo2:maskedFormatInfo2 ^ ZX_FORMAT_INFO_MASK_QR]; +} + ++ (ZXQRCodeFormatInformation *)doDecodeFormatInformation:(int)maskedFormatInfo1 maskedFormatInfo2:(int)maskedFormatInfo2 { + int bestDifference = INT_MAX; + int bestFormatInfo = 0; + + for (int i = 0; i < ZX_FORMAT_INFO_DECODE_LOOKUP_LEN; i++) { + int targetInfo = ZX_FORMAT_INFO_DECODE_LOOKUP[i][0]; + if (targetInfo == maskedFormatInfo1 || targetInfo == maskedFormatInfo2) { + return [[ZXQRCodeFormatInformation alloc] initWithFormatInfo:ZX_FORMAT_INFO_DECODE_LOOKUP[i][1]]; + } + int bitsDifference = [self numBitsDiffering:maskedFormatInfo1 b:targetInfo]; + if (bitsDifference < bestDifference) { + bestFormatInfo = ZX_FORMAT_INFO_DECODE_LOOKUP[i][1]; + bestDifference = bitsDifference; + } + if (maskedFormatInfo1 != maskedFormatInfo2) { + bitsDifference = [self numBitsDiffering:maskedFormatInfo2 b:targetInfo]; + if (bitsDifference < bestDifference) { + bestFormatInfo = ZX_FORMAT_INFO_DECODE_LOOKUP[i][1]; + bestDifference = bitsDifference; + } + } + } + + if (bestDifference <= 3) { + return [[ZXQRCodeFormatInformation alloc] initWithFormatInfo:bestFormatInfo]; + } + return nil; +} + +- (NSUInteger)hash { + return (self.errorCorrectionLevel.ordinal << 3) | (int)self.dataMask; +} + +- (BOOL)isEqual:(id)o { + if (![o isKindOfClass:[ZXQRCodeFormatInformation class]]) { + return NO; + } + ZXQRCodeFormatInformation *other = (ZXQRCodeFormatInformation *)o; + return self.errorCorrectionLevel == other.errorCorrectionLevel && self.dataMask == other.dataMask; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeMode.h b/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeMode.h new file mode 100755 index 0000000..6c41791 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeMode.h @@ -0,0 +1,56 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXQRCodeVersion; + +/** + * See ISO 18004:2006, 6.4.1, Tables 2 and 3. This enum encapsulates the various modes in which + * data can be encoded to bits in the QR code standard. + */ +@interface ZXQRCodeMode : NSObject + +@property (nonatomic, assign, readonly) int bits; +@property (nonatomic, copy, readonly) NSString *name; + +- (id)initWithCharacterCountBitsForVersions:(NSArray *)characterCountBitsForVersions bits:(int)bits name:(NSString *)name; + +/** + * @param bits four bits encoding a QR Code data mode + * @return Mode encoded by these bits or nil if bits do not correspond to a known mode + */ ++ (ZXQRCodeMode *)forBits:(int)bits; + +- (int)characterCountBits:(ZXQRCodeVersion *)version; + +/** + * @param version version in question + * @return number of bits used, in this QR Code symbol {@link Version}, to encode the + * count of characters that will follow encoded in this Mode + */ ++ (ZXQRCodeMode *)terminatorMode; // Not really a mode... ++ (ZXQRCodeMode *)numericMode; ++ (ZXQRCodeMode *)alphanumericMode; ++ (ZXQRCodeMode *)structuredAppendMode; // Not supported ++ (ZXQRCodeMode *)byteMode; ++ (ZXQRCodeMode *)eciMode; // character counts don't apply ++ (ZXQRCodeMode *)kanjiMode; ++ (ZXQRCodeMode *)fnc1FirstPositionMode; ++ (ZXQRCodeMode *)fnc1SecondPositionMode; + +/** See GBT 18284-2000; "Hanzi" is a transliteration of this mode name. */ ++ (ZXQRCodeMode *)hanziMode; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeMode.m b/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeMode.m new file mode 100755 index 0000000..e94cd1d --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeMode.m @@ -0,0 +1,172 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXQRCodeMode.h" +#import "ZXQRCodeVersion.h" + +@interface ZXQRCodeMode () + +@property (nonatomic, strong, readonly) NSArray *characterCountBitsForVersions; + +@end + +@implementation ZXQRCodeMode + +- (id)initWithCharacterCountBitsForVersions:(NSArray *)characterCountBitsForVersions bits:(int)bits name:(NSString *)name { + if (self = [super init]) { + _characterCountBitsForVersions = characterCountBitsForVersions; + _bits = bits; + _name = name; + } + + return self; +} + ++ (ZXQRCodeMode *)forBits:(int)bits { + switch (bits) { + case 0x0: + return [ZXQRCodeMode terminatorMode]; + case 0x1: + return [ZXQRCodeMode numericMode]; + case 0x2: + return [ZXQRCodeMode alphanumericMode]; + case 0x3: + return [ZXQRCodeMode structuredAppendMode]; + case 0x4: + return [ZXQRCodeMode byteMode]; + case 0x5: + return [ZXQRCodeMode fnc1FirstPositionMode]; + case 0x7: + return [ZXQRCodeMode eciMode]; + case 0x8: + return [ZXQRCodeMode kanjiMode]; + case 0x9: + return [ZXQRCodeMode fnc1SecondPositionMode]; + case 0xD: + return [ZXQRCodeMode hanziMode]; + default: + return nil; + } +} + +- (int)characterCountBits:(ZXQRCodeVersion *)version { + int number = version.versionNumber; + int offset; + if (number <= 9) { + offset = 0; + } else if (number <= 26) { + offset = 1; + } else { + offset = 2; + } + return [self.characterCountBitsForVersions[offset] intValue]; +} + +- (NSString *)description { + return self.name; +} + ++ (ZXQRCodeMode *)terminatorMode { + static ZXQRCodeMode *thisMode = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + thisMode = [[ZXQRCodeMode alloc] initWithCharacterCountBitsForVersions:@[@0, @0, @0] bits:0x00 name:@"TERMINATOR"]; + }); + return thisMode; +} + ++ (ZXQRCodeMode *)numericMode { + static ZXQRCodeMode *thisMode = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + thisMode = [[ZXQRCodeMode alloc] initWithCharacterCountBitsForVersions:@[@10, @12, @14] bits:0x01 name:@"NUMERIC"]; + }); + return thisMode; +} + ++ (ZXQRCodeMode *)alphanumericMode { + static ZXQRCodeMode *thisMode = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + thisMode = [[ZXQRCodeMode alloc] initWithCharacterCountBitsForVersions:@[@9, @11, @13] bits:0x02 name:@"ALPHANUMERIC"]; + }); + return thisMode; +} + ++ (ZXQRCodeMode *)structuredAppendMode { + static ZXQRCodeMode *thisMode = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + thisMode = [[ZXQRCodeMode alloc] initWithCharacterCountBitsForVersions:@[@0, @0, @0] bits:0x03 name:@"STRUCTURED_APPEND"]; + }); + return thisMode; +} + ++ (ZXQRCodeMode *)byteMode { + static ZXQRCodeMode *thisMode = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + thisMode = [[ZXQRCodeMode alloc] initWithCharacterCountBitsForVersions:@[@8, @16, @16] bits:0x04 name:@"BYTE"]; + }); + return thisMode; +} + ++ (ZXQRCodeMode *)eciMode { + static ZXQRCodeMode *thisMode = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + thisMode = [[ZXQRCodeMode alloc] initWithCharacterCountBitsForVersions:@[@0, @0, @0] bits:0x07 name:@"ECI"]; + }); + return thisMode; +} + ++ (ZXQRCodeMode *)kanjiMode { + static ZXQRCodeMode *thisMode = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + thisMode = [[ZXQRCodeMode alloc] initWithCharacterCountBitsForVersions:@[@8, @10, @12] bits:0x08 name:@"KANJI"]; + }); + return thisMode; +} + ++ (ZXQRCodeMode *)fnc1FirstPositionMode { + static ZXQRCodeMode *thisMode = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + thisMode = [[ZXQRCodeMode alloc] initWithCharacterCountBitsForVersions:@[@0, @0, @0] bits:0x05 name:@"FNC1_FIRST_POSITION"]; + }); + return thisMode; +} + ++ (ZXQRCodeMode *)fnc1SecondPositionMode { + static ZXQRCodeMode *thisMode = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + thisMode = [[ZXQRCodeMode alloc] initWithCharacterCountBitsForVersions:@[@0, @0, @0] bits:0x09 name:@"FNC1_SECOND_POSITION"]; + }); + return thisMode; +} + ++ (ZXQRCodeMode *)hanziMode { + static ZXQRCodeMode *thisMode = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + thisMode = [[ZXQRCodeMode alloc] initWithCharacterCountBitsForVersions:@[@8, @10, @12] bits:0x0D name:@"HANZI"]; + }); + return thisMode; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeVersion.h b/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeVersion.h new file mode 100755 index 0000000..b1d5061 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeVersion.h @@ -0,0 +1,71 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXBitMatrix, ZXIntArray, ZXQRCodeECB, ZXQRCodeECBlocks, ZXQRCodeErrorCorrectionLevel; + +/** + * See ISO 18004:2006 Annex D + */ +@interface ZXQRCodeVersion : NSObject + +@property (nonatomic, assign, readonly) int versionNumber; +@property (nonatomic, strong, readonly) ZXIntArray *alignmentPatternCenters; +@property (nonatomic, strong, readonly) NSArray *ecBlocks; +@property (nonatomic, assign, readonly) int totalCodewords; +@property (nonatomic, assign, readonly) int dimensionForVersion; + +- (ZXQRCodeECBlocks *)ecBlocksForLevel:(ZXQRCodeErrorCorrectionLevel *)ecLevel; ++ (ZXQRCodeVersion *)provisionalVersionForDimension:(int)dimension; ++ (ZXQRCodeVersion *)versionForNumber:(int)versionNumber; ++ (ZXQRCodeVersion *)decodeVersionInformation:(int)versionBits; +- (ZXBitMatrix *)buildFunctionPattern; + +@end + +/** + * Encapsulates a set of error-correction blocks in one symbol version. Most versions will + * use blocks of differing sizes within one version, so, this encapsulates the parameters for + * each set of blocks. It also holds the number of error-correction codewords per block since it + * will be the same across all blocks within one version. + */ +@interface ZXQRCodeECBlocks : NSObject + +@property (nonatomic, assign, readonly) int ecCodewordsPerBlock; +@property (nonatomic, assign, readonly) int numBlocks; +@property (nonatomic, assign, readonly) int totalECCodewords; +@property (nonatomic, strong, readonly) NSArray *ecBlocks; + +- (id)initWithEcCodewordsPerBlock:(int)ecCodewordsPerBlock ecBlocks:(ZXQRCodeECB *)ecBlocks; +- (id)initWithEcCodewordsPerBlock:(int)ecCodewordsPerBlock ecBlocks1:(ZXQRCodeECB *)ecBlocks1 ecBlocks2:(ZXQRCodeECB *)ecBlocks2; ++ (ZXQRCodeECBlocks *)ecBlocksWithEcCodewordsPerBlock:(int)ecCodewordsPerBlock ecBlocks:(ZXQRCodeECB *)ecBlocks; ++ (ZXQRCodeECBlocks *)ecBlocksWithEcCodewordsPerBlock:(int)ecCodewordsPerBlock ecBlocks1:(ZXQRCodeECB *)ecBlocks1 ecBlocks2:(ZXQRCodeECB *)ecBlocks2; + +@end + +/** + * Encapsualtes the parameters for one error-correction block in one symbol version. + * This includes the number of data codewords, and the number of times a block with these + * parameters is used consecutively in the QR code version's format. + */ +@interface ZXQRCodeECB : NSObject + +@property (nonatomic, assign, readonly) int count; +@property (nonatomic, assign, readonly) int dataCodewords; + +- (id)initWithCount:(int)count dataCodewords:(int)dataCodewords; ++ (ZXQRCodeECB *)ecbWithCount:(int)count dataCodewords:(int)dataCodewords; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeVersion.m b/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeVersion.m new file mode 100755 index 0000000..a012739 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/decoder/ZXQRCodeVersion.m @@ -0,0 +1,497 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitMatrix.h" +#import "ZXIntArray.h" +#import "ZXQRCodeErrorCorrectionLevel.h" +#import "ZXQRCodeFormatInformation.h" +#import "ZXQRCodeVersion.h" + +/** + * See ISO 18004:2006 Annex D. + * Element i represents the raw version bits that specify version i + 7 + */ +const int ZX_VERSION_DECODE_INFO[] = { + 0x07C94, 0x085BC, 0x09A99, 0x0A4D3, 0x0BBF6, + 0x0C762, 0x0D847, 0x0E60D, 0x0F928, 0x10B78, + 0x1145D, 0x12A17, 0x13532, 0x149A6, 0x15683, + 0x168C9, 0x177EC, 0x18EC4, 0x191E1, 0x1AFAB, + 0x1B08E, 0x1CC1A, 0x1D33F, 0x1ED75, 0x1F250, + 0x209D5, 0x216F0, 0x228BA, 0x2379F, 0x24B0B, + 0x2542E, 0x26A64, 0x27541, 0x28C69 +}; + +static NSArray *ZX_VERSIONS = nil; + +@implementation ZXQRCodeVersion + +- (id)initWithVersionNumber:(int)versionNumber alignmentPatternCenters:(ZXIntArray *)alignmentPatternCenters ecBlocks1:(ZXQRCodeECBlocks *)ecBlocks1 ecBlocks2:(ZXQRCodeECBlocks *)ecBlocks2 ecBlocks3:(ZXQRCodeECBlocks *)ecBlocks3 ecBlocks4:(ZXQRCodeECBlocks *)ecBlocks4 { + if (self = [super init]) { + _versionNumber = versionNumber; + _alignmentPatternCenters = alignmentPatternCenters; + _ecBlocks = @[ecBlocks1, ecBlocks2, ecBlocks3, ecBlocks4]; + int total = 0; + int ecCodewords = ecBlocks1.ecCodewordsPerBlock; + + for (ZXQRCodeECB *ecBlock in ecBlocks1.ecBlocks) { + total += ecBlock.count * (ecBlock.dataCodewords + ecCodewords); + } + + _totalCodewords = total; + } + + return self; +} + ++ (ZXQRCodeVersion *)ZXQRCodeVersionWithVersionNumber:(int)versionNumber alignmentPatternCenters:(ZXIntArray *)alignmentPatternCenters ecBlocks1:(ZXQRCodeECBlocks *)ecBlocks1 ecBlocks2:(ZXQRCodeECBlocks *)ecBlocks2 ecBlocks3:(ZXQRCodeECBlocks *)ecBlocks3 ecBlocks4:(ZXQRCodeECBlocks *)ecBlocks4 { + return [[ZXQRCodeVersion alloc] initWithVersionNumber:versionNumber alignmentPatternCenters:alignmentPatternCenters ecBlocks1:ecBlocks1 ecBlocks2:ecBlocks2 ecBlocks3:ecBlocks3 ecBlocks4:ecBlocks4]; +} + +- (int)dimensionForVersion { + return 17 + 4 * self.versionNumber; +} + +- (ZXQRCodeECBlocks *)ecBlocksForLevel:(ZXQRCodeErrorCorrectionLevel *)ecLevel { + return self.ecBlocks[[ecLevel ordinal]]; +} + +/** + * Deduces version information purely from QR Code dimensions. + * + * @param dimension dimension in modules + * @return Version for a QR Code of that dimension or nil if dimension is not 1 mod 4 + */ ++ (ZXQRCodeVersion *)provisionalVersionForDimension:(int)dimension { + if (dimension % 4 != 1) { + return nil; + } + + return [self versionForNumber:(dimension - 17) / 4]; +} + ++ (ZXQRCodeVersion *)versionForNumber:(int)versionNumber { + if (versionNumber < 1 || versionNumber > 40) { + return nil; + } + return ZX_VERSIONS[versionNumber - 1]; +} + ++ (ZXQRCodeVersion *)decodeVersionInformation:(int)versionBits { + int bestDifference = INT_MAX; + int bestVersion = 0; + + for (int i = 0; i < sizeof(ZX_VERSION_DECODE_INFO) / sizeof(int); i++) { + int targetVersion = ZX_VERSION_DECODE_INFO[i]; + if (targetVersion == versionBits) { + return [self versionForNumber:i + 7]; + } + int bitsDifference = [ZXQRCodeFormatInformation numBitsDiffering:versionBits b:targetVersion]; + if (bitsDifference < bestDifference) { + bestVersion = i + 7; + bestDifference = bitsDifference; + } + } + + if (bestDifference <= 3) { + return [self versionForNumber:bestVersion]; + } + return nil; +} + +/** + * See ISO 18004:2006 Annex E + */ +- (ZXBitMatrix *)buildFunctionPattern { + int dimension = [self dimensionForVersion]; + ZXBitMatrix *bitMatrix = [[ZXBitMatrix alloc] initWithDimension:dimension]; + [bitMatrix setRegionAtLeft:0 top:0 width:9 height:9]; + [bitMatrix setRegionAtLeft:dimension - 8 top:0 width:8 height:9]; + [bitMatrix setRegionAtLeft:0 top:dimension - 8 width:9 height:8]; + int max = self.alignmentPatternCenters.length; + + for (int x = 0; x < max; x++) { + int i = self.alignmentPatternCenters.array[x] - 2; + + for (int y = 0; y < max; y++) { + if ((x == 0 && (y == 0 || y == max - 1)) || (x == max - 1 && y == 0)) { + continue; + } + [bitMatrix setRegionAtLeft:self.alignmentPatternCenters.array[y] - 2 top:i width:5 height:5]; + } + } + + [bitMatrix setRegionAtLeft:6 top:9 width:1 height:dimension - 17]; + [bitMatrix setRegionAtLeft:9 top:6 width:dimension - 17 height:1]; + if (self.versionNumber > 6) { + [bitMatrix setRegionAtLeft:dimension - 11 top:0 width:3 height:6]; + [bitMatrix setRegionAtLeft:0 top:dimension - 11 width:6 height:3]; + } + return bitMatrix; +} + +- (NSString *)description { + return [@(self.versionNumber) stringValue]; +} + +/** + * See ISO 18004:2006 6.5.1 Table 9 + */ ++ (void)initialize { + if ([self class] != [ZXQRCodeVersion class]) return; + + ZX_VERSIONS = @[[ZXQRCodeVersion ZXQRCodeVersionWithVersionNumber:1 + alignmentPatternCenters:[[ZXIntArray alloc] initWithLength:0] + ecBlocks1:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:7 ecBlocks:[ZXQRCodeECB ecbWithCount:1 dataCodewords:19]] + ecBlocks2:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:10 ecBlocks:[ZXQRCodeECB ecbWithCount:1 dataCodewords:16]] + ecBlocks3:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:13 ecBlocks:[ZXQRCodeECB ecbWithCount:1 dataCodewords:13]] + ecBlocks4:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:17 ecBlocks:[ZXQRCodeECB ecbWithCount:1 dataCodewords:9]]], + + [ZXQRCodeVersion ZXQRCodeVersionWithVersionNumber:2 + alignmentPatternCenters:[[ZXIntArray alloc] initWithInts:6, 18, -1] + ecBlocks1:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:10 ecBlocks:[ZXQRCodeECB ecbWithCount:1 dataCodewords:34]] + ecBlocks2:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:16 ecBlocks:[ZXQRCodeECB ecbWithCount:1 dataCodewords:28]] + ecBlocks3:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:22 ecBlocks:[ZXQRCodeECB ecbWithCount:1 dataCodewords:22]] + ecBlocks4:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:28 ecBlocks:[ZXQRCodeECB ecbWithCount:1 dataCodewords:16]]], + + [ZXQRCodeVersion ZXQRCodeVersionWithVersionNumber:3 + alignmentPatternCenters:[[ZXIntArray alloc] initWithInts:6, 22, -1] + ecBlocks1:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:15 ecBlocks:[ZXQRCodeECB ecbWithCount:1 dataCodewords:55]] + ecBlocks2:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:26 ecBlocks:[ZXQRCodeECB ecbWithCount:1 dataCodewords:44]] + ecBlocks3:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:18 ecBlocks:[ZXQRCodeECB ecbWithCount:2 dataCodewords:17]] + ecBlocks4:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:22 ecBlocks:[ZXQRCodeECB ecbWithCount:2 dataCodewords:13]]], + + [ZXQRCodeVersion ZXQRCodeVersionWithVersionNumber:4 + alignmentPatternCenters:[[ZXIntArray alloc] initWithInts:6, 26, -1] + ecBlocks1:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:20 ecBlocks:[ZXQRCodeECB ecbWithCount:1 dataCodewords:80]] + ecBlocks2:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:18 ecBlocks:[ZXQRCodeECB ecbWithCount:2 dataCodewords:32]] + ecBlocks3:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:26 ecBlocks:[ZXQRCodeECB ecbWithCount:2 dataCodewords:24]] + ecBlocks4:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:16 ecBlocks:[ZXQRCodeECB ecbWithCount:4 dataCodewords:9]]], + + [ZXQRCodeVersion ZXQRCodeVersionWithVersionNumber:5 + alignmentPatternCenters:[[ZXIntArray alloc] initWithInts:6, 30, -1] + ecBlocks1:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:26 ecBlocks:[ZXQRCodeECB ecbWithCount:1 dataCodewords:108]] + ecBlocks2:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:24 ecBlocks:[ZXQRCodeECB ecbWithCount:2 dataCodewords:43]] + ecBlocks3:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:18 ecBlocks1:[ZXQRCodeECB ecbWithCount:2 dataCodewords:15] ecBlocks2:[ZXQRCodeECB ecbWithCount:2 dataCodewords:16]] + ecBlocks4:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:22 ecBlocks1:[ZXQRCodeECB ecbWithCount:2 dataCodewords:11] ecBlocks2:[ZXQRCodeECB ecbWithCount:2 dataCodewords:12]]], + + [ZXQRCodeVersion ZXQRCodeVersionWithVersionNumber:6 + alignmentPatternCenters:[[ZXIntArray alloc] initWithInts:6, 34, -1] + ecBlocks1:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:18 ecBlocks:[ZXQRCodeECB ecbWithCount:2 dataCodewords:68]] + ecBlocks2:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:16 ecBlocks:[ZXQRCodeECB ecbWithCount:4 dataCodewords:27]] + ecBlocks3:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:24 ecBlocks:[ZXQRCodeECB ecbWithCount:4 dataCodewords:19]] + ecBlocks4:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:28 ecBlocks:[ZXQRCodeECB ecbWithCount:4 dataCodewords:15]]], + + [ZXQRCodeVersion ZXQRCodeVersionWithVersionNumber:7 + alignmentPatternCenters:[[ZXIntArray alloc] initWithInts:6, 22, 38, -1] + ecBlocks1:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:20 ecBlocks:[ZXQRCodeECB ecbWithCount:2 dataCodewords:78]] + ecBlocks2:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:18 ecBlocks:[ZXQRCodeECB ecbWithCount:4 dataCodewords:31]] + ecBlocks3:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:18 ecBlocks1:[ZXQRCodeECB ecbWithCount:2 dataCodewords:14] ecBlocks2:[ZXQRCodeECB ecbWithCount:4 dataCodewords:15]] + ecBlocks4:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:26 ecBlocks1:[ZXQRCodeECB ecbWithCount:4 dataCodewords:13] ecBlocks2:[ZXQRCodeECB ecbWithCount:1 dataCodewords:14]]], + + [ZXQRCodeVersion ZXQRCodeVersionWithVersionNumber:8 + alignmentPatternCenters:[[ZXIntArray alloc] initWithInts:6, 24, 42, -1] + ecBlocks1:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:24 ecBlocks:[ZXQRCodeECB ecbWithCount:2 dataCodewords:97]] + ecBlocks2:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:22 ecBlocks1:[ZXQRCodeECB ecbWithCount:2 dataCodewords:38] ecBlocks2:[ZXQRCodeECB ecbWithCount:2 dataCodewords:39]] + ecBlocks3:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:22 ecBlocks1:[ZXQRCodeECB ecbWithCount:4 dataCodewords:18] ecBlocks2:[ZXQRCodeECB ecbWithCount:2 dataCodewords:19]] + ecBlocks4:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:26 ecBlocks1:[ZXQRCodeECB ecbWithCount:4 dataCodewords:14] ecBlocks2:[ZXQRCodeECB ecbWithCount:2 dataCodewords:15]]], + + [ZXQRCodeVersion ZXQRCodeVersionWithVersionNumber:9 + alignmentPatternCenters:[[ZXIntArray alloc] initWithInts:6, 26, 46, -1] + ecBlocks1:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks:[ZXQRCodeECB ecbWithCount:2 dataCodewords:116]] + ecBlocks2:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:22 ecBlocks1:[ZXQRCodeECB ecbWithCount:3 dataCodewords:36] ecBlocks2:[ZXQRCodeECB ecbWithCount:2 dataCodewords:37]] + ecBlocks3:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:20 ecBlocks1:[ZXQRCodeECB ecbWithCount:4 dataCodewords:16] ecBlocks2:[ZXQRCodeECB ecbWithCount:4 dataCodewords:17]] + ecBlocks4:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:24 ecBlocks1:[ZXQRCodeECB ecbWithCount:4 dataCodewords:12] ecBlocks2:[ZXQRCodeECB ecbWithCount:4 dataCodewords:13]]], + + [ZXQRCodeVersion ZXQRCodeVersionWithVersionNumber:10 + alignmentPatternCenters:[[ZXIntArray alloc] initWithInts:6, 28, 50, -1] + ecBlocks1:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:18 ecBlocks1:[ZXQRCodeECB ecbWithCount:2 dataCodewords:68] ecBlocks2:[ZXQRCodeECB ecbWithCount:2 dataCodewords:69]] + ecBlocks2:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:26 ecBlocks1:[ZXQRCodeECB ecbWithCount:4 dataCodewords:43] ecBlocks2:[ZXQRCodeECB ecbWithCount:1 dataCodewords:44]] + ecBlocks3:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:24 ecBlocks1:[ZXQRCodeECB ecbWithCount:6 dataCodewords:19] ecBlocks2:[ZXQRCodeECB ecbWithCount:2 dataCodewords:20]] + ecBlocks4:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:28 ecBlocks1:[ZXQRCodeECB ecbWithCount:6 dataCodewords:15] ecBlocks2:[ZXQRCodeECB ecbWithCount:2 dataCodewords:16]]], + + [ZXQRCodeVersion ZXQRCodeVersionWithVersionNumber:11 + alignmentPatternCenters:[[ZXIntArray alloc] initWithInts:6, 30, 54, -1] + ecBlocks1:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:20 ecBlocks:[ZXQRCodeECB ecbWithCount:4 dataCodewords:81]] + ecBlocks2:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:1 dataCodewords:50] ecBlocks2:[ZXQRCodeECB ecbWithCount:4 dataCodewords:51]] + ecBlocks3:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:28 ecBlocks1:[ZXQRCodeECB ecbWithCount:4 dataCodewords:22] ecBlocks2:[ZXQRCodeECB ecbWithCount:4 dataCodewords:23]] + ecBlocks4:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:24 ecBlocks1:[ZXQRCodeECB ecbWithCount:3 dataCodewords:12] ecBlocks2:[ZXQRCodeECB ecbWithCount:8 dataCodewords:13]]], + + [ZXQRCodeVersion ZXQRCodeVersionWithVersionNumber:12 + alignmentPatternCenters:[[ZXIntArray alloc] initWithInts:6, 32, 58, -1] + ecBlocks1:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:24 ecBlocks1:[ZXQRCodeECB ecbWithCount:2 dataCodewords:92] ecBlocks2:[ZXQRCodeECB ecbWithCount:2 dataCodewords:93]] + ecBlocks2:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:22 ecBlocks1:[ZXQRCodeECB ecbWithCount:6 dataCodewords:36] ecBlocks2:[ZXQRCodeECB ecbWithCount:2 dataCodewords:37]] + ecBlocks3:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:26 ecBlocks1:[ZXQRCodeECB ecbWithCount:4 dataCodewords:20] ecBlocks2:[ZXQRCodeECB ecbWithCount:6 dataCodewords:21]] + ecBlocks4:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:28 ecBlocks1:[ZXQRCodeECB ecbWithCount:7 dataCodewords:14] ecBlocks2:[ZXQRCodeECB ecbWithCount:4 dataCodewords:15]]], + + [ZXQRCodeVersion ZXQRCodeVersionWithVersionNumber:13 + alignmentPatternCenters:[[ZXIntArray alloc] initWithInts:6, 34, 62, -1] + ecBlocks1:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:26 ecBlocks:[ZXQRCodeECB ecbWithCount:4 dataCodewords:107]] + ecBlocks2:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:22 ecBlocks1:[ZXQRCodeECB ecbWithCount:8 dataCodewords:37] ecBlocks2:[ZXQRCodeECB ecbWithCount:1 dataCodewords:38]] + ecBlocks3:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:24 ecBlocks1:[ZXQRCodeECB ecbWithCount:8 dataCodewords:20] ecBlocks2:[ZXQRCodeECB ecbWithCount:4 dataCodewords:21]] + ecBlocks4:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:22 ecBlocks1:[ZXQRCodeECB ecbWithCount:12 dataCodewords:11] ecBlocks2:[ZXQRCodeECB ecbWithCount:4 dataCodewords:12]]], + + [ZXQRCodeVersion ZXQRCodeVersionWithVersionNumber:14 + alignmentPatternCenters:[[ZXIntArray alloc] initWithInts:6, 26, 46, 66, -1] + ecBlocks1:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:3 dataCodewords:115] ecBlocks2:[ZXQRCodeECB ecbWithCount:1 dataCodewords:116]] + ecBlocks2:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:24 ecBlocks1:[ZXQRCodeECB ecbWithCount:4 dataCodewords:40] ecBlocks2:[ZXQRCodeECB ecbWithCount:5 dataCodewords:41]] + ecBlocks3:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:20 ecBlocks1:[ZXQRCodeECB ecbWithCount:11 dataCodewords:16] ecBlocks2:[ZXQRCodeECB ecbWithCount:5 dataCodewords:17]] + ecBlocks4:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:24 ecBlocks1:[ZXQRCodeECB ecbWithCount:11 dataCodewords:12] ecBlocks2:[ZXQRCodeECB ecbWithCount:5 dataCodewords:13]]], + + [ZXQRCodeVersion ZXQRCodeVersionWithVersionNumber:15 + alignmentPatternCenters:[[ZXIntArray alloc] initWithInts:6, 26, 48, 70, -1] + ecBlocks1:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:22 ecBlocks1:[ZXQRCodeECB ecbWithCount:5 dataCodewords:87] ecBlocks2:[ZXQRCodeECB ecbWithCount:1 dataCodewords:88]] + ecBlocks2:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:24 ecBlocks1:[ZXQRCodeECB ecbWithCount:5 dataCodewords:41] ecBlocks2:[ZXQRCodeECB ecbWithCount:5 dataCodewords:42]] + ecBlocks3:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:5 dataCodewords:24] ecBlocks2:[ZXQRCodeECB ecbWithCount:7 dataCodewords:25]] + ecBlocks4:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:24 ecBlocks1:[ZXQRCodeECB ecbWithCount:11 dataCodewords:12] ecBlocks2:[ZXQRCodeECB ecbWithCount:7 dataCodewords:13]]], + + [ZXQRCodeVersion ZXQRCodeVersionWithVersionNumber:16 + alignmentPatternCenters:[[ZXIntArray alloc] initWithInts:6, 26, 50, 74, -1] + ecBlocks1:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:24 ecBlocks1:[ZXQRCodeECB ecbWithCount:5 dataCodewords:98] ecBlocks2:[ZXQRCodeECB ecbWithCount:1 dataCodewords:99]] + ecBlocks2:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:28 ecBlocks1:[ZXQRCodeECB ecbWithCount:7 dataCodewords:45] ecBlocks2:[ZXQRCodeECB ecbWithCount:3 dataCodewords:46]] + ecBlocks3:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:24 ecBlocks1:[ZXQRCodeECB ecbWithCount:15 dataCodewords:19] ecBlocks2:[ZXQRCodeECB ecbWithCount:2 dataCodewords:20]] + ecBlocks4:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:3 dataCodewords:15] ecBlocks2:[ZXQRCodeECB ecbWithCount:13 dataCodewords:16]]], + + [ZXQRCodeVersion ZXQRCodeVersionWithVersionNumber:17 + alignmentPatternCenters:[[ZXIntArray alloc] initWithInts:6, 30, 50, 78, -1] + ecBlocks1:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:28 ecBlocks1:[ZXQRCodeECB ecbWithCount:1 dataCodewords:107] ecBlocks2:[ZXQRCodeECB ecbWithCount:5 dataCodewords:108]] + ecBlocks2:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:28 ecBlocks1:[ZXQRCodeECB ecbWithCount:10 dataCodewords:46] ecBlocks2:[ZXQRCodeECB ecbWithCount:1 dataCodewords:47]] + ecBlocks3:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:28 ecBlocks1:[ZXQRCodeECB ecbWithCount:1 dataCodewords:22] ecBlocks2:[ZXQRCodeECB ecbWithCount:15 dataCodewords:23]] + ecBlocks4:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:28 ecBlocks1:[ZXQRCodeECB ecbWithCount:2 dataCodewords:14] ecBlocks2:[ZXQRCodeECB ecbWithCount:17 dataCodewords:15]]], + + [ZXQRCodeVersion ZXQRCodeVersionWithVersionNumber:18 + alignmentPatternCenters:[[ZXIntArray alloc] initWithInts:6, 30, 56, 82, -1] + ecBlocks1:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:5 dataCodewords:120] ecBlocks2:[ZXQRCodeECB ecbWithCount:1 dataCodewords:121]] + ecBlocks2:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:26 ecBlocks1:[ZXQRCodeECB ecbWithCount:9 dataCodewords:43] ecBlocks2:[ZXQRCodeECB ecbWithCount:4 dataCodewords:44]] + ecBlocks3:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:28 ecBlocks1:[ZXQRCodeECB ecbWithCount:17 dataCodewords:22] ecBlocks2:[ZXQRCodeECB ecbWithCount:1 dataCodewords:23]] + ecBlocks4:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:28 ecBlocks1:[ZXQRCodeECB ecbWithCount:2 dataCodewords:14] ecBlocks2:[ZXQRCodeECB ecbWithCount:19 dataCodewords:15]]], + + [ZXQRCodeVersion ZXQRCodeVersionWithVersionNumber:19 + alignmentPatternCenters:[[ZXIntArray alloc] initWithInts:6, 30, 58, 86, -1] + ecBlocks1:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:28 ecBlocks1:[ZXQRCodeECB ecbWithCount:3 dataCodewords:113] ecBlocks2:[ZXQRCodeECB ecbWithCount:4 dataCodewords:114]] + ecBlocks2:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:26 ecBlocks1:[ZXQRCodeECB ecbWithCount:3 dataCodewords:44] ecBlocks2:[ZXQRCodeECB ecbWithCount:11 dataCodewords:45]] + ecBlocks3:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:26 ecBlocks1:[ZXQRCodeECB ecbWithCount:17 dataCodewords:21] ecBlocks2:[ZXQRCodeECB ecbWithCount:4 dataCodewords:22]] + ecBlocks4:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:26 ecBlocks1:[ZXQRCodeECB ecbWithCount:9 dataCodewords:13] ecBlocks2:[ZXQRCodeECB ecbWithCount:16 dataCodewords:14]]], + + [ZXQRCodeVersion ZXQRCodeVersionWithVersionNumber:20 + alignmentPatternCenters:[[ZXIntArray alloc] initWithInts:6, 34, 62, 90, -1] + ecBlocks1:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:28 ecBlocks1:[ZXQRCodeECB ecbWithCount:3 dataCodewords:107] ecBlocks2:[ZXQRCodeECB ecbWithCount:5 dataCodewords:108]] + ecBlocks2:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:26 ecBlocks1:[ZXQRCodeECB ecbWithCount:3 dataCodewords:41] ecBlocks2:[ZXQRCodeECB ecbWithCount:13 dataCodewords:42]] + ecBlocks3:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:15 dataCodewords:24] ecBlocks2:[ZXQRCodeECB ecbWithCount:5 dataCodewords:25]] + ecBlocks4:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:28 ecBlocks1:[ZXQRCodeECB ecbWithCount:15 dataCodewords:15] ecBlocks2:[ZXQRCodeECB ecbWithCount:10 dataCodewords:16]]], + + [ZXQRCodeVersion ZXQRCodeVersionWithVersionNumber:21 + alignmentPatternCenters:[[ZXIntArray alloc] initWithInts:6, 28, 50, 72, 94, -1] + ecBlocks1:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:28 ecBlocks1:[ZXQRCodeECB ecbWithCount:4 dataCodewords:116] ecBlocks2:[ZXQRCodeECB ecbWithCount:4 dataCodewords:117]] + ecBlocks2:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:26 ecBlocks:[ZXQRCodeECB ecbWithCount:17 dataCodewords:42]] + ecBlocks3:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:28 ecBlocks1:[ZXQRCodeECB ecbWithCount:17 dataCodewords:22] ecBlocks2:[ZXQRCodeECB ecbWithCount:6 dataCodewords:23]] + ecBlocks4:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:19 dataCodewords:16] ecBlocks2:[ZXQRCodeECB ecbWithCount:6 dataCodewords:17]]], + + [ZXQRCodeVersion ZXQRCodeVersionWithVersionNumber:22 + alignmentPatternCenters:[[ZXIntArray alloc] initWithInts:6, 26, 50, 72, 98, -1] + ecBlocks1:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:28 ecBlocks1:[ZXQRCodeECB ecbWithCount:2 dataCodewords:111] ecBlocks2:[ZXQRCodeECB ecbWithCount:7 dataCodewords:112]] + ecBlocks2:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:28 ecBlocks:[ZXQRCodeECB ecbWithCount:17 dataCodewords:46]] + ecBlocks3:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:7 dataCodewords:24] ecBlocks2:[ZXQRCodeECB ecbWithCount:16 dataCodewords:25]] + ecBlocks4:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:24 ecBlocks:[ZXQRCodeECB ecbWithCount:34 dataCodewords:13]]], + + [ZXQRCodeVersion ZXQRCodeVersionWithVersionNumber:23 + alignmentPatternCenters:[[ZXIntArray alloc] initWithInts:6, 30, 54, 78, 102, -1] + ecBlocks1:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:4 dataCodewords:121] ecBlocks2:[ZXQRCodeECB ecbWithCount:5 dataCodewords:122]] + ecBlocks2:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:28 ecBlocks1:[ZXQRCodeECB ecbWithCount:4 dataCodewords:47] ecBlocks2:[ZXQRCodeECB ecbWithCount:14 dataCodewords:48]] + ecBlocks3:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:11 dataCodewords:24] ecBlocks2:[ZXQRCodeECB ecbWithCount:14 dataCodewords:25]] + ecBlocks4:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:16 dataCodewords:15] ecBlocks2:[ZXQRCodeECB ecbWithCount:14 dataCodewords:16]]], + + [ZXQRCodeVersion ZXQRCodeVersionWithVersionNumber:24 + alignmentPatternCenters:[[ZXIntArray alloc] initWithInts:6, 28, 54, 80, 106, -1] + ecBlocks1:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:6 dataCodewords:117] ecBlocks2:[ZXQRCodeECB ecbWithCount:4 dataCodewords:118]] + ecBlocks2:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:28 ecBlocks1:[ZXQRCodeECB ecbWithCount:6 dataCodewords:45] ecBlocks2:[ZXQRCodeECB ecbWithCount:14 dataCodewords:46]] + ecBlocks3:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:11 dataCodewords:24] ecBlocks2:[ZXQRCodeECB ecbWithCount:16 dataCodewords:25]] + ecBlocks4:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:30 dataCodewords:16] ecBlocks2:[ZXQRCodeECB ecbWithCount:2 dataCodewords:17]]], + + [ZXQRCodeVersion ZXQRCodeVersionWithVersionNumber:25 + alignmentPatternCenters:[[ZXIntArray alloc] initWithInts:6, 32, 58, 84, 110, -1] + ecBlocks1:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:26 ecBlocks1:[ZXQRCodeECB ecbWithCount:8 dataCodewords:106] ecBlocks2:[ZXQRCodeECB ecbWithCount:4 dataCodewords:107]] + ecBlocks2:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:28 ecBlocks1:[ZXQRCodeECB ecbWithCount:8 dataCodewords:47] ecBlocks2:[ZXQRCodeECB ecbWithCount:13 dataCodewords:48]] + ecBlocks3:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:7 dataCodewords:24] ecBlocks2:[ZXQRCodeECB ecbWithCount:22 dataCodewords:25]] + ecBlocks4:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:22 dataCodewords:15] ecBlocks2:[ZXQRCodeECB ecbWithCount:13 dataCodewords:16]]], + + [ZXQRCodeVersion ZXQRCodeVersionWithVersionNumber:26 + alignmentPatternCenters:[[ZXIntArray alloc] initWithInts:6, 30, 58, 86, 114, -1] + ecBlocks1:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:28 ecBlocks1:[ZXQRCodeECB ecbWithCount:10 dataCodewords:114] ecBlocks2:[ZXQRCodeECB ecbWithCount:2 dataCodewords:115]] + ecBlocks2:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:28 ecBlocks1:[ZXQRCodeECB ecbWithCount:19 dataCodewords:46] ecBlocks2:[ZXQRCodeECB ecbWithCount:4 dataCodewords:47]] + ecBlocks3:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:28 ecBlocks1:[ZXQRCodeECB ecbWithCount:28 dataCodewords:22] ecBlocks2:[ZXQRCodeECB ecbWithCount:6 dataCodewords:23]] + ecBlocks4:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:33 dataCodewords:16] ecBlocks2:[ZXQRCodeECB ecbWithCount:4 dataCodewords:17]]], + + [ZXQRCodeVersion ZXQRCodeVersionWithVersionNumber:27 + alignmentPatternCenters:[[ZXIntArray alloc] initWithInts:6, 34, 62, 90, 118, -1] + ecBlocks1:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:8 dataCodewords:122] ecBlocks2:[ZXQRCodeECB ecbWithCount:4 dataCodewords:123]] + ecBlocks2:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:28 ecBlocks1:[ZXQRCodeECB ecbWithCount:22 dataCodewords:45] ecBlocks2:[ZXQRCodeECB ecbWithCount:3 dataCodewords:46]] + ecBlocks3:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:8 dataCodewords:23] ecBlocks2:[ZXQRCodeECB ecbWithCount:26 dataCodewords:24]] + ecBlocks4:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:12 dataCodewords:15] ecBlocks2:[ZXQRCodeECB ecbWithCount:28 dataCodewords:16]]], + + [ZXQRCodeVersion ZXQRCodeVersionWithVersionNumber:28 + alignmentPatternCenters:[[ZXIntArray alloc] initWithInts:6, 26, 50, 74, 98, 122, -1] + ecBlocks1:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:3 dataCodewords:117] ecBlocks2:[ZXQRCodeECB ecbWithCount:10 dataCodewords:118]] + ecBlocks2:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:28 ecBlocks1:[ZXQRCodeECB ecbWithCount:3 dataCodewords:45] ecBlocks2:[ZXQRCodeECB ecbWithCount:23 dataCodewords:46]] + ecBlocks3:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:4 dataCodewords:24] ecBlocks2:[ZXQRCodeECB ecbWithCount:31 dataCodewords:25]] + ecBlocks4:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:11 dataCodewords:15] ecBlocks2:[ZXQRCodeECB ecbWithCount:31 dataCodewords:16]]], + + [ZXQRCodeVersion ZXQRCodeVersionWithVersionNumber:29 + alignmentPatternCenters:[[ZXIntArray alloc] initWithInts:6, 30, 54, 78, 102, 126, -1] + ecBlocks1:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:7 dataCodewords:116] ecBlocks2:[ZXQRCodeECB ecbWithCount:7 dataCodewords:117]] + ecBlocks2:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:28 ecBlocks1:[ZXQRCodeECB ecbWithCount:21 dataCodewords:45] ecBlocks2:[ZXQRCodeECB ecbWithCount:7 dataCodewords:46]] + ecBlocks3:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:1 dataCodewords:23] ecBlocks2:[ZXQRCodeECB ecbWithCount:37 dataCodewords:24]] + ecBlocks4:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:19 dataCodewords:15] ecBlocks2:[ZXQRCodeECB ecbWithCount:26 dataCodewords:16]]], + + [ZXQRCodeVersion ZXQRCodeVersionWithVersionNumber:30 + alignmentPatternCenters:[[ZXIntArray alloc] initWithInts:6, 26, 52, 78, 104, 130, -1] + ecBlocks1:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:5 dataCodewords:115] ecBlocks2:[ZXQRCodeECB ecbWithCount:10 dataCodewords:116]] + ecBlocks2:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:28 ecBlocks1:[ZXQRCodeECB ecbWithCount:19 dataCodewords:47] ecBlocks2:[ZXQRCodeECB ecbWithCount:10 dataCodewords:48]] + ecBlocks3:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:15 dataCodewords:24] ecBlocks2:[ZXQRCodeECB ecbWithCount:25 dataCodewords:25]] + ecBlocks4:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:23 dataCodewords:15] ecBlocks2:[ZXQRCodeECB ecbWithCount:25 dataCodewords:16]]], + + [ZXQRCodeVersion ZXQRCodeVersionWithVersionNumber:31 + alignmentPatternCenters:[[ZXIntArray alloc] initWithInts:6, 30, 56, 82, 108, 134, -1] + ecBlocks1:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:13 dataCodewords:115] ecBlocks2:[ZXQRCodeECB ecbWithCount:3 dataCodewords:116]] + ecBlocks2:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:28 ecBlocks1:[ZXQRCodeECB ecbWithCount:2 dataCodewords:46] ecBlocks2:[ZXQRCodeECB ecbWithCount:29 dataCodewords:47]] + ecBlocks3:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:42 dataCodewords:24] ecBlocks2:[ZXQRCodeECB ecbWithCount:1 dataCodewords:25]] + ecBlocks4:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:23 dataCodewords:15] ecBlocks2:[ZXQRCodeECB ecbWithCount:28 dataCodewords:16]]], + + [ZXQRCodeVersion ZXQRCodeVersionWithVersionNumber:32 + alignmentPatternCenters:[[ZXIntArray alloc] initWithInts:6, 34, 60, 86, 112, 138, -1] + ecBlocks1:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks:[ZXQRCodeECB ecbWithCount:17 dataCodewords:115]] + ecBlocks2:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:28 ecBlocks1:[ZXQRCodeECB ecbWithCount:10 dataCodewords:46] ecBlocks2:[ZXQRCodeECB ecbWithCount:23 dataCodewords:47]] + ecBlocks3:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:10 dataCodewords:24] ecBlocks2:[ZXQRCodeECB ecbWithCount:35 dataCodewords:25]] + ecBlocks4:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:19 dataCodewords:15] ecBlocks2:[ZXQRCodeECB ecbWithCount:35 dataCodewords:16]]], + + [ZXQRCodeVersion ZXQRCodeVersionWithVersionNumber:33 + alignmentPatternCenters:[[ZXIntArray alloc] initWithInts:6, 30, 58, 86, 114, 142, -1] + ecBlocks1:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:17 dataCodewords:115] ecBlocks2:[ZXQRCodeECB ecbWithCount:1 dataCodewords:116]] + ecBlocks2:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:28 ecBlocks1:[ZXQRCodeECB ecbWithCount:14 dataCodewords:46] ecBlocks2:[ZXQRCodeECB ecbWithCount:21 dataCodewords:47]] + ecBlocks3:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:29 dataCodewords:24] ecBlocks2:[ZXQRCodeECB ecbWithCount:19 dataCodewords:25]] + ecBlocks4:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:11 dataCodewords:15] ecBlocks2:[ZXQRCodeECB ecbWithCount:46 dataCodewords:16]]], + + [ZXQRCodeVersion ZXQRCodeVersionWithVersionNumber:34 + alignmentPatternCenters:[[ZXIntArray alloc] initWithInts:6, 34, 62, 90, 118, 146, -1] + ecBlocks1:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:13 dataCodewords:115] ecBlocks2:[ZXQRCodeECB ecbWithCount:6 dataCodewords:116]] + ecBlocks2:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:28 ecBlocks1:[ZXQRCodeECB ecbWithCount:14 dataCodewords:46] ecBlocks2:[ZXQRCodeECB ecbWithCount:23 dataCodewords:47]] + ecBlocks3:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:44 dataCodewords:24] ecBlocks2:[ZXQRCodeECB ecbWithCount:7 dataCodewords:25]] + ecBlocks4:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:59 dataCodewords:16] ecBlocks2:[ZXQRCodeECB ecbWithCount:1 dataCodewords:17]]], + + [ZXQRCodeVersion ZXQRCodeVersionWithVersionNumber:35 + alignmentPatternCenters:[[ZXIntArray alloc] initWithInts:6, 30, 54, 78, 102, 126, 150, -1] + ecBlocks1:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:12 dataCodewords:121] ecBlocks2:[ZXQRCodeECB ecbWithCount:7 dataCodewords:122]] + ecBlocks2:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:28 ecBlocks1:[ZXQRCodeECB ecbWithCount:12 dataCodewords:47] ecBlocks2:[ZXQRCodeECB ecbWithCount:26 dataCodewords:48]] + ecBlocks3:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:39 dataCodewords:24] ecBlocks2:[ZXQRCodeECB ecbWithCount:14 dataCodewords:25]] + ecBlocks4:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:22 dataCodewords:15] ecBlocks2:[ZXQRCodeECB ecbWithCount:41 dataCodewords:16]]], + + [ZXQRCodeVersion ZXQRCodeVersionWithVersionNumber:36 + alignmentPatternCenters:[[ZXIntArray alloc] initWithInts:6, 24, 50, 76, 102, 128, 154, -1] + ecBlocks1:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:6 dataCodewords:121] ecBlocks2:[ZXQRCodeECB ecbWithCount:14 dataCodewords:122]] + ecBlocks2:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:28 ecBlocks1:[ZXQRCodeECB ecbWithCount:6 dataCodewords:47] ecBlocks2:[ZXQRCodeECB ecbWithCount:34 dataCodewords:48]] + ecBlocks3:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:46 dataCodewords:24] ecBlocks2:[ZXQRCodeECB ecbWithCount:10 dataCodewords:25]] + ecBlocks4:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:2 dataCodewords:15] ecBlocks2:[ZXQRCodeECB ecbWithCount:64 dataCodewords:16]]], + + [ZXQRCodeVersion ZXQRCodeVersionWithVersionNumber:37 + alignmentPatternCenters:[[ZXIntArray alloc] initWithInts:6, 28, 54, 80, 106, 132, 158, -1] + ecBlocks1:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:17 dataCodewords:122] ecBlocks2:[ZXQRCodeECB ecbWithCount:4 dataCodewords:123]] + ecBlocks2:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:28 ecBlocks1:[ZXQRCodeECB ecbWithCount:29 dataCodewords:46] ecBlocks2:[ZXQRCodeECB ecbWithCount:14 dataCodewords:47]] + ecBlocks3:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:49 dataCodewords:24] ecBlocks2:[ZXQRCodeECB ecbWithCount:10 dataCodewords:25]] + ecBlocks4:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:24 dataCodewords:15] ecBlocks2:[ZXQRCodeECB ecbWithCount:46 dataCodewords:16]]], + + [ZXQRCodeVersion ZXQRCodeVersionWithVersionNumber:38 + alignmentPatternCenters:[[ZXIntArray alloc] initWithInts:6, 32, 58, 84, 110, 136, 162, -1] + ecBlocks1:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:4 dataCodewords:122] ecBlocks2:[ZXQRCodeECB ecbWithCount:18 dataCodewords:123]] + ecBlocks2:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:28 ecBlocks1:[ZXQRCodeECB ecbWithCount:13 dataCodewords:46] ecBlocks2:[ZXQRCodeECB ecbWithCount:32 dataCodewords:47]] + ecBlocks3:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:48 dataCodewords:24] ecBlocks2:[ZXQRCodeECB ecbWithCount:14 dataCodewords:25]] + ecBlocks4:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:42 dataCodewords:15] ecBlocks2:[ZXQRCodeECB ecbWithCount:32 dataCodewords:16]]], + + [ZXQRCodeVersion ZXQRCodeVersionWithVersionNumber:39 + alignmentPatternCenters:[[ZXIntArray alloc] initWithInts:6, 26, 54, 82, 110, 138, 166, -1] + ecBlocks1:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:20 dataCodewords:117] ecBlocks2:[ZXQRCodeECB ecbWithCount:4 dataCodewords:118]] + ecBlocks2:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:28 ecBlocks1:[ZXQRCodeECB ecbWithCount:40 dataCodewords:47] ecBlocks2:[ZXQRCodeECB ecbWithCount:7 dataCodewords:48]] + ecBlocks3:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:43 dataCodewords:24] ecBlocks2:[ZXQRCodeECB ecbWithCount:22 dataCodewords:25]] + ecBlocks4:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:10 dataCodewords:15] ecBlocks2:[ZXQRCodeECB ecbWithCount:67 dataCodewords:16]]], + + [ZXQRCodeVersion ZXQRCodeVersionWithVersionNumber:40 + alignmentPatternCenters:[[ZXIntArray alloc] initWithInts:6, 30, 58, 86, 114, 142, 170, -1] + ecBlocks1:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:19 dataCodewords:118] ecBlocks2:[ZXQRCodeECB ecbWithCount:6 dataCodewords:119]] + ecBlocks2:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:28 ecBlocks1:[ZXQRCodeECB ecbWithCount:18 dataCodewords:47] ecBlocks2:[ZXQRCodeECB ecbWithCount:31 dataCodewords:48]] + ecBlocks3:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:34 dataCodewords:24] ecBlocks2:[ZXQRCodeECB ecbWithCount:34 dataCodewords:25]] + ecBlocks4:[ZXQRCodeECBlocks ecBlocksWithEcCodewordsPerBlock:30 ecBlocks1:[ZXQRCodeECB ecbWithCount:20 dataCodewords:15] ecBlocks2:[ZXQRCodeECB ecbWithCount:61 dataCodewords:16]]]]; +} + +@end + +@implementation ZXQRCodeECBlocks + +- (id)initWithEcCodewordsPerBlock:(int)ecCodewordsPerBlock ecBlocks:(ZXQRCodeECB *)ecBlocks { + if (self = [super init]) { + _ecCodewordsPerBlock = ecCodewordsPerBlock; + _ecBlocks = @[ecBlocks]; + } + + return self; +} + +- (id)initWithEcCodewordsPerBlock:(int)ecCodewordsPerBlock ecBlocks1:(ZXQRCodeECB *)ecBlocks1 ecBlocks2:(ZXQRCodeECB *)ecBlocks2 { + if (self = [super init]) { + _ecCodewordsPerBlock = ecCodewordsPerBlock; + _ecBlocks = @[ecBlocks1, ecBlocks2]; + } + + return self; +} + ++ (ZXQRCodeECBlocks *)ecBlocksWithEcCodewordsPerBlock:(int)ecCodewordsPerBlock ecBlocks:(ZXQRCodeECB *)ecBlocks { + return [[ZXQRCodeECBlocks alloc] initWithEcCodewordsPerBlock:ecCodewordsPerBlock ecBlocks:ecBlocks]; +} + ++ (ZXQRCodeECBlocks *)ecBlocksWithEcCodewordsPerBlock:(int)ecCodewordsPerBlock ecBlocks1:(ZXQRCodeECB *)ecBlocks1 ecBlocks2:(ZXQRCodeECB *)ecBlocks2 { + return [[ZXQRCodeECBlocks alloc] initWithEcCodewordsPerBlock:ecCodewordsPerBlock ecBlocks1:ecBlocks1 ecBlocks2:ecBlocks2]; +} + +- (int)numBlocks { + int total = 0; + + for (ZXQRCodeECB *ecb in self.ecBlocks) { + total += [ecb count]; + } + + return total; +} + +- (int)totalECCodewords { + return self.ecCodewordsPerBlock * [self numBlocks]; +} + +@end + +@implementation ZXQRCodeECB + +- (id)initWithCount:(int)count dataCodewords:(int)dataCodewords { + if (self = [super init]) { + _count = count; + _dataCodewords = dataCodewords; + } + + return self; +} + ++ (ZXQRCodeECB *)ecbWithCount:(int)count dataCodewords:(int)dataCodewords { + return [[ZXQRCodeECB alloc] initWithCount:count dataCodewords:dataCodewords]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeAlignmentPattern.h b/iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeAlignmentPattern.h new file mode 100755 index 0000000..55f400c --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeAlignmentPattern.h @@ -0,0 +1,39 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXResultPoint.h" + +/** + * Encapsulates an alignment pattern, which are the smaller square patterns found in + * all but the simplest QR Codes. + */ +@interface ZXQRCodeAlignmentPattern : ZXResultPoint + +- (id)initWithPosX:(float)posX posY:(float)posY estimatedModuleSize:(float)estimatedModuleSize; + +/** + * Determines if this alignment pattern "about equals" an alignment pattern at the stated + * position and size -- meaning, it is at nearly the same center with nearly the same size. + */ +- (BOOL)aboutEquals:(float)moduleSize i:(float)i j:(float)j; + +/** + * Combines this object's current estimate of a finder pattern position and module size + * with a new estimate. It returns a new {@code FinderPattern} containing an average of the two. + */ +- (ZXQRCodeAlignmentPattern *)combineEstimateI:(float)i j:(float)j newModuleSize:(float)newModuleSize; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeAlignmentPattern.m b/iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeAlignmentPattern.m new file mode 100755 index 0000000..5c9a9ad --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeAlignmentPattern.m @@ -0,0 +1,51 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXQRCodeAlignmentPattern.h" + +@interface ZXQRCodeAlignmentPattern () + +@property (nonatomic, assign, readonly) float estimatedModuleSize; + +@end + +@implementation ZXQRCodeAlignmentPattern + +- (id)initWithPosX:(float)posX posY:(float)posY estimatedModuleSize:(float)estimatedModuleSize { + if (self = [super initWithX:posX y:posY]) { + _estimatedModuleSize = estimatedModuleSize; + } + + return self; +} + +- (BOOL)aboutEquals:(float)moduleSize i:(float)i j:(float)j { + if (fabsf(i - self.y) <= moduleSize && fabsf(j - self.x) <= moduleSize) { + float moduleSizeDiff = fabsf(moduleSize - self.estimatedModuleSize); + return moduleSizeDiff <= 1.0f || moduleSizeDiff <= self.estimatedModuleSize; + } + + return NO; +} + +- (ZXQRCodeAlignmentPattern *)combineEstimateI:(float)i j:(float)j newModuleSize:(float)newModuleSize { + float combinedX = (self.x + j) / 2.0f; + float combinedY = (self.y + i) / 2.0f; + float combinedModuleSize = (self.estimatedModuleSize + newModuleSize) / 2.0f; + return [[ZXQRCodeAlignmentPattern alloc] initWithPosX:combinedX posY:combinedY estimatedModuleSize:combinedModuleSize]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeAlignmentPatternFinder.h b/iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeAlignmentPatternFinder.h new file mode 100755 index 0000000..6c0af36 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeAlignmentPatternFinder.h @@ -0,0 +1,55 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@protocol ZXResultPointCallback; +@class ZXBitMatrix, ZXQRCodeAlignmentPattern; + +/** + * This class attempts to find alignment patterns in a QR Code. Alignment patterns look like finder + * patterns but are smaller and appear at regular intervals throughout the image. + * + * At the moment this only looks for the bottom-right alignment pattern. + * + * This is mostly a simplified copy of {@link FinderPatternFinder}. It is copied, + * pasted and stripped down here for maximum performance but does unfortunately duplicate + * some code. + * + * This class is thread-safe but not reentrant. Each thread must allocate its own object. + */ +@interface ZXQRCodeAlignmentPatternFinder : NSObject + +/** + * Creates a finder that will look in a portion of the whole image. + * + * @param image image to search + * @param startX left column from which to start searching + * @param startY top row from which to start searching + * @param width width of region to search + * @param height height of region to search + * @param moduleSize estimated module size so far + */ + +- (id)initWithImage:(ZXBitMatrix *)image startX:(int)startX startY:(int)startY width:(int)width height:(int)height moduleSize:(float)moduleSize resultPointCallback:(id)resultPointCallback; + +/** + * This method attempts to find the bottom-right alignment pattern in the image. It is a bit messy since + * it's pretty performance-critical and so is written to be fast foremost. + * + * @return ZXAlignmentPattern if found or nil if not found + */ +- (ZXQRCodeAlignmentPattern *)findWithError:(NSError **)error; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeAlignmentPatternFinder.m b/iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeAlignmentPatternFinder.m new file mode 100755 index 0000000..e9cde0c --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeAlignmentPatternFinder.m @@ -0,0 +1,239 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitMatrix.h" +#import "ZXErrors.h" +#import "ZXIntArray.h" +#import "ZXQRCodeAlignmentPattern.h" +#import "ZXQRCodeAlignmentPatternFinder.h" +#import "ZXResultPointCallback.h" + +@interface ZXQRCodeAlignmentPatternFinder () + +@property (nonatomic, strong, readonly) ZXBitMatrix *image; +@property (nonatomic, strong, readonly) NSMutableArray *possibleCenters; +@property (nonatomic, assign, readonly) int startX; +@property (nonatomic, assign, readonly) int startY; +@property (nonatomic, assign, readonly) int width; +@property (nonatomic, assign, readonly) int height; +@property (nonatomic, assign, readonly) float moduleSize; +@property (nonatomic, strong, readonly) ZXIntArray *crossCheckStateCount; +@property (nonatomic, weak, readonly) id resultPointCallback; + +@end + +@implementation ZXQRCodeAlignmentPatternFinder + +- (id)initWithImage:(ZXBitMatrix *)image startX:(int)startX startY:(int)startY width:(int)width height:(int)height moduleSize:(float)moduleSize resultPointCallback:(id)resultPointCallback { + if (self = [super init]) { + _image = image; + _possibleCenters = [NSMutableArray arrayWithCapacity:5]; + _startX = startX; + _startY = startY; + _width = width; + _height = height; + _moduleSize = moduleSize; + _crossCheckStateCount = [[ZXIntArray alloc] initWithLength:3]; + _resultPointCallback = resultPointCallback; + } + + return self; +} + +- (ZXQRCodeAlignmentPattern *)findWithError:(NSError **)error { + int maxJ = self.startX + self.width; + int middleI = self.startY + (self.height / 2); + int stateCount[3]; + + for (int iGen = 0; iGen < self.height; iGen++) { + int i = middleI + ((iGen & 0x01) == 0 ? (iGen + 1) / 2 : -((iGen + 1) / 2)); + stateCount[0] = 0; + stateCount[1] = 0; + stateCount[2] = 0; + int j = self.startX; + + while (j < maxJ && ![self.image getX:j y:i]) { + j++; + } + + int currentState = 0; + + while (j < maxJ) { + if ([self.image getX:j y:i]) { + if (currentState == 1) { + stateCount[currentState]++; + } else { + if (currentState == 2) { + if ([self foundPatternCross:stateCount]) { + ZXQRCodeAlignmentPattern *confirmed = [self handlePossibleCenter:stateCount i:i j:j]; + if (confirmed != nil) { + return confirmed; + } + } + stateCount[0] = stateCount[2]; + stateCount[1] = 1; + stateCount[2] = 0; + currentState = 1; + } else { + stateCount[++currentState]++; + } + } + } else { + if (currentState == 1) { + currentState++; + } + stateCount[currentState]++; + } + j++; + } + + if ([self foundPatternCross:stateCount]) { + ZXQRCodeAlignmentPattern *confirmed = [self handlePossibleCenter:stateCount i:i j:maxJ]; + if (confirmed != nil) { + return confirmed; + } + } + } + + if ([self.possibleCenters count] > 0) { + return self.possibleCenters[0]; + } + if (error) *error = ZXNotFoundErrorInstance(); + return nil; +} + +/** + * Given a count of black/white/black pixels just seen and an end position, + * figures the location of the center of this black/white/black run. + */ +- (float)centerFromEnd:(int *)stateCount end:(int)end { + return (float)(end - stateCount[2]) - stateCount[1] / 2.0f; +} + +/** + * @param stateCount count of black/white/black pixels just read + * @return true iff the proportions of the counts is close enough to the 1/1/1 ratios + * used by alignment patterns to be considered a match + */ +- (BOOL)foundPatternCross:(int *)stateCount { + float maxVariance = self.moduleSize / 2.0f; + + for (int i = 0; i < 3; i++) { + if (fabsf(self.moduleSize - stateCount[i]) >= maxVariance) { + return NO; + } + } + + return YES; +} + +/** + * After a horizontal scan finds a potential alignment pattern, this method + * "cross-checks" by scanning down vertically through the center of the possible + * alignment pattern to see if the same proportion is detected. + * + * @param startI row where an alignment pattern was detected + * @param centerJ center of the section that appears to cross an alignment pattern + * @param maxCount maximum reasonable number of modules that should be + * observed in any reading state, based on the results of the horizontal scan + * @return vertical center of alignment pattern, or {@link Float#NaN} if not found + */ +- (float)crossCheckVertical:(int)startI centerJ:(int)centerJ maxCount:(int)maxCount originalStateCountTotal:(int)originalStateCountTotal { + int maxI = self.image.height; + [self.crossCheckStateCount clear]; + int32_t *stateCount = self.crossCheckStateCount.array; + + int i = startI; + while (i >= 0 && [self.image getX:centerJ y:i] && stateCount[1] <= maxCount) { + stateCount[1]++; + i--; + } + + if (i < 0 || stateCount[1] > maxCount) { + return NAN; + } + + while (i >= 0 && ![self.image getX:centerJ y:i] && stateCount[0] <= maxCount) { + stateCount[0]++; + i--; + } + + if (stateCount[0] > maxCount) { + return NAN; + } + i = startI + 1; + + while (i < maxI && [self.image getX:centerJ y:i] && stateCount[1] <= maxCount) { + stateCount[1]++; + i++; + } + + if (i == maxI || stateCount[1] > maxCount) { + return NAN; + } + + while (i < maxI && ![self.image getX:centerJ y:i] && stateCount[2] <= maxCount) { + stateCount[2]++; + i++; + } + + if (stateCount[2] > maxCount) { + return NAN; + } + int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2]; + if (5 * abs(stateCountTotal - originalStateCountTotal) >= 2 * originalStateCountTotal) { + return NAN; + } + return [self foundPatternCross:stateCount] ? [self centerFromEnd:stateCount end:i] : NAN; +} + +/** + * This is called when a horizontal scan finds a possible alignment pattern. It will + * cross check with a vertical scan, and if successful, will see if this pattern had been + * found on a previous horizontal scan. If so, we consider it confirmed and conclude we have + * found the alignment pattern. + * + * @param stateCount reading state module counts from horizontal scan + * @param i row where alignment pattern may be found + * @param j end of possible alignment pattern in row + * @return ZXAlignmentPattern if we have found the same pattern twice, or null if not + */ +- (ZXQRCodeAlignmentPattern *)handlePossibleCenter:(int *)stateCount i:(int)i j:(int)j { + int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2]; + float centerJ = [self centerFromEnd:stateCount end:j]; + float centerI = [self crossCheckVertical:i centerJ:(int)centerJ maxCount:2 * stateCount[1] originalStateCountTotal:stateCountTotal]; + if (!isnan(centerI)) { + float estimatedModuleSize = (float)(stateCount[0] + stateCount[1] + stateCount[2]) / 3.0f; + int max = (int)self.possibleCenters.count; + + for (int index = 0; index < max; index++) { + ZXQRCodeAlignmentPattern *center = self.possibleCenters[index]; + // Look for about the same center and module size: + if ([center aboutEquals:estimatedModuleSize i:centerI j:centerJ]) { + return [center combineEstimateI:centerI j:centerJ newModuleSize:estimatedModuleSize]; + } + } + // Hadn't found this before; save it + ZXResultPoint *point = [[ZXQRCodeAlignmentPattern alloc] initWithPosX:centerJ posY:centerI estimatedModuleSize:estimatedModuleSize]; + [self.possibleCenters addObject:point]; + if (self.resultPointCallback != nil) { + [self.resultPointCallback foundPossibleResultPoint:point]; + } + } + return nil; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeDetector.h b/iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeDetector.h new file mode 100755 index 0000000..dcad42d --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeDetector.h @@ -0,0 +1,69 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXBitMatrix, ZXDecodeHints, ZXDetectorResult, ZXPerspectiveTransform, ZXQRCodeAlignmentPattern, ZXQRCodeFinderPatternInfo, ZXResultPoint; +@protocol ZXResultPointCallback; + +/** + * Encapsulates logic that can detect a QR Code in an image, even if the QR Code + * is rotated or skewed, or partially obscured. + */ +@interface ZXQRCodeDetector : NSObject + +@property (nonatomic, strong, readonly) ZXBitMatrix *image; +@property (nonatomic, weak, readonly) id resultPointCallback; + +- (id)initWithImage:(ZXBitMatrix *)image; + +/** + * Detects a QR Code in an image, simply. + * + * @return ZXDetectorResult encapsulating results of detecting a QR Code or nil + * if no QR Code can be found + */ +- (ZXDetectorResult *)detectWithError:(NSError **)error; + +/** + * Detects a QR Code in an image, simply. + * + * @param hints optional hints to detector + * @return ZXDetectorResult encapsulating results of detecting a QR Code + * @return nil if QR Code cannot be found + * @return nil if a QR Code cannot be decoded + */ +- (ZXDetectorResult *)detect:(ZXDecodeHints *)hints error:(NSError **)error; + +- (ZXDetectorResult *)processFinderPatternInfo:(ZXQRCodeFinderPatternInfo *)info error:(NSError **)error; + +/** + * Computes an average estimated module size based on estimated derived from the positions + * of the three finder patterns. + */ +- (float)calculateModuleSize:(ZXResultPoint *)topLeft topRight:(ZXResultPoint *)topRight bottomLeft:(ZXResultPoint *)bottomLeft; + +/** + * Attempts to locate an alignment pattern in a limited region of the image, which is + * guessed to contain it. This method uses ZXAlignmentPattern. + * + * @param overallEstModuleSize estimated module size so far + * @param estAlignmentX x coordinate of center of area probably containing alignment pattern + * @param estAlignmentY y coordinate of above + * @param allowanceFactor number of pixels in all directions to search from the center + * @return ZXAlignmentPattern if found, or nil if an unexpected error occurs during detection + */ +- (ZXQRCodeAlignmentPattern *)findAlignmentInRegion:(float)overallEstModuleSize estAlignmentX:(int)estAlignmentX estAlignmentY:(int)estAlignmentY allowanceFactor:(float)allowanceFactor error:(NSError **)error; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeDetector.m b/iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeDetector.m new file mode 100755 index 0000000..e6bc99f --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeDetector.m @@ -0,0 +1,331 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitMatrix.h" +#import "ZXDecodeHints.h" +#import "ZXDetectorResult.h" +#import "ZXErrors.h" +#import "ZXGridSampler.h" +#import "ZXIntArray.h" +#import "ZXMathUtils.h" +#import "ZXPerspectiveTransform.h" +#import "ZXQRCodeAlignmentPattern.h" +#import "ZXQRCodeAlignmentPatternFinder.h" +#import "ZXQRCodeDetector.h" +#import "ZXQRCodeFinderPattern.h" +#import "ZXQRCodeFinderPatternFinder.h" +#import "ZXQRCodeFinderPatternInfo.h" +#import "ZXQRCodeVersion.h" +#import "ZXResultPoint.h" +#import "ZXResultPointCallback.h" + +@interface ZXQRCodeDetector () + +@property (nonatomic, weak) id resultPointCallback; + +@end + +@implementation ZXQRCodeDetector + +- (id)initWithImage:(ZXBitMatrix *)image { + if (self = [super init]) { + _image = image; + } + + return self; +} + +- (ZXDetectorResult *)detectWithError:(NSError **)error { + return [self detect:nil error:error]; +} + +- (ZXDetectorResult *)detect:(ZXDecodeHints *)hints error:(NSError **)error { + self.resultPointCallback = hints == nil ? nil : hints.resultPointCallback; + + ZXQRCodeFinderPatternFinder *finder = [[ZXQRCodeFinderPatternFinder alloc] initWithImage:self.image resultPointCallback:self.resultPointCallback]; + ZXQRCodeFinderPatternInfo *info = [finder find:hints error:error]; + if (!info) { + return nil; + } + + return [self processFinderPatternInfo:info error:error]; +} + +- (ZXDetectorResult *)processFinderPatternInfo:(ZXQRCodeFinderPatternInfo *)info error:(NSError **)error { + ZXQRCodeFinderPattern *topLeft = info.topLeft; + ZXQRCodeFinderPattern *topRight = info.topRight; + ZXQRCodeFinderPattern *bottomLeft = info.bottomLeft; + + float moduleSize = [self calculateModuleSize:topLeft topRight:topRight bottomLeft:bottomLeft]; + if (moduleSize < 1.0f) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + int dimension = [ZXQRCodeDetector computeDimension:topLeft topRight:topRight bottomLeft:bottomLeft moduleSize:moduleSize error:error]; + if (dimension == -1) { + return nil; + } + + ZXQRCodeVersion *provisionalVersion = [ZXQRCodeVersion provisionalVersionForDimension:dimension]; + if (!provisionalVersion) { + if (error) *error = ZXFormatErrorInstance(); + return nil; + } + int modulesBetweenFPCenters = [provisionalVersion dimensionForVersion] - 7; + + ZXQRCodeAlignmentPattern *alignmentPattern = nil; + if (provisionalVersion.alignmentPatternCenters.length > 0) { + float bottomRightX = [topRight x] - [topLeft x] + [bottomLeft x]; + float bottomRightY = [topRight y] - [topLeft y] + [bottomLeft y]; + + float correctionToTopLeft = 1.0f - 3.0f / (float)modulesBetweenFPCenters; + int estAlignmentX = (int)([topLeft x] + correctionToTopLeft * (bottomRightX - [topLeft x])); + int estAlignmentY = (int)([topLeft y] + correctionToTopLeft * (bottomRightY - [topLeft y])); + + for (int i = 4; i <= 16; i <<= 1) { + NSError *alignmentError = nil; + alignmentPattern = [self findAlignmentInRegion:moduleSize estAlignmentX:estAlignmentX estAlignmentY:estAlignmentY allowanceFactor:(float)i error:&alignmentError]; + if (alignmentPattern) { + break; + } else if (alignmentError.code != ZXNotFoundError) { + if (error) *error = alignmentError; + return nil; + } + } + } + + ZXPerspectiveTransform *transform = [ZXQRCodeDetector createTransform:topLeft topRight:topRight bottomLeft:bottomLeft alignmentPattern:alignmentPattern dimension:dimension]; + ZXBitMatrix *bits = [self sampleGrid:self.image transform:transform dimension:dimension error:error]; + if (!bits) { + return nil; + } + NSArray *points; + if (alignmentPattern == nil) { + points = @[bottomLeft, topLeft, topRight]; + } else { + points = @[bottomLeft, topLeft, topRight, alignmentPattern]; + } + return [[ZXDetectorResult alloc] initWithBits:bits points:points]; +} + ++ (ZXPerspectiveTransform *)createTransform:(ZXResultPoint *)topLeft topRight:(ZXResultPoint *)topRight bottomLeft:(ZXResultPoint *)bottomLeft alignmentPattern:(ZXResultPoint *)alignmentPattern dimension:(int)dimension { + float dimMinusThree = (float)dimension - 3.5f; + float bottomRightX; + float bottomRightY; + float sourceBottomRightX; + float sourceBottomRightY; + if (alignmentPattern != nil) { + bottomRightX = alignmentPattern.x; + bottomRightY = alignmentPattern.y; + sourceBottomRightX = dimMinusThree - 3.0f; + sourceBottomRightY = sourceBottomRightX; + } else { + bottomRightX = (topRight.x - topLeft.x) + bottomLeft.x; + bottomRightY = (topRight.y - topLeft.y) + bottomLeft.y; + sourceBottomRightX = dimMinusThree; + sourceBottomRightY = dimMinusThree; + } + + return [ZXPerspectiveTransform quadrilateralToQuadrilateral:3.5f y0:3.5f + x1:dimMinusThree y1:3.5f + x2:sourceBottomRightX y2:sourceBottomRightY + x3:3.5f y3:dimMinusThree + x0p:topLeft.x y0p:topLeft.y + x1p:topRight.x y1p:topRight.y + x2p:bottomRightX y2p:bottomRightY + x3p:bottomLeft.x y3p:bottomLeft.y]; +} + +- (ZXBitMatrix *)sampleGrid:(ZXBitMatrix *)anImage transform:(ZXPerspectiveTransform *)transform dimension:(int)dimension error:(NSError **)error { + ZXGridSampler *sampler = [ZXGridSampler instance]; + return [sampler sampleGrid:anImage dimensionX:dimension dimensionY:dimension transform:transform error:error]; +} + +/** + * Computes the dimension (number of modules on a size) of the QR Code based on the position + * of the finder patterns and estimated module size. Returns -1 on an error. + */ ++ (int)computeDimension:(ZXResultPoint *)topLeft topRight:(ZXResultPoint *)topRight bottomLeft:(ZXResultPoint *)bottomLeft moduleSize:(float)moduleSize error:(NSError **)error { + int tltrCentersDimension = [ZXMathUtils round:[ZXResultPoint distance:topLeft pattern2:topRight] / moduleSize]; + int tlblCentersDimension = [ZXMathUtils round:[ZXResultPoint distance:topLeft pattern2:bottomLeft] / moduleSize]; + int dimension = ((tltrCentersDimension + tlblCentersDimension) / 2) + 7; + + switch (dimension & 0x03) { + case 0: + dimension++; + break; + case 2: + dimension--; + break; + case 3: + if (error) *error = ZXNotFoundErrorInstance(); + return -1; + } + return dimension; +} + +/** + * Computes an average estimated module size based on estimated derived from the positions + * of the three finder patterns. + */ +- (float)calculateModuleSize:(ZXResultPoint *)topLeft topRight:(ZXResultPoint *)topRight bottomLeft:(ZXResultPoint *)bottomLeft { + return ([self calculateModuleSizeOneWay:topLeft otherPattern:topRight] + [self calculateModuleSizeOneWay:topLeft otherPattern:bottomLeft]) / 2.0f; +} + +/** + * Estimates module size based on two finder patterns -- it uses + * sizeOfBlackWhiteBlackRunBothWays:fromY:toX:toY: to figure the + * width of each, measuring along the axis between their centers. + */ +- (float)calculateModuleSizeOneWay:(ZXResultPoint *)pattern otherPattern:(ZXResultPoint *)otherPattern { + float moduleSizeEst1 = [self sizeOfBlackWhiteBlackRunBothWays:(int)[pattern x] fromY:(int)[pattern y] toX:(int)[otherPattern x] toY:(int)[otherPattern y]]; + float moduleSizeEst2 = [self sizeOfBlackWhiteBlackRunBothWays:(int)[otherPattern x] fromY:(int)[otherPattern y] toX:(int)[pattern x] toY:(int)[pattern y]]; + if (isnan(moduleSizeEst1)) { + return moduleSizeEst2 / 7.0f; + } + if (isnan(moduleSizeEst2)) { + return moduleSizeEst1 / 7.0f; + } + return (moduleSizeEst1 + moduleSizeEst2) / 14.0f; +} + +/** + * See sizeOfBlackWhiteBlackRun:fromY:toX:toY: computes the total width of + * a finder pattern by looking for a black-white-black run from the center in the direction + * of another point (another finder pattern center), and in the opposite direction too.

+ */ +- (float)sizeOfBlackWhiteBlackRunBothWays:(int)fromX fromY:(int)fromY toX:(int)toX toY:(int)toY { + float result = [self sizeOfBlackWhiteBlackRun:fromX fromY:fromY toX:toX toY:toY]; + + // Now count other way -- don't run off image though of course + float scale = 1.0f; + int otherToX = fromX - (toX - fromX); + if (otherToX < 0) { + scale = (float)fromX / (float)(fromX - otherToX); + otherToX = 0; + } else if (otherToX >= self.image.width) { + scale = (float)(self.image.width - 1 - fromX) / (float)(otherToX - fromX); + otherToX = self.image.width - 1; + } + int otherToY = (int)(fromY - (toY - fromY) * scale); + + scale = 1.0f; + if (otherToY < 0) { + scale = (float)fromY / (float)(fromY - otherToY); + otherToY = 0; + } else if (otherToY >= self.image.height) { + scale = (float)(self.image.height - 1 - fromY) / (float)(otherToY - fromY); + otherToY = self.image.height - 1; + } + otherToX = (int)(fromX + (otherToX - fromX) * scale); + + result += [self sizeOfBlackWhiteBlackRun:fromX fromY:fromY toX:otherToX toY:otherToY]; + + // Middle pixel is double-counted this way; subtract 1 + return result - 1.0f; +} + +/** + * This method traces a line from a point in the image, in the direction towards another point. + * It begins in a black region, and keeps going until it finds white, then black, then white again. + * It reports the distance from the start to this point. + * + * This is used when figuring out how wide a finder pattern is, when the finder pattern + * may be skewed or rotated. + */ +- (float)sizeOfBlackWhiteBlackRun:(int)fromX fromY:(int)fromY toX:(int)toX toY:(int)toY { + // Mild variant of Bresenham's algorithm; + // see http://en.wikipedia.org/wiki/Bresenham's_line_algorithm + BOOL steep = abs(toY - fromY) > abs(toX - fromX); + if (steep) { + int temp = fromX; + fromX = fromY; + fromY = temp; + temp = toX; + toX = toY; + toY = temp; + } + + int dx = abs(toX - fromX); + int dy = abs(toY - fromY); + int error = -dx / 2; + int xstep = fromX < toX ? 1 : -1; + int ystep = fromY < toY ? 1 : -1; + + // In black pixels, looking for white, first or second time. + int state = 0; + // Loop up until x == toX, but not beyond + int xLimit = toX + xstep; + for (int x = fromX, y = fromY; x != xLimit; x += xstep) { + int realX = steep ? y : x; + int realY = steep ? x : y; + + // Does current pixel mean we have moved white to black or vice versa? + // Scanning black in state 0,2 and white in state 1, so if we find the wrong + // color, advance to next state or end if we are in state 2 already + if ((state == 1) == [self.image getX:realX y:realY]) { + if (state == 2) { + return [ZXMathUtils distanceInt:x aY:y bX:fromX bY:fromY]; + } + state++; + } + + error += dy; + if (error > 0) { + if (y == toY) { + break; + } + y += ystep; + error -= dx; + } + } + // Found black-white-black; give the benefit of the doubt that the next pixel outside the image + // is "white" so this last point at (toX+xStep,toY) is the right ending. This is really a + // small approximation; (toX+xStep,toY+yStep) might be really correct. Ignore this. + if (state == 2) { + return [ZXMathUtils distanceInt:toX + xstep aY:toY bX:fromX bY:fromY]; + } + // else we didn't find even black-white-black; no estimate is really possible + return NAN; +} + +- (ZXQRCodeAlignmentPattern *)findAlignmentInRegion:(float)overallEstModuleSize estAlignmentX:(int)estAlignmentX estAlignmentY:(int)estAlignmentY allowanceFactor:(float)allowanceFactor error:(NSError **)error { + int allowance = (int)(allowanceFactor * overallEstModuleSize); + int alignmentAreaLeftX = MAX(0, estAlignmentX - allowance); + int alignmentAreaRightX = MIN(self.image.width - 1, estAlignmentX + allowance); + if (alignmentAreaRightX - alignmentAreaLeftX < overallEstModuleSize * 3) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + + int alignmentAreaTopY = MAX(0, estAlignmentY - allowance); + int alignmentAreaBottomY = MIN(self.image.height - 1, estAlignmentY + allowance); + if (alignmentAreaBottomY - alignmentAreaTopY < overallEstModuleSize * 3) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + + ZXQRCodeAlignmentPatternFinder *alignmentFinder = [[ZXQRCodeAlignmentPatternFinder alloc] initWithImage:self.image + startX:alignmentAreaLeftX + startY:alignmentAreaTopY + width:alignmentAreaRightX - alignmentAreaLeftX + height:alignmentAreaBottomY - alignmentAreaTopY + moduleSize:overallEstModuleSize + resultPointCallback:self.resultPointCallback]; + return [alignmentFinder findWithError:error]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeFinderPattern.h b/iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeFinderPattern.h new file mode 100755 index 0000000..32ea5de --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeFinderPattern.h @@ -0,0 +1,48 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXResultPoint.h" + +/** + * Encapsulates a finder pattern, which are the three square patterns found in + * the corners of QR Codes. It also encapsulates a count of similar finder patterns, + * as a convenience to the finder's bookkeeping. + */ +@interface ZXQRCodeFinderPattern : ZXResultPoint + +@property (nonatomic, assign, readonly) int count; +@property (nonatomic, assign, readonly) float estimatedModuleSize; + +- (id)initWithPosX:(float)posX posY:(float)posY estimatedModuleSize:(float)estimatedModuleSize; + +- (id)initWithPosX:(float)posX posY:(float)posY estimatedModuleSize:(float)estimatedModuleSize count:(int)count; + +//- (void)incrementCount; + +/** + * Determines if this finder pattern "about equals" a finder pattern at the stated + * position and size -- meaning, it is at nearly the same center with nearly the same size. + */ +- (BOOL)aboutEquals:(float)moduleSize i:(float)i j:(float)j; + +/** + * Combines this object's current estimate of a finder pattern position and module size + * with a new estimate. It returns a new ZXFinderPattern containing a weighted average + * based on count. + */ +- (ZXQRCodeFinderPattern *)combineEstimateI:(float)i j:(float)j newModuleSize:(float)newModuleSize; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeFinderPattern.m b/iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeFinderPattern.m new file mode 100755 index 0000000..7a112ce --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeFinderPattern.m @@ -0,0 +1,59 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXQRCodeFinderPattern.h" + +@implementation ZXQRCodeFinderPattern + +- (id)initWithPosX:(float)posX posY:(float)posY estimatedModuleSize:(float)estimatedModuleSize { + return [self initWithPosX:posX posY:posY estimatedModuleSize:estimatedModuleSize count:1]; +} + +- (id)initWithPosX:(float)posX posY:(float)posY estimatedModuleSize:(float)estimatedModuleSize count:(int)count { + if (self = [super initWithX:posX y:posY]) { + _estimatedModuleSize = estimatedModuleSize; + _count = count; + } + + return self; +} + +/* +- (void)incrementCount { + self.count++; +} +*/ + +- (BOOL)aboutEquals:(float)moduleSize i:(float)i j:(float)j { + if (fabsf(i - [self y]) <= moduleSize && fabsf(j - [self x]) <= moduleSize) { + float moduleSizeDiff = fabsf(moduleSize - self.estimatedModuleSize); + return moduleSizeDiff <= 1.0f || moduleSizeDiff <= self.estimatedModuleSize; + } + return NO; +} + +- (ZXQRCodeFinderPattern *)combineEstimateI:(float)i j:(float)j newModuleSize:(float)newModuleSize { + int combinedCount = self.count + 1; + float combinedX = (self.count * self.x + j) / combinedCount; + float combinedY = (self.count * self.y + i) / combinedCount; + float combinedModuleSize = (self.count * self.estimatedModuleSize + newModuleSize) / combinedCount; + return [[ZXQRCodeFinderPattern alloc] initWithPosX:combinedX + posY:combinedY + estimatedModuleSize:combinedModuleSize + count:combinedCount]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeFinderPatternFinder.h b/iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeFinderPatternFinder.h new file mode 100755 index 0000000..ada43ad --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeFinderPatternFinder.h @@ -0,0 +1,71 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +extern const int ZX_FINDER_PATTERN_MIN_SKIP; +extern const int ZX_FINDER_PATTERN_MAX_MODULES; + +@protocol ZXResultPointCallback; +@class ZXBitMatrix, ZXDecodeHints, ZXQRCodeFinderPatternInfo; + +/** + * This class attempts to find finder patterns in a QR Code. Finder patterns are the square + * markers at three corners of a QR Code. + * + * This class is thread-safe but not reentrant. Each thread must allocate its own object. + */ +@interface ZXQRCodeFinderPatternFinder : NSObject + +@property (nonatomic, strong, readonly) ZXBitMatrix *image; +@property (nonatomic, strong, readonly) NSMutableArray *possibleCenters; + +/** + * Creates a finder that will search the image for three finder patterns. + * + * @param image image to search + */ +- (id)initWithImage:(ZXBitMatrix *)image; + +- (id)initWithImage:(ZXBitMatrix *)image resultPointCallback:(id)resultPointCallback; + +- (ZXQRCodeFinderPatternInfo *)find:(ZXDecodeHints *)hints error:(NSError **)error; + +/** + * @param stateCount count of black/white/black/white/black pixels just read + * @return true iff the proportions of the counts is close enough to the 1/1/3/1/1 ratios + * used by finder patterns to be considered a match + */ ++ (BOOL)foundPatternCross:(const int[])stateCount; + +/** + * This is called when a horizontal scan finds a possible alignment pattern. It will + * cross check with a vertical scan, and if successful, will, ah, cross-cross-check + * with another horizontal scan. This is needed primarily to locate the real horizontal + * center of the pattern in cases of extreme skew. + * And then we cross-cross-cross check with another diagonal scan. + * + * If that succeeds the finder pattern location is added to a list that tracks + * the number of times each location has been nearly-matched as a finder pattern. + * Each additional find is more evidence that the location is in fact a finder + * pattern center + * + * @param stateCount reading state module counts from horizontal scan + * @param i row where finder pattern may be found + * @param j end of possible finder pattern in row + * @return true if a finder pattern candidate was found this time + */ +- (BOOL)handlePossibleCenter:(const int[])stateCount i:(int)i j:(int)j pureBarcode:(BOOL)pureBarcode; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeFinderPatternFinder.m b/iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeFinderPatternFinder.m new file mode 100755 index 0000000..3a3b7b2 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeFinderPatternFinder.m @@ -0,0 +1,570 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitMatrix.h" +#import "ZXDecodeHints.h" +#import "ZXErrors.h" +#import "ZXQRCodeFinderPattern.h" +#import "ZXQRCodeFinderPatternInfo.h" +#import "ZXQRCodeFinderPatternFinder.h" +#import "ZXResultPoint.h" +#import "ZXResultPointCallback.h" + +const int ZX_CENTER_QUORUM = 2; +const int ZX_FINDER_PATTERN_MIN_SKIP = 3; +const int ZX_FINDER_PATTERN_MAX_MODULES = 57; + +@interface ZXQRCodeFinderPatternFinder () + +NSInteger centerCompare(id center1, id center2, void *context); +NSInteger furthestFromAverageCompare(id center1, id center2, void *context); + +@property (nonatomic, assign) BOOL hasSkipped; +@property (nonatomic, weak, readonly) id resultPointCallback; +@property (nonatomic, strong) NSMutableArray *possibleCenters; + +@end + +@implementation ZXQRCodeFinderPatternFinder + +- (id)initWithImage:(ZXBitMatrix *)image { + return [self initWithImage:image resultPointCallback:nil]; +} + +- (id)initWithImage:(ZXBitMatrix *)image resultPointCallback:(id)resultPointCallback { + if (self = [super init]) { + _image = image; + _possibleCenters = [NSMutableArray array]; + _resultPointCallback = resultPointCallback; + } + + return self; +} + +- (ZXQRCodeFinderPatternInfo *)find:(ZXDecodeHints *)hints error:(NSError **)error { + BOOL tryHarder = hints != nil && hints.tryHarder; + BOOL pureBarcode = hints != nil && hints.pureBarcode; + int maxI = self.image.height; + int maxJ = self.image.width; + int iSkip = (3 * maxI) / (4 * ZX_FINDER_PATTERN_MAX_MODULES); + if (iSkip < ZX_FINDER_PATTERN_MIN_SKIP || tryHarder) { + iSkip = ZX_FINDER_PATTERN_MIN_SKIP; + } + + BOOL done = NO; + int stateCount[5]; + for (int i = iSkip - 1; i < maxI && !done; i += iSkip) { + stateCount[0] = 0; + stateCount[1] = 0; + stateCount[2] = 0; + stateCount[3] = 0; + stateCount[4] = 0; + int currentState = 0; + + for (int j = 0; j < maxJ; j++) { + if ([self.image getX:j y:i]) { + if ((currentState & 1) == 1) { + currentState++; + } + stateCount[currentState]++; + } else { + if ((currentState & 1) == 0) { + if (currentState == 4) { + if ([ZXQRCodeFinderPatternFinder foundPatternCross:stateCount]) { + BOOL confirmed = [self handlePossibleCenter:stateCount i:i j:j pureBarcode:pureBarcode]; + if (confirmed) { + iSkip = 2; + if (self.hasSkipped) { + done = [self haveMultiplyConfirmedCenters]; + } else { + int rowSkip = [self findRowSkip]; + if (rowSkip > stateCount[2]) { + i += rowSkip - stateCount[2] - iSkip; + j = maxJ - 1; + } + } + } else { + stateCount[0] = stateCount[2]; + stateCount[1] = stateCount[3]; + stateCount[2] = stateCount[4]; + stateCount[3] = 1; + stateCount[4] = 0; + currentState = 3; + continue; + } + currentState = 0; + stateCount[0] = 0; + stateCount[1] = 0; + stateCount[2] = 0; + stateCount[3] = 0; + stateCount[4] = 0; + } else { + stateCount[0] = stateCount[2]; + stateCount[1] = stateCount[3]; + stateCount[2] = stateCount[4]; + stateCount[3] = 1; + stateCount[4] = 0; + currentState = 3; + } + } else { + stateCount[++currentState]++; + } + } else { + stateCount[currentState]++; + } + } + } + + if ([ZXQRCodeFinderPatternFinder foundPatternCross:stateCount]) { + BOOL confirmed = [self handlePossibleCenter:stateCount i:i j:maxJ pureBarcode:pureBarcode]; + if (confirmed) { + iSkip = stateCount[0]; + if (self.hasSkipped) { + done = [self haveMultiplyConfirmedCenters]; + } + } + } + } + + NSMutableArray *patternInfo = [self selectBestPatterns]; + if (!patternInfo) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + [ZXResultPoint orderBestPatterns:patternInfo]; + return [[ZXQRCodeFinderPatternInfo alloc] initWithPatternCenters:patternInfo]; +} + +/** + * Given a count of black/white/black/white/black pixels just seen and an end position, + * figures the location of the center of this run. + */ +- (float)centerFromEnd:(const int[])stateCount end:(int)end { + return (float)(end - stateCount[4] - stateCount[3]) - stateCount[2] / 2.0f; +} + ++ (BOOL)foundPatternCross:(const int[])stateCount { + int totalModuleSize = 0; + for (int i = 0; i < 5; i++) { + int count = stateCount[i]; + if (count == 0) { + return NO; + } + totalModuleSize += count; + } + if (totalModuleSize < 7) { + return NO; + } + float moduleSize = totalModuleSize / 7.0f; + float maxVariance = moduleSize / 2.0f; + // Allow less than 50% variance from 1-1-3-1-1 proportions + return + ABS(moduleSize - stateCount[0]) < maxVariance && + ABS(moduleSize - stateCount[1]) < maxVariance && + ABS(3.0f * moduleSize - stateCount[2]) < 3 * maxVariance && + ABS(moduleSize - stateCount[3]) < maxVariance && + ABS(moduleSize - stateCount[4]) < maxVariance; +} + +/** + * After a vertical and horizontal scan finds a potential finder pattern, this method + * "cross-cross-cross-checks" by scanning down diagonally through the center of the possible + * finder pattern to see if the same proportion is detected. + * + * @param startI row where a finder pattern was detected + * @param centerJ center of the section that appears to cross a finder pattern + * @param maxCount maximum reasonable number of modules that should be + * observed in any reading state, based on the results of the horizontal scan + * @param originalStateCountTotal The original state count total. + * @return true if proportions are withing expected limits + */ +- (BOOL)crossCheckDiagonal:(int)startI centerJ:(int)centerJ maxCount:(int)maxCount originalStateCountTotal:(int)originalStateCountTotal { + int stateCount[5] = {0, 0, 0, 0, 0}; + + // Start counting up, left from center finding black center mass + int i = 0; + while (startI >= i && centerJ >= i && [self.image getX:centerJ - i y:startI - i]) { + stateCount[2]++; + i++; + } + + if (startI < i || centerJ < i) { + return NO; + } + + // Continue up, left finding white space + while (startI >= i && centerJ >= i && ![self.image getX:centerJ - i y:startI - i] && + stateCount[1] <= maxCount) { + stateCount[1]++; + i++; + } + + // If already too many modules in this state or ran off the edge: + if (startI < i || centerJ < i || stateCount[1] > maxCount) { + return NO; + } + + // Continue up, left finding black border + while (startI >= i && centerJ >= i && [self.image getX:centerJ - i y:startI - i] && + stateCount[0] <= maxCount) { + stateCount[0]++; + i++; + } + if (stateCount[0] > maxCount) { + return NO; + } + + int maxI = self.image.height; + int maxJ = self.image.width; + + // Now also count down, right from center + i = 1; + while (startI + i < maxI && centerJ + i < maxJ && [self.image getX:centerJ + i y:startI + i]) { + stateCount[2]++; + i++; + } + + // Ran off the edge? + if (startI + i >= maxI || centerJ + i >= maxJ) { + return NO; + } + + while (startI + i < maxI && centerJ + i < maxJ && ![self.image getX:centerJ + i y:startI + i] && + stateCount[3] < maxCount) { + stateCount[3]++; + i++; + } + + if (startI + i >= maxI || centerJ + i >= maxJ || stateCount[3] >= maxCount) { + return NO; + } + + while (startI + i < maxI && centerJ + i < maxJ && [self.image getX:centerJ + i y:startI + i] && + stateCount[4] < maxCount) { + stateCount[4]++; + i++; + } + + if (stateCount[4] >= maxCount) { + return NO; + } + + // If we found a finder-pattern-like section, but its size is more than 100% different than + // the original, assume it's a false positive + int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4]; + return + abs(stateCountTotal - originalStateCountTotal) < 2 * originalStateCountTotal && + [ZXQRCodeFinderPatternFinder foundPatternCross:stateCount]; +} + +/** + * After a horizontal scan finds a potential finder pattern, this method + * "cross-checks" by scanning down vertically through the center of the possible + * finder pattern to see if the same proportion is detected. + * + * @param startI row where a finder pattern was detected + * @param centerJ center of the section that appears to cross a finder pattern + * @param maxCount maximum reasonable number of modules that should be + * observed in any reading state, based on the results of the horizontal scan + * @return vertical center of finder pattern, or {@link Float#NaN} if not found + */ +- (float)crossCheckVertical:(int)startI centerJ:(int)centerJ maxCount:(int)maxCount originalStateCountTotal:(int)originalStateCountTotal { + int maxI = self.image.height; + int stateCount[5] = {0, 0, 0, 0, 0}; + + int i = startI; + while (i >= 0 && [self.image getX:centerJ y:i]) { + stateCount[2]++; + i--; + } + if (i < 0) { + return NAN; + } + while (i >= 0 && ![self.image getX:centerJ y:i] && stateCount[1] <= maxCount) { + stateCount[1]++; + i--; + } + if (i < 0 || stateCount[1] > maxCount) { + return NAN; + } + while (i >= 0 && [self.image getX:centerJ y:i] && stateCount[0] <= maxCount) { + stateCount[0]++; + i--; + } + if (stateCount[0] > maxCount) { + return NAN; + } + + i = startI + 1; + while (i < maxI && [self.image getX:centerJ y:i]) { + stateCount[2]++; + i++; + } + if (i == maxI) { + return NAN; + } + while (i < maxI && ![self.image getX:centerJ y:i] && stateCount[3] < maxCount) { + stateCount[3]++; + i++; + } + if (i == maxI || stateCount[3] >= maxCount) { + return NAN; + } + while (i < maxI && [self.image getX:centerJ y:i] && stateCount[4] < maxCount) { + stateCount[4]++; + i++; + } + if (stateCount[4] >= maxCount) { + return NAN; + } + + int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4]; + if (5 * abs(stateCountTotal - originalStateCountTotal) >= 2 * originalStateCountTotal) { + return NAN; + } + return [ZXQRCodeFinderPatternFinder foundPatternCross:stateCount] ? [self centerFromEnd:stateCount end:i] : NAN; +} + +/** + * Like crossCheckVertical, and in fact is basically identical, + * except it reads horizontally instead of vertically. This is used to cross-cross + * check a vertical cross check and locate the real center of the alignment pattern. + */ +- (float)crossCheckHorizontal:(int)startJ centerI:(int)centerI maxCount:(int)maxCount originalStateCountTotal:(int)originalStateCountTotal { + int maxJ = self.image.width; + int stateCount[5] = {0, 0, 0, 0, 0}; + + int j = startJ; + while (j >= 0 && [self.image getX:j y:centerI]) { + stateCount[2]++; + j--; + } + if (j < 0) { + return NAN; + } + while (j >= 0 && ![self.image getX:j y:centerI] && stateCount[1] <= maxCount) { + stateCount[1]++; + j--; + } + if (j < 0 || stateCount[1] > maxCount) { + return NAN; + } + while (j >= 0 && [self.image getX:j y:centerI] && stateCount[0] <= maxCount) { + stateCount[0]++; + j--; + } + if (stateCount[0] > maxCount) { + return NAN; + } + + j = startJ + 1; + while (j < maxJ && [self.image getX:j y:centerI]) { + stateCount[2]++; + j++; + } + if (j == maxJ) { + return NAN; + } + while (j < maxJ && ![self.image getX:j y:centerI] && stateCount[3] < maxCount) { + stateCount[3]++; + j++; + } + if (j == maxJ || stateCount[3] >= maxCount) { + return NAN; + } + while (j < maxJ && [self.image getX:j y:centerI] && stateCount[4] < maxCount) { + stateCount[4]++; + j++; + } + if (stateCount[4] >= maxCount) { + return NAN; + } + + int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4]; + if (5 * abs(stateCountTotal - originalStateCountTotal) >= originalStateCountTotal) { + return NAN; + } + + return [ZXQRCodeFinderPatternFinder foundPatternCross:stateCount] ? [self centerFromEnd:stateCount end:j] : NAN; +} + +- (BOOL)handlePossibleCenter:(const int[])stateCount i:(int)i j:(int)j pureBarcode:(BOOL)pureBarcode { + int stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2] + stateCount[3] + stateCount[4]; + float centerJ = [self centerFromEnd:stateCount end:j]; + float centerI = [self crossCheckVertical:i centerJ:(int)centerJ maxCount:stateCount[2] originalStateCountTotal:stateCountTotal]; + if (!isnan(centerI)) { + centerJ = [self crossCheckHorizontal:(int)centerJ centerI:(int)centerI maxCount:stateCount[2] originalStateCountTotal:stateCountTotal]; + if (!isnan(centerJ) && + (!pureBarcode || [self crossCheckDiagonal:(int)centerI centerJ:(int) centerJ maxCount:stateCount[2] originalStateCountTotal:stateCountTotal])) { + float estimatedModuleSize = (float)stateCountTotal / 7.0f; + BOOL found = NO; + int max = (int)[self.possibleCenters count]; + for (int index = 0; index < max; index++) { + ZXQRCodeFinderPattern *center = self.possibleCenters[index]; + if ([center aboutEquals:estimatedModuleSize i:centerI j:centerJ]) { + self.possibleCenters[index] = [center combineEstimateI:centerI j:centerJ newModuleSize:estimatedModuleSize]; + found = YES; + break; + } + } + + if (!found) { + ZXResultPoint *point = [[ZXQRCodeFinderPattern alloc] initWithPosX:centerJ posY:centerI estimatedModuleSize:estimatedModuleSize]; + [self.possibleCenters addObject:point]; + if (self.resultPointCallback != nil) { + [self.resultPointCallback foundPossibleResultPoint:point]; + } + } + return YES; + } + } + return NO; +} + +/** + * @return number of rows we could safely skip during scanning, based on the first + * two finder patterns that have been located. In some cases their position will + * allow us to infer that the third pattern must lie below a certain point farther + * down in the image. + */ +- (int)findRowSkip { + int max = (int)[self.possibleCenters count]; + if (max <= 1) { + return 0; + } + ZXResultPoint *firstConfirmedCenter = nil; + for (int i = 0; i < max; i++) { + ZXQRCodeFinderPattern *center = self.possibleCenters[i]; + if ([center count] >= ZX_CENTER_QUORUM) { + if (firstConfirmedCenter == nil) { + firstConfirmedCenter = center; + } else { + self.hasSkipped = YES; + return (int)(fabsf([firstConfirmedCenter x] - [center x]) - fabsf([firstConfirmedCenter y] - [center y])) / 2; + } + } + } + return 0; +} + +/** + * @return true iff we have found at least 3 finder patterns that have been detected + * at least ZX_CENTER_QUORUM times each, and, the estimated module size of the + * candidates is "pretty similar" + */ +- (BOOL)haveMultiplyConfirmedCenters { + int confirmedCount = 0; + float totalModuleSize = 0.0f; + int max = (int)[self.possibleCenters count]; + for (int i = 0; i < max; i++) { + ZXQRCodeFinderPattern *pattern = self.possibleCenters[i]; + if ([pattern count] >= ZX_CENTER_QUORUM) { + confirmedCount++; + totalModuleSize += [pattern estimatedModuleSize]; + } + } + if (confirmedCount < 3) { + return NO; + } + + float average = totalModuleSize / (float)max; + float totalDeviation = 0.0f; + for (int i = 0; i < max; i++) { + ZXQRCodeFinderPattern *pattern = self.possibleCenters[i]; + totalDeviation += fabsf([pattern estimatedModuleSize] - average); + } + return totalDeviation <= 0.05f * totalModuleSize; +} + +/** + * Orders by ZXFinderPattern count, descending. + */ +NSInteger centerCompare(id center1, id center2, void *context) { + float average = [(__bridge NSNumber *)context floatValue]; + + if ([((ZXQRCodeFinderPattern *)center2) count] == [((ZXQRCodeFinderPattern *)center1) count]) { + float dA = fabsf([((ZXQRCodeFinderPattern *)center2) estimatedModuleSize] - average); + float dB = fabsf([((ZXQRCodeFinderPattern *)center1) estimatedModuleSize] - average); + return dA < dB ? 1 : dA == dB ? 0 : -1; + } else { + return [((ZXQRCodeFinderPattern *)center2) count] - [((ZXQRCodeFinderPattern *)center1) count]; + } +} + +/** + * Orders by furthest from average + */ +NSInteger furthestFromAverageCompare(id center1, id center2, void *context) { + float average = [(__bridge NSNumber *)context floatValue]; + + float dA = fabsf([((ZXQRCodeFinderPattern *)center2) estimatedModuleSize] - average); + float dB = fabsf([((ZXQRCodeFinderPattern *)center1) estimatedModuleSize] - average); + return dA < dB ? -1 : dA == dB ? 0 : 1; +} + +/** + * @return the 3 best ZXFinderPatterns from our list of candidates. The "best" are + * those that have been detected at least ZXCENTER_QUORUM times, and whose module + * size differs from the average among those patterns the least + * @return nil if 3 such finder patterns do not exist + */ +- (NSMutableArray *)selectBestPatterns { + int startSize = (int)[self.possibleCenters count]; + if (startSize < 3) { + return nil; + } + + if (startSize > 3) { + float totalModuleSize = 0.0f; + float square = 0.0f; + for (int i = 0; i < startSize; i++) { + float size = [self.possibleCenters[i] estimatedModuleSize]; + totalModuleSize += size; + square += size * size; + } + float average = totalModuleSize / (float)startSize; + float stdDev = (float)sqrt(square / startSize - average * average); + + [self.possibleCenters sortUsingFunction: furthestFromAverageCompare context: (__bridge void *)@(average)]; + + float limit = MAX(0.2f * average, stdDev); + + for (int i = 0; i < [self.possibleCenters count] && [self.possibleCenters count] > 3; i++) { + ZXQRCodeFinderPattern *pattern = self.possibleCenters[i]; + if (fabsf([pattern estimatedModuleSize] - average) > limit) { + [self.possibleCenters removeObjectAtIndex:i]; + i--; + } + } + } + + if ([self.possibleCenters count] > 3) { + float totalModuleSize = 0.0f; + for (int i = 0; i < [self.possibleCenters count]; i++) { + totalModuleSize += [self.possibleCenters[i] estimatedModuleSize]; + } + + float average = totalModuleSize / (float)[self.possibleCenters count]; + + [self.possibleCenters sortUsingFunction:centerCompare context:(__bridge void *)(@(average))]; + + self.possibleCenters = [[NSMutableArray alloc] initWithArray:[self.possibleCenters subarrayWithRange:NSMakeRange(0, 3)]]; + } + + return [@[self.possibleCenters[0], self.possibleCenters[1], self.possibleCenters[2]] mutableCopy]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeFinderPatternInfo.h b/iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeFinderPatternInfo.h new file mode 100755 index 0000000..f529186 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeFinderPatternInfo.h @@ -0,0 +1,31 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXQRCodeFinderPattern; + +/** + * Encapsulates information about finder patterns in an image, including the location of + * the three finder patterns, and their estimated module size. + */ +@interface ZXQRCodeFinderPatternInfo : NSObject + +@property (nonatomic, strong, readonly) ZXQRCodeFinderPattern *bottomLeft; +@property (nonatomic, strong, readonly) ZXQRCodeFinderPattern *topLeft; +@property (nonatomic, strong, readonly) ZXQRCodeFinderPattern *topRight; + +- (id)initWithPatternCenters:(NSArray *)patternCenters; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeFinderPatternInfo.m b/iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeFinderPatternInfo.m new file mode 100755 index 0000000..9d63893 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/detector/ZXQRCodeFinderPatternInfo.m @@ -0,0 +1,32 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXQRCodeFinderPattern.h" +#import "ZXQRCodeFinderPatternInfo.h" + +@implementation ZXQRCodeFinderPatternInfo + +- (id)initWithPatternCenters:(NSArray *)patternCenters { + if (self = [super init]) { + _bottomLeft = patternCenters[0]; + _topLeft = patternCenters[1]; + _topRight = patternCenters[2]; + } + + return self; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/encoder/ZXQRCode.h b/iDearQRCode/Tools/ZXingObjC/qrcode/encoder/ZXQRCode.h new file mode 100755 index 0000000..20ba525 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/encoder/ZXQRCode.h @@ -0,0 +1,31 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +extern const int ZX_NUM_MASK_PATTERNS; + +@class ZXByteMatrix, ZXQRCodeErrorCorrectionLevel, ZXQRCodeMode, ZXQRCodeVersion; + +@interface ZXQRCode : NSObject + +@property (nonatomic, strong) ZXQRCodeMode *mode; +@property (nonatomic, strong) ZXQRCodeErrorCorrectionLevel *ecLevel; +@property (nonatomic, strong) ZXQRCodeVersion *version; +@property (nonatomic, assign) int maskPattern; +@property (nonatomic, strong) ZXByteMatrix *matrix; + ++ (BOOL)isValidMaskPattern:(int)maskPattern; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/encoder/ZXQRCode.m b/iDearQRCode/Tools/ZXingObjC/qrcode/encoder/ZXQRCode.m new file mode 100755 index 0000000..3e84654 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/encoder/ZXQRCode.m @@ -0,0 +1,58 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXByteMatrix.h" +#import "ZXQRCode.h" +#import "ZXQRCodeErrorCorrectionLevel.h" +#import "ZXQRCodeMode.h" + +const int ZX_NUM_MASK_PATTERNS = 8; + +@implementation ZXQRCode + +- (id)init { + if (self = [super init]) { + _mode = nil; + _ecLevel = nil; + _version = nil; + _maskPattern = -1; + _matrix = nil; + } + + return self; +} + +- (NSString *)description { + NSMutableString *result = [NSMutableString stringWithCapacity:200]; + [result appendFormat:@"<<\n mode: %@", self.mode]; + [result appendFormat:@"\n ecLevel: %@", self.ecLevel]; + [result appendFormat:@"\n version: %@", self.version]; + [result appendFormat:@"\n maskPattern: %d", self.maskPattern]; + if (self.matrix == nil) { + [result appendString:@"\n matrix: (null)\n"]; + } else { + [result appendFormat:@"\n matrix:\n%@", [self.matrix description]]; + } + [result appendString:@">>\n"]; + return [NSString stringWithString:result]; +} + +// Check if "mask_pattern" is valid. ++ (BOOL)isValidMaskPattern:(int)maskPattern { + return maskPattern >= 0 && maskPattern < ZX_NUM_MASK_PATTERNS; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/encoder/ZXQRCodeBlockPair.h b/iDearQRCode/Tools/ZXingObjC/qrcode/encoder/ZXQRCodeBlockPair.h new file mode 100755 index 0000000..16c6882 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/encoder/ZXQRCodeBlockPair.h @@ -0,0 +1,26 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXByteArray; + +@interface ZXQRCodeBlockPair : NSObject + +@property (nonatomic, strong, readonly) ZXByteArray *dataBytes; +@property (nonatomic, strong, readonly) ZXByteArray *errorCorrectionBytes; + +- (id)initWithData:(ZXByteArray *)data errorCorrection:(ZXByteArray *)errorCorrection; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/encoder/ZXQRCodeBlockPair.m b/iDearQRCode/Tools/ZXingObjC/qrcode/encoder/ZXQRCodeBlockPair.m new file mode 100755 index 0000000..b77fa32 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/encoder/ZXQRCodeBlockPair.m @@ -0,0 +1,30 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXQRCodeBlockPair.h" + +@implementation ZXQRCodeBlockPair + +- (id)initWithData:(ZXByteArray *)data errorCorrection:(ZXByteArray *)errorCorrection { + if (self = [super init]) { + _dataBytes = data; + _errorCorrectionBytes = errorCorrection; + } + + return self; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/encoder/ZXQRCodeEncoder.h b/iDearQRCode/Tools/ZXingObjC/qrcode/encoder/ZXQRCodeEncoder.h new file mode 100755 index 0000000..a5cd026 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/encoder/ZXQRCodeEncoder.h @@ -0,0 +1,87 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXBitArray, ZXByteArray, ZXEncodeHints, ZXQRCode, ZXQRCodeErrorCorrectionLevel, ZXQRCodeMode, ZXQRCodeVersion; + +extern const NSStringEncoding ZX_DEFAULT_BYTE_MODE_ENCODING; + +@interface ZXQRCodeEncoder : NSObject + +/** + * Encode "bytes" with the error correction level "ecLevel". The encoding mode will be chosen + * internally by chooseMode:. On success, store the result in "qrCode". + * + * We recommend you to use QRCode.EC_LEVEL_L (the lowest level) for + * "getECLevel" since our primary use is to show QR code on desktop screens. We don't need very + * strong error correction for this purpose. + * + * Note that there is no way to encode bytes in MODE_KANJI. We might want to add EncodeWithMode() + * with which clients can specify the encoding mode. For now, we don't need the functionality. + */ ++ (ZXQRCode *)encode:(NSString *)content ecLevel:(ZXQRCodeErrorCorrectionLevel *)ecLevel error:(NSError **)error; + ++ (ZXQRCode *)encode:(NSString *)content ecLevel:(ZXQRCodeErrorCorrectionLevel *)ecLevel hints:(ZXEncodeHints *)hints error:(NSError **)error; + +/** + * Return the code point of the table used in alphanumeric mode or + * -1 if there is no corresponding code in the table. + */ ++ (int)alphanumericCode:(int)code; + +/** + * Terminate bits as described in 8.4.8 and 8.4.9 of JISX0510:2004 (p.24). + */ ++ (BOOL)terminateBits:(int)numDataBytes bits:(ZXBitArray *)bits error:(NSError **)error; + +/** + * Get number of data bytes and number of error correction bytes for block id "blockID". Store + * the result in "numDataBytesInBlock", and "numECBytesInBlock". See table 12 in 8.5.1 of + * JISX0510:2004 (p.30) + */ ++ (BOOL)numDataBytesAndNumECBytesForBlockID:(int)numTotalBytes numDataBytes:(int)numDataBytes numRSBlocks:(int)numRSBlocks blockID:(int)blockID numDataBytesInBlock:(int[])numDataBytesInBlock numECBytesInBlock:(int[])numECBytesInBlock error:(NSError **)error; + +/** + * Interleave "bits" with corresponding error correction bytes. On success, store the result in + * "result". The interleave rule is complicated. See 8.6 of JISX0510:2004 (p.37) for details. + */ ++ (ZXBitArray *)interleaveWithECBytes:(ZXBitArray *)bits numTotalBytes:(int)numTotalBytes numDataBytes:(int)numDataBytes numRSBlocks:(int)numRSBlocks error:(NSError **)error; + ++ (ZXByteArray *)generateECBytes:(ZXByteArray *)dataBytes numEcBytesInBlock:(int)numEcBytesInBlock; + +/** + * Append mode info. On success, store the result in "bits". + */ ++ (void)appendModeInfo:(ZXQRCodeMode *)mode bits:(ZXBitArray *)bits; + +/** + * Append length info. On success, store the result in "bits". + */ ++ (BOOL)appendLengthInfo:(int)numLetters version:(ZXQRCodeVersion *)version mode:(ZXQRCodeMode *)mode bits:(ZXBitArray *)bits error:(NSError **)error; + +/** + * Append "bytes" in "mode" mode (encoding) into "bits". On success, store the result in "bits". + */ ++ (BOOL)appendBytes:(NSString *)content mode:(ZXQRCodeMode *)mode bits:(ZXBitArray *)bits encoding:(NSStringEncoding)encoding error:(NSError **)error; + ++ (void)appendNumericBytes:(NSString *)content bits:(ZXBitArray *)bits; + ++ (BOOL)appendAlphanumericBytes:(NSString *)content bits:(ZXBitArray *)bits error:(NSError **)error; + ++ (void)append8BitBytes:(NSString *)content bits:(ZXBitArray *)bits encoding:(NSStringEncoding)encoding; + ++ (BOOL)appendKanjiBytes:(NSString *)content bits:(ZXBitArray *)bits error:(NSError **)error; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/encoder/ZXQRCodeEncoder.m b/iDearQRCode/Tools/ZXingObjC/qrcode/encoder/ZXQRCodeEncoder.m new file mode 100755 index 0000000..f0d163f --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/encoder/ZXQRCodeEncoder.m @@ -0,0 +1,563 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitArray.h" +#import "ZXByteArray.h" +#import "ZXByteMatrix.h" +#import "ZXCharacterSetECI.h" +#import "ZXEncodeHints.h" +#import "ZXErrors.h" +#import "ZXGenericGF.h" +#import "ZXIntArray.h" +#import "ZXQRCode.h" +#import "ZXQRCodeBlockPair.h" +#import "ZXQRCodeEncoder.h" +#import "ZXQRCodeErrorCorrectionLevel.h" +#import "ZXQRCodeMaskUtil.h" +#import "ZXQRCodeMatrixUtil.h" +#import "ZXQRCodeMode.h" +#import "ZXQRCodeVersion.h" +#import "ZXReedSolomonEncoder.h" + +// The original table is defined in the table 5 of JISX0510:2004 (p.19). +const int ZX_ALPHANUMERIC_TABLE[] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x00-0x0f + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x10-0x1f + 36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, // 0x20-0x2f + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1, // 0x30-0x3f + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 0x40-0x4f + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, // 0x50-0x5f +}; + +const NSStringEncoding ZX_DEFAULT_BYTE_MODE_ENCODING = NSISOLatin1StringEncoding; + +@implementation ZXQRCodeEncoder + +// The mask penalty calculation is complicated. See Table 21 of JISX0510:2004 (p.45) for details. +// Basically it applies four rules and summate all penalties. ++ (int)calculateMaskPenalty:(ZXByteMatrix *)matrix { + return [ZXQRCodeMaskUtil applyMaskPenaltyRule1:matrix] + + [ZXQRCodeMaskUtil applyMaskPenaltyRule2:matrix] + + [ZXQRCodeMaskUtil applyMaskPenaltyRule3:matrix] + + [ZXQRCodeMaskUtil applyMaskPenaltyRule4:matrix]; +} + ++ (ZXQRCode *)encode:(NSString *)content ecLevel:(ZXQRCodeErrorCorrectionLevel *)ecLevel error:(NSError **)error { + return [self encode:content ecLevel:ecLevel hints:nil error:error]; +} + ++ (ZXQRCode *)encode:(NSString *)content ecLevel:(ZXQRCodeErrorCorrectionLevel *)ecLevel hints:(ZXEncodeHints *)hints error:(NSError **)error { + // Determine what character encoding has been specified by the caller, if any + NSStringEncoding encoding = hints == nil ? 0 : hints.encoding; + if (encoding == 0) { + encoding = ZX_DEFAULT_BYTE_MODE_ENCODING; + } + + // Pick an encoding mode appropriate for the content. Note that this will not attempt to use + // multiple modes / segments even if that were more efficient. Twould be nice. + ZXQRCodeMode *mode = [self chooseMode:content encoding:encoding]; + + // This will store the header information, like mode and + // length, as well as "header" segments like an ECI segment. + ZXBitArray *headerBits = [[ZXBitArray alloc] init]; + + // Append ECI segment if applicable + if ([mode isEqual:[ZXQRCodeMode byteMode]] && ZX_DEFAULT_BYTE_MODE_ENCODING != encoding) { + ZXCharacterSetECI *eci = [ZXCharacterSetECI characterSetECIByEncoding:encoding]; + if (eci != nil) { + [self appendECI:eci bits:headerBits]; + } + } + + // (With ECI in place,) Write the mode marker + [self appendModeInfo:mode bits:headerBits]; + + // Collect data within the main segment, separately, to count its size if needed. Don't add it to + // main payload yet. + ZXBitArray *dataBits = [[ZXBitArray alloc] init]; + if (![self appendBytes:content mode:mode bits:dataBits encoding:encoding error:error]) { + return nil; + } + + // Hard part: need to know version to know how many bits length takes. But need to know how many + // bits it takes to know version. First we take a guess at version by assuming version will be + // the minimum, 1: + + int provisionalBitsNeeded = headerBits.size + + [mode characterCountBits:[ZXQRCodeVersion versionForNumber:1]] + + dataBits.size; + ZXQRCodeVersion *provisionalVersion = [self chooseVersion:provisionalBitsNeeded ecLevel:ecLevel error:error]; + if (!provisionalVersion) { + return nil; + } + + // Use that guess to calculate the right version. I am still not sure this works in 100% of cases. + + int bitsNeeded = headerBits.size + + [mode characterCountBits:provisionalVersion] + + dataBits.size; + ZXQRCodeVersion *version = [self chooseVersion:bitsNeeded ecLevel:ecLevel error:error]; + if (!version) { + return nil; + } + + ZXBitArray *headerAndDataBits = [[ZXBitArray alloc] init]; + [headerAndDataBits appendBitArray:headerBits]; + // Find "length" of main segment and write it + int numLetters = [mode isEqual:[ZXQRCodeMode byteMode]] ? [dataBits sizeInBytes] : (int)[content length]; + if (![self appendLengthInfo:numLetters version:version mode:mode bits:headerAndDataBits error:error]) { + return nil; + } + // Put data together into the overall payload + [headerAndDataBits appendBitArray:dataBits]; + + ZXQRCodeECBlocks *ecBlocks = [version ecBlocksForLevel:ecLevel]; + int numDataBytes = version.totalCodewords - ecBlocks.totalECCodewords; + + // Terminate the bits properly. + if (![self terminateBits:numDataBytes bits:headerAndDataBits error:error]) { + return nil; + } + + // Interleave data bits with error correction code. + ZXBitArray *finalBits = [self interleaveWithECBytes:headerAndDataBits numTotalBytes:version.totalCodewords numDataBytes:numDataBytes + numRSBlocks:ecBlocks.numBlocks error:error]; + if (!finalBits) { + return nil; + } + + ZXQRCode *qrCode = [[ZXQRCode alloc] init]; + + qrCode.ecLevel = ecLevel; + qrCode.mode = mode; + qrCode.version = version; + + // Choose the mask pattern and set to "qrCode". + int dimension = version.dimensionForVersion; + ZXByteMatrix *matrix = [[ZXByteMatrix alloc] initWithWidth:dimension height:dimension]; + int maskPattern = [self chooseMaskPattern:finalBits ecLevel:[qrCode ecLevel] version:[qrCode version] matrix:matrix error:error]; + if (maskPattern == -1) { + return nil; + } + [qrCode setMaskPattern:maskPattern]; + + // Build the matrix and set it to "qrCode". + if (![ZXQRCodeMatrixUtil buildMatrix:finalBits ecLevel:ecLevel version:version maskPattern:maskPattern matrix:matrix error:error]) { + return nil; + } + [qrCode setMatrix:matrix]; + + return qrCode; +} + ++ (int)alphanumericCode:(int)code { + if (code < sizeof(ZX_ALPHANUMERIC_TABLE) / sizeof(int)) { + return ZX_ALPHANUMERIC_TABLE[code]; + } + return -1; +} + ++ (ZXQRCodeMode *)chooseMode:(NSString *)content { + return [self chooseMode:content encoding:-1]; +} + +/** + * Choose the best mode by examining the content. Note that 'encoding' is used as a hint; + * if it is Shift_JIS, and the input is only double-byte Kanji, then we return {@link Mode#KANJI}. + */ ++ (ZXQRCodeMode *)chooseMode:(NSString *)content encoding:(NSStringEncoding)encoding { + if (NSShiftJISStringEncoding == encoding) { + return [self isOnlyDoubleByteKanji:content] ? [ZXQRCodeMode kanjiMode] : [ZXQRCodeMode byteMode]; + } + BOOL hasNumeric = NO; + BOOL hasAlphanumeric = NO; + for (int i = 0; i < [content length]; ++i) { + unichar c = [content characterAtIndex:i]; + if (c >= '0' && c <= '9') { + hasNumeric = YES; + } else if ([self alphanumericCode:c] != -1) { + hasAlphanumeric = YES; + } else { + return [ZXQRCodeMode byteMode]; + } + } + if (hasAlphanumeric) { + return [ZXQRCodeMode alphanumericMode]; + } + if (hasNumeric) { + return [ZXQRCodeMode numericMode]; + } + return [ZXQRCodeMode byteMode]; +} + ++ (BOOL)isOnlyDoubleByteKanji:(NSString *)content { + NSData *data = [content dataUsingEncoding:NSShiftJISStringEncoding]; + int8_t *bytes = (int8_t *)[data bytes]; + NSUInteger length = [data length]; + if (length % 2 != 0) { + return NO; + } + for (int i = 0; i < length; i += 2) { + int byte1 = bytes[i] & 0xFF; + if ((byte1 < 0x81 || byte1 > 0x9F) && (byte1 < 0xE0 || byte1 > 0xEB)) { + return NO; + } + } + return YES; +} + ++ (int)chooseMaskPattern:(ZXBitArray *)bits ecLevel:(ZXQRCodeErrorCorrectionLevel *)ecLevel version:(ZXQRCodeVersion *)version matrix:(ZXByteMatrix *)matrix error:(NSError **)error { + int minPenalty = INT_MAX; + int bestMaskPattern = -1; + + for (int maskPattern = 0; maskPattern < ZX_NUM_MASK_PATTERNS; maskPattern++) { + if (![ZXQRCodeMatrixUtil buildMatrix:bits ecLevel:ecLevel version:version maskPattern:maskPattern matrix:matrix error:error]) { + return -1; + } + int penalty = [self calculateMaskPenalty:matrix]; + if (penalty < minPenalty) { + minPenalty = penalty; + bestMaskPattern = maskPattern; + } + } + return bestMaskPattern; +} + ++ (ZXQRCodeVersion *)chooseVersion:(int)numInputBits ecLevel:(ZXQRCodeErrorCorrectionLevel *)ecLevel error:(NSError **)error { + // In the following comments, we use numbers of Version 7-H. + for (int versionNum = 1; versionNum <= 40; versionNum++) { + ZXQRCodeVersion *version = [ZXQRCodeVersion versionForNumber:versionNum]; + // numBytes = 196 + int numBytes = version.totalCodewords; + // getNumECBytes = 130 + ZXQRCodeECBlocks *ecBlocks = [version ecBlocksForLevel:ecLevel]; + int numEcBytes = ecBlocks.totalECCodewords; + // getNumDataBytes = 196 - 130 = 66 + int numDataBytes = numBytes - numEcBytes; + int totalInputBytes = (numInputBits + 7) / 8; + if (numDataBytes >= totalInputBytes) { + return version; + } + } + + NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @"Data too big"}; + + if (error) *error = [[NSError alloc] initWithDomain:ZXErrorDomain code:ZXWriterError userInfo:userInfo]; + return nil; +} + ++ (int)totalInputBytes:(int)numInputBits version:(ZXQRCodeVersion *)version mode:(ZXQRCodeMode *)mode { + int modeInfoBits = 4; + int charCountBits = [mode characterCountBits:version]; + int headerBits = modeInfoBits + charCountBits; + int totalBits = numInputBits + headerBits; + + return (totalBits + 7) / 8; +} + ++ (BOOL)terminateBits:(int)numDataBytes bits:(ZXBitArray *)bits error:(NSError **)error { + int capacity = numDataBytes * 8; + if ([bits size] > capacity) { + NSDictionary *userInfo = @{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"data bits cannot fit in the QR Code %d > %d", [bits size], capacity]}; + + if (error) *error = [[NSError alloc] initWithDomain:ZXErrorDomain code:ZXWriterError userInfo:userInfo]; + return NO; + } + for (int i = 0; i < 4 && [bits size] < capacity; ++i) { + [bits appendBit:NO]; + } + int numBitsInLastByte = [bits size] & 0x07; + if (numBitsInLastByte > 0) { + for (int i = numBitsInLastByte; i < 8; i++) { + [bits appendBit:NO]; + } + } + int numPaddingBytes = numDataBytes - [bits sizeInBytes]; + for (int i = 0; i < numPaddingBytes; ++i) { + [bits appendBits:(i & 0x01) == 0 ? 0xEC : 0x11 numBits:8]; + } + if ([bits size] != capacity) { + NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @"Bits size does not equal capacity"}; + + if (error) *error = [[NSError alloc] initWithDomain:ZXErrorDomain code:ZXWriterError userInfo:userInfo]; + return NO; + } + return YES; +} + ++ (BOOL)numDataBytesAndNumECBytesForBlockID:(int)numTotalBytes numDataBytes:(int)numDataBytes numRSBlocks:(int)numRSBlocks blockID:(int)blockID numDataBytesInBlock:(int[])numDataBytesInBlock numECBytesInBlock:(int[])numECBytesInBlock error:(NSError **)error { + if (blockID >= numRSBlocks) { + NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @"Block ID too large"}; + + if (error) *error = [[NSError alloc] initWithDomain:ZXErrorDomain code:ZXWriterError userInfo:userInfo]; + return NO; + } + int numRsBlocksInGroup2 = numTotalBytes % numRSBlocks; + int numRsBlocksInGroup1 = numRSBlocks - numRsBlocksInGroup2; + int numTotalBytesInGroup1 = numTotalBytes / numRSBlocks; + int numTotalBytesInGroup2 = numTotalBytesInGroup1 + 1; + int numDataBytesInGroup1 = numDataBytes / numRSBlocks; + int numDataBytesInGroup2 = numDataBytesInGroup1 + 1; + int numEcBytesInGroup1 = numTotalBytesInGroup1 - numDataBytesInGroup1; + int numEcBytesInGroup2 = numTotalBytesInGroup2 - numDataBytesInGroup2; + if (numEcBytesInGroup1 != numEcBytesInGroup2) { + NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @"EC bytes mismatch"}; + + if (error) *error = [[NSError alloc] initWithDomain:ZXErrorDomain code:ZXWriterError userInfo:userInfo]; + return NO; + } + if (numRSBlocks != numRsBlocksInGroup1 + numRsBlocksInGroup2) { + NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @"RS blocks mismatch"}; + + if (error) *error = [[NSError alloc] initWithDomain:ZXErrorDomain code:ZXWriterError userInfo:userInfo]; + return NO; + } + if (numTotalBytes != ((numDataBytesInGroup1 + numEcBytesInGroup1) * numRsBlocksInGroup1) + ((numDataBytesInGroup2 + numEcBytesInGroup2) * numRsBlocksInGroup2)) { + NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @"Total bytes mismatch"}; + + if (error) *error = [[NSError alloc] initWithDomain:ZXErrorDomain code:ZXWriterError userInfo:userInfo]; + return NO; + } + if (blockID < numRsBlocksInGroup1) { + numDataBytesInBlock[0] = numDataBytesInGroup1; + numECBytesInBlock[0] = numEcBytesInGroup1; + } else { + numDataBytesInBlock[0] = numDataBytesInGroup2; + numECBytesInBlock[0] = numEcBytesInGroup2; + } + return YES; +} + ++ (ZXBitArray *)interleaveWithECBytes:(ZXBitArray *)bits numTotalBytes:(int)numTotalBytes numDataBytes:(int)numDataBytes numRSBlocks:(int)numRSBlocks error:(NSError **)error { + // "bits" must have "getNumDataBytes" bytes of data. + if ([bits sizeInBytes] != numDataBytes) { + NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @"Number of bits and data bytes does not match"}; + + if (error) *error = [[NSError alloc] initWithDomain:ZXErrorDomain code:ZXWriterError userInfo:userInfo]; + return nil; + } + + // Step 1. Divide data bytes into blocks and generate error correction bytes for them. We'll + // store the divided data bytes blocks and error correction bytes blocks into "blocks". + int dataBytesOffset = 0; + int maxNumDataBytes = 0; + int maxNumEcBytes = 0; + + // Since, we know the number of reedsolmon blocks, we can initialize the vector with the number. + NSMutableArray *blocks = [NSMutableArray arrayWithCapacity:numRSBlocks]; + + for (int i = 0; i < numRSBlocks; ++i) { + int numDataBytesInBlock[1]; + int numEcBytesInBlock[1]; + if (![self numDataBytesAndNumECBytesForBlockID:numTotalBytes numDataBytes:numDataBytes numRSBlocks:numRSBlocks + blockID:i numDataBytesInBlock:numDataBytesInBlock + numECBytesInBlock:numEcBytesInBlock error:error]) { + return nil; + } + + int size = numDataBytesInBlock[0]; + ZXByteArray *dataBytes = [[ZXByteArray alloc] initWithLength:size]; + [bits toBytes:8 * dataBytesOffset array:dataBytes offset:0 numBytes:size]; + ZXByteArray *ecBytes = [self generateECBytes:dataBytes numEcBytesInBlock:numEcBytesInBlock[0]]; + [blocks addObject:[[ZXQRCodeBlockPair alloc] initWithData:dataBytes errorCorrection:ecBytes]]; + + maxNumDataBytes = MAX(maxNumDataBytes, size); + maxNumEcBytes = MAX(maxNumEcBytes, numEcBytesInBlock[0]); + dataBytesOffset += numDataBytesInBlock[0]; + } + if (numDataBytes != dataBytesOffset) { + NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @"Data bytes does not match offset"}; + + if (error) *error = [[NSError alloc] initWithDomain:ZXErrorDomain code:ZXWriterError userInfo:userInfo]; + return nil; + } + + ZXBitArray *result = [[ZXBitArray alloc] init]; + + // First, place data blocks. + for (int i = 0; i < maxNumDataBytes; ++i) { + for (ZXQRCodeBlockPair *block in blocks) { + ZXByteArray *dataBytes = block.dataBytes; + NSUInteger length = dataBytes.length; + if (i < length) { + [result appendBits:dataBytes.array[i] numBits:8]; + } + } + } + // Then, place error correction blocks. + for (int i = 0; i < maxNumEcBytes; ++i) { + for (ZXQRCodeBlockPair *block in blocks) { + ZXByteArray *ecBytes = block.errorCorrectionBytes; + int length = ecBytes.length; + if (i < length) { + [result appendBits:ecBytes.array[i] numBits:8]; + } + } + } + if (numTotalBytes != [result sizeInBytes]) { + NSDictionary *userInfo = @{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Interleaving error: %d and %d differ.", numTotalBytes, [result sizeInBytes]]}; + + if (error) *error = [[NSError alloc] initWithDomain:ZXErrorDomain code:ZXWriterError userInfo:userInfo]; + return nil; + } + + return result; +} + ++ (ZXByteArray *)generateECBytes:(ZXByteArray *)dataBytes numEcBytesInBlock:(int)numEcBytesInBlock { + int numDataBytes = dataBytes.length; + ZXIntArray *toEncode = [[ZXIntArray alloc] initWithLength:numDataBytes + numEcBytesInBlock]; + for (int i = 0; i < numDataBytes; i++) { + toEncode.array[i] = dataBytes.array[i] & 0xFF; + } + [[[ZXReedSolomonEncoder alloc] initWithField:[ZXGenericGF QrCodeField256]] encode:toEncode ecBytes:numEcBytesInBlock]; + + ZXByteArray *ecBytes = [[ZXByteArray alloc] initWithLength:numEcBytesInBlock]; + for (int i = 0; i < numEcBytesInBlock; i++) { + ecBytes.array[i] = (int8_t) toEncode.array[numDataBytes + i]; + } + + return ecBytes; +} + ++ (void)appendModeInfo:(ZXQRCodeMode *)mode bits:(ZXBitArray *)bits { + [bits appendBits:[mode bits] numBits:4]; +} + +/** + * Append length info. On success, store the result in "bits". + */ ++ (BOOL)appendLengthInfo:(int)numLetters version:(ZXQRCodeVersion *)version mode:(ZXQRCodeMode *)mode bits:(ZXBitArray *)bits error:(NSError **)error { + int numBits = [mode characterCountBits:version]; + if (numLetters >= (1 << numBits)) { + NSDictionary *userInfo = @{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"%d is bigger than %d", numLetters, ((1 << numBits) - 1)]}; + + if (error) *error = [[NSError alloc] initWithDomain:ZXErrorDomain code:ZXWriterError userInfo:userInfo]; + return NO; + } + [bits appendBits:numLetters numBits:numBits]; + return YES; +} + ++ (BOOL)appendBytes:(NSString *)content mode:(ZXQRCodeMode *)mode bits:(ZXBitArray *)bits encoding:(NSStringEncoding)encoding error:(NSError **)error { + if ([mode isEqual:[ZXQRCodeMode numericMode]]) { + [self appendNumericBytes:content bits:bits]; + } else if ([mode isEqual:[ZXQRCodeMode alphanumericMode]]) { + if (![self appendAlphanumericBytes:content bits:bits error:error]) { + return NO; + } + } else if ([mode isEqual:[ZXQRCodeMode byteMode]]) { + [self append8BitBytes:content bits:bits encoding:encoding]; + } else if ([mode isEqual:[ZXQRCodeMode kanjiMode]]) { + if (![self appendKanjiBytes:content bits:bits error:error]) { + return NO; + } + } else { + NSDictionary *userInfo = @{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Invalid mode: %@", mode]}; + + if (error) *error = [[NSError alloc] initWithDomain:ZXErrorDomain code:ZXWriterError userInfo:userInfo]; + return NO; + } + return YES; +} + ++ (void)appendNumericBytes:(NSString *)content bits:(ZXBitArray *)bits { + NSUInteger length = [content length]; + int i = 0; + while (i < length) { + int num1 = [content characterAtIndex:i] - '0'; + if (i + 2 < length) { + int num2 = [content characterAtIndex:i + 1] - '0'; + int num3 = [content characterAtIndex:i + 2] - '0'; + [bits appendBits:num1 * 100 + num2 * 10 + num3 numBits:10]; + i += 3; + } else if (i + 1 < length) { + int num2 = [content characterAtIndex:i + 1] - '0'; + [bits appendBits:num1 * 10 + num2 numBits:7]; + i += 2; + } else { + [bits appendBits:num1 numBits:4]; + i++; + } + } +} + ++ (BOOL)appendAlphanumericBytes:(NSString *)content bits:(ZXBitArray *)bits error:(NSError **)error { + NSUInteger length = [content length]; + int i = 0; + + while (i < length) { + int code1 = [self alphanumericCode:[content characterAtIndex:i]]; + if (code1 == -1) { + if (error) *error = [[NSError alloc] initWithDomain:ZXErrorDomain code:ZXWriterError userInfo:nil]; + return NO; + } + if (i + 1 < length) { + int code2 = [self alphanumericCode:[content characterAtIndex:i + 1]]; + if (code2 == -1) { + if (error) *error = [[NSError alloc] initWithDomain:ZXErrorDomain code:ZXWriterError userInfo:nil]; + return NO; + } + [bits appendBits:code1 * 45 + code2 numBits:11]; + i += 2; + } else { + [bits appendBits:code1 numBits:6]; + i++; + } + } + return YES; +} + ++ (void)append8BitBytes:(NSString *)content bits:(ZXBitArray *)bits encoding:(NSStringEncoding)encoding { + NSData *data = [content dataUsingEncoding:encoding]; + int8_t *bytes = (int8_t *)[data bytes]; + + for (int i = 0; i < [data length]; ++i) { + [bits appendBits:bytes[i] numBits:8]; + } +} + ++ (BOOL)appendKanjiBytes:(NSString *)content bits:(ZXBitArray *)bits error:(NSError **)error { + NSData *data = [content dataUsingEncoding:NSShiftJISStringEncoding]; + int8_t *bytes = (int8_t *)[data bytes]; + for (int i = 0; i < [data length]; i += 2) { + int byte1 = bytes[i] & 0xFF; + int byte2 = bytes[i + 1] & 0xFF; + int code = (byte1 << 8) | byte2; + int subtracted = -1; + if (code >= 0x8140 && code <= 0x9ffc) { + subtracted = code - 0x8140; + } else if (code >= 0xe040 && code <= 0xebbf) { + subtracted = code - 0xc140; + } + if (subtracted == -1) { + NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @"Invalid byte sequence"}; + + if (error) *error = [[NSError alloc] initWithDomain:ZXErrorDomain code:ZXWriterError userInfo:userInfo]; + return NO; + } + int encoded = ((subtracted >> 8) * 0xc0) + (subtracted & 0xff); + [bits appendBits:encoded numBits:13]; + } + return YES; +} + ++ (void)appendECI:(ZXCharacterSetECI *)eci bits:(ZXBitArray *)bits { + [bits appendBits:[[ZXQRCodeMode eciMode] bits] numBits:4]; + [bits appendBits:[eci value] numBits:8]; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/encoder/ZXQRCodeMaskUtil.h b/iDearQRCode/Tools/ZXingObjC/qrcode/encoder/ZXQRCodeMaskUtil.h new file mode 100755 index 0000000..a70a5d8 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/encoder/ZXQRCodeMaskUtil.h @@ -0,0 +1,53 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXByteMatrix; + +@interface ZXQRCodeMaskUtil : NSObject + +/** + * Apply mask penalty rule 1 and return the penalty. Find repetitive cells with the same color and + * give penalty to them. Example: 00000 or 11111. + */ ++ (int)applyMaskPenaltyRule1:(ZXByteMatrix *)matrix; + +/** + * Apply mask penalty rule 2 and return the penalty. Find 2x2 blocks with the same color and give + * penalty to them. This is actually equivalent to the spec's rule, which is to find MxN blocks and give a + * penalty proportional to (M-1)x(N-1), because this is the number of 2x2 blocks inside such a block. + */ ++ (int)applyMaskPenaltyRule2:(ZXByteMatrix *)matrix; + +/** + * Apply mask penalty rule 3 and return the penalty. Find consecutive runs of 1:1:3:1:1:4 + * starting with black, or 4:1:1:3:1:1 starting with white, and give penalty to them. If we + * find patterns like 000010111010000, we give penalty once. + */ ++ (int)applyMaskPenaltyRule3:(ZXByteMatrix *)matrix; + +/** + * Apply mask penalty rule 4 and return the penalty. Calculate the ratio of dark cells and give + * penalty if the ratio is far from 50%. It gives 10 penalty for 5% distance. + */ ++ (int)applyMaskPenaltyRule4:(ZXByteMatrix *)matrix; + +/** + * Return the mask bit for "getMaskPattern" at "x" and "y". See 8.8 of JISX0510:2004 for mask + * pattern conditions. + */ ++ (BOOL)dataMaskBit:(int)maskPattern x:(int)x y:(int)y; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/encoder/ZXQRCodeMaskUtil.m b/iDearQRCode/Tools/ZXingObjC/qrcode/encoder/ZXQRCodeMaskUtil.m new file mode 100755 index 0000000..ba5b443 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/encoder/ZXQRCodeMaskUtil.m @@ -0,0 +1,190 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXByteMatrix.h" +#import "ZXQRCode.h" +#import "ZXQRCodeMaskUtil.h" + +// Penalty weights from section 6.8.2.1 +const int ZX_N1 = 3; +const int ZX_N2 = 3; +const int ZX_N3 = 40; +const int ZX_N4 = 10; + +@implementation ZXQRCodeMaskUtil + ++ (int)applyMaskPenaltyRule1:(ZXByteMatrix *)matrix { + return [self applyMaskPenaltyRule1Internal:matrix isHorizontal:YES] + [self applyMaskPenaltyRule1Internal:matrix isHorizontal:NO]; +} + ++ (int)applyMaskPenaltyRule2:(ZXByteMatrix *)matrix { + int penalty = 0; + int8_t **array = matrix.array; + int width = matrix.width; + int height = matrix.height; + + for (int y = 0; y < height - 1; y++) { + for (int x = 0; x < width - 1; x++) { + int value = array[y][x]; + if (value == array[y][x + 1] && value == array[y + 1][x] && value == array[y + 1][x + 1]) { + penalty++; + } + } + } + + return ZX_N2 * penalty; +} + ++ (int)applyMaskPenaltyRule3:(ZXByteMatrix *)matrix { + int numPenalties = 0; + int8_t **array = matrix.array; + int width = matrix.width; + int height = matrix.height; + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + int8_t *arrayY = array[y]; // We can at least optimize this access + if (x + 6 < width && + arrayY[x] == 1 && + arrayY[x + 1] == 0 && + arrayY[x + 2] == 1 && + arrayY[x + 3] == 1 && + arrayY[x + 4] == 1 && + arrayY[x + 5] == 0 && + arrayY[x + 6] == 1 && + ([self isWhiteHorizontal:arrayY length:width from:x - 4 to:x] || [self isWhiteHorizontal:arrayY length:width from:x + 7 to:x + 11])) { + numPenalties++; + } + if (y + 6 < height && + array[y][x] == 1 && + array[y + 1][x] == 0 && + array[y + 2][x] == 1 && + array[y + 3][x] == 1 && + array[y + 4][x] == 1 && + array[y + 5][x] == 0 && + array[y + 6][x] == 1 && + ([self isWhiteVertical:array length:width col:x from:y - 4 to:y] || [self isWhiteVertical:array length:height col:x from:y + 7 to:y + 11])) { + numPenalties++; + } + } + } + return numPenalties * ZX_N3; +} + ++ (BOOL)isWhiteHorizontal:(int8_t *)rowArray length:(int)length from:(int)from to:(int)to { + for (int i = from; i < to; i++) { + if (i >= 0 && i < length && rowArray[i] == 1) { + return NO; + } + } + return YES; +} + ++ (BOOL)isWhiteVertical:(int8_t **)array length:(int)length col:(int)col from:(int)from to:(int)to { + for (int i = from; i < to; i++) { + if (i >= 0 && i < length && array[i][col] == 1) { + return NO; + } + } + return YES; +} + ++ (int)applyMaskPenaltyRule4:(ZXByteMatrix *)matrix { + int numDarkCells = 0; + int8_t **array = matrix.array; + int width = matrix.width; + int height = matrix.height; + for (int y = 0; y < height; y++) { + int8_t *arrayY = array[y]; + for (int x = 0; x < width; x++) { + if (arrayY[x] == 1) { + numDarkCells++; + } + } + } + int numTotalCells = [matrix height] * [matrix width]; + int fivePercentVariances = abs(numDarkCells * 2 - numTotalCells) * 10 / numTotalCells; + return fivePercentVariances * ZX_N4; +} + ++ (BOOL)dataMaskBit:(int)maskPattern x:(int)x y:(int)y { + int intermediate; + int temp; + switch (maskPattern) { + case 0: + intermediate = (y + x) & 0x1; + break; + case 1: + intermediate = y & 0x1; + break; + case 2: + intermediate = x % 3; + break; + case 3: + intermediate = (y + x) % 3; + break; + case 4: + intermediate = ((y / 2) + (x / 3)) & 0x1; + break; + case 5: + temp = y * x; + intermediate = (temp & 0x1) + (temp % 3); + break; + case 6: + temp = y * x; + intermediate = ((temp & 0x1) + (temp % 3)) & 0x1; + break; + case 7: + temp = y * x; + intermediate = ((temp % 3) + ((y + x) & 0x1)) & 0x1; + break; + default: + [NSException raise:NSInvalidArgumentException format:@"Invalid mask pattern: %d", maskPattern]; + } + return intermediate == 0; +} + +/** + * Helper function for applyMaskPenaltyRule1. We need this for doing this calculation in both + * vertical and horizontal orders respectively. + */ ++ (int)applyMaskPenaltyRule1Internal:(ZXByteMatrix *)matrix isHorizontal:(BOOL)isHorizontal { + int penalty = 0; + int iLimit = isHorizontal ? matrix.height : matrix.width; + int jLimit = isHorizontal ? matrix.width : matrix.height; + int8_t **array = matrix.array; + for (int i = 0; i < iLimit; i++) { + int numSameBitCells = 0; + int prevBit = -1; + for (int j = 0; j < jLimit; j++) { + int bit = isHorizontal ? array[i][j] : array[j][i]; + if (bit == prevBit) { + numSameBitCells++; + } else { + if (numSameBitCells >= 5) { + penalty += ZX_N1 + (numSameBitCells - 5); + } + numSameBitCells = 1; // Include the cell itself. + prevBit = bit; + } + } + if (numSameBitCells >= 5) { + penalty += ZX_N1 + (numSameBitCells - 5); + } + } + return penalty; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/encoder/ZXQRCodeMatrixUtil.h b/iDearQRCode/Tools/ZXingObjC/qrcode/encoder/ZXQRCodeMatrixUtil.h new file mode 100755 index 0000000..ab89bf4 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/encoder/ZXQRCodeMatrixUtil.h @@ -0,0 +1,91 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@class ZXBitArray, ZXByteMatrix, ZXQRCodeErrorCorrectionLevel, ZXQRCodeVersion; + +@interface ZXQRCodeMatrixUtil : NSObject + +// Set all cells to -1. -1 means that the cell is empty (not set yet). ++ (void)clearMatrix:(ZXByteMatrix *)matrix; + +// Build 2D matrix of QR Code from "dataBits" with "ecLevel", "version" and "getMaskPattern". On +// success, store the result in "matrix" and return true. ++ (BOOL)buildMatrix:(ZXBitArray *)dataBits ecLevel:(ZXQRCodeErrorCorrectionLevel *)ecLevel version:(ZXQRCodeVersion *)version maskPattern:(int)maskPattern matrix:(ZXByteMatrix *)matrix error:(NSError **)error; + +// Embed basic patterns. On success, modify the matrix and return true. +// The basic patterns are: +// - Position detection patterns +// - Timing patterns +// - Dark dot at the left bottom corner +// - Position adjustment patterns, if need be ++ (BOOL)embedBasicPatterns:(ZXQRCodeVersion *)version matrix:(ZXByteMatrix *)matrix error:(NSError **)error; + +// Embed type information. On success, modify the matrix. ++ (BOOL)embedTypeInfo:(ZXQRCodeErrorCorrectionLevel *)ecLevel maskPattern:(int)maskPattern matrix:(ZXByteMatrix *)matrix error:(NSError **)error; + +// Embed version information if need be. On success, modify the matrix and return true. +// See 8.10 of JISX0510:2004 (p.47) for how to embed version information. ++ (BOOL)maybeEmbedVersionInfo:(ZXQRCodeVersion *)version matrix:(ZXByteMatrix *)matrix error:(NSError **)error; + +// Embed "dataBits" using "getMaskPattern". On success, modify the matrix and return true. +// For debugging purposes, it skips masking process if "getMaskPattern" is -1. +// See 8.7 of JISX0510:2004 (p.38) for how to embed data bits. ++ (BOOL)embedDataBits:(ZXBitArray *)dataBits maskPattern:(int)maskPattern matrix:(ZXByteMatrix *)matrix error:(NSError **)error; + +// Return the position of the most significant bit set (to one) in the "value". The most +// significant bit is position 32. If there is no bit set, return 0. Examples: +// - findMSBSet(0) => 0 +// - findMSBSet(1) => 1 +// - findMSBSet(255) => 8 ++ (int)findMSBSet:(int)value; + +// Calculate BCH (Bose-Chaudhuri-Hocquenghem) code for "value" using polynomial "poly". The BCH +// code is used for encoding type information and version information. +// Example: Calculation of version information of 7. +// f(x) is created from 7. +// - 7 = 000111 in 6 bits +// - f(x) = x^2 + x^1 + x^0 +// g(x) is given by the standard (p. 67) +// - g(x) = x^12 + x^11 + x^10 + x^9 + x^8 + x^5 + x^2 + 1 +// Multiply f(x) by x^(18 - 6) +// - f'(x) = f(x) * x^(18 - 6) +// - f'(x) = x^14 + x^13 + x^12 +// Calculate the remainder of f'(x) / g(x) +// x^2 +// __________________________________________________ +// g(x) )x^14 + x^13 + x^12 +// x^14 + x^13 + x^12 + x^11 + x^10 + x^7 + x^4 + x^2 +// -------------------------------------------------- +// x^11 + x^10 + x^7 + x^4 + x^2 +// +// The remainder is x^11 + x^10 + x^7 + x^4 + x^2 +// Encode it in binary: 110010010100 +// The return value is 0xc94 (1100 1001 0100) +// +// Since all coefficients in the polynomials are 1 or 0, we can do the calculation by bit +// operations. We don't care if cofficients are positive or negative. ++ (int)calculateBCHCode:(int)value poly:(int)poly; + +// Make bit vector of type information. On success, store the result in "bits" and return true. +// Encode error correction level and mask pattern. See 8.9 of +// JISX0510:2004 (p.45) for details. ++ (BOOL)makeTypeInfoBits:(ZXQRCodeErrorCorrectionLevel *)ecLevel maskPattern:(int)maskPattern bits:(ZXBitArray *)bits error:(NSError **)error; + +// Make bit vector of version information. On success, store the result in "bits" and return true. +// See 8.10 of JISX0510:2004 (p.45) for details. ++ (BOOL)makeVersionInfoBits:(ZXQRCodeVersion *)version bits:(ZXBitArray *)bits error:(NSError **)error; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/encoder/ZXQRCodeMatrixUtil.m b/iDearQRCode/Tools/ZXingObjC/qrcode/encoder/ZXQRCodeMatrixUtil.m new file mode 100755 index 0000000..422e6cf --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/encoder/ZXQRCodeMatrixUtil.m @@ -0,0 +1,466 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitArray.h" +#import "ZXByteMatrix.h" +#import "ZXErrors.h" +#import "ZXQRCode.h" +#import "ZXQRCodeErrorCorrectionLevel.h" +#import "ZXQRCodeMaskUtil.h" +#import "ZXQRCodeMatrixUtil.h" +#import "ZXQRCodeVersion.h" + +const int ZX_POSITION_DETECTION_PATTERN[][7] = { + {1, 1, 1, 1, 1, 1, 1}, + {1, 0, 0, 0, 0, 0, 1}, + {1, 0, 1, 1, 1, 0, 1}, + {1, 0, 1, 1, 1, 0, 1}, + {1, 0, 1, 1, 1, 0, 1}, + {1, 0, 0, 0, 0, 0, 1}, + {1, 1, 1, 1, 1, 1, 1}, +}; + +const int ZX_POSITION_ADJUSTMENT_PATTERN[][5] = { + {1, 1, 1, 1, 1}, + {1, 0, 0, 0, 1}, + {1, 0, 1, 0, 1}, + {1, 0, 0, 0, 1}, + {1, 1, 1, 1, 1}, +}; + +// From Appendix E. Table 1, JIS0510X:2004 (p 71). The table was double-checked by komatsu. +const int ZX_POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[][7] = { + {-1, -1, -1, -1, -1, -1, -1}, // Version 1 + { 6, 18, -1, -1, -1, -1, -1}, // Version 2 + { 6, 22, -1, -1, -1, -1, -1}, // Version 3 + { 6, 26, -1, -1, -1, -1, -1}, // Version 4 + { 6, 30, -1, -1, -1, -1, -1}, // Version 5 + { 6, 34, -1, -1, -1, -1, -1}, // Version 6 + { 6, 22, 38, -1, -1, -1, -1}, // Version 7 + { 6, 24, 42, -1, -1, -1, -1}, // Version 8 + { 6, 26, 46, -1, -1, -1, -1}, // Version 9 + { 6, 28, 50, -1, -1, -1, -1}, // Version 10 + { 6, 30, 54, -1, -1, -1, -1}, // Version 11 + { 6, 32, 58, -1, -1, -1, -1}, // Version 12 + { 6, 34, 62, -1, -1, -1, -1}, // Version 13 + { 6, 26, 46, 66, -1, -1, -1}, // Version 14 + { 6, 26, 48, 70, -1, -1, -1}, // Version 15 + { 6, 26, 50, 74, -1, -1, -1}, // Version 16 + { 6, 30, 54, 78, -1, -1, -1}, // Version 17 + { 6, 30, 56, 82, -1, -1, -1}, // Version 18 + { 6, 30, 58, 86, -1, -1, -1}, // Version 19 + { 6, 34, 62, 90, -1, -1, -1}, // Version 20 + { 6, 28, 50, 72, 94, -1, -1}, // Version 21 + { 6, 26, 50, 74, 98, -1, -1}, // Version 22 + { 6, 30, 54, 78, 102, -1, -1}, // Version 23 + { 6, 28, 54, 80, 106, -1, -1}, // Version 24 + { 6, 32, 58, 84, 110, -1, -1}, // Version 25 + { 6, 30, 58, 86, 114, -1, -1}, // Version 26 + { 6, 34, 62, 90, 118, -1, -1}, // Version 27 + { 6, 26, 50, 74, 98, 122, -1}, // Version 28 + { 6, 30, 54, 78, 102, 126, -1}, // Version 29 + { 6, 26, 52, 78, 104, 130, -1}, // Version 30 + { 6, 30, 56, 82, 108, 134, -1}, // Version 31 + { 6, 34, 60, 86, 112, 138, -1}, // Version 32 + { 6, 30, 58, 86, 114, 142, -1}, // Version 33 + { 6, 34, 62, 90, 118, 146, -1}, // Version 34 + { 6, 30, 54, 78, 102, 126, 150}, // Version 35 + { 6, 24, 50, 76, 102, 128, 154}, // Version 36 + { 6, 28, 54, 80, 106, 132, 158}, // Version 37 + { 6, 32, 58, 84, 110, 136, 162}, // Version 38 + { 6, 26, 54, 82, 110, 138, 166}, // Version 39 + { 6, 30, 58, 86, 114, 142, 170}, // Version 40 +}; + +// Type info cells at the left top corner. +const int ZX_TYPE_INFO_COORDINATES[][2] = { + {8, 0}, + {8, 1}, + {8, 2}, + {8, 3}, + {8, 4}, + {8, 5}, + {8, 7}, + {8, 8}, + {7, 8}, + {5, 8}, + {4, 8}, + {3, 8}, + {2, 8}, + {1, 8}, + {0, 8}, +}; + +// From Appendix D in JISX0510:2004 (p. 67) +const int ZX_VERSION_INFO_POLY = 0x1f25; // 1 1111 0010 0101 + +// From Appendix C in JISX0510:2004 (p.65). +const int ZX_TYPE_INFO_POLY = 0x537; +const int ZX_TYPE_INFO_MASK_PATTERN = 0x5412; + +@implementation ZXQRCodeMatrixUtil + ++ (void)clearMatrix:(ZXByteMatrix *)matrix { + [matrix clear:-1]; +} + ++ (BOOL)buildMatrix:(ZXBitArray *)dataBits ecLevel:(ZXQRCodeErrorCorrectionLevel *)ecLevel version:(ZXQRCodeVersion *)version maskPattern:(int)maskPattern matrix:(ZXByteMatrix *)matrix error:(NSError **)error { + [self clearMatrix:matrix]; + if (![self embedBasicPatterns:version matrix:matrix error:error]) { + return NO; + } + // Type information appear with any version. + if (![self embedTypeInfo:ecLevel maskPattern:maskPattern matrix:matrix error:error]) { + return NO; + } + // Version info appear if version >= 7. + if (![self maybeEmbedVersionInfo:version matrix:matrix error:error]) { + return NO; + } + // Data should be embedded at end. + if (![self embedDataBits:dataBits maskPattern:maskPattern matrix:matrix error:error]) { + return NO; + } + return YES; +} + ++ (BOOL)embedBasicPatterns:(ZXQRCodeVersion *)version matrix:(ZXByteMatrix *)matrix error:(NSError **)error { + // Let's get started with embedding big squares at corners. + if (![self embedPositionDetectionPatternsAndSeparators:matrix]) { + if (error) *error = [[NSError alloc] initWithDomain:ZXErrorDomain code:ZXNotFoundError userInfo:nil]; + return NO; + } + // Then, embed the dark dot at the left bottom corner. + if (![self embedDarkDotAtLeftBottomCorner:matrix]) { + if (error) *error = [[NSError alloc] initWithDomain:ZXErrorDomain code:ZXNotFoundError userInfo:nil]; + return NO; + } + + // Position adjustment patterns appear if version >= 2. + [self maybeEmbedPositionAdjustmentPatterns:version matrix:matrix]; + // Timing patterns should be embedded after position adj. patterns. + [self embedTimingPatterns:matrix]; + + return YES; +} + ++ (BOOL)embedTypeInfo:(ZXQRCodeErrorCorrectionLevel *)ecLevel maskPattern:(int)maskPattern matrix:(ZXByteMatrix *)matrix error:(NSError **)error { + ZXBitArray *typeInfoBits = [[ZXBitArray alloc] init]; + if (![self makeTypeInfoBits:ecLevel maskPattern:maskPattern bits:typeInfoBits error:error]) { + return NO; + } + + for (int i = 0; i < [typeInfoBits size]; ++i) { + // Place bits in LSB to MSB order. LSB (least significant bit) is the last value in + // "typeInfoBits". + BOOL bit = [typeInfoBits get:[typeInfoBits size] - 1 - i]; + + // Type info bits at the left top corner. See 8.9 of JISX0510:2004 (p.46). + int x1 = ZX_TYPE_INFO_COORDINATES[i][0]; + int y1 = ZX_TYPE_INFO_COORDINATES[i][1]; + [matrix setX:x1 y:y1 boolValue:bit]; + + if (i < 8) { + // Right top corner. + int x2 = [matrix width] - i - 1; + int y2 = 8; + [matrix setX:x2 y:y2 boolValue:bit]; + } else { + // Left bottom corner. + int x2 = 8; + int y2 = [matrix height] - 7 + (i - 8); + [matrix setX:x2 y:y2 boolValue:bit]; + } + } + + return YES; +} + ++ (BOOL)maybeEmbedVersionInfo:(ZXQRCodeVersion *)version matrix:(ZXByteMatrix *)matrix error:(NSError **)error { + if (version.versionNumber < 7) { // Version info is necessary if version >= 7. + return YES; // Don't need version info. + } + ZXBitArray *versionInfoBits = [[ZXBitArray alloc] init]; + if (![self makeVersionInfoBits:version bits:versionInfoBits error:error]) { + return NO; + } + + int bitIndex = 6 * 3 - 1; // It will decrease from 17 to 0. + for (int i = 0; i < 6; ++i) { + for (int j = 0; j < 3; ++j) { + // Place bits in LSB (least significant bit) to MSB order. + BOOL bit = [versionInfoBits get:bitIndex]; + bitIndex--; + // Left bottom corner. + [matrix setX:i y:[matrix height] - 11 + j boolValue:bit]; + // Right bottom corner. + [matrix setX:[matrix height] - 11 + j y:i boolValue:bit]; + } + } + + return YES; +} + ++ (BOOL)embedDataBits:(ZXBitArray *)dataBits maskPattern:(int)maskPattern matrix:(ZXByteMatrix *)matrix error:(NSError **)error { + int bitIndex = 0; + int direction = -1; + // Start from the right bottom cell. + int x = [matrix width] - 1; + int y = [matrix height] - 1; + while (x > 0) { + // Skip the vertical timing pattern. + if (x == 6) { + x -= 1; + } + while (y >= 0 && y < [matrix height]) { + for (int i = 0; i < 2; ++i) { + int xx = x - i; + // Skip the cell if it's not empty. + if (![self isEmpty:[matrix getX:xx y:y]]) { + continue; + } + BOOL bit; + if (bitIndex < [dataBits size]) { + bit = [dataBits get:bitIndex]; + ++bitIndex; + } else { + // Padding bit. If there is no bit left, we'll fill the left cells with 0, as described + // in 8.4.9 of JISX0510:2004 (p. 24). + bit = NO; + } + + // Skip masking if mask_pattern is -1. + if (maskPattern != -1 && [ZXQRCodeMaskUtil dataMaskBit:maskPattern x:xx y:y]) { + bit = !bit; + } + [matrix setX:xx y:y boolValue:bit]; + } + y += direction; + } + direction = -direction; // Reverse the direction. + y += direction; + x -= 2; // Move to the left. + } + // All bits should be consumed. + if (bitIndex != [dataBits size]) { + NSDictionary *userInfo = @{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"Not all bits consumed: %d/%d", bitIndex, [dataBits size]]}; + + if (error) *error = [[NSError alloc] initWithDomain:ZXErrorDomain code:ZXNotFoundError userInfo:userInfo]; + return NO; + } + + return YES; +} + ++ (int)findMSBSet:(int)value { + int numDigits = 0; + while (value != 0) { + value = (int)((unsigned int)value >> 1); + ++numDigits; + } + return numDigits; +} + ++ (int)calculateBCHCode:(int)value poly:(int)poly { + // If poly is "1 1111 0010 0101" (version info poly), msbSetInPoly is 13. We'll subtract 1 + // from 13 to make it 12. + int msbSetInPoly = [self findMSBSet:poly]; + value <<= msbSetInPoly - 1; + // Do the division business using exclusive-or operations. + while ([self findMSBSet:value] >= msbSetInPoly) { + value ^= poly << ([self findMSBSet:value] - msbSetInPoly); + } + // Now the "value" is the remainder (i.e. the BCH code) + return value; +} + ++ (BOOL)makeTypeInfoBits:(ZXQRCodeErrorCorrectionLevel *)ecLevel maskPattern:(int)maskPattern bits:(ZXBitArray *)bits error:(NSError **)error { + if (![ZXQRCode isValidMaskPattern:maskPattern]) { + NSDictionary *userInfo = @{NSLocalizedDescriptionKey: @"Invalid mask pattern"}; + + if (error) *error = [[NSError alloc] initWithDomain:ZXErrorDomain code:ZXNotFoundError userInfo:userInfo]; + return NO; + } + int typeInfo = ([ecLevel bits] << 3) | maskPattern; + [bits appendBits:typeInfo numBits:5]; + + int bchCode = [self calculateBCHCode:typeInfo poly:ZX_TYPE_INFO_POLY]; + [bits appendBits:bchCode numBits:10]; + + ZXBitArray *maskBits = [[ZXBitArray alloc] init]; + [maskBits appendBits:ZX_TYPE_INFO_MASK_PATTERN numBits:15]; + [bits xor:maskBits]; + + if ([bits size] != 15) { // Just in case. + NSDictionary *userInfo = @{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"should not happen but we got: %d", [bits size]]}; + + if (error) *error = [[NSError alloc] initWithDomain:ZXErrorDomain code:ZXNotFoundError userInfo:userInfo]; + return NO; + } + + return YES; +} + ++ (BOOL)makeVersionInfoBits:(ZXQRCodeVersion *)version bits:(ZXBitArray *)bits error:(NSError **)error { + [bits appendBits:version.versionNumber numBits:6]; + int bchCode = [self calculateBCHCode:version.versionNumber poly:ZX_VERSION_INFO_POLY]; + [bits appendBits:bchCode numBits:12]; + + if ([bits size] != 18) { // Just in case. + NSDictionary *userInfo = @{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"should not happen but we got: %d", [bits size]]}; + + if (error) *error = [[NSError alloc] initWithDomain:ZXErrorDomain code:ZXNotFoundError userInfo:userInfo]; + return NO; + } + + return YES; +} + +// Check if "value" is empty. ++ (BOOL)isEmpty:(int)value { + return value == -1; +} + ++ (void)embedTimingPatterns:(ZXByteMatrix *)matrix { + // -8 is for skipping position detection patterns (size 7), and two horizontal/vertical + // separation patterns (size 1). Thus, 8 = 7 + 1. + for (int i = 8; i < [matrix width] - 8; ++i) { + int bit = (i + 1) % 2; + // Horizontal line. + if ([self isEmpty:[matrix getX:i y:6]]) { + [matrix setX:i y:6 boolValue:bit]; + } + // Vertical line. + if ([self isEmpty:[matrix getX:6 y:i]]) { + [matrix setX:6 y:i boolValue:bit]; + } + } +} + +// Embed the lonely dark dot at left bottom corner. JISX0510:2004 (p.46) ++ (BOOL)embedDarkDotAtLeftBottomCorner:(ZXByteMatrix *)matrix { + if ([matrix getX:8 y:matrix.height - 8] == 0) { + return NO; + } + [matrix setX:8 y:matrix.height - 8 intValue:1]; + + return YES; +} + ++ (BOOL)embedHorizontalSeparationPattern:(int)xStart yStart:(int)yStart matrix:(ZXByteMatrix *)matrix { + for (int x = 0; x < 8; ++x) { + if (![self isEmpty:[matrix getX:xStart + x y:yStart]]) { + return NO; + } + [matrix setX:xStart + x y:yStart intValue:0]; + } + + return YES; +} + ++ (BOOL)embedVerticalSeparationPattern:(int)xStart yStart:(int)yStart matrix:(ZXByteMatrix *)matrix { + for (int y = 0; y < 7; ++y) { + if (![self isEmpty:[matrix getX:xStart y:yStart + y]]) { + return NO; + } + [matrix setX:xStart y:yStart + y intValue:0]; + } + + return YES; +} + +// Note that we cannot unify the function with embedPositionDetectionPattern() despite they are +// almost identical, since we cannot write a function that takes 2D arrays in different sizes in +// C/C++. We should live with the fact. ++ (void)embedPositionAdjustmentPattern:(int)xStart yStart:(int)yStart matrix:(ZXByteMatrix *)matrix { + for (int y = 0; y < 5; ++y) { + for (int x = 0; x < 5; ++x) { + [matrix setX:xStart + x y:yStart + y intValue:ZX_POSITION_ADJUSTMENT_PATTERN[y][x]]; + } + } +} + ++ (void)embedPositionDetectionPattern:(int)xStart yStart:(int)yStart matrix:(ZXByteMatrix *)matrix { + for (int y = 0; y < 7; ++y) { + for (int x = 0; x < 7; ++x) { + [matrix setX:xStart + x y:yStart + y intValue:ZX_POSITION_DETECTION_PATTERN[y][x]]; + } + } +} + +// Embed position detection patterns and surrounding vertical/horizontal separators. ++ (BOOL)embedPositionDetectionPatternsAndSeparators:(ZXByteMatrix *)matrix { + // Embed three big squares at corners. + int pdpWidth = sizeof(ZX_POSITION_DETECTION_PATTERN[0]) / sizeof(int); + // Left top corner. + [self embedPositionDetectionPattern:0 yStart:0 matrix:matrix]; + // Right top corner. + [self embedPositionDetectionPattern:[matrix width] - pdpWidth yStart:0 matrix:matrix]; + // Left bottom corner. + [self embedPositionDetectionPattern:0 yStart:[matrix width] - pdpWidth matrix:matrix]; + + // Embed horizontal separation patterns around the squares. + int hspWidth = 8; + // Left top corner. + [self embedHorizontalSeparationPattern:0 yStart:hspWidth - 1 matrix:matrix]; + // Right top corner. + [self embedHorizontalSeparationPattern:[matrix width] - hspWidth yStart:hspWidth - 1 matrix:matrix]; + // Left bottom corner. + [self embedHorizontalSeparationPattern:0 yStart:[matrix width] - hspWidth matrix:matrix]; + + // Embed vertical separation patterns around the squares. + int vspSize = 7; + // Left top corner. + if (![self embedVerticalSeparationPattern:vspSize yStart:0 matrix:matrix]) { + return NO; + } + // Right top corner. + if (![self embedVerticalSeparationPattern:[matrix height] - vspSize - 1 yStart:0 matrix:matrix]) { + return NO; + } + // Left bottom corner. + if (![self embedVerticalSeparationPattern:vspSize yStart:[matrix height] - vspSize matrix:matrix]) { + return NO; + } + + return YES; +} + +// Embed position adjustment patterns if need be. ++ (void)maybeEmbedPositionAdjustmentPatterns:(ZXQRCodeVersion *)version matrix:(ZXByteMatrix *)matrix { + if (version.versionNumber < 2) { // The patterns appear if version >= 2 + return; + } + int index = version.versionNumber - 1; + int numCoordinates = sizeof(ZX_POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[index]) / sizeof(int); + for (int i = 0; i < numCoordinates; ++i) { + for (int j = 0; j < numCoordinates; ++j) { + int y = ZX_POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[index][i]; + int x = ZX_POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[index][j]; + if (x == -1 || y == -1) { + continue; + } + // If the cell is unset, we embed the position adjustment pattern here. + if ([self isEmpty:[matrix getX:x y:y]]) { + // -2 is necessary since the x/y coordinates point to the center of the pattern, not the + // left top corner. + [self embedPositionAdjustmentPattern:x - 2 yStart:y - 2 matrix:matrix]; + } + } + } +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/multi/ZXQRCodeMultiReader.h b/iDearQRCode/Tools/ZXingObjC/qrcode/multi/ZXQRCodeMultiReader.h new file mode 100755 index 0000000..0c2fba9 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/multi/ZXQRCodeMultiReader.h @@ -0,0 +1,25 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXMultipleBarcodeReader.h" +#import "ZXQRCodeReader.h" + +/** + * This implementation can detect and decode multiple QR Codes in an image. + */ +@interface ZXQRCodeMultiReader : ZXQRCodeReader + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/multi/ZXQRCodeMultiReader.m b/iDearQRCode/Tools/ZXingObjC/qrcode/multi/ZXQRCodeMultiReader.m new file mode 100755 index 0000000..aa4fa6c --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/multi/ZXQRCodeMultiReader.m @@ -0,0 +1,147 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXByteArray.h" +#import "ZXDecoderResult.h" +#import "ZXDetectorResult.h" +#import "ZXMultiDetector.h" +#import "ZXQRCodeDecoder.h" +#import "ZXQRCodeDecoderMetaData.h" +#import "ZXQRCodeMultiReader.h" +#import "ZXResult.h" + +@implementation ZXQRCodeMultiReader + +- (NSArray *)decodeMultiple:(ZXBinaryBitmap *)image error:(NSError **)error { + return [self decodeMultiple:image hints:nil error:error]; +} + +- (NSArray *)decodeMultiple:(ZXBinaryBitmap *)image hints:(ZXDecodeHints *)hints error:(NSError **)error { + ZXBitMatrix *matrix = [image blackMatrixWithError:error]; + if (!matrix) { + return nil; + } + NSMutableArray *results = [NSMutableArray array]; + NSArray *detectorResults = [[[ZXMultiDetector alloc] initWithImage:matrix] detectMulti:hints error:error]; + if (!detectorResults) { + return nil; + } + for (ZXDetectorResult *detectorResult in detectorResults) { + ZXDecoderResult *decoderResult = [[self decoder] decodeMatrix:[detectorResult bits] hints:hints error:nil]; + if (decoderResult) { + NSMutableArray *points = [[detectorResult points] mutableCopy]; + // If the code was mirrored: swap the bottom-left and the top-right points. + if ([decoderResult.other isKindOfClass:[ZXQRCodeDecoderMetaData class]]) { + [(ZXQRCodeDecoderMetaData *)decoderResult.other applyMirroredCorrection:points]; + } + ZXResult *result = [ZXResult resultWithText:decoderResult.text + rawBytes:decoderResult.rawBytes + resultPoints:points + format:kBarcodeFormatQRCode]; + NSMutableArray *byteSegments = decoderResult.byteSegments; + if (byteSegments != nil) { + [result putMetadata:kResultMetadataTypeByteSegments value:byteSegments]; + } + NSString *ecLevel = decoderResult.ecLevel; + if (ecLevel != nil) { + [result putMetadata:kResultMetadataTypeErrorCorrectionLevel value:ecLevel]; + } + if ([decoderResult hasStructuredAppend]) { + [result putMetadata:kResultMetadataTypeStructuredAppendSequence + value:@(decoderResult.structuredAppendSequenceNumber)]; + [result putMetadata:kResultMetadataTypeStructuredAppendParity + value:@(decoderResult.structuredAppendParity)]; + } + [results addObject:result]; + } + } + + results = [self processStructuredAppend:results]; + return results; +} + +- (NSMutableArray *)processStructuredAppend:(NSMutableArray *)results { + BOOL hasSA = NO; + + // first, check, if there is at least on SA result in the list + for (ZXResult *result in results) { + if (result.resultMetadata[@(kResultMetadataTypeStructuredAppendSequence)]) { + hasSA = YES; + break; + } + } + if (!hasSA) { + return results; + } + + // it is, second, split the lists and built a new result list + NSMutableArray *newResults = [NSMutableArray array]; + NSMutableArray *saResults = [NSMutableArray array]; + for (ZXResult *result in results) { + [newResults addObject:result]; + if (result.resultMetadata[@(kResultMetadataTypeStructuredAppendSequence)]) { + [saResults addObject:result]; + } + } + // sort and concatenate the SA list items + [saResults sortUsingComparator:^NSComparisonResult(ZXResult *a, ZXResult *b) { + int aNumber = [a.resultMetadata[@(kResultMetadataTypeStructuredAppendSequence)] intValue]; + int bNumber = [b.resultMetadata[@(kResultMetadataTypeStructuredAppendSequence)] intValue]; + if (aNumber < bNumber) { + return NSOrderedAscending; + } + if (aNumber > bNumber) { + return NSOrderedDescending; + } + return NSOrderedSame; + }]; + NSMutableString *concatedText = [NSMutableString string]; + int rawBytesLen = 0; + int byteSegmentLength = 0; + for (ZXResult *saResult in saResults) { + [concatedText appendString:saResult.text]; + rawBytesLen += saResult.rawBytes.length; + if (saResult.resultMetadata[@(kResultMetadataTypeByteSegments)]) { + for (ZXByteArray *segment in saResult.resultMetadata[@(kResultMetadataTypeByteSegments)]) { + byteSegmentLength += segment.length; + } + } + } + ZXByteArray *newRawBytes = [[ZXByteArray alloc] initWithLength:rawBytesLen]; + ZXByteArray *newByteSegment = [[ZXByteArray alloc] initWithLength:byteSegmentLength]; + int newRawBytesIndex = 0; + int byteSegmentIndex = 0; + for (ZXResult *saResult in saResults) { + memcpy(newRawBytes.array, saResult.rawBytes.array, saResult.rawBytes.length * sizeof(int8_t)); + newRawBytesIndex += saResult.rawBytes.length; + if (saResult.resultMetadata[@(kResultMetadataTypeByteSegments)]) { + for (ZXByteArray *segment in saResult.resultMetadata[@(kResultMetadataTypeByteSegments)]) { + memcpy(newByteSegment.array, segment.array, segment.length * sizeof(int8_t)); + byteSegmentIndex += segment.length; + } + } + } + ZXResult *newResult = [[ZXResult alloc] initWithText:concatedText rawBytes:newRawBytes resultPoints:@[] format:kBarcodeFormatQRCode]; + if (byteSegmentLength > 0) { + NSMutableArray *byteSegmentList = [NSMutableArray array]; + [byteSegmentList addObject:newByteSegment]; + [newResult putMetadata:kResultMetadataTypeByteSegments value:byteSegmentList]; + } + [newResults addObject:newResult]; + return newResults; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/multi/detector/ZXMultiDetector.h b/iDearQRCode/Tools/ZXingObjC/qrcode/multi/detector/ZXMultiDetector.h new file mode 100755 index 0000000..348b768 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/multi/detector/ZXMultiDetector.h @@ -0,0 +1,30 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXQRCodeDetector.h" + +/** + * Encapsulates logic that can detect one or more QR Codes in an image, even if the QR Code + * is rotated or skewed, or partially obscured. + */ + +@class ZXDecodeHints; + +@interface ZXMultiDetector : ZXQRCodeDetector + +- (NSArray *)detectMulti:(ZXDecodeHints *)hints error:(NSError **)error; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/multi/detector/ZXMultiDetector.m b/iDearQRCode/Tools/ZXingObjC/qrcode/multi/detector/ZXMultiDetector.m new file mode 100755 index 0000000..399d3ad --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/multi/detector/ZXMultiDetector.m @@ -0,0 +1,45 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXDecodeHints.h" +#import "ZXErrors.h" +#import "ZXMultiDetector.h" +#import "ZXMultiFinderPatternFinder.h" +#import "ZXResultPointCallback.h" + +@implementation ZXMultiDetector + +- (NSArray *)detectMulti:(ZXDecodeHints *)hints error:(NSError **)error { + id resultPointCallback = hints == nil ? nil : hints.resultPointCallback; + ZXMultiFinderPatternFinder *finder = [[ZXMultiFinderPatternFinder alloc] initWithImage:self.image resultPointCallback:resultPointCallback]; + NSArray *info = [finder findMulti:hints error:error]; + if ([info count] == 0) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + + NSMutableArray *result = [NSMutableArray array]; + for (int i = 0; i < [info count]; i++) { + ZXDetectorResult *patternInfo = [self processFinderPatternInfo:info[i] error:nil]; + if (patternInfo) { + [result addObject:patternInfo]; + } + } + + return result; +} + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/multi/detector/ZXMultiFinderPatternFinder.h b/iDearQRCode/Tools/ZXingObjC/qrcode/multi/detector/ZXMultiFinderPatternFinder.h new file mode 100755 index 0000000..b61025a --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/multi/detector/ZXMultiFinderPatternFinder.h @@ -0,0 +1,36 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXQRCodeFinderPatternFinder.h" + +@class ZXDecodeHints; + +/** + * This class attempts to find finder patterns in a QR Code. Finder patterns are the square + * markers at three corners of a QR Code. + * + * This class is thread-safe but not reentrant. Each thread must allocate its own object. + * + * In contrast to ZXFinderPatternFinder, this class will return an array of all possible + * QR code locations in the image. + * + * Use the tryHarder hint to ask for a more thorough detection. + */ +@interface ZXMultiFinderPatternFinder : ZXQRCodeFinderPatternFinder + +- (NSArray *)findMulti:(ZXDecodeHints *)hints error:(NSError **)error; + +@end diff --git a/iDearQRCode/Tools/ZXingObjC/qrcode/multi/detector/ZXMultiFinderPatternFinder.m b/iDearQRCode/Tools/ZXingObjC/qrcode/multi/detector/ZXMultiFinderPatternFinder.m new file mode 100755 index 0000000..d49f3b4 --- /dev/null +++ b/iDearQRCode/Tools/ZXingObjC/qrcode/multi/detector/ZXMultiFinderPatternFinder.m @@ -0,0 +1,240 @@ +/* + * Copyright 2012 ZXing authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "ZXBitMatrix.h" +#import "ZXDecodeHints.h" +#import "ZXErrors.h" +#import "ZXMultiFinderPatternFinder.h" +#import "ZXQRCodeFinderPattern.h" +#import "ZXQRCodeFinderPatternInfo.h" + +// TODO MIN_MODULE_COUNT and MAX_MODULE_COUNT would be great hints to ask the user for +// since it limits the number of regions to decode + +// max. legal count of modules per QR code edge (177) +float const ZX_MAX_MODULE_COUNT_PER_EDGE = 180; +// min. legal count per modules per QR code edge (11) +float const ZX_MIN_MODULE_COUNT_PER_EDGE = 9; + +/** + * More or less arbitrary cutoff point for determining if two finder patterns might belong + * to the same code if they differ less than DIFF_MODSIZE_CUTOFF_PERCENT percent in their + * estimated modules sizes. + */ +float const ZX_DIFF_MODSIZE_CUTOFF_PERCENT = 0.05f; + +/** + * More or less arbitrary cutoff point for determining if two finder patterns might belong + * to the same code if they differ less than DIFF_MODSIZE_CUTOFF pixels/module in their + * estimated modules sizes. + */ +float const ZX_DIFF_MODSIZE_CUTOFF = 0.5f; + +@implementation ZXMultiFinderPatternFinder + +/** + * Returns the 3 best {@link FinderPattern}s from our list of candidates. The "best" are + * those that have been detected at least {@link #CENTER_QUORUM} times, and whose module + * size differs from the average among those patterns the least + */ +- (NSArray *)selectBestPatternsWithError:(NSError **)error { + NSMutableArray *_possibleCenters = [NSMutableArray arrayWithArray:[self possibleCenters]]; + NSUInteger size = [_possibleCenters count]; + + if (size < 3) { + if (error) *error = ZXNotFoundErrorInstance(); + return nil; + } + + /* + * Begin HE modifications to safely detect multiple codes of equal size + */ + if (size == 3) { + return @[[@[_possibleCenters[0], _possibleCenters[1], _possibleCenters[2]] mutableCopy]]; + } + + [_possibleCenters sortUsingFunction:moduleSizeCompare context:nil]; + + /* + * Now lets start: build a list of tuples of three finder locations that + * - feature similar module sizes + * - are placed in a distance so the estimated module count is within the QR specification + * - have similar distance between upper left/right and left top/bottom finder patterns + * - form a triangle with 90° angle (checked by comparing top right/bottom left distance + * with pythagoras) + * + * Note: we allow each point to be used for more than one code region: this might seem + * counterintuitive at first, but the performance penalty is not that big. At this point, + * we cannot make a good quality decision whether the three finders actually represent + * a QR code, or are just by chance layouted so it looks like there might be a QR code there. + * So, if the layout seems right, lets have the decoder try to decode. + */ + + NSMutableArray *results = [NSMutableArray array]; + + for (int i1 = 0; i1 < (size - 2); i1++) { + ZXQRCodeFinderPattern *p1 = self.possibleCenters[i1]; + if (p1 == nil) { + continue; + } + + for (int i2 = i1 + 1; i2 < (size - 1); i2++) { + ZXQRCodeFinderPattern *p2 = self.possibleCenters[i2]; + if (p2 == nil) { + continue; + } + + float vModSize12 = ([p1 estimatedModuleSize] - [p2 estimatedModuleSize]) / MIN([p1 estimatedModuleSize], [p2 estimatedModuleSize]); + float vModSize12A = fabsf([p1 estimatedModuleSize] - [p2 estimatedModuleSize]); + if (vModSize12A > ZX_DIFF_MODSIZE_CUTOFF && vModSize12 >= ZX_DIFF_MODSIZE_CUTOFF_PERCENT) { + break; + } + + for (int i3 = i2 + 1; i3 < size; i3++) { + ZXQRCodeFinderPattern *p3 = self.possibleCenters[i3]; + if (p3 == nil) { + continue; + } + + float vModSize23 = ([p2 estimatedModuleSize] - [p3 estimatedModuleSize]) / MIN([p2 estimatedModuleSize], [p3 estimatedModuleSize]); + float vModSize23A = fabsf([p2 estimatedModuleSize] - [p3 estimatedModuleSize]); + if (vModSize23A > ZX_DIFF_MODSIZE_CUTOFF && vModSize23 >= ZX_DIFF_MODSIZE_CUTOFF_PERCENT) { + break; + } + + NSMutableArray *test = [NSMutableArray arrayWithObjects:p1, p2, p3, nil]; + [ZXResultPoint orderBestPatterns:test]; + + ZXQRCodeFinderPatternInfo *info = [[ZXQRCodeFinderPatternInfo alloc] initWithPatternCenters:test]; + float dA = [ZXResultPoint distance:[info topLeft] pattern2:[info bottomLeft]]; + float dC = [ZXResultPoint distance:[info topRight] pattern2:[info bottomLeft]]; + float dB = [ZXResultPoint distance:[info topLeft] pattern2:[info topRight]]; + + float estimatedModuleCount = (dA + dB) / ([p1 estimatedModuleSize] * 2.0f); + if (estimatedModuleCount > ZX_MAX_MODULE_COUNT_PER_EDGE || estimatedModuleCount < ZX_MIN_MODULE_COUNT_PER_EDGE) { + continue; + } + + float vABBC = fabsf((dA - dB) / MIN(dA, dB)); + if (vABBC >= 0.1f) { + continue; + } + + float dCpy = (float)sqrt(dA * dA + dB * dB); + float vPyC = fabsf((dC - dCpy) / MIN(dC, dCpy)); + + if (vPyC >= 0.1f) { + continue; + } + + [results addObject:test]; + } + } + } + + if ([results count] > 0) { + return results; + } + + if (error) *error = ZXNotFoundErrorInstance(); + return nil; +} + +- (NSArray *)findMulti:(ZXDecodeHints *)hints error:(NSError **)error { + BOOL tryHarder = hints != nil && hints.tryHarder; + BOOL pureBarcode = hints != nil && hints.pureBarcode; + int maxI = self.image.height; + int maxJ = self.image.width; + // We are looking for black/white/black/white/black modules in + // 1:1:3:1:1 ratio; this tracks the number of such modules seen so far + + // Let's assume that the maximum version QR Code we support takes up 1/4 the height of the + // image, and then account for the center being 3 modules in size. This gives the smallest + // number of pixels the center could be, so skip this often. When trying harder, look for all + // QR versions regardless of how dense they are. + int iSkip = (int)(maxI / (ZX_FINDER_PATTERN_MAX_MODULES * 4.0f) * 3); + if (iSkip < ZX_FINDER_PATTERN_MIN_SKIP || tryHarder) { + iSkip = ZX_FINDER_PATTERN_MIN_SKIP; + } + + int stateCount[5]; + for (int i = iSkip - 1; i < maxI; i += iSkip) { + stateCount[0] = 0; + stateCount[1] = 0; + stateCount[2] = 0; + stateCount[3] = 0; + stateCount[4] = 0; + int currentState = 0; + + for (int j = 0; j < maxJ; j++) { + if ([self.image getX:j y:i]) { + if ((currentState & 1) == 1) { + currentState++; + } + stateCount[currentState]++; + } else { + if ((currentState & 1) == 0) { + if (currentState == 4) { + if ([ZXQRCodeFinderPatternFinder foundPatternCross:stateCount] && [self handlePossibleCenter:stateCount i:i j:j pureBarcode:pureBarcode]) { + currentState = 0; + stateCount[0] = 0; + stateCount[1] = 0; + stateCount[2] = 0; + stateCount[3] = 0; + stateCount[4] = 0; + } else { + stateCount[0] = stateCount[2]; + stateCount[1] = stateCount[3]; + stateCount[2] = stateCount[4]; + stateCount[3] = 1; + stateCount[4] = 0; + currentState = 3; + } + } else { + stateCount[++currentState]++; + } + } else { + stateCount[currentState]++; + } + } + } + + if ([ZXQRCodeFinderPatternFinder foundPatternCross:stateCount]) { + [self handlePossibleCenter:stateCount i:i j:maxJ pureBarcode:pureBarcode]; + } + } + NSArray *patternInfo = [self selectBestPatternsWithError:error]; + if (!patternInfo) { + return nil; + } + NSMutableArray *result = [NSMutableArray array]; + for (NSMutableArray *pattern in patternInfo) { + [ZXResultPoint orderBestPatterns:pattern]; + [result addObject:[[ZXQRCodeFinderPatternInfo alloc] initWithPatternCenters:pattern]]; + } + + return result; +} + +/** + * A comparator that orders FinderPatterns by their estimated module size. + */ +NSInteger moduleSizeCompare(id center1, id center2, void *context) { + float value = [((ZXQRCodeFinderPattern *)center2) estimatedModuleSize] - [((ZXQRCodeFinderPattern *)center1) estimatedModuleSize]; + return value < 0.0 ? -1 : value > 0.0 ? 1 : 0; +} + +@end diff --git a/iDearQRCode/iDear_Public.h b/iDearQRCode/iDear_Public.h index 24b26ed..d5b802a 100644 --- a/iDearQRCode/iDear_Public.h +++ b/iDearQRCode/iDear_Public.h @@ -11,7 +11,8 @@ // 1.判断是否为iOS7 #define iOS7 ([[UIDevice currentDevice].systemVersion doubleValue] >= 7.0) - +//获取系统版本 +#define IOS_SYSTEM_VERSION [[[UIDevice currentDevice] systemVersion] floatValue] // 2.获得RGB颜色 #define RGBA(r, g, b, a) [UIColor colorWithRed:r/255.0f green:g/255.0f blue:b/255.0f alpha:a] #define RGB(r, g, b) RGBA(r, g, b, 1.0f) @@ -25,6 +26,9 @@ #define line_Color RGB(201, 205, 205) //组长 #define do_Color RGB(160, 226, 224) + +#define topView_Color RGB(15, 194, 175) +//#define promit_Color RGB(15, 194, 175) //字体 #define kFont_16 [UIFont systemFontOfSize:16] #define kFont_14 [UIFont systemFontOfSize:14]