Configure MICR project
MICR is a 32-bit COM object. The following explain how to configure your project:
C#
- Set Platform to x86
- Add Reference on COM Tab to ClearCheck21 MICR Reader
VB
- Set Platform to x86
- Add Reference on COM Tab to ClearCheck21 MICR Reader
Delphi
- Import Type Library for ClearCheck21 MICR Reader
IIS
- Set in Application Pool’s Advanced Settings:
Enable 32-bit Applications to True
Read MICR line and obtain fields
The following code demonstrates MICR line reading from an image file. After the value of the MICR line is obtained, the value of the MICR subfields can be obtain form CcMicrInfo.TextANSI
property.
C#
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
using ClearImage;using ClearMicr; static System.Threading.Mutex mut = new System.Threading.Mutex();void ReadMICR(string file, int page) { try { // Prevent re-entrancy mut.WaitOne(); // Create reader ClearMicr.CcMicrReader reader = new ClearMicr.CcMicrReader(); // Set options as needed reader.Flags = ClearMicr.EMicrReaderFlags.emrfEnforceAbaParsing; reader.Flags |= ClearMicr.EMicrReaderFlags.emrfExtendedMicrSearch; // Open image reader.Image.Open(file, page); // Do actual reading int cnt = reader.FindMICR(); // Obtain results for (int idx = 1; idx <= cnt; idx++) { ClearMicr.CcMicr micr = reader.MicrLine[idx]; Console.WriteLine(""); Console.WriteLine("Document: {0} DPI: {1}", micr.DocumentType, micr.Dpi); DisplayMicrInfo(micr.Info); DisplayMicrInfo(micr.Routing); DisplayMicrInfo(micr.RoutingChecksum); Console.WriteLine("ABA Routing Number: " + micr.Routing.TextANSI + micr.RoutingChecksum.TextANSI); DisplayMicrInfo(micr.AuxOnUs); DisplayMicrInfo(micr.EPC); DisplayMicrInfo(micr.OnUs); DisplayMicrInfo(micr.Amount); DisplayMicrInfo(micr.Account); DisplayMicrInfo(micr.CheckNumber); DisplayCharacters(micr); } if (cnt == 0) Console.WriteLine("No MICR found"); } catch (Exception ex) { ProcessException(ex); } finally { mut.ReleaseMutex(); GC.Collect(); GC.WaitForPendingFinalizers(); } } void DisplayMicrInfo(ClearMicr.CcMicrInfo info) { if (!info.IsRead) return; Console.WriteLine("{0, 15} {1} conf:{2, 6:N1}% '{3}'", info.Name, info.IsAbaCompliant ? "ABA" : " ", info.Conf, info.TextANSI); } void DisplayCharacters(ClearMicr.CcMicr micr) { Console.WriteLine(""); Console.WriteLine(" pos chr conf(%) altchr conf(%) dif(%)"); for (int pos = 1; pos < 1000; pos++) { ClearMicr.CcMicrInfo chr = micr.GetObject(ClearMicr.ECmFieldType.emftChr, pos, 0); ClearMicr.CcMicrInfo altchr = micr.GetObject(ClearMicr.ECmFieldType.emftChrAlt, pos, 0); if (chr == null) break; Console.WriteLine(" {0,-3} {1,-2} {2, 6:N1} {3,2} {4,6:N1} {5,6:N1}", pos, chr.TextANSI, chr.Conf, altchr.TextANSI, altchr.Conf, chr.Conf - altchr.Conf); } }
VB
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
Imports ClearImageImports ClearMicr Shared mut As New System.Threading.Mutex()Sub ReadMICR(file As String, page As Integer) Try ' Prevent re-entrancy mut.WaitOne() ' Create reader Dim reader As New ClearMicr.CcMicrReader() ' Set options as needed reader.Flags = ClearMicr.EMicrReaderFlags.emrfEnforceAbaParsing reader.Flags |= ClearMicr.EMicrReaderFlags.emrfExtendedMicrSearch ' Open image reader.Image.Open(file, page) ' Do actual reading Dim cnt As Integer = reader.FindMICR() ' Obtain results For idx As Integer = 1 To cnt Dim micr As ClearMicr.CcMicr = reader.MicrLine(idx) Console.WriteLine("") Console.WriteLine("Document: {0} DPI: {1}", micr.DocumentType, micr.Dpi) DisplayMicrInfo(micr.Info) DisplayMicrInfo(micr.Routing) DisplayMicrInfo(micr.RoutingChecksum) Console.WriteLine("ABA Routing Number: " + micr.Routing.TextANSI + micr.RoutingChecksum.TextANSI) DisplayMicrInfo(micr.AuxOnUs) DisplayMicrInfo(micr.EPC) DisplayMicrInfo(micr.OnUs) DisplayMicrInfo(micr.Amount) DisplayMicrInfo(micr.Account) DisplayMicrInfo(micr.CheckNumber) DisplayCharacters(micr) Next If cnt = 0 Then Console.WriteLine("No MICR found") Catch ex As Exception ProcessException(ex) Finally mut.ReleaseMutex() GC.Collect() GC.WaitForPendingFinalizers() End TryEnd Sub Private Sub DisplayMicrInfo(info As ClearMicr.CcMicrInfo) If Not info.IsRead Then Return Console.WriteLine("{0, 15} {1} conf:{2, 6:N1}% '{3}'", info.Name, _ If(info.IsAbaCompliant, "ABA", " "), info.Conf, _ info.TextANSI)End Sub Private Sub DisplayCharacters(micr As ClearMicr.CcMicr) Console.WriteLine("") Console.WriteLine(" pos chr conf(%) altchr conf(%) dif(%)") For pos As Integer = 1 To 999 Dim chr As ClearMicr.CcMicrInfo = micr.GetObject(ClearMicr.ECmFieldType.emftChr, pos, 0) Dim altchr As ClearMicr.CcMicrInfo = micr.GetObject(ClearMicr.ECmFieldType.emftChrAlt, pos, 0) If chr Is Nothing Then Exit For Console.WriteLine(" {0,-3} {1,-2} {2, 6:N1} {3,2} {4,6:N1} {5,6:N1}", pos, _ chr.TextANSI, chr.Conf, _ altchr.TextANSI, altchr.Conf, _ chr.Conf - altchr.Conf) NextEnd Sub
C++
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
#import "progid:ClearImage.ClearImage" exclude("LONG_PTR") no_namespace named_guids#import "msvbvm60.dll" rename("RGB","VBRGB") rename("EOF","VBEOF") rename("GetObject","VBGetObject")using namespace VBA;#import "progid:ClearMicr.CcMicrReader" no_namespace named_guids void ReadMICR (const char *fileName, const long page) { try { _CcMicrReaderPtr reader; // Create reader HRESULT hr = reader.CreateInstance(__uuidof(CcMicrReader)); // Set options as needed reader->Flags = emrfEnforceAbaParsing; reader->Flags |= emrfExtendedMicrSearch; // Open image reader->Image->Open(_bstr_t(fileName), page); // Find MICR int cnt = reader->FindMICR(); // Display results for (int idx = 1; idx <= cnt; idx++) { _CcMicrPtr micr = reader->MicrLine[idx]; printf ("\nDocument: %s DPI: %4.1f\n", (LPCTSTR)(micr->DocumentType), micr->Dpi); DisplayMicrInfo(micr->Info); DisplayMicrInfo(micr->Routing); DisplayMicrInfo(micr->RoutingChecksum); printf ("ABA Routing Number: %s%s\n", micr->Routing->TextANSI, micr->RoutingChecksum->TextANSI); DisplayMicrInfo(micr->AuxOnUs); DisplayMicrInfo(micr->EPC); DisplayMicrInfo(micr->OnUs); DisplayMicrInfo(micr->Amount); DisplayMicrInfo(micr->Account); DisplayMicrInfo(micr->CheckNumber); DisplayCharacters(micr); } } catch (_com_error &ex) {ProcessException(ex);} } void DisplayMicrInfo (_CcMicrInfoPtr &info) { if (!info->IsRead) return; printf ("%-15s %s conf: %6.2f%% '%s' \n", (LPCTSTR) (info->Name), info->IsAbaCompliant ? "ABA" : " ", info->Conf, (LPCTSTR) info->TextANSI); } void DisplayCharacters (_CcMicrPtr micr) { // print characters info printf ("\n pos chr conf(%%) altchr conf(%%) dif(%%) \n"); VARIANT varpos; varpos.vt = VT_I4; ECmFieldType ct = emftChr, ca = emftChrAlt; VARIANT var0; var0.lVal = 0; var0.vt = VT_I4; for (int pos = 1; pos < 1000; pos++) { varpos.lVal = pos; _CcMicrInfoPtr chr = micr->GetObject(&ct, &varpos, &var0); _CcMicrInfoPtr altchr = micr->GetObject(&ca, &varpos, &var0); if (chr == NULL) break; printf (" %-3d %-2s %6.1f %-2s %6.1f %6.1f\n", pos, (LPCTSTR) (chr->TextANSI), chr->Conf, (LPCTSTR) (altchr->TextANSI), altchr->Conf, chr->Conf - altchr->Conf); } }
PHP
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
<?phpif (isCgi()) $echo = "echoCGI"; // HTML outputelse $echo = "echoCLI"; // Text output ReadMICR("your_image_filename", 1); function ReadMICR($fileName, $page) { global $echo; $echo ("MICR in FILE: " . $fileName . "\n"); try{ // Create reader $reader = new COM("ClearMicr.CcMicrReader"); // Set options as needed $emrfEnforceAbaParsing = 16; $emrfExtendedMicrSearch = 07; $reader->Flags = $emrfEnforceAbaParsing; $reader->Flags |= $emrfExtendedMicrSearch; // Open image $reader->Image->Open($fileName, $page); // Read Barcode $cnt = $reader->FindMICR(); // Process results for ($idx=1; $idx<=$cnt; $idx++) { $micr = $reader->MicrLine($idx); $echo(sprintf("\nDocument: %s DPI: %4.1f\n", $micr->DocumentType, $micr->Dpi)); DisplayMicrInfo($micr->Info); DisplayMicrInfo($micr->Routing); DisplayMicrInfo($micr->RoutingChecksum); $echo(sprintf("ABA Routing Number: %s%s\n", $micr->Routing->TextANSI, $micr->RoutingChecksum->TextANSI)); DisplayMicrInfo($micr->AuxOnUs); DisplayMicrInfo($micr->EPC); DisplayMicrInfo($micr->OnUs); DisplayMicrInfo($micr->Amount); DisplayMicrInfo($micr->Account); DisplayMicrInfo($micr->CheckNumber); // DisplayCharacters($micr); } } catch (Exception $e) { $echo("\n" . "Exceptiom in line " . $e->getLine()); $echo("\n" . $e->getMessage() . "\n"); $echo("\n" . $e->getTraceAsString() . "\n"); } } function DisplayMicrInfo($info) { global $echo; if (!$info->IsRead) return; $echo(sprintf("%-15s %s conf: %6.2f%% '%s' \n", $info->Name, $info->IsAbaCompliant ? "ABA" : " ", $info->Conf, $info->TextANSI)); } function DisplayCharacters($micr) { global $echo; $echo(sprintf("\n pos chr conf(%%) altchr conf(%%) dif(%%) \n")); $emftChr = 182; $emftChrAlt = 184; $var0 = new VARIANT(0); for ($pos = 1; $pos < 1000; $pos++) { $chr = $micr->GetObject($emftChr, $pos, $var0); $altchr = $micr->GetObject($emftChrAlt, $pos, $var0); if ($chr == NULL) break; $echo(sprintf(" %-3d %-2s %6.1f %-2s %6.1f %6.1f\n", $pos, $chr->TextANSI, $chr->Conf, $altchr->TextANSI, $altchr->Conf, $chr->Conf - $altchr->Conf)); } } function echoCGI($sin) { echo "<font face='Courier'>"; $sout = str_replace(" ", " ", $sin); $sout = nl2br($sout); echo $sout; echo "</font>"; } function echoCLI($sin) { echo $sin; } function isCgi() { return !empty($_SERVER['GATEWAY_INTERFACE']); } ?>
Delphi
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
uses: ... ClearMicr_TLB; procedure ReadMICR(const fileName: string; const page: integer); var reader: _CcMicrReader; cnt, idx: Integer; micr: ccMicr; s: string; CR, LF, CRLF: string; begin try try begin // Create reader reader:=CoCcMicrReader.Create; // Open image reader.Image.Open(fileName, page); // Read MICRs cnt := reader.FindMICR; // Process results for idx := 1 to cnt do begin CR := #13; LF := #10; CRLF := CR + LF; s := ''; micr := reader.MicrLine[idx]; s := s + CRLF + 'Document: ' + micr.DocumentType + ' DPI: ' + FloatToStrF(micr.Dpi, ffFixed, 4, 0) + CRLF; s := s + DisplayMicrInfo(micr.Info); s := s + DisplayMicrInfo(micr.Routing); s := s + DisplayMicrInfo(micr.RoutingChecksum); s := s + DisplayMicrInfo(micr.AuxOnUs); s := s + DisplayMicrInfo(micr.EPC); s := s + DisplayMicrInfo(micr.OnUs); s := s + DisplayMicrInfo(micr.Amount); s := s + DisplayMicrInfo(micr.Account); s := s + DisplayMicrInfo(micr.CheckNumber); s := s + DisplayCharacters(micr); ShowMessage (s) end end except on E:Exception do //Process errors ShowMessage(Format('Error:%s.File:%s', [E.Message,FileName])); end finally end end; function DisplayMicrInfo(info: ccMicrInfo): string; var s: string; CR, LF, CRLF: string; begin s := ''; CR := #13; LF := #10; CRLF := CR + LF; if (info.IsRead) Then begin s := s + info.Name + ' '; if (info.IsAbaCompliant) Then s := s + 'ABA '; s := s + FloatToStrF(info.Conf, ffFixed, 6, 2) + '%' + ' "' + info.TextANSI + '"' + CRLF; end; DisplayMicrInfo := s; end; function DisplayCharacters(micr: ccMicr): string; var s: string; CR, LF, CRLF: string; pos: integer; ch, altch: ccMicrInfo; vpos, v0: OleVariant; vemftChr, vemftChrAlt: ECmFieldType; begin s := ''; v0 := 0; CR := #13; LF := #10; CRLF := CR + LF; s := s + ' pos chr conf(%) altch conf(%) dif(%)' + CRLF; for pos := 1 To 999 do begin vemftChr := emftChr; vemftChrAlt := emftChrAlt; vpos := pos; ch := micr.GetObject(vemftChr, vpos, v0); altch := micr.GetObject(vemftChrAlt, vpos, v0); if (ch = nil) Then break; s := s + IntToStr(pos) + ' ' + ch.TextANSI + ' ' + FloatToStrF(ch.Conf, ffFixed, 6, 1) + ' ' + altch.TextANSI + ' ' + FloatToStrF(altch.Conf, ffFixed, 6, 1) + ' ' + FloatToStrF(ch.Conf - altch.Conf, ffFixed, 6, 1) + CRLF; end; DisplayCharacters := s; end;
VBScript/ASP
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
Sub ReadMicr(fileName, page) On Error Resume Next Dim reader, micr, emrfEnforceAbaParsing, emrfExtendedMicrSearch 'Create reader Set reader = CreateObject("ClearMicr.CcMicrReader") If Err.Number <> 0 Then WScript.Echo Err.Description : Exit Sub ' Set options as needed emrfEnforceAbaParsing = 16 emrfExtendedMicrSearch = 07 reader.Flags = emrfEnforceAbaParsing reader.Flags = reader.Flags or emrfExtendedMicrSearch ' Open image reader.Image.Open fileName, page If Err.Number <> 0 Then WScript.Echo Err.Description : Exit Sub ' Read Barcode cnt = reader.FindMICR If Err.Number <> 0 Then WScript.Echo Err.Description : Exit Sub ' Process results For idx = 1 To cnt s = "" Set micr = reader.MicrLine(idx) If Err.Number <> 0 Then WScript.Echo Err.Description : Exit Sub s = s + vbCrLf + "Document: " + " DPI: " + CStr(micr.Dpi) + vbCrLf s = s + DisplayMicrInfo(micr.Info) s = s + DisplayMicrInfo(micr.Routing) s = s + DisplayMicrInfo(micr.RoutingChecksum) s = s + "ABA Routing Number: " + micr.Routing.TextANSI + micr.RoutingChecksum.TextANSI + vbCrLf s = s + DisplayMicrInfo(micr.AuxOnUs) s = s + DisplayMicrInfo(micr.EPC) s = s + DisplayMicrInfo(micr.OnUs) s = s + DisplayMicrInfo(micr.Amount) s = s + DisplayMicrInfo(micr.Account) s = s + DisplayMicrInfo(micr.CheckNumber) WScript.Echo s Next If cnt = 0 Then WScript.Echo "No MICR found" End Sub Function DisplayMicrInfo(info) s = "" If info.IsRead Then s = s + info.Name + " " If (info.IsAbaCompliant) Then s = s + "ABA " s = s + FormatNumber(info.Conf, 1) + "%" + " '" + info.TextANSI + "'" + vbCrLf End If DisplayMicrInfo = sEnd Function
Recommended practices
Image resolution
It is recommended to scan checks with resolution of at least 100 dpi grayscale or 200 dpi bitonal.
The resolution reference value stored in the file should be the actual scanning resolution. . It is often the case that JPEG compressed check images carry an incorrect resolution tag. JPEG file resolution is frequently set to a default value of 72dpi or 96 dpi, when the actual scanning resolution might be 200 dpi. If the actual scanning resolution is known, but is incorrectly set in the file, then assign the correct resolution values to CcMicrReader.Image.HorztDpi
and CcMicrReader.Image.VertDpi.
Camera images (including mobile phones) do not have correct resolution property. To read MICR from such images, set the emrfExtendedMicrSearch flag in CcMicrReader.Flags
. To read only the bottom MICR line set CcMicrReader.MaxMicrCount
to 1
MICR Line Location and orientation
CcMicrReader.FindMICR()
method expects the MICR line to be located at the bottom of the an image and fairly horizontal (with respect to the image edge)
If location and/or orientation of MICR line is arbitrary use CcMicrReader.ExtractCheck()
method to read MICR. This method also obtains check portion of an image in the correct orientation. The location of a check portion in the original document is available in CcMicr.Document
properties: Top, Left, Right, Bottom
Multiple MICR lines
An Image may contain multiple MICR lines. e.g. IRD image, check image with coupon, or corrections strips, or multiple checks on one image.
CcMicrReader.FindMICR()
reads multiple lines ordered from bottom up.
To read only the bottom MICR line set CcMicrReader.MaxMicrCount
to 1
Since the check image portion of IRD (substitute check) may be scaled, its MICR resolution is not known. To read the check MICR from an IRD:
- Scan at higher resolution e.g. 150 dpi grayscale 300 dpi bitonal to maintain quality of this MICR line
- Set emrfExtendedMicrSearch flag in
CcMicrReader.Flags
. to compensate for unknown scale factor
ABA and Non-US checks
CcMicrReader reads E-13B MICR fonts as defined in X9.100-20. It does not read CMC-7 fonts.
To enforce compliance X9.100-160 (formerly X9.13) set emrfEnforceAbaParsing flag in CcMicrReader.Flags
. If flag is not set it is possible to read Non-US checks. Parsing of individual fields is performed so long as the format of the MICR line resembles the ABA format. However the application can always perform its own parsing if needed
Routing number
The routing number identifies the issuing bank. In US it is a 9 digit number consisting of 8 digit CcMicr.Routing
and 1 digit CcMicr.RoutingChecksum
. If the checksum is correct, then the confidence of the routing number is 100%
To obtain 9 digit routing concatenate CcMicr.Routing.TextANSI
and CcMicr.RoutingChecksum.TextANSI
Text formats
Text value of MICR line and individual fields can be obtained is the following formats:
CcMicrInfo.TextANSI
- Fields are formatted according X9.100-180 (formerly X9.37)
Symbols: Routing: #, On-Us: / , Dash: -, Amount: $, Can’t Read: *CcMicrInfo.TextRaw -
All MICR characters are returned
Symbols: Routing: T, On-Us: U , Dash: D, Amount: A, Can’t Read: ?, Space: _CcMicrInfo.TextPacked -
Same asCcMicrInfo.TextRaw
except "space" is removed
Poor quality image
If image is poor quality and MICR line is not read, try to set emrfExtendedMicrSearch flag in CcMicrReader.Flags
. This activates a slower but more thorough MICR reading algorithm.
Individual characters of MICR line can be damaged (e.g. by handwriting) or by poor quality. Examples show how to obtain the value and confidence properties of the main (ECmFieldType.emftChr
) and the alternative (ECmFieldType.emftChrAlt
) character in every MICR line position. If confidence difference between main and alternative values is less than 15% it is possible that a substitution error has occurred.
Recognition speed
Using emrfExtendedMicrSearch flag in CcMicrReader.Flag
improves reading of camera and poor quality images. However it can make reading significantly slower. To improve recognition speed set CcMicrReader.MaxMicrCount
to 1 in case your images have at most one MICR line.
Using ClearImage Repair and Tools before reading MICR
It might be required to pre-process image before reading MICR using CiRepair
and CiTools
class methods. In such cases use CcMicrReader.Ci
object to create objects of these classes. For example:
CiRepair repair = reader.Ci.CreateRepair()