Programming with LEADTOOLS .NET OCR

The LEADTOOLS OCR Library provides methods for incorporating optical character recognition (OCR) technology into an application. OCR is used to process bitmap document images into text.

After the LEADTOOLS .NET OCR toolkit is installed to the system, programming with LEADTOOLS OCR can begin. Note that OCR features must be unlocked before the OCR properties, methods, and events can be used. For more information about unlocking LEAD features, refer to Unlocking Special LEAD Features.

To start using LEADTOOLS for .NET OCR in your application, add references to the Leadtools.Ocr.dll and Leadtools.Document.Writer.dll assemblies in your .NET application. These assemblies contain the various interfaces, classes, structures, and delegates used to program with LEADTOOLS OCR.

The code that interfaces with the engine is stored in a separate assembly that will be loaded dynamically after an instance of the IOcrEngine interface is created. Hence, be sure the engine assembly used resides next to the Leadtools.Ocr.dll assembly. You can add the engine assembly as a reference to your project—if desired—to automatically detect dependencies, even though this is not required by LEADTOOLS.

LEADTOOLS provides methods to:

Using the OCR Engine

LEADTOOLS uses an OCR handle to interact with the OCR engine and the OCR document containing the list of pages. The OCR handle is a communication session between LEADTOOLS OCR and an OCR engine installed on the system. This OCR handle is an internal structure that contains all the necessary information for recognition, getting and setting information, and text verification.

Outline of General Steps of Recognition

  1. Select the engine type you wish to use and create an instance of the IOcrEngine interface. For more information, refer to Creating an OCR Engine Instance.
  2. Start up the OCR Engine with the IOcrEngine.Startup method. For more information, refer to Starting and Shutting down the Engine.
  3. Optional. If saving is required, establish an OCR document with one or more pages. For more information, refer to Working with OCR Pages.
  4. Optional. Establish zones on the page(s), either manually or automatically. (This is optional. A page can be recognized with or without zones.) For more information, refer to Working with OCR Zones.
  5. Optional. Set the active languages to be used by the OCR engine. (The default language is English). For more information, refer to Working with OCR Languages.
  6. Optional. Set the properties for spell-checking. For more information, refer to OCR Spell Language Dictionaries.
  7. Optional. Set any special recognition module options. This is required only if the page contains zones, which can be created either automatically or manually. For more information, refer to Recognizing OCR Pages and Using OMR in LEADTOOLS .NET OCR.
  8. Recognize. For more information, refer to Recognizing OCR Pages.
  9. Optional. Save the recognition results, if desired. Results can be saved to either a file or to memory. For more information, refer to Recognizing OCR Pages.
  10. Shut down the OCR engine when finished. For more information, refer to Starting and Shutting down the Engine.

Steps 4, 5, 6 and 7 can be done pretty much in any order, as long as the steps are carried out after starting up the OCR engine and before recognizing a page.

For more information on the engine assemblies, refer to OcrEngineType and Files To Be Included With Your Application .

Ways the LEADTOOLS OCR Engine can be Used

Code Examples

C#
VB

C#

// Assuming you added "using Leadtools.Codecs;", "using Leadtools.Ocr;" and "using Leadtools.Document.Writer;" at the beginning of this class 
// *** Step 1: Specify the engine type and create an instance of the IOcrEngine interface. 
             
// This example will use the LEADTOOLS OCR Module - LEAD Engine and use it in the same process 
IOcrEngine ocrEngine = OcrEngineManager.CreateEngine(OcrEngineType.LEAD); 
             
// *** Step 2: Start up the engine. 
             
// Use the default parameters 
ocrEngine.Startup(null, null, null, @"C:\LEADTOOLS23\Bin\Common\OcrLEADRuntime"); 
             
// *** Step 3: Create an OCR document with one or more pages. 
             
IOcrDocument ocrDocument = ocrEngine.DocumentManager.CreateDocument(); 
              
// Add all the pages of a multipage TIF image to the document 
ocrDocument.Pages.AddPages(@"C:\LEADTOOLS23\Resources\Images\Ocr.tif", 1, -1, null); 
             
// *** Step 4: (Optional) Establish zones on the page(s), either manually or automatically 
             
// Automatic zoning 
ocrDocument.Pages.AutoZone(null); 
             
// *** Step 5: (Optional) Set the active languages to be used by the OCR engine 
             
// Enable both the English and German languages 
ocrEngine.LanguageManager.EnableLanguages(new string[] { "en", "de" }); 
             
// *** Step 6: (Optional) Set the spell checking engine 
             
// Enable the spell-checking system 
ocrEngine.SpellCheckManager.SpellCheckEngine = OcrSpellCheckEngine.Native; 
             
// *** Step 7: (Optional) Set any special recognition module options 
             
// Set the zoning method for the first zone in the first page to be Graphic so it will not be recognized 
OcrZone ocrZone = ocrDocument.Pages[0].Zones[0]; 
ocrZone.ZoneType = OcrZoneType.Graphic; 
ocrDocument.Pages[0].Zones[0] = ocrZone; 
             
// *** Step 8: Recognize 
             
ocrDocument.Pages.Recognize(null); 
             
// *** Step 9: Save recognition results 
             
// Save the results to a PDF file 
ocrDocument.Save(@"C:\LEADTOOLS23\Resources\Images\Document.pdf", DocumentFormat.Pdf, null); 
ocrDocument.Dispose(); 
             
// *** Step 10: Shut down the OCR engine when finished 
ocrEngine.Shutdown(); 
ocrEngine.Dispose(); 

VB

' Assuming you added "Imports Leadtools.Ocr" and "Imports Leadtools.Document.Writer" at the beginning of this class 
' *** Step 1: Specify the engine type and create an instance of the IOcrEngine interface 
' This example will use the LEADTOOLS OCR Module - LEAD Engine and use it in the same process 
Dim ocrEngine As IOcrEngine = OcrEngineManager.CreateEngine(OcrEngineType.LEAD) 
             
' *** Step 2: Start up the engine. 
             
' Use the default parameters 
ocrEngine.Startup(Nothing, Nothing, Nothing, "C:\LEADTOOLS23\Bin\Common\OcrLEADRuntime") 
             
' *** Step 3: Create an OCR document with one or more pages 
             
Dim ocrDocument As IOcrDocument = ocrEngine.DocumentManager.CreateDocument() 
             
' Add all the pages of a multipage TIF image to the document 
ocrDocument.Pages.AddPages("C:\LEADTOOLS23\Resources\Images\Ocr.tif", 1, -1, Nothing) 
             
' *** Step 4: (Optional) Establish zones on the page(s), either manually or automatically 
             
' Automatic zoning 
ocrDocument.Pages.AutoZone(Nothing) 
             
' *** Step 5: (Optional) Set the active languages to be used by the OCR engine 
             
' Enable both the English and the German languages 
ocrEngine.LanguageManager.EnableLanguages(New String() {"en", "de"}) 
             
' *** Step 6: (Optional) Set the spell-checking engine 
' Enable the spell checking engine 
ocrEngine.SpellCheckManager.SpellCheckEngine = OcrSpellCheckEngine.Native 
             
' *** Step 7: (Optional) Set any special recognition module options 
             
' Change the zoning method for the first zone in the first page to be Graphics so it will not be recognized 
Dim ocrZone As OcrZone = ocrDocument.Pages(0).Zones(0) 
ocrZone.ZoneType = OcrZoneType.Graphics 
ocrDocument.Pages(0).Zones(0) = ocrZone 
             
' *** Step 8: Recognize the document 
             
ocrDocument.Pages.Recognize(Nothing) 
             
            ' *** Step 9: Save the recognition results 
             
            ' Save the results to a PDF file 
ocrDocument.Save("C:\LEADTOOLS23\Resources\Images\Document.pdf", DocumentFormat.Pdf, Nothing) 
ocrDocument.Dispose() 
             
' *** Step 10: Shut down the OCR engine when finished 
ocrEngine.Shutdown() 
ocrEngine.Dispose() 

The following examples demonstrate some of the different ways the LEADTOOLS OCR engine can be used.

Using IOcrPage

OCR an image file (or LEADTOOLS RasterImage object) and obtain the text with optional formatting and position information. In this mode, an IOcrDocument object is not needed since the result is not going to be saved. Use the IOcrEngine.CreatePage method to quickly create an IOcrPage from the RasterImage directly: call the necessary method (such as IOcrPage.Recognize) and then obtain the text directly using IOcrPage.GetText or IOcrPage.GetRecognizedCharacters.

Note: This mode is supported only by the LEADTOOLS OCR Module - LEAD Engine. Calling IOcrEngine.CreatePage using any other OCR engine will result in an exception being thrown.

The following example uses an OCR page without a document.

C#
VB

C#

// Create the engine instance 
using (IOcrEngine ocrEngine = OcrEngineManager.CreateEngine(OcrEngineType.LEAD)) 
{ 
   // Start up the engine 
   ocrEngine.Startup(null, null, null, @"C:\LEADTOOLS23\Bin\Common\OcrLEADRuntime"); 
              
   // Load the first page as a RasterImage 
   RasterImage rasterImage = ocrEngine.RasterCodecsInstance.Load(@"C:\LEADTOOLS23\Resources\Images\Ocr.tif", 1); 
              
   // Create an OCR page from this image, transferring ownership of the RasterImage object 
   using (IOcrPage ocrPage = ocrEngine.CreatePage(rasterImage, OcrImageSharingMode.AutoDispose)) 
   { 
      // Recognize the page 
      ocrPage.Recognize(null); 
              
      // Show the text of all zones 
      for (int zoneIndex = 0; zoneIndex < ocrPage.Zones.Count; zoneIndex++) 
      { 
         string text = ocrPage.GetText(zoneIndex); 
         Console.WriteLine(text); 
      } 
   } 
              
   // The engine will automatically shut down when Dispose is called 
} 

VB

' Create the engine instance 
Using ocrEngine As IOcrEngine = OcrEngineManager.CreateEngine(OcrEngineType.LEAD) 
   ' Start up the engine 
   ocrEngine.Startup(Nothing, Nothing, Nothing, "C:\LEADTOOLS23\Bin\Common\OcrLEADRuntime") 
              
   ' Load the first page as a RasterImage 
   Dim rasterImage As RasterImage = ocrEngine.RasterCodecsInstance.Load("C:\LEADTOOLS23\Resources\Images\Ocr.tif", 1) 
              
   ' Create an OCR page from this image, transferring ownership of the RasterImage object 
   Using ocrPage As IOcrPage = ocrEngine.CreatePage(RasterImage, OcrImageSharingMode.AutoDispose) 
      ' Recognize the page 
      ocrPage.Recognize(Nothing) 
              
      ' Show the text in all zones 
      For zoneIndex As Integer = 0 To ocrPage.Zones.Count - 1 
         Dim text As String = ocrPage.GetText(zoneIndex) 
         Console.WriteLine(text) 
      Next 
   End Using 
              
   ' The engine will automatically shut down when Dispose is called 
End Using 

Using IOcrDocument

Saving OCR results to a final document such as PDF or DOCX requires an instance of IOcrDocument. One or more OCR pages can be added to the document and then the various Save methods can be called to create the final document.

IOcrDocument can be used in two ways:

Memory-Based Documents

In memory-based mode, the OCR pages are required to be in memory before saving. This is not recommended when the document has a large number of pages and either a file-based document or the LEADTOOLS Temporary file format DocumentFormat.Ltd is required.

In memory-based IOcrDocument, the IOcrPageCollection holds the pages. Any or all of the pages can be recognized at any time and pages can be added or removed at will.

The following example uses a memory-based document to create a multipage PDF file. Note how all the pages are kept in memory during the save operation.

C#
VB

C#

// Create the engine instance 
using (IOcrEngine ocrEngine = OcrEngineManager.CreateEngine(OcrEngineType.LEAD)) 
{ 
   // Start up the engine 
   ocrEngine.Startup(null, null, null, @"C:\LEADTOOLS23\Bin\Common\OcrLEADRuntime"); 
              
   // Create the OCR document in memory 
   using (IOcrDocument ocrDocument = ocrEngine.DocumentManager.CreateDocument(null, OcrCreateDocumentOptions.InMemory)) 
   { 
      string imageFile = @"C:\LEADTOOLS23\Resources\Images\Ocr.tif"; 
             
      // Add all the pages to the document 
      ocrDocument.Pages.AddPages(imageFile, 1, -1, null); 
              
      // Recognize all the pages 
      ocrDocument.Pages.Recognize(null); 
              
      // Save the recognition results in PDF format 
      ocrDocument.Save(@"C:\LEADTOOLS23\Resources\Images\Document.pdf", DocumentFormat.Pdf, null); 
   } 
} 

VB

' Create the engine instance 
Using ocrEngine As IOcrEngine = OcrEngineManager.CreateEngine(OcrEngineType.LEAD) 
   ' Start up the engine 
   ocrEngine.Startup(Nothing, Nothing, Nothing, "C:\LEADTOOLS23\Bin\Common\OcrLEADRuntime") 
              
   ' Create the OCR document in memory 
   Using ocrDocument As IOcrDocument = ocrEngine.DocumentManager.CreateDocument(Nothing, OcrCreateDocumentOptions.InMemory) 
      Dim imageFile As String = "C:\LEADTOOLS23\Resources\Images\Ocr.tif" 
              
      ' Add all the pages to the document 
      ocrDocument.Pages.AddPages(imageFile, 1, -1, Nothing) 
              
      ' Recognize all the pages 
      ocrDocument.Pages.Recognize(Nothing) 
              
      ' Save the recognition results in PDF format 
      ocrDocument.Save("C:\LEADTOOLS23\Resources\Images\Document.pdf", DocumentFormat.Pdf, Nothing) 
   End Using 
End Using 

File-Based Documents

In file-based document mode, OCR pages are not required to be in memory before saving. This mode is best when the document has a large number of pages.

In file-based IOcrDocument mode, the IOcrPageCollection stores only views of the pages. When a page is added, a snapshot of the current recognition data is saved into the document. This data cannot be modified any more and the page is no longer needed. Pages must be recognized before they are added to the document and pages can only be added. They cannot be removed.

The following example uses a file-based document to create a multipage PDF file. Notice that the pages are disposed after they are recognized and are not required during the save operation.

C#
VB

C#

// Create the engine instance 
using (IOcrEngine ocrEngine = OcrEngineManager.CreateEngine(OcrEngineType.LEAD)) 
{ 
   // Start up the engine 
   ocrEngine.Startup(null, null, null, @"C:\LEADTOOLS23\Bin\Common\OcrLEADRuntime"); 
              
   // Create a file-based OCR document 
   using (IOcrDocument ocrDocument = ocrEngine.DocumentManager.CreateDocument(null, OcrCreateDocumentOptions.AutoDeleteFile)) 
   { 
      string imageFile = @"C:\LEADTOOLS23\Resources\Images\Ocr.tif"; 
             
      // Get the number of pages in the document 
      int pageCount = ocrEngine.RasterCodecsInstance.GetTotalPages(imageFile); 
             
      // Create a page 
      for (int page = 1; page <= pageCount; page++) 
      { 
         // Load a RasterImage 
         RasterImage rasterImage = ocrEngine.RasterCodecsInstance.Load(imageFile, page); 
              
         // Create an OCR page from this image, transferring ownership of the RasterImage object 
         using (IOcrPage ocrPage = ocrEngine.CreatePage(rasterImage, OcrImageSharingMode.AutoDispose)) 
         { 
            // Recognize the page 
            ocrPage.Recognize(null); 
              
            // Add it to the document 
            ocrDocument.Pages.Add(ocrPage); 
              
            // Page will be disposed here and its memory freed 
         } 
      } 
              
      // Save the recognition results in PDF format 
      ocrDocument.Save(@"C:\LEADTOOLS23\Resources\Images\Document.pdf", DocumentFormat.Pdf, null); 
   } 
} 

VB

' Create the engine instance 
Using ocrEngine As IOcrEngine = OcrEngineManager.CreateEngine(OcrEngineType.LEAD) 
   ' Start up the engine 
   ocrEngine.Startup(Nothing, Nothing, Nothing, "C:\LEADTOOLS23\Bin\Common\OcrLEADRuntime") 
              
   ' Create a file-based OCR document 
   Using ocrDocument As IOcrDocument = ocrEngine.DocumentManager.CreateDocument(Nothing, OcrCreateDocumentOptions.AutoDeleteFile) 
      Dim imageFile As String = "C:\LEADTOOLS23\Resources\Images\Ocr.tif" 
             
      ' Get the number of pages in the document 
      Dim pageCount As Integer = ocrEngine.RasterCodecsInstance.GetTotalPages(imageFile) 
             
      ' Create a page 
      For page As Integer = 1 To pageCount 
         ' Load a RasterImage 
         Dim rasterImage As RasterImage = ocrEngine.RasterCodecsInstance.Load(imageFile, page) 
              
         ' Create an OCR page from this image, transferring ownership of the RasterImage object 
         Using ocrPage As IOcrPage = ocrEngine.CreatePage(rasterImage, OcrImageSharingMode.AutoDispose) 
            ' Recognize the page 
            ocrPage.Recognize(Nothing) 
              
            ' Add it to the document 
            ocrDocument.Pages.Add(ocrPage) 
              
            ' Page will be disposed here and its memory freed 
         End Using 
      Next 
              
      ' Save the recognition results in PDF format 
         ocrDocument.Save(@"C:\LEADTOOLS23\Resources\Images\Document.pdf", DocumentFormat.Pdf, Nothing) 
   End Using 
End Using 

File-based documents can also be saved and re-loaded to continue adding pages, or to convert it to the final document format at a later time. The following example shows how to do this.

C#
VB

C#

private static void Test4() 
{ 
   // Create the engine instance 
   IOcrEngine ocrEngine = OcrEngineManager.CreateEngine(OcrEngineType.LEAD); 
   // Start up the engine 
   ocrEngine.Startup(null, null, null, @"C:\LEADTOOLS23\Bin\Common\OcrLEADRuntime"); 
             
   string imageFile1 = @"C:\LEADTOOLS23\Resources\Images\Ocr1.tif"; 
   string imageFile2 = @"C:\LEADTOOLS23\Resources\Images\Ocr2.tif"; 
             
   // Create a file-based OCR document 
   // Pass a file name (the name will be re-used) and tell the document to not delete it 
   string documentFile = @"C:\LEADTOOLS23\Resources\Images\document.bin"; 
   using (IOcrDocument ocrDocument = ocrEngine.DocumentManager.CreateDocument(documentFile, OcrCreateDocumentOptions.None)) 
   { 
      // Verify the document does not have any pages 
      System.Diagnostics.Debug.Assert(ocrDocument.Pages.Count == 0); 
             
      // Add a page 
      RasterImage rasterImage = ocrEngine.RasterCodecsInstance.Load(imageFile1, 1); 
      using (IOcrPage ocrPage = ocrEngine.CreatePage(rasterImage, OcrImageSharingMode.AutoDispose)) 
      { 
         ocrPage.Recognize(null); 
         ocrDocument.Pages.Add(ocrPage); 
      } 
             
      // Here the document is disposed but the file will not be deleted 
   } 
             
   // Re-load the document 
   using (IOcrDocument ocrDocument = ocrEngine.DocumentManager.CreateDocument(documentFile, OcrCreateDocumentOptions.LoadExisting)) 
   { 
      // Verify the document has one page 
      System.Diagnostics.Debug.Assert(ocrDocument.Pages.Count == 1); 
             
      // Add another page 
      RasterImage rasterImage = ocrEngine.RasterCodecsInstance.Load(imageFile2, 1); 
      using (IOcrPage ocrPage = ocrEngine.CreatePage(rasterImage, OcrImageSharingMode.AutoDispose)) 
      { 
         ocrPage.Recognize(null); 
         ocrDocument.Pages.Add(ocrPage); 
      } 
             
      // Verify that the document has 2 pages 
      System.Diagnostics.Debug.Assert(ocrDocument.Pages.Count == 2); 
             
      // Save the document 
      ocrDocument.Save(@"C:\LEADTOOLS23\Resources\Images\Document.pdf", DocumentFormat.Pdf, null); 
             
      // The result will be a PDF file with two pages 
   } 
             
   // Finally, delete the document file 
   System.IO.File.Delete(documentFile); 
   ocrEngine.Dispose(); 
} 

VB

' Create the engine instance 
Dim ocrEngine As IOcrEngine = OcrEngineManager.CreateEngine(OcrEngineType.LEAD) 
' Start up the engine 
ocrEngine.Startup(Nothing, Nothing, Nothing, "C:\LEADTOOLS23\Bin\Common\OcrLEADRuntime") 
             
Dim imageFile1 As String = "C:\LEADTOOLS23\Resources\Images\Ocr1.tif" 
Dim imageFile2 As String = "C:\LEADTOOLS23\Resources\Images\Ocr2.tif" 
             
' Create a file-based OCR document 
' Pass a file name (the name will be re-used) and tell the document to not delete it 
Dim documentFile As String = "C:\LEADTOOLS23\Resources\Images\document.bin" 
Using ocrDocument As IOcrDocument = ocrEngine.DocumentManager.CreateDocument(documentFile, OcrCreateDocumentOptions.None) 
   ' Verify the document does not have any pages 
   System.Diagnostics.Debug.Assert(ocrDocument.Pages.Count = 0) 
             
   ' Add a page 
   Dim rasterImage As RasterImage = ocrEngine.RasterCodecsInstance.Load(imageFile1, 1) 
   Using ocrPage As IOcrPage = ocrEngine.CreatePage(rasterImage, OcrImageSharingMode.AutoDispose) 
      ocrPage.Recognize(Nothing) 
      ocrDocument.Pages.Add(ocrPage) 
   End Using 
             
   ' Here the document is disposed but the file will not be deleted 
End Using 
             
' Re-load the document 
Using ocrDocument As IOcrDocument = ocrEngine.DocumentManager.CreateDocument(documentFile, OcrCreateDocumentOptions.LoadExisting) 
   ' Verify the document has one page 
   System.Diagnostics.Debug.Assert(ocrDocument.Pages.Count = 1) 
             
   ' Add another page 
   Dim rasterImage As RasterImage = ocrEngine.RasterCodecsInstance.Load(imageFile2, 1) 
   Using ocrPage As IOcrPage = ocrEngine.CreatePage(rasterImage, OcrImageSharingMode.AutoDispose) 
      ocrPage.Recognize(Nothing) 
      ocrDocument.Pages.Add(ocrPage) 
   End Using 
             
   ' Verify that the document has 2 pages 
   System.Diagnostics.Debug.Assert(ocrDocument.Pages.Count = 2) 
             
   ' Save the document 
   ocrDocument.Save("C:\LEADTOOLS23\Resources\Images\Document.pdf", DocumentFormat.Pdf, Nothing) 
             
   ' The result will be a PDF file with two pages 
End Using 
             
' Finally, delete the document file 
System.IO.File.Delete(documentFile) 
             
ocrEngine.Dispose() 

Using IOcrAutoRecognizeManager

All of the previous techniques required low-level code to load a page, recognize it, and add it to a document. The LEADTOOLS OCR engines also support performing the same task above using the one shot "fire and forget" IOcrAutoRecognizeManager interface. In this high-level OCR, the input image is converted directly to the output format using the best options and just one method.

C#
VB

C#

// Create the engine instance 
using(IOcrEngine ocrEngine = OcrEngineManager.CreateEngine(OcrEngineType.LEAD)) 
{ 
   // Start up the engine 
   ocrEngine.Startup(null, null, null, @"C:\LEADTOOLS23\Bin\Common\OcrLEADRuntime"); 
             
   // Convert the multipage TIF image to a PDF document 
   ocrEngine.AutoRecognizeManager.Run( 
      @"C:\LEADTOOLS23\Resources\Images\Ocr.tif", 
      @"C:\LEADTOOLS23\Resources\Images\Document.pdf", 
      DocumentFormat.Pdf, 
      null, 
      null); 
} 

VB

' Create the engine instance 
Using ocrEngine As IOcrEngine = OcrEngineManager.CreateEngine(OcrEngineType.LEAD) 
   ' Start up the engine 
   ocrEngine.Startup(Nothing, Nothing, Nothing, "C:\LEADTOOLS23\Bin\Common\OcrLEADRuntime") 
             
   ' Convert the multipage TIF image to a PDF document 
   ocrEngine.AutoRecognizeManager.Run( _ 
      "C:\LEADTOOLS23\Resources\Images\Ocr.tif", _ 
      "C:\LEADTOOLS23\Resources\Images\Document.pdf", _ 
      DocumentFormat.Pdf, _ 
      Nothing, _ 
      Nothing) 
End Using 

See Also

Help Version 23.0.2024.8.27
Products | Support | Contact Us | Intellectual Property Notices
© 1991-2024 LEAD Technologies, Inc. All Rights Reserved.

LEADTOOLS Imaging, Medical, and Document
Products | Support | Contact Us | Intellectual Property Notices
© 1991-2023 LEAD Technologies, Inc. All Rights Reserved.